diff options
217 files changed, 5893 insertions, 1498 deletions
diff --git a/core/string/char_range.inc b/core/string/char_range.inc index 5dffe4f20d..b7d6bbdb61 100644 --- a/core/string/char_range.inc +++ b/core/string/char_range.inc @@ -1,5 +1,5 @@ /**************************************************************************/ -/* color_names.inc */ +/* char_range.inc */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -689,7 +689,6 @@ inline constexpr CharRange xid_start[] = { { 0x2ceb0, 0x2ebe0 }, { 0x2f800, 0x2fa1d }, { 0x30000, 0x3134a }, - { 0x0, 0x0 }, }; inline constexpr CharRange xid_continue[] = { @@ -1450,7 +1449,1316 @@ inline constexpr CharRange xid_continue[] = { { 0x2f800, 0x2fa1d }, { 0x30000, 0x3134a }, { 0xe0100, 0xe01ef }, - { 0x0, 0x0 }, +}; + +inline constexpr CharRange uppercase_letter[] = { + { 0x41, 0x5a }, + { 0xc0, 0xd6 }, + { 0xd8, 0xde }, + { 0x100, 0x100 }, + { 0x102, 0x102 }, + { 0x104, 0x104 }, + { 0x106, 0x106 }, + { 0x108, 0x108 }, + { 0x10a, 0x10a }, + { 0x10c, 0x10c }, + { 0x10e, 0x10e }, + { 0x110, 0x110 }, + { 0x112, 0x112 }, + { 0x114, 0x114 }, + { 0x116, 0x116 }, + { 0x118, 0x118 }, + { 0x11a, 0x11a }, + { 0x11c, 0x11c }, + { 0x11e, 0x11e }, + { 0x120, 0x120 }, + { 0x122, 0x122 }, + { 0x124, 0x124 }, + { 0x126, 0x126 }, + { 0x128, 0x128 }, + { 0x12a, 0x12a }, + { 0x12c, 0x12c }, + { 0x12e, 0x12e }, + { 0x130, 0x130 }, + { 0x132, 0x132 }, + { 0x134, 0x134 }, + { 0x136, 0x136 }, + { 0x139, 0x139 }, + { 0x13b, 0x13b }, + { 0x13d, 0x13d }, + { 0x13f, 0x13f }, + { 0x141, 0x141 }, + { 0x143, 0x143 }, + { 0x145, 0x145 }, + { 0x147, 0x147 }, + { 0x14a, 0x14a }, + { 0x14c, 0x14c }, + { 0x14e, 0x14e }, + { 0x150, 0x150 }, + { 0x152, 0x152 }, + { 0x154, 0x154 }, + { 0x156, 0x156 }, + { 0x158, 0x158 }, + { 0x15a, 0x15a }, + { 0x15c, 0x15c }, + { 0x15e, 0x15e }, + { 0x160, 0x160 }, + { 0x162, 0x162 }, + { 0x164, 0x164 }, + { 0x166, 0x166 }, + { 0x168, 0x168 }, + { 0x16a, 0x16a }, + { 0x16c, 0x16c }, + { 0x16e, 0x16e }, + { 0x170, 0x170 }, + { 0x172, 0x172 }, + { 0x174, 0x174 }, + { 0x176, 0x176 }, + { 0x178, 0x179 }, + { 0x17b, 0x17b }, + { 0x17d, 0x17d }, + { 0x181, 0x182 }, + { 0x184, 0x184 }, + { 0x186, 0x187 }, + { 0x189, 0x18b }, + { 0x18e, 0x191 }, + { 0x193, 0x194 }, + { 0x196, 0x198 }, + { 0x19c, 0x19d }, + { 0x19f, 0x1a0 }, + { 0x1a2, 0x1a2 }, + { 0x1a4, 0x1a4 }, + { 0x1a6, 0x1a7 }, + { 0x1a9, 0x1a9 }, + { 0x1ac, 0x1ac }, + { 0x1ae, 0x1af }, + { 0x1b1, 0x1b3 }, + { 0x1b5, 0x1b5 }, + { 0x1b7, 0x1b8 }, + { 0x1bc, 0x1bc }, + { 0x1c4, 0x1c4 }, + { 0x1c7, 0x1c7 }, + { 0x1ca, 0x1ca }, + { 0x1cd, 0x1cd }, + { 0x1cf, 0x1cf }, + { 0x1d1, 0x1d1 }, + { 0x1d3, 0x1d3 }, + { 0x1d5, 0x1d5 }, + { 0x1d7, 0x1d7 }, + { 0x1d9, 0x1d9 }, + { 0x1db, 0x1db }, + { 0x1de, 0x1de }, + { 0x1e0, 0x1e0 }, + { 0x1e2, 0x1e2 }, + { 0x1e4, 0x1e4 }, + { 0x1e6, 0x1e6 }, + { 0x1e8, 0x1e8 }, + { 0x1ea, 0x1ea }, + { 0x1ec, 0x1ec }, + { 0x1ee, 0x1ee }, + { 0x1f1, 0x1f1 }, + { 0x1f4, 0x1f4 }, + { 0x1f6, 0x1f8 }, + { 0x1fa, 0x1fa }, + { 0x1fc, 0x1fc }, + { 0x1fe, 0x1fe }, + { 0x200, 0x200 }, + { 0x202, 0x202 }, + { 0x204, 0x204 }, + { 0x206, 0x206 }, + { 0x208, 0x208 }, + { 0x20a, 0x20a }, + { 0x20c, 0x20c }, + { 0x20e, 0x20e }, + { 0x210, 0x210 }, + { 0x212, 0x212 }, + { 0x214, 0x214 }, + { 0x216, 0x216 }, + { 0x218, 0x218 }, + { 0x21a, 0x21a }, + { 0x21c, 0x21c }, + { 0x21e, 0x21e }, + { 0x220, 0x220 }, + { 0x222, 0x222 }, + { 0x224, 0x224 }, + { 0x226, 0x226 }, + { 0x228, 0x228 }, + { 0x22a, 0x22a }, + { 0x22c, 0x22c }, + { 0x22e, 0x22e }, + { 0x230, 0x230 }, + { 0x232, 0x232 }, + { 0x23a, 0x23b }, + { 0x23d, 0x23e }, + { 0x241, 0x241 }, + { 0x243, 0x246 }, + { 0x248, 0x248 }, + { 0x24a, 0x24a }, + { 0x24c, 0x24c }, + { 0x24e, 0x24e }, + { 0x370, 0x370 }, + { 0x372, 0x372 }, + { 0x376, 0x376 }, + { 0x37f, 0x37f }, + { 0x386, 0x386 }, + { 0x388, 0x38a }, + { 0x38c, 0x38c }, + { 0x38e, 0x38f }, + { 0x391, 0x3a1 }, + { 0x3a3, 0x3ab }, + { 0x3cf, 0x3cf }, + { 0x3d2, 0x3d4 }, + { 0x3d8, 0x3d8 }, + { 0x3da, 0x3da }, + { 0x3dc, 0x3dc }, + { 0x3de, 0x3de }, + { 0x3e0, 0x3e0 }, + { 0x3e2, 0x3e2 }, + { 0x3e4, 0x3e4 }, + { 0x3e6, 0x3e6 }, + { 0x3e8, 0x3e8 }, + { 0x3ea, 0x3ea }, + { 0x3ec, 0x3ec }, + { 0x3ee, 0x3ee }, + { 0x3f4, 0x3f4 }, + { 0x3f7, 0x3f7 }, + { 0x3f9, 0x3fa }, + { 0x3fd, 0x42f }, + { 0x460, 0x460 }, + { 0x462, 0x462 }, + { 0x464, 0x464 }, + { 0x466, 0x466 }, + { 0x468, 0x468 }, + { 0x46a, 0x46a }, + { 0x46c, 0x46c }, + { 0x46e, 0x46e }, + { 0x470, 0x470 }, + { 0x472, 0x472 }, + { 0x474, 0x474 }, + { 0x476, 0x476 }, + { 0x478, 0x478 }, + { 0x47a, 0x47a }, + { 0x47c, 0x47c }, + { 0x47e, 0x47e }, + { 0x480, 0x480 }, + { 0x48a, 0x48a }, + { 0x48c, 0x48c }, + { 0x48e, 0x48e }, + { 0x490, 0x490 }, + { 0x492, 0x492 }, + { 0x494, 0x494 }, + { 0x496, 0x496 }, + { 0x498, 0x498 }, + { 0x49a, 0x49a }, + { 0x49c, 0x49c }, + { 0x49e, 0x49e }, + { 0x4a0, 0x4a0 }, + { 0x4a2, 0x4a2 }, + { 0x4a4, 0x4a4 }, + { 0x4a6, 0x4a6 }, + { 0x4a8, 0x4a8 }, + { 0x4aa, 0x4aa }, + { 0x4ac, 0x4ac }, + { 0x4ae, 0x4ae }, + { 0x4b0, 0x4b0 }, + { 0x4b2, 0x4b2 }, + { 0x4b4, 0x4b4 }, + { 0x4b6, 0x4b6 }, + { 0x4b8, 0x4b8 }, + { 0x4ba, 0x4ba }, + { 0x4bc, 0x4bc }, + { 0x4be, 0x4be }, + { 0x4c0, 0x4c1 }, + { 0x4c3, 0x4c3 }, + { 0x4c5, 0x4c5 }, + { 0x4c7, 0x4c7 }, + { 0x4c9, 0x4c9 }, + { 0x4cb, 0x4cb }, + { 0x4cd, 0x4cd }, + { 0x4d0, 0x4d0 }, + { 0x4d2, 0x4d2 }, + { 0x4d4, 0x4d4 }, + { 0x4d6, 0x4d6 }, + { 0x4d8, 0x4d8 }, + { 0x4da, 0x4da }, + { 0x4dc, 0x4dc }, + { 0x4de, 0x4de }, + { 0x4e0, 0x4e0 }, + { 0x4e2, 0x4e2 }, + { 0x4e4, 0x4e4 }, + { 0x4e6, 0x4e6 }, + { 0x4e8, 0x4e8 }, + { 0x4ea, 0x4ea }, + { 0x4ec, 0x4ec }, + { 0x4ee, 0x4ee }, + { 0x4f0, 0x4f0 }, + { 0x4f2, 0x4f2 }, + { 0x4f4, 0x4f4 }, + { 0x4f6, 0x4f6 }, + { 0x4f8, 0x4f8 }, + { 0x4fa, 0x4fa }, + { 0x4fc, 0x4fc }, + { 0x4fe, 0x4fe }, + { 0x500, 0x500 }, + { 0x502, 0x502 }, + { 0x504, 0x504 }, + { 0x506, 0x506 }, + { 0x508, 0x508 }, + { 0x50a, 0x50a }, + { 0x50c, 0x50c }, + { 0x50e, 0x50e }, + { 0x510, 0x510 }, + { 0x512, 0x512 }, + { 0x514, 0x514 }, + { 0x516, 0x516 }, + { 0x518, 0x518 }, + { 0x51a, 0x51a }, + { 0x51c, 0x51c }, + { 0x51e, 0x51e }, + { 0x520, 0x520 }, + { 0x522, 0x522 }, + { 0x524, 0x524 }, + { 0x526, 0x526 }, + { 0x528, 0x528 }, + { 0x52a, 0x52a }, + { 0x52c, 0x52c }, + { 0x52e, 0x52e }, + { 0x531, 0x556 }, + { 0x10a0, 0x10c5 }, + { 0x10c7, 0x10c7 }, + { 0x10cd, 0x10cd }, + { 0x13a0, 0x13f5 }, + { 0x1c90, 0x1cba }, + { 0x1cbd, 0x1cbf }, + { 0x1e00, 0x1e00 }, + { 0x1e02, 0x1e02 }, + { 0x1e04, 0x1e04 }, + { 0x1e06, 0x1e06 }, + { 0x1e08, 0x1e08 }, + { 0x1e0a, 0x1e0a }, + { 0x1e0c, 0x1e0c }, + { 0x1e0e, 0x1e0e }, + { 0x1e10, 0x1e10 }, + { 0x1e12, 0x1e12 }, + { 0x1e14, 0x1e14 }, + { 0x1e16, 0x1e16 }, + { 0x1e18, 0x1e18 }, + { 0x1e1a, 0x1e1a }, + { 0x1e1c, 0x1e1c }, + { 0x1e1e, 0x1e1e }, + { 0x1e20, 0x1e20 }, + { 0x1e22, 0x1e22 }, + { 0x1e24, 0x1e24 }, + { 0x1e26, 0x1e26 }, + { 0x1e28, 0x1e28 }, + { 0x1e2a, 0x1e2a }, + { 0x1e2c, 0x1e2c }, + { 0x1e2e, 0x1e2e }, + { 0x1e30, 0x1e30 }, + { 0x1e32, 0x1e32 }, + { 0x1e34, 0x1e34 }, + { 0x1e36, 0x1e36 }, + { 0x1e38, 0x1e38 }, + { 0x1e3a, 0x1e3a }, + { 0x1e3c, 0x1e3c }, + { 0x1e3e, 0x1e3e }, + { 0x1e40, 0x1e40 }, + { 0x1e42, 0x1e42 }, + { 0x1e44, 0x1e44 }, + { 0x1e46, 0x1e46 }, + { 0x1e48, 0x1e48 }, + { 0x1e4a, 0x1e4a }, + { 0x1e4c, 0x1e4c }, + { 0x1e4e, 0x1e4e }, + { 0x1e50, 0x1e50 }, + { 0x1e52, 0x1e52 }, + { 0x1e54, 0x1e54 }, + { 0x1e56, 0x1e56 }, + { 0x1e58, 0x1e58 }, + { 0x1e5a, 0x1e5a }, + { 0x1e5c, 0x1e5c }, + { 0x1e5e, 0x1e5e }, + { 0x1e60, 0x1e60 }, + { 0x1e62, 0x1e62 }, + { 0x1e64, 0x1e64 }, + { 0x1e66, 0x1e66 }, + { 0x1e68, 0x1e68 }, + { 0x1e6a, 0x1e6a }, + { 0x1e6c, 0x1e6c }, + { 0x1e6e, 0x1e6e }, + { 0x1e70, 0x1e70 }, + { 0x1e72, 0x1e72 }, + { 0x1e74, 0x1e74 }, + { 0x1e76, 0x1e76 }, + { 0x1e78, 0x1e78 }, + { 0x1e7a, 0x1e7a }, + { 0x1e7c, 0x1e7c }, + { 0x1e7e, 0x1e7e }, + { 0x1e80, 0x1e80 }, + { 0x1e82, 0x1e82 }, + { 0x1e84, 0x1e84 }, + { 0x1e86, 0x1e86 }, + { 0x1e88, 0x1e88 }, + { 0x1e8a, 0x1e8a }, + { 0x1e8c, 0x1e8c }, + { 0x1e8e, 0x1e8e }, + { 0x1e90, 0x1e90 }, + { 0x1e92, 0x1e92 }, + { 0x1e94, 0x1e94 }, + { 0x1e9e, 0x1e9e }, + { 0x1ea0, 0x1ea0 }, + { 0x1ea2, 0x1ea2 }, + { 0x1ea4, 0x1ea4 }, + { 0x1ea6, 0x1ea6 }, + { 0x1ea8, 0x1ea8 }, + { 0x1eaa, 0x1eaa }, + { 0x1eac, 0x1eac }, + { 0x1eae, 0x1eae }, + { 0x1eb0, 0x1eb0 }, + { 0x1eb2, 0x1eb2 }, + { 0x1eb4, 0x1eb4 }, + { 0x1eb6, 0x1eb6 }, + { 0x1eb8, 0x1eb8 }, + { 0x1eba, 0x1eba }, + { 0x1ebc, 0x1ebc }, + { 0x1ebe, 0x1ebe }, + { 0x1ec0, 0x1ec0 }, + { 0x1ec2, 0x1ec2 }, + { 0x1ec4, 0x1ec4 }, + { 0x1ec6, 0x1ec6 }, + { 0x1ec8, 0x1ec8 }, + { 0x1eca, 0x1eca }, + { 0x1ecc, 0x1ecc }, + { 0x1ece, 0x1ece }, + { 0x1ed0, 0x1ed0 }, + { 0x1ed2, 0x1ed2 }, + { 0x1ed4, 0x1ed4 }, + { 0x1ed6, 0x1ed6 }, + { 0x1ed8, 0x1ed8 }, + { 0x1eda, 0x1eda }, + { 0x1edc, 0x1edc }, + { 0x1ede, 0x1ede }, + { 0x1ee0, 0x1ee0 }, + { 0x1ee2, 0x1ee2 }, + { 0x1ee4, 0x1ee4 }, + { 0x1ee6, 0x1ee6 }, + { 0x1ee8, 0x1ee8 }, + { 0x1eea, 0x1eea }, + { 0x1eec, 0x1eec }, + { 0x1eee, 0x1eee }, + { 0x1ef0, 0x1ef0 }, + { 0x1ef2, 0x1ef2 }, + { 0x1ef4, 0x1ef4 }, + { 0x1ef6, 0x1ef6 }, + { 0x1ef8, 0x1ef8 }, + { 0x1efa, 0x1efa }, + { 0x1efc, 0x1efc }, + { 0x1efe, 0x1efe }, + { 0x1f08, 0x1f0f }, + { 0x1f18, 0x1f1d }, + { 0x1f28, 0x1f2f }, + { 0x1f38, 0x1f3f }, + { 0x1f48, 0x1f4d }, + { 0x1f59, 0x1f59 }, + { 0x1f5b, 0x1f5b }, + { 0x1f5d, 0x1f5d }, + { 0x1f5f, 0x1f5f }, + { 0x1f68, 0x1f6f }, + { 0x1fb8, 0x1fbb }, + { 0x1fc8, 0x1fcb }, + { 0x1fd8, 0x1fdb }, + { 0x1fe8, 0x1fec }, + { 0x1ff8, 0x1ffb }, + { 0x2102, 0x2102 }, + { 0x2107, 0x2107 }, + { 0x210b, 0x210d }, + { 0x2110, 0x2112 }, + { 0x2115, 0x2115 }, + { 0x2119, 0x211d }, + { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, + { 0x2128, 0x2128 }, + { 0x212a, 0x212d }, + { 0x2130, 0x2133 }, + { 0x213e, 0x213f }, + { 0x2145, 0x2145 }, + { 0x2183, 0x2183 }, + { 0x2c00, 0x2c2f }, + { 0x2c60, 0x2c60 }, + { 0x2c62, 0x2c64 }, + { 0x2c67, 0x2c67 }, + { 0x2c69, 0x2c69 }, + { 0x2c6b, 0x2c6b }, + { 0x2c6d, 0x2c70 }, + { 0x2c72, 0x2c72 }, + { 0x2c75, 0x2c75 }, + { 0x2c7e, 0x2c80 }, + { 0x2c82, 0x2c82 }, + { 0x2c84, 0x2c84 }, + { 0x2c86, 0x2c86 }, + { 0x2c88, 0x2c88 }, + { 0x2c8a, 0x2c8a }, + { 0x2c8c, 0x2c8c }, + { 0x2c8e, 0x2c8e }, + { 0x2c90, 0x2c90 }, + { 0x2c92, 0x2c92 }, + { 0x2c94, 0x2c94 }, + { 0x2c96, 0x2c96 }, + { 0x2c98, 0x2c98 }, + { 0x2c9a, 0x2c9a }, + { 0x2c9c, 0x2c9c }, + { 0x2c9e, 0x2c9e }, + { 0x2ca0, 0x2ca0 }, + { 0x2ca2, 0x2ca2 }, + { 0x2ca4, 0x2ca4 }, + { 0x2ca6, 0x2ca6 }, + { 0x2ca8, 0x2ca8 }, + { 0x2caa, 0x2caa }, + { 0x2cac, 0x2cac }, + { 0x2cae, 0x2cae }, + { 0x2cb0, 0x2cb0 }, + { 0x2cb2, 0x2cb2 }, + { 0x2cb4, 0x2cb4 }, + { 0x2cb6, 0x2cb6 }, + { 0x2cb8, 0x2cb8 }, + { 0x2cba, 0x2cba }, + { 0x2cbc, 0x2cbc }, + { 0x2cbe, 0x2cbe }, + { 0x2cc0, 0x2cc0 }, + { 0x2cc2, 0x2cc2 }, + { 0x2cc4, 0x2cc4 }, + { 0x2cc6, 0x2cc6 }, + { 0x2cc8, 0x2cc8 }, + { 0x2cca, 0x2cca }, + { 0x2ccc, 0x2ccc }, + { 0x2cce, 0x2cce }, + { 0x2cd0, 0x2cd0 }, + { 0x2cd2, 0x2cd2 }, + { 0x2cd4, 0x2cd4 }, + { 0x2cd6, 0x2cd6 }, + { 0x2cd8, 0x2cd8 }, + { 0x2cda, 0x2cda }, + { 0x2cdc, 0x2cdc }, + { 0x2cde, 0x2cde }, + { 0x2ce0, 0x2ce0 }, + { 0x2ce2, 0x2ce2 }, + { 0x2ceb, 0x2ceb }, + { 0x2ced, 0x2ced }, + { 0x2cf2, 0x2cf2 }, + { 0xa640, 0xa640 }, + { 0xa642, 0xa642 }, + { 0xa644, 0xa644 }, + { 0xa646, 0xa646 }, + { 0xa648, 0xa648 }, + { 0xa64a, 0xa64a }, + { 0xa64c, 0xa64c }, + { 0xa64e, 0xa64e }, + { 0xa650, 0xa650 }, + { 0xa652, 0xa652 }, + { 0xa654, 0xa654 }, + { 0xa656, 0xa656 }, + { 0xa658, 0xa658 }, + { 0xa65a, 0xa65a }, + { 0xa65c, 0xa65c }, + { 0xa65e, 0xa65e }, + { 0xa660, 0xa660 }, + { 0xa662, 0xa662 }, + { 0xa664, 0xa664 }, + { 0xa666, 0xa666 }, + { 0xa668, 0xa668 }, + { 0xa66a, 0xa66a }, + { 0xa66c, 0xa66c }, + { 0xa680, 0xa680 }, + { 0xa682, 0xa682 }, + { 0xa684, 0xa684 }, + { 0xa686, 0xa686 }, + { 0xa688, 0xa688 }, + { 0xa68a, 0xa68a }, + { 0xa68c, 0xa68c }, + { 0xa68e, 0xa68e }, + { 0xa690, 0xa690 }, + { 0xa692, 0xa692 }, + { 0xa694, 0xa694 }, + { 0xa696, 0xa696 }, + { 0xa698, 0xa698 }, + { 0xa69a, 0xa69a }, + { 0xa722, 0xa722 }, + { 0xa724, 0xa724 }, + { 0xa726, 0xa726 }, + { 0xa728, 0xa728 }, + { 0xa72a, 0xa72a }, + { 0xa72c, 0xa72c }, + { 0xa72e, 0xa72e }, + { 0xa732, 0xa732 }, + { 0xa734, 0xa734 }, + { 0xa736, 0xa736 }, + { 0xa738, 0xa738 }, + { 0xa73a, 0xa73a }, + { 0xa73c, 0xa73c }, + { 0xa73e, 0xa73e }, + { 0xa740, 0xa740 }, + { 0xa742, 0xa742 }, + { 0xa744, 0xa744 }, + { 0xa746, 0xa746 }, + { 0xa748, 0xa748 }, + { 0xa74a, 0xa74a }, + { 0xa74c, 0xa74c }, + { 0xa74e, 0xa74e }, + { 0xa750, 0xa750 }, + { 0xa752, 0xa752 }, + { 0xa754, 0xa754 }, + { 0xa756, 0xa756 }, + { 0xa758, 0xa758 }, + { 0xa75a, 0xa75a }, + { 0xa75c, 0xa75c }, + { 0xa75e, 0xa75e }, + { 0xa760, 0xa760 }, + { 0xa762, 0xa762 }, + { 0xa764, 0xa764 }, + { 0xa766, 0xa766 }, + { 0xa768, 0xa768 }, + { 0xa76a, 0xa76a }, + { 0xa76c, 0xa76c }, + { 0xa76e, 0xa76e }, + { 0xa779, 0xa779 }, + { 0xa77b, 0xa77b }, + { 0xa77d, 0xa77e }, + { 0xa780, 0xa780 }, + { 0xa782, 0xa782 }, + { 0xa784, 0xa784 }, + { 0xa786, 0xa786 }, + { 0xa78b, 0xa78b }, + { 0xa78d, 0xa78d }, + { 0xa790, 0xa790 }, + { 0xa792, 0xa792 }, + { 0xa796, 0xa796 }, + { 0xa798, 0xa798 }, + { 0xa79a, 0xa79a }, + { 0xa79c, 0xa79c }, + { 0xa79e, 0xa79e }, + { 0xa7a0, 0xa7a0 }, + { 0xa7a2, 0xa7a2 }, + { 0xa7a4, 0xa7a4 }, + { 0xa7a6, 0xa7a6 }, + { 0xa7a8, 0xa7a8 }, + { 0xa7aa, 0xa7ae }, + { 0xa7b0, 0xa7b4 }, + { 0xa7b6, 0xa7b6 }, + { 0xa7b8, 0xa7b8 }, + { 0xa7ba, 0xa7ba }, + { 0xa7bc, 0xa7bc }, + { 0xa7be, 0xa7be }, + { 0xa7c0, 0xa7c0 }, + { 0xa7c2, 0xa7c2 }, + { 0xa7c4, 0xa7c7 }, + { 0xa7c9, 0xa7c9 }, + { 0xa7d0, 0xa7d0 }, + { 0xa7d6, 0xa7d6 }, + { 0xa7d8, 0xa7d8 }, + { 0xa7f5, 0xa7f5 }, + { 0xff21, 0xff3a }, + { 0x10400, 0x10427 }, + { 0x104b0, 0x104d3 }, + { 0x10570, 0x1057a }, + { 0x1057c, 0x1058a }, + { 0x1058c, 0x10592 }, + { 0x10594, 0x10595 }, + { 0x10c80, 0x10cb2 }, + { 0x118a0, 0x118bf }, + { 0x16e40, 0x16e5f }, + { 0x1d400, 0x1d419 }, + { 0x1d434, 0x1d44d }, + { 0x1d468, 0x1d481 }, + { 0x1d49c, 0x1d49c }, + { 0x1d49e, 0x1d49f }, + { 0x1d4a2, 0x1d4a2 }, + { 0x1d4a5, 0x1d4a6 }, + { 0x1d4a9, 0x1d4ac }, + { 0x1d4ae, 0x1d4b5 }, + { 0x1d4d0, 0x1d4e9 }, + { 0x1d504, 0x1d505 }, + { 0x1d507, 0x1d50a }, + { 0x1d50d, 0x1d514 }, + { 0x1d516, 0x1d51c }, + { 0x1d538, 0x1d539 }, + { 0x1d53b, 0x1d53e }, + { 0x1d540, 0x1d544 }, + { 0x1d546, 0x1d546 }, + { 0x1d54a, 0x1d550 }, + { 0x1d56c, 0x1d585 }, + { 0x1d5a0, 0x1d5b9 }, + { 0x1d5d4, 0x1d5ed }, + { 0x1d608, 0x1d621 }, + { 0x1d63c, 0x1d655 }, + { 0x1d670, 0x1d689 }, + { 0x1d6a8, 0x1d6c0 }, + { 0x1d6e2, 0x1d6fa }, + { 0x1d71c, 0x1d734 }, + { 0x1d756, 0x1d76e }, + { 0x1d790, 0x1d7a8 }, + { 0x1d7ca, 0x1d7ca }, + { 0x1e900, 0x1e921 }, +}; + +inline constexpr CharRange lowercase_letter[] = { + { 0x61, 0x7a }, + { 0xb5, 0xb5 }, + { 0xdf, 0xf6 }, + { 0xf8, 0xff }, + { 0x101, 0x101 }, + { 0x103, 0x103 }, + { 0x105, 0x105 }, + { 0x107, 0x107 }, + { 0x109, 0x109 }, + { 0x10b, 0x10b }, + { 0x10d, 0x10d }, + { 0x10f, 0x10f }, + { 0x111, 0x111 }, + { 0x113, 0x113 }, + { 0x115, 0x115 }, + { 0x117, 0x117 }, + { 0x119, 0x119 }, + { 0x11b, 0x11b }, + { 0x11d, 0x11d }, + { 0x11f, 0x11f }, + { 0x121, 0x121 }, + { 0x123, 0x123 }, + { 0x125, 0x125 }, + { 0x127, 0x127 }, + { 0x129, 0x129 }, + { 0x12b, 0x12b }, + { 0x12d, 0x12d }, + { 0x12f, 0x12f }, + { 0x131, 0x131 }, + { 0x133, 0x133 }, + { 0x135, 0x135 }, + { 0x137, 0x138 }, + { 0x13a, 0x13a }, + { 0x13c, 0x13c }, + { 0x13e, 0x13e }, + { 0x140, 0x140 }, + { 0x142, 0x142 }, + { 0x144, 0x144 }, + { 0x146, 0x146 }, + { 0x148, 0x149 }, + { 0x14b, 0x14b }, + { 0x14d, 0x14d }, + { 0x14f, 0x14f }, + { 0x151, 0x151 }, + { 0x153, 0x153 }, + { 0x155, 0x155 }, + { 0x157, 0x157 }, + { 0x159, 0x159 }, + { 0x15b, 0x15b }, + { 0x15d, 0x15d }, + { 0x15f, 0x15f }, + { 0x161, 0x161 }, + { 0x163, 0x163 }, + { 0x165, 0x165 }, + { 0x167, 0x167 }, + { 0x169, 0x169 }, + { 0x16b, 0x16b }, + { 0x16d, 0x16d }, + { 0x16f, 0x16f }, + { 0x171, 0x171 }, + { 0x173, 0x173 }, + { 0x175, 0x175 }, + { 0x177, 0x177 }, + { 0x17a, 0x17a }, + { 0x17c, 0x17c }, + { 0x17e, 0x180 }, + { 0x183, 0x183 }, + { 0x185, 0x185 }, + { 0x188, 0x188 }, + { 0x18c, 0x18d }, + { 0x192, 0x192 }, + { 0x195, 0x195 }, + { 0x199, 0x19b }, + { 0x19e, 0x19e }, + { 0x1a1, 0x1a1 }, + { 0x1a3, 0x1a3 }, + { 0x1a5, 0x1a5 }, + { 0x1a8, 0x1a8 }, + { 0x1aa, 0x1ab }, + { 0x1ad, 0x1ad }, + { 0x1b0, 0x1b0 }, + { 0x1b4, 0x1b4 }, + { 0x1b6, 0x1b6 }, + { 0x1b9, 0x1ba }, + { 0x1bd, 0x1bf }, + { 0x1c6, 0x1c6 }, + { 0x1c9, 0x1c9 }, + { 0x1cc, 0x1cc }, + { 0x1ce, 0x1ce }, + { 0x1d0, 0x1d0 }, + { 0x1d2, 0x1d2 }, + { 0x1d4, 0x1d4 }, + { 0x1d6, 0x1d6 }, + { 0x1d8, 0x1d8 }, + { 0x1da, 0x1da }, + { 0x1dc, 0x1dd }, + { 0x1df, 0x1df }, + { 0x1e1, 0x1e1 }, + { 0x1e3, 0x1e3 }, + { 0x1e5, 0x1e5 }, + { 0x1e7, 0x1e7 }, + { 0x1e9, 0x1e9 }, + { 0x1eb, 0x1eb }, + { 0x1ed, 0x1ed }, + { 0x1ef, 0x1f0 }, + { 0x1f3, 0x1f3 }, + { 0x1f5, 0x1f5 }, + { 0x1f9, 0x1f9 }, + { 0x1fb, 0x1fb }, + { 0x1fd, 0x1fd }, + { 0x1ff, 0x1ff }, + { 0x201, 0x201 }, + { 0x203, 0x203 }, + { 0x205, 0x205 }, + { 0x207, 0x207 }, + { 0x209, 0x209 }, + { 0x20b, 0x20b }, + { 0x20d, 0x20d }, + { 0x20f, 0x20f }, + { 0x211, 0x211 }, + { 0x213, 0x213 }, + { 0x215, 0x215 }, + { 0x217, 0x217 }, + { 0x219, 0x219 }, + { 0x21b, 0x21b }, + { 0x21d, 0x21d }, + { 0x21f, 0x21f }, + { 0x221, 0x221 }, + { 0x223, 0x223 }, + { 0x225, 0x225 }, + { 0x227, 0x227 }, + { 0x229, 0x229 }, + { 0x22b, 0x22b }, + { 0x22d, 0x22d }, + { 0x22f, 0x22f }, + { 0x231, 0x231 }, + { 0x233, 0x239 }, + { 0x23c, 0x23c }, + { 0x23f, 0x240 }, + { 0x242, 0x242 }, + { 0x247, 0x247 }, + { 0x249, 0x249 }, + { 0x24b, 0x24b }, + { 0x24d, 0x24d }, + { 0x24f, 0x293 }, + { 0x295, 0x2af }, + { 0x371, 0x371 }, + { 0x373, 0x373 }, + { 0x377, 0x377 }, + { 0x37b, 0x37d }, + { 0x390, 0x390 }, + { 0x3ac, 0x3ce }, + { 0x3d0, 0x3d1 }, + { 0x3d5, 0x3d7 }, + { 0x3d9, 0x3d9 }, + { 0x3db, 0x3db }, + { 0x3dd, 0x3dd }, + { 0x3df, 0x3df }, + { 0x3e1, 0x3e1 }, + { 0x3e3, 0x3e3 }, + { 0x3e5, 0x3e5 }, + { 0x3e7, 0x3e7 }, + { 0x3e9, 0x3e9 }, + { 0x3eb, 0x3eb }, + { 0x3ed, 0x3ed }, + { 0x3ef, 0x3f3 }, + { 0x3f5, 0x3f5 }, + { 0x3f8, 0x3f8 }, + { 0x3fb, 0x3fc }, + { 0x430, 0x45f }, + { 0x461, 0x461 }, + { 0x463, 0x463 }, + { 0x465, 0x465 }, + { 0x467, 0x467 }, + { 0x469, 0x469 }, + { 0x46b, 0x46b }, + { 0x46d, 0x46d }, + { 0x46f, 0x46f }, + { 0x471, 0x471 }, + { 0x473, 0x473 }, + { 0x475, 0x475 }, + { 0x477, 0x477 }, + { 0x479, 0x479 }, + { 0x47b, 0x47b }, + { 0x47d, 0x47d }, + { 0x47f, 0x47f }, + { 0x481, 0x481 }, + { 0x48b, 0x48b }, + { 0x48d, 0x48d }, + { 0x48f, 0x48f }, + { 0x491, 0x491 }, + { 0x493, 0x493 }, + { 0x495, 0x495 }, + { 0x497, 0x497 }, + { 0x499, 0x499 }, + { 0x49b, 0x49b }, + { 0x49d, 0x49d }, + { 0x49f, 0x49f }, + { 0x4a1, 0x4a1 }, + { 0x4a3, 0x4a3 }, + { 0x4a5, 0x4a5 }, + { 0x4a7, 0x4a7 }, + { 0x4a9, 0x4a9 }, + { 0x4ab, 0x4ab }, + { 0x4ad, 0x4ad }, + { 0x4af, 0x4af }, + { 0x4b1, 0x4b1 }, + { 0x4b3, 0x4b3 }, + { 0x4b5, 0x4b5 }, + { 0x4b7, 0x4b7 }, + { 0x4b9, 0x4b9 }, + { 0x4bb, 0x4bb }, + { 0x4bd, 0x4bd }, + { 0x4bf, 0x4bf }, + { 0x4c2, 0x4c2 }, + { 0x4c4, 0x4c4 }, + { 0x4c6, 0x4c6 }, + { 0x4c8, 0x4c8 }, + { 0x4ca, 0x4ca }, + { 0x4cc, 0x4cc }, + { 0x4ce, 0x4cf }, + { 0x4d1, 0x4d1 }, + { 0x4d3, 0x4d3 }, + { 0x4d5, 0x4d5 }, + { 0x4d7, 0x4d7 }, + { 0x4d9, 0x4d9 }, + { 0x4db, 0x4db }, + { 0x4dd, 0x4dd }, + { 0x4df, 0x4df }, + { 0x4e1, 0x4e1 }, + { 0x4e3, 0x4e3 }, + { 0x4e5, 0x4e5 }, + { 0x4e7, 0x4e7 }, + { 0x4e9, 0x4e9 }, + { 0x4eb, 0x4eb }, + { 0x4ed, 0x4ed }, + { 0x4ef, 0x4ef }, + { 0x4f1, 0x4f1 }, + { 0x4f3, 0x4f3 }, + { 0x4f5, 0x4f5 }, + { 0x4f7, 0x4f7 }, + { 0x4f9, 0x4f9 }, + { 0x4fb, 0x4fb }, + { 0x4fd, 0x4fd }, + { 0x4ff, 0x4ff }, + { 0x501, 0x501 }, + { 0x503, 0x503 }, + { 0x505, 0x505 }, + { 0x507, 0x507 }, + { 0x509, 0x509 }, + { 0x50b, 0x50b }, + { 0x50d, 0x50d }, + { 0x50f, 0x50f }, + { 0x511, 0x511 }, + { 0x513, 0x513 }, + { 0x515, 0x515 }, + { 0x517, 0x517 }, + { 0x519, 0x519 }, + { 0x51b, 0x51b }, + { 0x51d, 0x51d }, + { 0x51f, 0x51f }, + { 0x521, 0x521 }, + { 0x523, 0x523 }, + { 0x525, 0x525 }, + { 0x527, 0x527 }, + { 0x529, 0x529 }, + { 0x52b, 0x52b }, + { 0x52d, 0x52d }, + { 0x52f, 0x52f }, + { 0x560, 0x588 }, + { 0x10d0, 0x10fa }, + { 0x10fd, 0x10ff }, + { 0x13f8, 0x13fd }, + { 0x1c80, 0x1c88 }, + { 0x1d00, 0x1d2b }, + { 0x1d6b, 0x1d77 }, + { 0x1d79, 0x1d9a }, + { 0x1e01, 0x1e01 }, + { 0x1e03, 0x1e03 }, + { 0x1e05, 0x1e05 }, + { 0x1e07, 0x1e07 }, + { 0x1e09, 0x1e09 }, + { 0x1e0b, 0x1e0b }, + { 0x1e0d, 0x1e0d }, + { 0x1e0f, 0x1e0f }, + { 0x1e11, 0x1e11 }, + { 0x1e13, 0x1e13 }, + { 0x1e15, 0x1e15 }, + { 0x1e17, 0x1e17 }, + { 0x1e19, 0x1e19 }, + { 0x1e1b, 0x1e1b }, + { 0x1e1d, 0x1e1d }, + { 0x1e1f, 0x1e1f }, + { 0x1e21, 0x1e21 }, + { 0x1e23, 0x1e23 }, + { 0x1e25, 0x1e25 }, + { 0x1e27, 0x1e27 }, + { 0x1e29, 0x1e29 }, + { 0x1e2b, 0x1e2b }, + { 0x1e2d, 0x1e2d }, + { 0x1e2f, 0x1e2f }, + { 0x1e31, 0x1e31 }, + { 0x1e33, 0x1e33 }, + { 0x1e35, 0x1e35 }, + { 0x1e37, 0x1e37 }, + { 0x1e39, 0x1e39 }, + { 0x1e3b, 0x1e3b }, + { 0x1e3d, 0x1e3d }, + { 0x1e3f, 0x1e3f }, + { 0x1e41, 0x1e41 }, + { 0x1e43, 0x1e43 }, + { 0x1e45, 0x1e45 }, + { 0x1e47, 0x1e47 }, + { 0x1e49, 0x1e49 }, + { 0x1e4b, 0x1e4b }, + { 0x1e4d, 0x1e4d }, + { 0x1e4f, 0x1e4f }, + { 0x1e51, 0x1e51 }, + { 0x1e53, 0x1e53 }, + { 0x1e55, 0x1e55 }, + { 0x1e57, 0x1e57 }, + { 0x1e59, 0x1e59 }, + { 0x1e5b, 0x1e5b }, + { 0x1e5d, 0x1e5d }, + { 0x1e5f, 0x1e5f }, + { 0x1e61, 0x1e61 }, + { 0x1e63, 0x1e63 }, + { 0x1e65, 0x1e65 }, + { 0x1e67, 0x1e67 }, + { 0x1e69, 0x1e69 }, + { 0x1e6b, 0x1e6b }, + { 0x1e6d, 0x1e6d }, + { 0x1e6f, 0x1e6f }, + { 0x1e71, 0x1e71 }, + { 0x1e73, 0x1e73 }, + { 0x1e75, 0x1e75 }, + { 0x1e77, 0x1e77 }, + { 0x1e79, 0x1e79 }, + { 0x1e7b, 0x1e7b }, + { 0x1e7d, 0x1e7d }, + { 0x1e7f, 0x1e7f }, + { 0x1e81, 0x1e81 }, + { 0x1e83, 0x1e83 }, + { 0x1e85, 0x1e85 }, + { 0x1e87, 0x1e87 }, + { 0x1e89, 0x1e89 }, + { 0x1e8b, 0x1e8b }, + { 0x1e8d, 0x1e8d }, + { 0x1e8f, 0x1e8f }, + { 0x1e91, 0x1e91 }, + { 0x1e93, 0x1e93 }, + { 0x1e95, 0x1e9d }, + { 0x1e9f, 0x1e9f }, + { 0x1ea1, 0x1ea1 }, + { 0x1ea3, 0x1ea3 }, + { 0x1ea5, 0x1ea5 }, + { 0x1ea7, 0x1ea7 }, + { 0x1ea9, 0x1ea9 }, + { 0x1eab, 0x1eab }, + { 0x1ead, 0x1ead }, + { 0x1eaf, 0x1eaf }, + { 0x1eb1, 0x1eb1 }, + { 0x1eb3, 0x1eb3 }, + { 0x1eb5, 0x1eb5 }, + { 0x1eb7, 0x1eb7 }, + { 0x1eb9, 0x1eb9 }, + { 0x1ebb, 0x1ebb }, + { 0x1ebd, 0x1ebd }, + { 0x1ebf, 0x1ebf }, + { 0x1ec1, 0x1ec1 }, + { 0x1ec3, 0x1ec3 }, + { 0x1ec5, 0x1ec5 }, + { 0x1ec7, 0x1ec7 }, + { 0x1ec9, 0x1ec9 }, + { 0x1ecb, 0x1ecb }, + { 0x1ecd, 0x1ecd }, + { 0x1ecf, 0x1ecf }, + { 0x1ed1, 0x1ed1 }, + { 0x1ed3, 0x1ed3 }, + { 0x1ed5, 0x1ed5 }, + { 0x1ed7, 0x1ed7 }, + { 0x1ed9, 0x1ed9 }, + { 0x1edb, 0x1edb }, + { 0x1edd, 0x1edd }, + { 0x1edf, 0x1edf }, + { 0x1ee1, 0x1ee1 }, + { 0x1ee3, 0x1ee3 }, + { 0x1ee5, 0x1ee5 }, + { 0x1ee7, 0x1ee7 }, + { 0x1ee9, 0x1ee9 }, + { 0x1eeb, 0x1eeb }, + { 0x1eed, 0x1eed }, + { 0x1eef, 0x1eef }, + { 0x1ef1, 0x1ef1 }, + { 0x1ef3, 0x1ef3 }, + { 0x1ef5, 0x1ef5 }, + { 0x1ef7, 0x1ef7 }, + { 0x1ef9, 0x1ef9 }, + { 0x1efb, 0x1efb }, + { 0x1efd, 0x1efd }, + { 0x1eff, 0x1f07 }, + { 0x1f10, 0x1f15 }, + { 0x1f20, 0x1f27 }, + { 0x1f30, 0x1f37 }, + { 0x1f40, 0x1f45 }, + { 0x1f50, 0x1f57 }, + { 0x1f60, 0x1f67 }, + { 0x1f70, 0x1f7d }, + { 0x1f80, 0x1f87 }, + { 0x1f90, 0x1f97 }, + { 0x1fa0, 0x1fa7 }, + { 0x1fb0, 0x1fb4 }, + { 0x1fb6, 0x1fb7 }, + { 0x1fbe, 0x1fbe }, + { 0x1fc2, 0x1fc4 }, + { 0x1fc6, 0x1fc7 }, + { 0x1fd0, 0x1fd3 }, + { 0x1fd6, 0x1fd7 }, + { 0x1fe0, 0x1fe7 }, + { 0x1ff2, 0x1ff4 }, + { 0x1ff6, 0x1ff7 }, + { 0x210a, 0x210a }, + { 0x210e, 0x210f }, + { 0x2113, 0x2113 }, + { 0x212f, 0x212f }, + { 0x2134, 0x2134 }, + { 0x2139, 0x2139 }, + { 0x213c, 0x213d }, + { 0x2146, 0x2149 }, + { 0x214e, 0x214e }, + { 0x2184, 0x2184 }, + { 0x2c30, 0x2c5f }, + { 0x2c61, 0x2c61 }, + { 0x2c65, 0x2c66 }, + { 0x2c68, 0x2c68 }, + { 0x2c6a, 0x2c6a }, + { 0x2c6c, 0x2c6c }, + { 0x2c71, 0x2c71 }, + { 0x2c73, 0x2c74 }, + { 0x2c76, 0x2c7b }, + { 0x2c81, 0x2c81 }, + { 0x2c83, 0x2c83 }, + { 0x2c85, 0x2c85 }, + { 0x2c87, 0x2c87 }, + { 0x2c89, 0x2c89 }, + { 0x2c8b, 0x2c8b }, + { 0x2c8d, 0x2c8d }, + { 0x2c8f, 0x2c8f }, + { 0x2c91, 0x2c91 }, + { 0x2c93, 0x2c93 }, + { 0x2c95, 0x2c95 }, + { 0x2c97, 0x2c97 }, + { 0x2c99, 0x2c99 }, + { 0x2c9b, 0x2c9b }, + { 0x2c9d, 0x2c9d }, + { 0x2c9f, 0x2c9f }, + { 0x2ca1, 0x2ca1 }, + { 0x2ca3, 0x2ca3 }, + { 0x2ca5, 0x2ca5 }, + { 0x2ca7, 0x2ca7 }, + { 0x2ca9, 0x2ca9 }, + { 0x2cab, 0x2cab }, + { 0x2cad, 0x2cad }, + { 0x2caf, 0x2caf }, + { 0x2cb1, 0x2cb1 }, + { 0x2cb3, 0x2cb3 }, + { 0x2cb5, 0x2cb5 }, + { 0x2cb7, 0x2cb7 }, + { 0x2cb9, 0x2cb9 }, + { 0x2cbb, 0x2cbb }, + { 0x2cbd, 0x2cbd }, + { 0x2cbf, 0x2cbf }, + { 0x2cc1, 0x2cc1 }, + { 0x2cc3, 0x2cc3 }, + { 0x2cc5, 0x2cc5 }, + { 0x2cc7, 0x2cc7 }, + { 0x2cc9, 0x2cc9 }, + { 0x2ccb, 0x2ccb }, + { 0x2ccd, 0x2ccd }, + { 0x2ccf, 0x2ccf }, + { 0x2cd1, 0x2cd1 }, + { 0x2cd3, 0x2cd3 }, + { 0x2cd5, 0x2cd5 }, + { 0x2cd7, 0x2cd7 }, + { 0x2cd9, 0x2cd9 }, + { 0x2cdb, 0x2cdb }, + { 0x2cdd, 0x2cdd }, + { 0x2cdf, 0x2cdf }, + { 0x2ce1, 0x2ce1 }, + { 0x2ce3, 0x2ce4 }, + { 0x2cec, 0x2cec }, + { 0x2cee, 0x2cee }, + { 0x2cf3, 0x2cf3 }, + { 0x2d00, 0x2d25 }, + { 0x2d27, 0x2d27 }, + { 0x2d2d, 0x2d2d }, + { 0xa641, 0xa641 }, + { 0xa643, 0xa643 }, + { 0xa645, 0xa645 }, + { 0xa647, 0xa647 }, + { 0xa649, 0xa649 }, + { 0xa64b, 0xa64b }, + { 0xa64d, 0xa64d }, + { 0xa64f, 0xa64f }, + { 0xa651, 0xa651 }, + { 0xa653, 0xa653 }, + { 0xa655, 0xa655 }, + { 0xa657, 0xa657 }, + { 0xa659, 0xa659 }, + { 0xa65b, 0xa65b }, + { 0xa65d, 0xa65d }, + { 0xa65f, 0xa65f }, + { 0xa661, 0xa661 }, + { 0xa663, 0xa663 }, + { 0xa665, 0xa665 }, + { 0xa667, 0xa667 }, + { 0xa669, 0xa669 }, + { 0xa66b, 0xa66b }, + { 0xa66d, 0xa66d }, + { 0xa681, 0xa681 }, + { 0xa683, 0xa683 }, + { 0xa685, 0xa685 }, + { 0xa687, 0xa687 }, + { 0xa689, 0xa689 }, + { 0xa68b, 0xa68b }, + { 0xa68d, 0xa68d }, + { 0xa68f, 0xa68f }, + { 0xa691, 0xa691 }, + { 0xa693, 0xa693 }, + { 0xa695, 0xa695 }, + { 0xa697, 0xa697 }, + { 0xa699, 0xa699 }, + { 0xa69b, 0xa69b }, + { 0xa723, 0xa723 }, + { 0xa725, 0xa725 }, + { 0xa727, 0xa727 }, + { 0xa729, 0xa729 }, + { 0xa72b, 0xa72b }, + { 0xa72d, 0xa72d }, + { 0xa72f, 0xa731 }, + { 0xa733, 0xa733 }, + { 0xa735, 0xa735 }, + { 0xa737, 0xa737 }, + { 0xa739, 0xa739 }, + { 0xa73b, 0xa73b }, + { 0xa73d, 0xa73d }, + { 0xa73f, 0xa73f }, + { 0xa741, 0xa741 }, + { 0xa743, 0xa743 }, + { 0xa745, 0xa745 }, + { 0xa747, 0xa747 }, + { 0xa749, 0xa749 }, + { 0xa74b, 0xa74b }, + { 0xa74d, 0xa74d }, + { 0xa74f, 0xa74f }, + { 0xa751, 0xa751 }, + { 0xa753, 0xa753 }, + { 0xa755, 0xa755 }, + { 0xa757, 0xa757 }, + { 0xa759, 0xa759 }, + { 0xa75b, 0xa75b }, + { 0xa75d, 0xa75d }, + { 0xa75f, 0xa75f }, + { 0xa761, 0xa761 }, + { 0xa763, 0xa763 }, + { 0xa765, 0xa765 }, + { 0xa767, 0xa767 }, + { 0xa769, 0xa769 }, + { 0xa76b, 0xa76b }, + { 0xa76d, 0xa76d }, + { 0xa76f, 0xa76f }, + { 0xa771, 0xa778 }, + { 0xa77a, 0xa77a }, + { 0xa77c, 0xa77c }, + { 0xa77f, 0xa77f }, + { 0xa781, 0xa781 }, + { 0xa783, 0xa783 }, + { 0xa785, 0xa785 }, + { 0xa787, 0xa787 }, + { 0xa78c, 0xa78c }, + { 0xa78e, 0xa78e }, + { 0xa791, 0xa791 }, + { 0xa793, 0xa795 }, + { 0xa797, 0xa797 }, + { 0xa799, 0xa799 }, + { 0xa79b, 0xa79b }, + { 0xa79d, 0xa79d }, + { 0xa79f, 0xa79f }, + { 0xa7a1, 0xa7a1 }, + { 0xa7a3, 0xa7a3 }, + { 0xa7a5, 0xa7a5 }, + { 0xa7a7, 0xa7a7 }, + { 0xa7a9, 0xa7a9 }, + { 0xa7af, 0xa7af }, + { 0xa7b5, 0xa7b5 }, + { 0xa7b7, 0xa7b7 }, + { 0xa7b9, 0xa7b9 }, + { 0xa7bb, 0xa7bb }, + { 0xa7bd, 0xa7bd }, + { 0xa7bf, 0xa7bf }, + { 0xa7c1, 0xa7c1 }, + { 0xa7c3, 0xa7c3 }, + { 0xa7c8, 0xa7c8 }, + { 0xa7ca, 0xa7ca }, + { 0xa7d1, 0xa7d1 }, + { 0xa7d3, 0xa7d3 }, + { 0xa7d5, 0xa7d5 }, + { 0xa7d7, 0xa7d7 }, + { 0xa7d9, 0xa7d9 }, + { 0xa7f6, 0xa7f6 }, + { 0xa7fa, 0xa7fa }, + { 0xab30, 0xab5a }, + { 0xab60, 0xab68 }, + { 0xab70, 0xabbf }, + { 0xfb00, 0xfb06 }, + { 0xfb13, 0xfb17 }, + { 0xff41, 0xff5a }, + { 0x10428, 0x1044f }, + { 0x104d8, 0x104fb }, + { 0x10597, 0x105a1 }, + { 0x105a3, 0x105b1 }, + { 0x105b3, 0x105b9 }, + { 0x105bb, 0x105bc }, + { 0x10cc0, 0x10cf2 }, + { 0x118c0, 0x118df }, + { 0x16e60, 0x16e7f }, + { 0x1d41a, 0x1d433 }, + { 0x1d44e, 0x1d454 }, + { 0x1d456, 0x1d467 }, + { 0x1d482, 0x1d49b }, + { 0x1d4b6, 0x1d4b9 }, + { 0x1d4bb, 0x1d4bb }, + { 0x1d4bd, 0x1d4c3 }, + { 0x1d4c5, 0x1d4cf }, + { 0x1d4ea, 0x1d503 }, + { 0x1d51e, 0x1d537 }, + { 0x1d552, 0x1d56b }, + { 0x1d586, 0x1d59f }, + { 0x1d5ba, 0x1d5d3 }, + { 0x1d5ee, 0x1d607 }, + { 0x1d622, 0x1d63b }, + { 0x1d656, 0x1d66f }, + { 0x1d68a, 0x1d6a5 }, + { 0x1d6c2, 0x1d6da }, + { 0x1d6dc, 0x1d6e1 }, + { 0x1d6fc, 0x1d714 }, + { 0x1d716, 0x1d71b }, + { 0x1d736, 0x1d74e }, + { 0x1d750, 0x1d755 }, + { 0x1d770, 0x1d788 }, + { 0x1d78a, 0x1d78f }, + { 0x1d7aa, 0x1d7c2 }, + { 0x1d7c4, 0x1d7c9 }, + { 0x1d7cb, 0x1d7cb }, + { 0x1df00, 0x1df09 }, + { 0x1df0b, 0x1df1e }, + { 0x1df25, 0x1df2a }, + { 0x1e922, 0x1e943 }, }; #endif // CHAR_RANGE_INC diff --git a/core/string/char_utils.h b/core/string/char_utils.h index 4ff8fb7320..aa9bc198ca 100644 --- a/core/string/char_utils.h +++ b/core/string/char_utils.h @@ -35,24 +35,43 @@ #include "char_range.inc" +#define BSEARCH_CHAR_RANGE(m_array) \ + int low = 0; \ + int high = sizeof(m_array) / sizeof(m_array[0]) - 1; \ + int middle; \ + \ + while (low <= high) { \ + middle = (low + high) / 2; \ + \ + if (c < m_array[middle].start) { \ + high = middle - 1; \ + } else if (c > m_array[middle].end) { \ + low = middle + 1; \ + } else { \ + return true; \ + } \ + } \ + \ + return false + static _FORCE_INLINE_ bool is_unicode_identifier_start(char32_t c) { - for (int i = 0; xid_start[i].start != 0; i++) { - if (c >= xid_start[i].start && c <= xid_start[i].end) { - return true; - } - } - return false; + BSEARCH_CHAR_RANGE(xid_start); } static _FORCE_INLINE_ bool is_unicode_identifier_continue(char32_t c) { - for (int i = 0; xid_continue[i].start != 0; i++) { - if (c >= xid_continue[i].start && c <= xid_continue[i].end) { - return true; - } - } - return false; + BSEARCH_CHAR_RANGE(xid_continue); +} + +static _FORCE_INLINE_ bool is_unicode_upper_case(char32_t c) { + BSEARCH_CHAR_RANGE(uppercase_letter); } +static _FORCE_INLINE_ bool is_unicode_lower_case(char32_t c) { + BSEARCH_CHAR_RANGE(lowercase_letter); +} + +#undef BSEARCH_CHAR_RANGE + static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) { return (c >= 'A' && c <= 'Z'); } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 67b0fdee20..540891b3b0 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1044,17 +1044,17 @@ String String::_camelcase_to_underscore() const { int start_index = 0; for (int i = 1; i < size(); i++) { - bool is_prev_upper = is_ascii_upper_case(cstr[i - 1]); - bool is_prev_lower = is_ascii_lower_case(cstr[i - 1]); + bool is_prev_upper = is_unicode_upper_case(cstr[i - 1]); + bool is_prev_lower = is_unicode_lower_case(cstr[i - 1]); bool is_prev_digit = is_digit(cstr[i - 1]); - bool is_curr_upper = is_ascii_upper_case(cstr[i]); - bool is_curr_lower = is_ascii_lower_case(cstr[i]); + bool is_curr_upper = is_unicode_upper_case(cstr[i]); + bool is_curr_lower = is_unicode_lower_case(cstr[i]); bool is_curr_digit = is_digit(cstr[i]); bool is_next_lower = false; if (i + 1 < size()) { - is_next_lower = is_ascii_lower_case(cstr[i + 1]); + is_next_lower = is_unicode_lower_case(cstr[i + 1]); } const bool cond_a = is_prev_lower && is_curr_upper; // aA diff --git a/core/variant/callable.h b/core/variant/callable.h index 3ae424e9bf..38872b71ef 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -99,7 +99,7 @@ public: bool is_valid() const; template <typename... VarArgs> - Callable bind(VarArgs... p_args); + Callable bind(VarArgs... p_args) const; Callable bindv(const Array &p_arguments); Callable bindp(const Variant **p_arguments, int p_argcount) const; diff --git a/core/variant/variant.h b/core/variant/variant.h index d685444c30..c358559c9b 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -865,7 +865,7 @@ Variant Callable::call(VarArgs... p_args) const { } template <typename... VarArgs> -Callable Callable::bind(VarArgs... p_args) { +Callable Callable::bind(VarArgs... p_args) const { 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++) { diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index ce7bf4ef5c..dc7bbe0e4f 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -362,7 +362,7 @@ [/codeblock] </description> </method> - <method name="ease"> + <method name="ease" keywords="smooth"> <return type="float" /> <param index="0" name="x" type="float" /> <param index="1" name="curve" type="float" /> @@ -518,7 +518,7 @@ [/codeblocks] </description> </method> - <method name="inverse_lerp"> + <method name="inverse_lerp" keywords="interpolate"> <return type="float" /> <param index="0" name="from" type="float" /> <param index="1" name="to" type="float" /> @@ -537,7 +537,7 @@ See also [method lerp], which performs the reverse of this operation, and [method remap] to map a continuous series of values to another. </description> </method> - <method name="is_equal_approx"> + <method name="is_equal_approx" keywords="roughly"> <return type="bool" /> <param index="0" name="a" type="float" /> <param index="1" name="b" type="float" /> @@ -615,7 +615,7 @@ This function is faster than using [method is_equal_approx] with one value as zero. </description> </method> - <method name="lerp"> + <method name="lerp" keywords="interpolate"> <return type="Variant" /> <param index="0" name="from" type="Variant" /> <param index="1" name="to" type="Variant" /> @@ -630,7 +630,7 @@ [b]Note:[/b] For better type safety, use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp]. </description> </method> - <method name="lerp_angle"> + <method name="lerp_angle" keywords="interpolate"> <return type="float" /> <param index="0" name="from" type="float" /> <param index="1" name="to" type="float" /> @@ -1080,7 +1080,7 @@ [b]Note:[/b] This function is called automatically when the project is run. If you need to fix the seed to have consistent, reproducible results, use [method seed] to initialize the random number generator. </description> </method> - <method name="remap" keywords="range, lerp"> + <method name="remap" keywords="range, lerp, interpolate"> <return type="float" /> <param index="0" name="value" type="float" /> <param index="1" name="istart" type="float" /> diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml index 26d28f9c50..9ccaa385db 100644 --- a/doc/classes/AnimationMixer.xml +++ b/doc/classes/AnimationMixer.xml @@ -357,6 +357,7 @@ </constant> <constant name="ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT" value="0" enum="AnimationCallbackModeDiscrete"> An [constant Animation.UPDATE_DISCRETE] track value takes precedence when blending [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and [constant Animation.UPDATE_DISCRETE] track values. This is the default behavior for [AnimationPlayer]. + [b]Note:[/b] If a value track has non-numeric type key values, it is internally converted to use [constant ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT] with [constant Animation.UPDATE_DISCRETE]. </constant> <constant name="ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE" value="1" enum="AnimationCallbackModeDiscrete"> An [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track value takes precedence when blending the [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and the [constant Animation.UPDATE_DISCRETE] track values. diff --git a/doc/classes/AudioListener2D.xml b/doc/classes/AudioListener2D.xml index 8328e82dbd..85505438e7 100644 --- a/doc/classes/AudioListener2D.xml +++ b/doc/classes/AudioListener2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioListener2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="AudioListener2D" inherits="Node2D" keywords="sound" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Overrides the location sounds are heard from. </brief_description> diff --git a/doc/classes/AudioListener3D.xml b/doc/classes/AudioListener3D.xml index a5fe0153c4..c9de089195 100644 --- a/doc/classes/AudioListener3D.xml +++ b/doc/classes/AudioListener3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioListener3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="AudioListener3D" inherits="Node3D" keywords="sound" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Overrides the location sounds are heard from. </brief_description> diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index ac50a5ee30..fbe2508da3 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamPlayer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="AudioStreamPlayer" inherits="Node" keywords="sound, music, song" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Plays back audio non-positionally. </brief_description> diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index 77a038c5fa..8b81887976 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamPlayer2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="AudioStreamPlayer2D" inherits="Node2D" keywords="sound, sfx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Plays positional sound in 2D space. </brief_description> diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index f4c9adcaec..af92fd4a44 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamPlayer3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="AudioStreamPlayer3D" inherits="Node3D" keywords="sound, sfx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Plays positional sound in 3D space. </brief_description> diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml index c5998ad8a1..764f4a65b5 100644 --- a/doc/classes/BaseButton.xml +++ b/doc/classes/BaseButton.xml @@ -59,7 +59,7 @@ If [code]true[/code], the button's state is pressed. Means the button is pressed down or toggled (if [member toggle_mode] is active). Only works if [member toggle_mode] is [code]true[/code]. [b]Note:[/b] Setting [member button_pressed] will result in [signal toggled] to be emitted. If you want to change the pressed state without emitting that signal, use [method set_pressed_no_signal]. </member> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled"> If [code]true[/code], the button is in disabled state and can't be clicked or toggled. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 2a54ae0527..1bd4183b3c 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -57,19 +57,19 @@ </method> </methods> <members> - <member name="albedo_color" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)"> + <member name="albedo_color" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)" keywords="albedo_colour, diffuse_color, diffuse_colour"> The material's base color. [b]Note:[/b] If [member detail_enabled] is [code]true[/code] and a [member detail_albedo] texture is specified, [member albedo_color] will [i]not[/i] modulate the detail texture. This can be used to color partial areas of a material by not specifying an albedo texture and using a transparent [member detail_albedo] texture instead. </member> - <member name="albedo_texture" type="Texture2D" setter="set_texture" getter="get_texture"> + <member name="albedo_texture" type="Texture2D" setter="set_texture" getter="get_texture" keywords="diffuse_texture"> Texture to multiply by [member albedo_color]. Used for basic texturing of objects. If the texture appears unexpectedly too dark or too bright, check [member albedo_texture_force_srgb]. </member> - <member name="albedo_texture_force_srgb" type="bool" setter="set_flag" getter="get_flag" default="false"> + <member name="albedo_texture_force_srgb" type="bool" setter="set_flag" getter="get_flag" default="false" keywords="diffuse_texture_force_srgb"> If [code]true[/code], forces a conversion of the [member albedo_texture] from sRGB color space to linear color space. See also [member vertex_color_is_srgb]. This should only be enabled when needed (typically when using a [ViewportTexture] as [member albedo_texture]). If [member albedo_texture_force_srgb] is [code]true[/code] when it shouldn't be, the texture will appear to be too dark. If [member albedo_texture_force_srgb] is [code]false[/code] when it shouldn't be, the texture will appear to be too bright. </member> - <member name="albedo_texture_msdf" type="bool" setter="set_flag" getter="get_flag" default="false"> + <member name="albedo_texture_msdf" type="bool" setter="set_flag" getter="get_flag" default="false" keywords="diffuse_texture_force_srgb"> Enables multichannel signed distance field rendering shader. Use [member msdf_pixel_range] and [member msdf_outline_size] to configure MSDF parameters. </member> <member name="alpha_antialiasing_edge" type="float" setter="set_alpha_antialiasing_edge" getter="get_alpha_antialiasing_edge"> @@ -81,7 +81,7 @@ <member name="alpha_hash_scale" type="float" setter="set_alpha_hash_scale" getter="get_alpha_hash_scale"> The hashing scale for Alpha Hash. Recommended values between [code]0[/code] and [code]2[/code]. </member> - <member name="alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold"> + <member name="alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold" keywords="alpha_test_threshold"> Threshold at which the alpha scissor will discard values. Higher values will result in more pixels being discarded. If the material becomes too opaque at a distance, try increasing [member alpha_scissor_threshold]. If the material disappears at a distance, try decreasing [member alpha_scissor_threshold]. </member> <member name="anisotropy" type="float" setter="set_anisotropy" getter="get_anisotropy" default="0.0"> @@ -534,7 +534,7 @@ <constant name="TRANSPARENCY_ALPHA" value="1" enum="Transparency"> The material will use the texture's alpha values for transparency. This is the slowest to render, and disables shadow casting. </constant> - <constant name="TRANSPARENCY_ALPHA_SCISSOR" value="2" enum="Transparency"> + <constant name="TRANSPARENCY_ALPHA_SCISSOR" value="2" enum="Transparency" keywords="TRANSPARENCY_ALPHA_TEST"> The material will cut off all values below a threshold, the rest will remain opaque. The opaque portions will be rendered in the depth prepass. This is faster to render than alpha blending, but slower than opaque rendering. This also supports casting shadows. </constant> <constant name="TRANSPARENCY_ALPHA_HASH" value="3" enum="Transparency"> diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 8731b27fc9..3865e54e26 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -297,7 +297,7 @@ [/codeblocks] </description> </method> - <method name="slerp" qualifiers="const"> + <method name="slerp" qualifiers="const" keywords="interpolate"> <return type="Basis" /> <param index="0" name="to" type="Basis" /> <param index="1" name="weight" type="float" /> diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml index 111e58e981..227f6817cc 100644 --- a/doc/classes/BoneAttachment3D.xml +++ b/doc/classes/BoneAttachment3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BoneAttachment3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="BoneAttachment3D" inherits="Node3D" keywords="tag" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> А node that dynamically copies or overrides the 3D transform of a bone in its parent [Skeleton3D]. </brief_description> diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index d7782a816d..739a824655 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -134,7 +134,7 @@ <theme_item name="icon" data_type="icon" type="Texture2D"> Default icon for the [Button]. Appears only if [member icon] is not assigned. </theme_item> - <theme_item name="disabled" data_type="style" type="StyleBox"> + <theme_item name="disabled" data_type="style" type="StyleBox" keywords="enabled"> [StyleBox] used when the [Button] is disabled. </theme_item> <theme_item name="disabled_mirrored" data_type="style" type="StyleBox"> diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index 92a57007bd..99411c73aa 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -126,7 +126,7 @@ <member name="anim_speed_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> Minimum equivalent of [member anim_speed_max]. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> Each particle's initial color. If [member texture] is defined, it will be multiplied by this color. </member> <member name="color_initial_ramp" type="Gradient" setter="set_color_initial_ramp" getter="get_color_initial_ramp"> diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index 79283d6f85..27726ff8a2 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -125,7 +125,7 @@ <member name="anim_speed_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> Minimum particle animation speed. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> Each particle's initial color. [b]Note:[/b] [member color] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color] will have no visible effect. </member> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 7604e4b75c..608a47d416 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -576,7 +576,7 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> The material applied to this [CanvasItem]. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour"> The color applied to this [CanvasItem]. This property does affect child [CanvasItem]s, unlike [member self_modulate] which only affects the node itself. </member> <member name="self_modulate" type="Color" setter="set_self_modulate" getter="get_self_modulate" default="Color(1, 1, 1, 1)"> diff --git a/doc/classes/CanvasModulate.xml b/doc/classes/CanvasModulate.xml index 214b3959c7..7db0361020 100644 --- a/doc/classes/CanvasModulate.xml +++ b/doc/classes/CanvasModulate.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CanvasModulate" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="CanvasModulate" inherits="Node2D" keywords="color" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A node that applies a color tint to a canvas. </brief_description> @@ -9,7 +9,7 @@ <tutorials> </tutorials> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> The tint color to apply. </member> </members> diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml index ce74227298..403033f85d 100644 --- a/doc/classes/CharFXTransform.xml +++ b/doc/classes/CharFXTransform.xml @@ -11,7 +11,7 @@ <link title="RichTextEffect test project (third-party)">https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project</link> </tutorials> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)" keywords="colour"> The color the character will be drawn with. </member> <member name="elapsed_time" type="float" setter="set_elapsed_time" getter="get_elapsed_time" default="0.0"> diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml index acb3f66c17..12f7024518 100644 --- a/doc/classes/CollisionPolygon2D.xml +++ b/doc/classes/CollisionPolygon2D.xml @@ -13,7 +13,7 @@ <member name="build_mode" type="int" setter="set_build_mode" getter="get_build_mode" enum="CollisionPolygon2D.BuildMode" default="0"> Collision build mode. Use one of the [enum BuildMode] constants. </member> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled"> If [code]true[/code], no collisions will be detected. </member> <member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false"> diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml index ed6fa0ba3c..16090c203e 100644 --- a/doc/classes/CollisionPolygon3D.xml +++ b/doc/classes/CollisionPolygon3D.xml @@ -13,7 +13,7 @@ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0"> Length that the resulting collision extends in either direction perpendicular to its 2D polygon. </member> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled"> If [code]true[/code], no collision will be produced. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04"> diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml index f3143e1f5c..1320982376 100644 --- a/doc/classes/CollisionShape2D.xml +++ b/doc/classes/CollisionShape2D.xml @@ -17,7 +17,7 @@ The collision shape debug color. [b]Note:[/b] The default value is [member ProjectSettings.debug/shapes/collision/shape_color]. The [code]Color(0, 0, 0, 1)[/code] value documented here is a placeholder, and not the actual default debug color. </member> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled"> A disabled collision shape has no effect in the world. This property should be changed with [method Object.set_deferred]. </member> <member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false"> diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml index 0dcfa75e5b..f6c0c323f4 100644 --- a/doc/classes/CollisionShape3D.xml +++ b/doc/classes/CollisionShape3D.xml @@ -29,7 +29,7 @@ </method> </methods> <members> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled"> A disabled collision shape has no effect in the world. </member> <member name="shape" type="Shape3D" setter="set_shape" getter="get_shape"> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 393e852584..517fb6bef7 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -299,7 +299,7 @@ Returns [code]true[/code] if this color and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component. </description> </method> - <method name="lerp" qualifiers="const"> + <method name="lerp" qualifiers="const" keywords="interpolate"> <return type="Color" /> <param index="0" name="to" type="Color" /> <param index="1" name="weight" type="float" /> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index ce450f6786..9aa0122ed2 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -58,7 +58,7 @@ <member name="can_add_swatches" type="bool" setter="set_can_add_swatches" getter="are_swatches_enabled" default="true"> If [code]true[/code], it's possible to add presets under Swatches. If [code]false[/code], the button to add presets is disabled. </member> - <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(1, 1, 1, 1)" keywords="colour"> The currently selected color. </member> <member name="color_mode" type="int" setter="set_color_mode" getter="get_color_mode" enum="ColorPicker.ColorModeType" default="0"> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index 89cb01407d..c53d61f036 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -29,7 +29,7 @@ </method> </methods> <members> - <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(0, 0, 0, 1)"> + <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(0, 0, 0, 1)" keywords="colour"> The currently selected color. </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true"> diff --git a/doc/classes/ColorRect.xml b/doc/classes/ColorRect.xml index 5bc97e6f46..413d51db72 100644 --- a/doc/classes/ColorRect.xml +++ b/doc/classes/ColorRect.xml @@ -10,7 +10,7 @@ <link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link> </tutorials> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> The fill color of the rectangle. </member> </members> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 226c5edbce..43c3f5c1be 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -949,16 +949,16 @@ <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0"> The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard, gamepad, and mouse signals. </member> - <member name="focus_neighbor_bottom" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")"> + <member name="focus_neighbor_bottom" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")" keywords="focus_neighbour_bottom"> Tells Godot which node it should give focus to if the user presses the down arrow on the keyboard or down on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_down] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one. </member> - <member name="focus_neighbor_left" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")"> + <member name="focus_neighbor_left" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")" keywords="focus_neighbour_left"> Tells Godot which node it should give focus to if the user presses the left arrow on the keyboard or left on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_left] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the left of this one. </member> - <member name="focus_neighbor_right" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")"> + <member name="focus_neighbor_right" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")" keywords="focus_neighbour_right"> Tells Godot which node it should give focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_right] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the right of this one. </member> - <member name="focus_neighbor_top" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")"> + <member name="focus_neighbor_top" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")" keywords="focus_neighbour_top"> Tells Godot which node it should give focus to if the user presses the top arrow on the keyboard or top on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_up] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the top of this one. </member> <member name="focus_next" type="NodePath" setter="set_focus_next" getter="get_focus_next" default="NodePath("")"> diff --git a/doc/classes/Decal.xml b/doc/classes/Decal.xml index b89db8dc9e..10ac769e77 100644 --- a/doc/classes/Decal.xml +++ b/doc/classes/Decal.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Decal" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="Decal" inherits="VisualInstance3D" keywords="stain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Node that projects a texture onto a [MeshInstance3D]. </brief_description> @@ -65,13 +65,13 @@ <member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575"> Specifies which [member VisualInstance3D.layers] this decal will project on. By default, Decals affect all layers. This is used so you can specify which types of objects receive the Decal and which do not. This is especially useful so you can ensure that dynamic objects don't accidentally receive a Decal intended for the terrain under them. </member> - <member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="40.0"> + <member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="40.0" keywords="lod_begin"> The distance from the camera at which the Decal begins to fade away (in 3D units). </member> - <member name="distance_fade_enabled" type="bool" setter="set_enable_distance_fade" getter="is_distance_fade_enabled" default="false"> + <member name="distance_fade_enabled" type="bool" setter="set_enable_distance_fade" getter="is_distance_fade_enabled" default="false" keywords="lod_enabled"> If [code]true[/code], decals will smoothly fade away when far from the active [Camera3D] starting at [member distance_fade_begin]. The Decal will fade out over [member distance_fade_begin] + [member distance_fade_length], after which it will be culled and not sent to the shader at all. Use this to reduce the number of active Decals in a scene and thus improve performance. </member> - <member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0"> + <member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0" keywords="lod_length"> The distance over which the Decal fades (in 3D units). The Decal becomes slowly more transparent over this distance and is completely invisible at the end. Higher values result in a smoother fade-out transition, which is more suited when the camera moves fast. </member> <member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy" default="1.0"> @@ -80,7 +80,7 @@ <member name="lower_fade" type="float" setter="set_lower_fade" getter="get_lower_fade" default="0.3"> Sets the curve over which the decal will fade as the surface gets further from the center of the [AABB]. Only positive values are valid (negative values will be clamped to [code]0.0[/code]). See also [member upper_fade]. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour"> Changes the [Color] of the Decal by multiplying the albedo and emission colors with this value. The alpha component is only taken into account when multiplying the albedo color, not the emission color. See also [member emission_energy] and [member albedo_mix] to change the emission and albedo intensity independently of each other. </member> <member name="normal_fade" type="float" setter="set_normal_fade" getter="get_normal_fade" default="0.0"> diff --git a/doc/classes/DirectionalLight2D.xml b/doc/classes/DirectionalLight2D.xml index 02909c95fa..d037f10c5b 100644 --- a/doc/classes/DirectionalLight2D.xml +++ b/doc/classes/DirectionalLight2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="DirectionalLight2D" inherits="Light2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="DirectionalLight2D" inherits="Light2D" keywords="sun" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Directional 2D light from a distance. </brief_description> diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml index d3cca5fa6d..0a307a4ade 100644 --- a/doc/classes/DirectionalLight3D.xml +++ b/doc/classes/DirectionalLight3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="DirectionalLight3D" inherits="Light3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="DirectionalLight3D" inherits="Light3D" keywords="sun" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Directional light from a distance, as from the Sun. </brief_description> diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 4fd288f16d..2b1083393f 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -84,7 +84,7 @@ <member name="label" type="String" setter="set_label" getter="get_label" default=""""> Set this property to change the label (if you want to show one). </member> - <member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false"> + <member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false" keywords="enabled, disabled, editable"> Used by the inspector, set to [code]true[/code] when the property is read-only. </member> </members> diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml index f139502e18..4649e26edf 100644 --- a/doc/classes/EditorResourcePicker.xml +++ b/doc/classes/EditorResourcePicker.xml @@ -43,7 +43,7 @@ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default=""""> The base type of allowed resource types. Can be a comma-separated list of several options. </member> - <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true"> + <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> If [code]true[/code], the value can be selected and edited. </member> <member name="edited_resource" type="Resource" setter="set_edited_resource" getter="get_edited_resource"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 5dcfdb21b1..0f87ba2ae5 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -445,6 +445,66 @@ The color to use for the TileMap editor's grid. [b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code]. </member> + <member name="editors/visual_editors/category_colors/color_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Color" category. + </member> + <member name="editors/visual_editors/category_colors/conditional_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Conditional" category. + </member> + <member name="editors/visual_editors/category_colors/input_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Input" category. + </member> + <member name="editors/visual_editors/category_colors/output_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Output" category. + </member> + <member name="editors/visual_editors/category_colors/particle_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Particle" category. + </member> + <member name="editors/visual_editors/category_colors/scalar_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Scalar" category. + </member> + <member name="editors/visual_editors/category_colors/special_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Special" category. + </member> + <member name="editors/visual_editors/category_colors/textures_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Textures" category. + </member> + <member name="editors/visual_editors/category_colors/transform_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Transform" category. + </member> + <member name="editors/visual_editors/category_colors/utility_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Utility" category. + </member> + <member name="editors/visual_editors/category_colors/vector_color" type="Color" setter="" getter=""> + The color of a graph node's header when it belongs to the "Vector" category. + </member> + <member name="editors/visual_editors/color_theme" type="String" setter="" getter=""> + The color theme to use in the visual shader editor. + </member> + <member name="editors/visual_editors/connection_colors/boolean_color" type="Color" setter="" getter=""> + The color of a port/connection of boolean type. + </member> + <member name="editors/visual_editors/connection_colors/sampler_color" type="Color" setter="" getter=""> + The color of a port/connection of sampler type. + </member> + <member name="editors/visual_editors/connection_colors/scalar_color" type="Color" setter="" getter=""> + The color of a port/connection of scalar type (float, int, unsigned int). + </member> + <member name="editors/visual_editors/connection_colors/transform_color" type="Color" setter="" getter=""> + The color of a port/connection of transform type. + </member> + <member name="editors/visual_editors/connection_colors/vector2_color" type="Color" setter="" getter=""> + The color of a port/connection of Vector2 type. + </member> + <member name="editors/visual_editors/connection_colors/vector3_color" type="Color" setter="" getter=""> + The color of a port/connection of Vector3 type. + </member> + <member name="editors/visual_editors/connection_colors/vector4_color" type="Color" setter="" getter=""> + The color of a port/connection of Vector4 type. + </member> + <member name="editors/visual_editors/grid_pattern" type="int" setter="" getter=""> + The pattern used for the background grid. + </member> <member name="editors/visual_editors/lines_curvature" type="float" setter="" getter=""> The curvature to use for connection lines in the visual shader editor. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines. </member> @@ -755,6 +815,9 @@ <member name="interface/theme/draw_extra_borders" type="bool" setter="" getter=""> If [code]true[/code], draws additional borders around interactive UI elements in the editor. This is automatically enabled when using the [b]Black (OLED)[/b] theme preset, as this theme preset uses a fully black background. </member> + <member name="interface/theme/follow_system_theme" type="bool" setter="" getter=""> + If [code]true[/code], the editor theme preset will attempt to automatically match the system theme. + </member> <member name="interface/theme/icon_and_font_color" type="int" setter="" getter=""> The icon and font color scheme to use in the editor. - [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color]. @@ -774,6 +837,10 @@ <member name="interface/theme/spacing_preset" type="String" setter="" getter=""> The editor theme spacing preset to use. See also [member interface/theme/base_spacing] and [member interface/theme/additional_spacing]. </member> + <member name="interface/theme/use_system_accent_color" type="bool" setter="" getter=""> + If [code]true[/code], set accent color based on system settings. + [b]Note:[/b] This setting is only effective on Windows and MacOS. + </member> <member name="interface/touchscreen/enable_long_press_as_right_click" type="bool" setter="" getter=""> If [code]true[/code], long press on touchscreen is treated as right click. [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices. diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml index 7108f873e6..783f1243e2 100644 --- a/doc/classes/EditorSpinSlider.xml +++ b/doc/classes/EditorSpinSlider.xml @@ -20,7 +20,7 @@ <member name="label" type="String" setter="set_label" getter="get_label" default=""""> The text that displays to the left of the value. </member> - <member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false"> + <member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false" keywords="enabled, disabled, editable"> If [code]true[/code], the slider can't be interacted with. </member> <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" /> diff --git a/doc/classes/FogMaterial.xml b/doc/classes/FogMaterial.xml index a6acaaef00..f256555d86 100644 --- a/doc/classes/FogMaterial.xml +++ b/doc/classes/FogMaterial.xml @@ -10,7 +10,7 @@ <tutorials> </tutorials> <members> - <member name="albedo" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)"> + <member name="albedo" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)" keywords="color, colour"> The single-scattering [Color] of the [FogVolume]. Internally, [member albedo] is converted into single-scattering, which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo]. </member> <member name="density" type="float" setter="set_density" getter="get_density" default="1.0"> diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml index 6b0d2e4a62..a93f77e324 100644 --- a/doc/classes/GeometryInstance3D.xml +++ b/doc/classes/GeometryInstance3D.xml @@ -42,7 +42,7 @@ <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale" default="0"> The texel density to use for lightmapping in [LightmapGI]. Greater scale values provide higher resolution in the lightmap, which can result in sharper shadows for lights that have both direct and indirect light baked. However, greater scale values will also increase the space taken by the mesh in the lightmap texture, which increases the memory, storage, and bake time requirements. When using a single mesh at different scales, consider adjusting this value to keep the lightmap texel density consistent across meshes. </member> - <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="1"> + <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="1" keywords="global_illumination_mode, light_bake_mode"> The global illumination mode to use for the whole geometry. To avoid inconsistent results, use a mode that matches the purpose of the mesh during gameplay (static/dynamic). [b]Note:[/b] Lights' bake mode will also affect the global illumination rendering. See [member Light3D.light_bake_mode]. </member> @@ -62,26 +62,26 @@ The material override for the whole geometry. If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh. </member> - <member name="transparency" type="float" setter="set_transparency" getter="get_transparency" default="0.0"> + <member name="transparency" type="float" setter="set_transparency" getter="get_transparency" default="0.0" keywords="opacity"> The transparency applied to the whole geometry (as a multiplier of the materials' existing transparency). [code]0.0[/code] is fully opaque, while [code]1.0[/code] is fully transparent. Values greater than [code]0.0[/code] (exclusive) will force the geometry's materials to go through the transparent pipeline, which is slower to render and can exhibit rendering issues due to incorrect transparency sorting. However, unlike using a transparent material, setting [member transparency] to a value greater than [code]0.0[/code] (exclusive) will [i]not[/i] disable shadow rendering. In spatial shaders, [code]1.0 - transparency[/code] is set as the default value of the [code]ALPHA[/code] built-in. [b]Note:[/b] [member transparency] is clamped between [code]0.0[/code] and [code]1.0[/code], so this property cannot be used to make transparent materials more opaque than they originally are. </member> - <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0"> + <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0" keywords="lod_begin, hlod_begin"> Starting distance from which the GeometryInstance3D will be visible, taking [member visibility_range_begin_margin] into account as well. The default value of 0 is used to disable the range check. </member> - <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0"> + <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0" keywords="lod_begin_margin, hlod_begin_margin"> Margin for the [member visibility_range_begin] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_begin] threshold by this amount. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_DISABLED], this acts as a hysteresis distance. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_SELF] or [constant VISIBILITY_RANGE_FADE_DEPENDENCIES], this acts as a fade transition distance and must be set to a value greater than [code]0.0[/code] for the effect to be noticeable. </member> - <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0"> + <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0" keywords="lod_end, hlod_end"> Distance from which the GeometryInstance3D will be hidden, taking [member visibility_range_end_margin] into account as well. The default value of 0 is used to disable the range check. </member> - <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0"> + <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0" keywords="lod_end_margin, hlod_end_margin"> Margin for the [member visibility_range_end] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_end] threshold by this amount. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_DISABLED], this acts as a hysteresis distance. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_SELF] or [constant VISIBILITY_RANGE_FADE_DEPENDENCIES], this acts as a fade transition distance and must be set to a value greater than [code]0.0[/code] for the effect to be noticeable. </member> - <member name="visibility_range_fade_mode" type="int" setter="set_visibility_range_fade_mode" getter="get_visibility_range_fade_mode" enum="GeometryInstance3D.VisibilityRangeFadeMode" default="0"> + <member name="visibility_range_fade_mode" type="int" setter="set_visibility_range_fade_mode" getter="get_visibility_range_fade_mode" enum="GeometryInstance3D.VisibilityRangeFadeMode" default="0" keywords="lod_fade_mode, hlod_fade_mode"> Controls which instances will be faded when approaching the limits of the visibility range. See [enum VisibilityRangeFadeMode] for possible values. </member> </members> diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml index 9fe3362e0f..129a181614 100644 --- a/doc/classes/IP.xml +++ b/doc/classes/IP.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="IP" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="IP" inherits="Object" keywords="dns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Internet protocol (IP) support functions such as DNS resolution. </brief_description> @@ -65,7 +65,7 @@ Returns a queued hostname's status as a [enum ResolverStatus] constant, given its queue [param id]. </description> </method> - <method name="resolve_hostname"> + <method name="resolve_hostname" keywords="dns"> <return type="String" /> <param index="0" name="host" type="String" /> <param index="1" name="ip_type" type="int" enum="IP.Type" default="3" /> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 984d426c0a..d9b2ef59e3 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -234,7 +234,7 @@ Returns [code]true[/code] if any action, key, joypad button, or mouse button is being pressed. This will also return [code]true[/code] if any action is simulated via code by calling [method action_press]. </description> </method> - <method name="is_joy_button_pressed" qualifiers="const"> + <method name="is_joy_button_pressed" qualifiers="const" keywords="is_gamepad_button_pressed, is_controller_button_pressed"> <return type="bool" /> <param index="0" name="device" type="int" /> <param index="1" name="button" type="int" enum="JoyButton" /> @@ -242,7 +242,7 @@ Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButton]). </description> </method> - <method name="is_joy_known"> + <method name="is_joy_known" keywords="is_gamepad_known, is_controller_known"> <return type="bool" /> <param index="0" name="device" type="int" /> <description> diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml index a545eaf811..3d1842fa77 100644 --- a/doc/classes/InputEventJoypadButton.xml +++ b/doc/classes/InputEventJoypadButton.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="InputEventJoypadButton" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="InputEventJoypadButton" inherits="InputEvent" keywords="gamepad, controller" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Represents a gamepad button being pressed or released. </brief_description> diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml index f6b9692d38..ab939874e5 100644 --- a/doc/classes/InputEventJoypadMotion.xml +++ b/doc/classes/InputEventJoypadMotion.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="InputEventJoypadMotion" inherits="InputEvent" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="InputEventJoypadMotion" inherits="InputEvent" keywords="gamepad, controller" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Represents axis motions (such as joystick or analog triggers) from a gamepad. </brief_description> diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index 77ead8fca0..edd8a3e436 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Label" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="Label" inherits="Control" keywords="text" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A control for displaying plain text. </brief_description> diff --git a/doc/classes/Label3D.xml b/doc/classes/Label3D.xml index 977fb00402..4c70897452 100644 --- a/doc/classes/Label3D.xml +++ b/doc/classes/Label3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Label3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="Label3D" inherits="GeometryInstance3D" keywords="text" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A node for displaying plain text in 3D space. </brief_description> @@ -81,7 +81,7 @@ <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0"> Vertical space between lines in multiline [Label3D]. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour"> Text [Color] of the [Label3D]. </member> <member name="no_depth_test" type="bool" setter="set_draw_flag" getter="get_draw_flag" default="false"> diff --git a/doc/classes/Light2D.xml b/doc/classes/Light2D.xml index 9e0cf664de..a1c1a57ae4 100644 --- a/doc/classes/Light2D.xml +++ b/doc/classes/Light2D.xml @@ -28,7 +28,7 @@ <member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="Light2D.BlendMode" default="0"> The Light2D's blend mode. See [enum BlendMode] constants for values. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> The Light2D's [Color]. </member> <member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false"> diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index d0bc7926ca..bffa20bf23 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -35,31 +35,31 @@ </method> </methods> <members> - <member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="40.0"> + <member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="40.0" keywords="lod_begin"> The distance from the camera at which the light begins to fade away (in 3D units). [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D]. </member> - <member name="distance_fade_enabled" type="bool" setter="set_enable_distance_fade" getter="is_distance_fade_enabled" default="false"> + <member name="distance_fade_enabled" type="bool" setter="set_enable_distance_fade" getter="is_distance_fade_enabled" default="false" keywords="lod_enabled"> If [code]true[/code], the light will smoothly fade away when far from the active [Camera3D] starting at [member distance_fade_begin]. This acts as a form of level of detail (LOD). The light will fade out over [member distance_fade_begin] + [member distance_fade_length], after which it will be culled and not sent to the shader at all. Use this to reduce the number of active lights in a scene and thus improve performance. [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D]. </member> - <member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0"> + <member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0" keywords="lod_length"> Distance over which the light and its shadow fades. The light's energy and shadow's opacity is progressively reduced over this distance and is completely invisible at the end. [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D]. </member> - <member name="distance_fade_shadow" type="float" setter="set_distance_fade_shadow" getter="get_distance_fade_shadow" default="50.0"> + <member name="distance_fade_shadow" type="float" setter="set_distance_fade_shadow" getter="get_distance_fade_shadow" default="50.0" keywords="lod_shadow"> The distance from the camera at which the light's shadow cuts off (in 3D units). Set this to a value lower than [member distance_fade_begin] + [member distance_fade_length] to further improve performance, as shadow rendering is often more expensive than light rendering itself. [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D], and only when [member shadow_enabled] is [code]true[/code]. </member> <member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false"> If [code]true[/code], the light only appears in the editor and will not be visible at runtime. If [code]true[/code], the light will never be baked in [LightmapGI] regardless of its [member light_bake_mode]. </member> - <member name="light_angular_distance" type="float" setter="set_param" getter="get_param" default="0.0"> + <member name="light_angular_distance" type="float" setter="set_param" getter="get_param" default="0.0" keywords="pcss"> The light's angular size in degrees. Increasing this will make shadows softer at greater distances (also called percentage-closer soft shadows, or PCSS). Only available for [DirectionalLight3D]s. For reference, the Sun from the Earth is approximately [code]0.5[/code]. Increasing this value above [code]0.0[/code] for lights with shadows enabled will have a noticeable performance cost due to PCSS. [b]Note:[/b] [member light_angular_distance] is not affected by [member Node3D.scale] (the light's scale or its parent's scale). [b]Note:[/b] PCSS for directional lights is only supported in the Forward+ rendering method, not Mobile or Compatibility. </member> - <member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="2"> + <member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="2" keywords="global_illumination_mode, gi_mode"> The light's bake mode. This will affect the global illumination techniques that have an effect on the light's rendering. See [enum BakeMode]. [b]Note:[/b] Meshes' global illumination mode will also affect the global illumination rendering. See [member GeometryInstance3D.gi_mode]. </member> @@ -88,12 +88,12 @@ <member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false"> If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows. </member> - <member name="light_projector" type="Texture2D" setter="set_projector" getter="get_projector"> + <member name="light_projector" type="Texture2D" setter="set_projector" getter="get_projector" keywords="cookie, gobo"> [Texture2D] projected by light. [member shadow_enabled] must be on for the projector to work. Light projectors make the light appear as if it is shining through a colored but transparent object, almost like light shining through stained-glass. [b]Note:[/b] Unlike [BaseMaterial3D] whose filter mode can be adjusted on a per-material basis, the filter mode for light projector textures is set globally with [member ProjectSettings.rendering/textures/light_projectors/filter]. [b]Note:[/b] Light projector textures are only supported in the Forward+ and Mobile rendering methods, not Compatibility. </member> - <member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0"> + <member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0" keywords="pcss"> The size of the light in Godot units. Only available for [OmniLight3D]s and [SpotLight3D]s. Increasing this value will make the light fade out slower and shadows appear blurrier (also called percentage-closer soft shadows, or PCSS). This can be used to simulate area lights to an extent. Increasing this value above [code]0.0[/code] for lights with shadows enabled will have a noticeable performance cost due to PCSS. [b]Note:[/b] [member light_size] is not affected by [member Node3D.scale] (the light's scale or its parent's scale). [b]Note:[/b] PCSS for positional lights is only supported in the Forward+ and Mobile rendering methods, not Compatibility. diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index e706e3d6e0..1f25e926c9 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="LineEdit" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="LineEdit" inherits="Control" keywords="text, input" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> An input field for single-line text. </brief_description> @@ -216,7 +216,7 @@ <member name="draw_control_chars" type="bool" setter="set_draw_control_chars" getter="get_draw_control_chars" default="false"> If [code]true[/code], control characters are displayed. </member> - <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true"> + <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> If [code]false[/code], existing text cannot be modified and new text cannot be added. </member> <member name="expand_to_text_length" type="bool" setter="set_expand_to_text_length_enabled" getter="is_expand_to_text_length_enabled" default="false"> @@ -494,7 +494,7 @@ <theme_item name="normal" data_type="style" type="StyleBox"> Default background for the [LineEdit]. </theme_item> - <theme_item name="read_only" data_type="style" type="StyleBox"> + <theme_item name="read_only" data_type="style" type="StyleBox" keywords="enabled, disabled, editable"> Background used when [LineEdit] is in read-only mode ([member editable] is set to [code]false[/code]). </theme_item> </theme_items> diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index 458b3d4107..17cc0d78d3 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -30,6 +30,7 @@ [csharp] using Godot; + [GlobalClass] public partial class CustomMainLoop : MainLoop { private double _timeElapsed = 0; diff --git a/doc/classes/MarginContainer.xml b/doc/classes/MarginContainer.xml index b83ee7ba00..e3dd64648f 100644 --- a/doc/classes/MarginContainer.xml +++ b/doc/classes/MarginContainer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MarginContainer" inherits="Container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MarginContainer" inherits="Container" keywords="padding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A container that keeps a margin around its child controls. </brief_description> diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml index 07f64d0572..8812017e49 100644 --- a/doc/classes/MenuBar.xml +++ b/doc/classes/MenuBar.xml @@ -151,7 +151,7 @@ <theme_item name="font_size" data_type="font_size" type="int"> Font size of the menu item's text. </theme_item> - <theme_item name="disabled" data_type="style" type="StyleBox"> + <theme_item name="disabled" data_type="style" type="StyleBox" keywords="enabled"> [StyleBox] used when the menu item is disabled. </theme_item> <theme_item name="disabled_mirrored" data_type="style" type="StyleBox"> diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 1ac79cd3da..c608ee79f1 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiMesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiMesh" inherits="Resource" keywords="batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Provides high-performance drawing of a mesh multiple times using GPU instancing. </brief_description> diff --git a/doc/classes/MultiMeshInstance2D.xml b/doc/classes/MultiMeshInstance2D.xml index dc38d920bc..0d8a0e136a 100644 --- a/doc/classes/MultiMeshInstance2D.xml +++ b/doc/classes/MultiMeshInstance2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiMeshInstance2D" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiMeshInstance2D" inherits="Node2D" keywords="batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Node that instances a [MultiMesh] in 2D. </brief_description> diff --git a/doc/classes/MultiMeshInstance3D.xml b/doc/classes/MultiMeshInstance3D.xml index 65abd174ed..5b6fd92d99 100644 --- a/doc/classes/MultiMeshInstance3D.xml +++ b/doc/classes/MultiMeshInstance3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiMeshInstance3D" inherits="GeometryInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiMeshInstance3D" inherits="GeometryInstance3D" keywords="batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Node that instances a [MultiMesh]. </brief_description> diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index 95baf7c706..009d7c03ea 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerAPI" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiplayerAPI" inherits="RefCounted" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> High-level multiplayer API interface. </brief_description> diff --git a/doc/classes/MultiplayerAPIExtension.xml b/doc/classes/MultiplayerAPIExtension.xml index 7f6e7951b2..cc6d3b7fcf 100644 --- a/doc/classes/MultiplayerAPIExtension.xml +++ b/doc/classes/MultiplayerAPIExtension.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerAPIExtension" inherits="MultiplayerAPI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiplayerAPIExtension" inherits="MultiplayerAPI" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Base class used for extending the [MultiplayerAPI]. </brief_description> diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index 39980a05e1..04fd282457 100644 --- a/doc/classes/MultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerPeer" inherits="PacketPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiplayerPeer" inherits="PacketPeer" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Abstract class for specialized [PacketPeer]s used by the [MultiplayerAPI]. </brief_description> diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml index 8fd6755a7b..b7d55f31b6 100644 --- a/doc/classes/MultiplayerPeerExtension.xml +++ b/doc/classes/MultiplayerPeerExtension.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerPeerExtension" inherits="MultiplayerPeer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="MultiplayerPeerExtension" inherits="MultiplayerPeer" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Class that can be inherited to implement custom multiplayer API networking layers via GDExtension. </brief_description> diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index 39f0718a71..dccdd02d0a 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -504,6 +504,14 @@ Returns the edge connection margin of the map. The edge connection margin is a distance used to connect two regions. </description> </method> + <method name="map_get_iteration_id" qualifiers="const"> + <return type="int" /> + <param index="0" name="map" type="RID" /> + <description> + Returns the current iteration id of the navigation map. Every time the navigation map changes and synchronizes the iteration id increases. An iteration id of 0 means the navigation map has never synchronized. + [b]Note:[/b] The iteration id will wrap back to 1 after reaching its range limit. + </description> + </method> <method name="map_get_link_connection_radius" qualifiers="const"> <return type="float" /> <param index="0" name="map" type="RID" /> diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index e88792cade..4fc75461e7 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -568,6 +568,14 @@ Returns the edge connection margin of the map. This distance is the minimum vertex distance needed to connect two edges from different regions. </description> </method> + <method name="map_get_iteration_id" qualifiers="const"> + <return type="int" /> + <param index="0" name="map" type="RID" /> + <description> + Returns the current iteration id of the navigation map. Every time the navigation map changes and synchronizes the iteration id increases. An iteration id of 0 means the navigation map has never synchronized. + [b]Note:[/b] The iteration id will wrap back to 1 after reaching its range limit. + </description> + </method> <method name="map_get_link_connection_radius" qualifiers="const"> <return type="float" /> <param index="0" name="map" type="RID" /> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index abfb181f65..307eaa5e00 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -220,7 +220,7 @@ <return type="bool" /> <param index="0" name="property" type="StringName" /> <description> - Override this method to customize the given [param property]'s revert behavior. Should return [code]true[/code] if the [param property] can be reverted in the Inspector dock. Use [method _property_get_revert] to specify the [param property]'s default value. + Override this method to customize the given [param property]'s revert behavior. Should return [code]true[/code] if the [param property] has a custom default value and is revertible in the Inspector dock. Use [method _property_get_revert] to specify the [param property]'s default value. [b]Note:[/b] This method must return consistently, regardless of the current value of the [param property]. </description> </method> diff --git a/doc/classes/OmniLight3D.xml b/doc/classes/OmniLight3D.xml index db2e27fbd6..64bf981a90 100644 --- a/doc/classes/OmniLight3D.xml +++ b/doc/classes/OmniLight3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="OmniLight3D" inherits="Light3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="OmniLight3D" inherits="Light3D" keywords="point" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Omnidirectional light, such as a light bulb or a candle. </brief_description> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 4e223c12fa..f04b0d942f 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="OptionButton" inherits="Button" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="OptionButton" inherits="Button" keywords="select" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A button that brings up a dropdown with selectable options when pressed. </brief_description> diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml index d0c3e64b7d..8d0ae317b9 100644 --- a/doc/classes/ParticleProcessMaterial.xml +++ b/doc/classes/ParticleProcessMaterial.xml @@ -147,7 +147,7 @@ <member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false"> If [code]true[/code], [member GPUParticles3D.collision_base_size] is multiplied by the particle's effective scale (see [member scale_min], [member scale_max], [member scale_curve], and [member scale_over_velocity_curve]). </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. [b]Note:[/b] [member color] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color] will have no visible effect. </member> diff --git a/doc/classes/PointLight2D.xml b/doc/classes/PointLight2D.xml index 556ad50cb1..9af3667126 100644 --- a/doc/classes/PointLight2D.xml +++ b/doc/classes/PointLight2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PointLight2D" inherits="Light2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="PointLight2D" inherits="Light2D" keywords="omni, spot" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Positional 2D light source. </brief_description> diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml index 25adc57990..029a69a399 100644 --- a/doc/classes/Polygon2D.xml +++ b/doc/classes/Polygon2D.xml @@ -74,7 +74,7 @@ <member name="bones" type="Array" setter="_set_bones" getter="_get_bones" default="[]"> Internal list of [Bone2D] nodes used by the assigned [member skeleton]. Edited using the Polygon2D editor ("UV" button on the top toolbar). </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> The polygon's fill color. If [member texture] is set, it will be multiplied by this color. It will also be the default color for vertices not set in [member vertex_colors]. </member> <member name="internal_vertex_count" type="int" setter="set_internal_vertex_count" getter="get_internal_vertex_count" default="0"> diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml index 61bc4f4720..411935aa79 100644 --- a/doc/classes/Quaternion.xml +++ b/doc/classes/Quaternion.xml @@ -134,7 +134,7 @@ Returns whether the quaternion is normalized or not. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length of the quaternion. @@ -158,7 +158,7 @@ Returns a copy of the quaternion, normalized to unit length. </description> </method> - <method name="slerp" qualifiers="const"> + <method name="slerp" qualifiers="const" keywords="interpolate"> <return type="Quaternion" /> <param index="0" name="to" type="Quaternion" /> <param index="1" name="weight" type="float" /> diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml index c7d067b94d..367942682e 100644 --- a/doc/classes/ReflectionProbe.xml +++ b/doc/classes/ReflectionProbe.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ReflectionProbe" inherits="VisualInstance3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="ReflectionProbe" inherits="VisualInstance3D" keywords="environment, envmap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Captures its surroundings to create fast, accurate reflections from a given point. </brief_description> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 62215493fc..b368e8374d 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1014,7 +1014,7 @@ Sets the cull [param mask] in the decal specified by the [param decal] RID. Equivalent to [member Decal.cull_mask]. </description> </method> - <method name="decal_set_distance_fade"> + <method name="decal_set_distance_fade" keywords="decal_set_lod"> <return type="void" /> <param index="0" name="decal" type="RID" /> <param index="1" name="enabled" type="bool" /> @@ -1958,7 +1958,7 @@ Sets the cull mask for this 3D light. Lights only affect objects in the selected layers. Equivalent to [member Light3D.light_cull_mask]. </description> </method> - <method name="light_set_distance_fade"> + <method name="light_set_distance_fade" keywords="light_set_lod"> <return type="void" /> <param index="0" name="decal" type="RID" /> <param index="1" name="enabled" type="bool" /> @@ -1994,7 +1994,7 @@ Sets the specified 3D light parameter. See [enum LightParam] for options. Equivalent to [method Light3D.set_param]. </description> </method> - <method name="light_set_projector"> + <method name="light_set_projector" keywords="light_set_cookie"> <return type="void" /> <param index="0" name="light" type="RID" /> <param index="1" name="texture" type="RID" /> @@ -5223,13 +5223,13 @@ <constant name="SHADOW_CASTING_SETTING_SHADOWS_ONLY" value="3" enum="ShadowCastingSetting"> Only render the shadows from the object. The object itself will not be drawn. </constant> - <constant name="VISIBILITY_RANGE_FADE_DISABLED" value="0" enum="VisibilityRangeFadeMode"> + <constant name="VISIBILITY_RANGE_FADE_DISABLED" value="0" enum="VisibilityRangeFadeMode" keywords="LOD_FADE_DISABLED"> Disable visibility range fading for the given instance. </constant> - <constant name="VISIBILITY_RANGE_FADE_SELF" value="1" enum="VisibilityRangeFadeMode"> + <constant name="VISIBILITY_RANGE_FADE_SELF" value="1" enum="VisibilityRangeFadeMode" keywords="LOD_FADE_SELF"> Fade-out the given instance when it approaches its visibility range limits. </constant> - <constant name="VISIBILITY_RANGE_FADE_DEPENDENCIES" value="2" enum="VisibilityRangeFadeMode"> + <constant name="VISIBILITY_RANGE_FADE_DEPENDENCIES" value="2" enum="VisibilityRangeFadeMode" keywords="LOD_FADE_DEPENDENCIES"> Fade-in the given instance's dependencies when reaching its visibility range limits. </constant> <constant name="BAKE_CHANNEL_ALBEDO_ALPHA" value="0" enum="BakeChannels"> diff --git a/doc/classes/RootMotionView.xml b/doc/classes/RootMotionView.xml index 648ea04a7d..d7fbb2d80d 100644 --- a/doc/classes/RootMotionView.xml +++ b/doc/classes/RootMotionView.xml @@ -17,7 +17,7 @@ <member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size" default="1.0"> The grid's cell size in 3D units. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0.5, 0.5, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0.5, 0.5, 1, 1)" keywords="colour"> The grid's color. </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0"> diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml index 492b6164bf..a4ffa5c1e7 100644 --- a/doc/classes/Slider.xml +++ b/doc/classes/Slider.xml @@ -9,7 +9,7 @@ <tutorials> </tutorials> <members> - <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true"> + <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> If [code]true[/code], the slider can be interacted with. If [code]false[/code], the value can be changed only by code. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml index 8627a9e40f..44427c8c5e 100644 --- a/doc/classes/SpinBox.xml +++ b/doc/classes/SpinBox.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="SpinBox" inherits="Range" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="SpinBox" inherits="Range" keywords="number, numeric, input" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> An input field for numbers. </brief_description> @@ -52,7 +52,7 @@ <member name="custom_arrow_step" type="float" setter="set_custom_arrow_step" getter="get_custom_arrow_step" default="0.0"> If not [code]0[/code], [member Range.value] will always be rounded to a multiple of [member custom_arrow_step] when interacting with the arrow buttons of the [SpinBox]. </member> - <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true"> + <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> If [code]true[/code], the [SpinBox] will be editable. Otherwise, it will be read only. </member> <member name="prefix" type="String" setter="set_prefix" getter="get_prefix" default=""""> diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml index e5c4c01d65..8dcf286b3a 100644 --- a/doc/classes/Sprite2D.xml +++ b/doc/classes/Sprite2D.xml @@ -44,7 +44,7 @@ <return type="bool" /> <param index="0" name="pos" type="Vector2" /> <description> - Returns [code]true[/code], if the pixel at the given position is opaque and [code]false[/code] in other case. + Returns [code]true[/code], if the pixel at the given position is opaque and [code]false[/code] in other case. The position is in local coordinates. [b]Note:[/b] It also returns [code]false[/code], if the sprite's texture is [code]null[/code] or if the given position is invalid. </description> </method> diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml index 4488351212..d6f8a519db 100644 --- a/doc/classes/SpriteBase3D.xml +++ b/doc/classes/SpriteBase3D.xml @@ -75,7 +75,7 @@ <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v" default="false"> If [code]true[/code], texture is flipped vertically. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour"> A color value used to [i]multiply[/i] the texture's colors. Can be used for mood-coloring or to simulate the color of ambient light. [b]Note:[/b] Unlike [member CanvasItem.modulate] for 2D, colors with values above [code]1.0[/code] (overbright) are not supported. [b]Note:[/b] If a [member GeometryInstance3D.material_override] is defined on the [SpriteBase3D], the material override must be configured to take vertex colors into account for albedo. Otherwise, the color defined in [member modulate] will be ignored. For a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] must be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. diff --git a/doc/classes/StatusIndicator.xml b/doc/classes/StatusIndicator.xml index b92018e172..6b015c3d15 100644 --- a/doc/classes/StatusIndicator.xml +++ b/doc/classes/StatusIndicator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="StatusIndicator" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="StatusIndicator" inherits="Node" keywords="tray" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Application status indicator (aka notification area icon). [b]Note:[/b] Status indicator is implemented on macOS and Windows. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 3acd174196..cffe9e219d 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -531,7 +531,7 @@ [/codeblock] </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="int" /> <description> Returns the number of characters in the string. Empty strings ([code]""[/code]) always return [code]0[/code]. See also [method is_empty]. diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index 8db19ec957..41763489f1 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -507,7 +507,7 @@ [/codeblock] </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="int" /> <description> Returns the number of characters in the string. Empty strings ([code]""[/code]) always return [code]0[/code]. See also [method is_empty]. diff --git a/doc/classes/StyleBoxLine.xml b/doc/classes/StyleBoxLine.xml index 8958cf9fc8..5f9d3332f2 100644 --- a/doc/classes/StyleBoxLine.xml +++ b/doc/classes/StyleBoxLine.xml @@ -9,7 +9,7 @@ <tutorials> </tutorials> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)" keywords="colour"> The line's color. </member> <member name="grow_begin" type="float" setter="set_grow_begin" getter="get_grow_begin" default="1.0"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 6a1879baa4..001cf06db4 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TextEdit" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="TextEdit" inherits="Control" keywords="textarea" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A multiline text editor. </brief_description> @@ -1144,7 +1144,7 @@ <member name="draw_tabs" type="bool" setter="set_draw_tabs" getter="is_drawing_tabs" default="false"> If [code]true[/code], the "tab" character will have a visible representation. </member> - <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true"> + <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> If [code]false[/code], existing text cannot be modified and new text cannot be added. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> @@ -1480,7 +1480,7 @@ <theme_item name="normal" data_type="style" type="StyleBox"> Sets the [StyleBox] of this [TextEdit]. </theme_item> - <theme_item name="read_only" data_type="style" type="StyleBox"> + <theme_item name="read_only" data_type="style" type="StyleBox" keywords="enabled, disabled, editable"> Sets the [StyleBox] of this [TextEdit] when [member editable] is disabled. </theme_item> </theme_items> diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml index 6ab1b86e5c..d3e334ef55 100644 --- a/doc/classes/TextureProgressBar.xml +++ b/doc/classes/TextureProgressBar.xml @@ -70,13 +70,13 @@ <member name="texture_under" type="Texture2D" setter="set_under_texture" getter="get_under_texture"> [Texture2D] that draws under the progress bar. The bar's background. </member> - <member name="tint_over" type="Color" setter="set_tint_over" getter="get_tint_over" default="Color(1, 1, 1, 1)"> + <member name="tint_over" type="Color" setter="set_tint_over" getter="get_tint_over" default="Color(1, 1, 1, 1)" keywords="color, colour"> Multiplies the color of the bar's [member texture_over] texture. The effect is similar to [member CanvasItem.modulate], except it only affects this specific texture instead of the entire node. </member> - <member name="tint_progress" type="Color" setter="set_tint_progress" getter="get_tint_progress" default="Color(1, 1, 1, 1)"> + <member name="tint_progress" type="Color" setter="set_tint_progress" getter="get_tint_progress" default="Color(1, 1, 1, 1)" keywords="color, colour"> Multiplies the color of the bar's [member texture_progress] texture. </member> - <member name="tint_under" type="Color" setter="set_tint_under" getter="get_tint_under" default="Color(1, 1, 1, 1)"> + <member name="tint_under" type="Color" setter="set_tint_under" getter="get_tint_under" default="Color(1, 1, 1, 1)" keywords="color, colour"> Multiplies the color of the bar's [member texture_under] texture. </member> </members> diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml index 9e833e0236..c5b86f079e 100644 --- a/doc/classes/TileData.xml +++ b/doc/classes/TileData.xml @@ -214,7 +214,7 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> The [Material] to use for this [TileData]. This can be a [CanvasItemMaterial] to use the default shader, or a [ShaderMaterial] to use a custom shader. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)" keywords="color, colour"> Color modulation of the tile. </member> <member name="probability" type="float" setter="set_probability" getter="get_probability" default="1.0"> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 1bb23211c9..daa0eec230 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TileMap" inherits="TileMapLayerGroup" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="TileMap" inherits="TileMapLayerGroup" keywords="gridmap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Node for 2D tile-based maps. </brief_description> diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 3fa7bb46fc..76f97d0968 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -236,7 +236,7 @@ This method is faster than using [method is_equal_approx] with one value as a zero vector. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length (magnitude) of this vector. @@ -249,7 +249,7 @@ This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula. </description> </method> - <method name="lerp" qualifiers="const"> + <method name="lerp" qualifiers="const" keywords="interpolate"> <return type="Vector2" /> <param index="0" name="to" type="Vector2" /> <param index="1" name="weight" type="float" /> @@ -257,7 +257,7 @@ Returns the result of the linear interpolation between this vector and [param to] by amount [param weight]. [param weight] is on the range of [code]0.0[/code] to [code]1.0[/code], representing the amount of interpolation. </description> </method> - <method name="limit_length" qualifiers="const"> + <method name="limit_length" qualifiers="const" keywords="truncate"> <return type="Vector2" /> <param index="0" name="length" type="float" default="1.0" /> <description> @@ -344,7 +344,7 @@ Returns a new vector with each component set to [code]1.0[/code] if it's positive, [code]-1.0[/code] if it's negative, and [code]0.0[/code] if it's zero. The result is identical to calling [method @GlobalScope.sign] on each component. </description> </method> - <method name="slerp" qualifiers="const"> + <method name="slerp" qualifiers="const" keywords="interpolate"> <return type="Vector2" /> <param index="0" name="to" type="Vector2" /> <param index="1" name="weight" type="float" /> diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml index e004755818..18291e06a9 100644 --- a/doc/classes/Vector2i.xml +++ b/doc/classes/Vector2i.xml @@ -79,7 +79,7 @@ Returns the distance between this vector and [param to]. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length (magnitude) of this vector. diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 83a8c6af73..5730826043 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -204,7 +204,7 @@ This method is faster than using [method is_equal_approx] with one value as a zero vector. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length (magnitude) of this vector. @@ -217,7 +217,7 @@ This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula. </description> </method> - <method name="lerp" qualifiers="const"> + <method name="lerp" qualifiers="const" keywords="interpolate"> <return type="Vector3" /> <param index="0" name="to" type="Vector3" /> <param index="1" name="weight" type="float" /> @@ -225,7 +225,7 @@ Returns the result of the linear interpolation between this vector and [param to] by amount [param weight]. [param weight] is on the range of [code]0.0[/code] to [code]1.0[/code], representing the amount of interpolation. </description> </method> - <method name="limit_length" qualifiers="const"> + <method name="limit_length" qualifiers="const" keywords="truncate"> <return type="Vector3" /> <param index="0" name="length" type="float" default="1.0" /> <description> @@ -337,7 +337,7 @@ Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and negative in a clockwise direction when viewed from the side specified by the [param axis]. </description> </method> - <method name="slerp" qualifiers="const"> + <method name="slerp" qualifiers="const" keywords="interpolate"> <return type="Vector3" /> <param index="0" name="to" type="Vector3" /> <param index="1" name="weight" type="float" /> diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml index 96760ed9f9..ffebd3e1f3 100644 --- a/doc/classes/Vector3i.xml +++ b/doc/classes/Vector3i.xml @@ -74,7 +74,7 @@ Returns the distance between this vector and [param to]. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length (magnitude) of this vector. diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml index c5503a9357..8514670231 100644 --- a/doc/classes/Vector4.xml +++ b/doc/classes/Vector4.xml @@ -155,7 +155,7 @@ This method is faster than using [method is_equal_approx] with one value as a zero vector. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length (magnitude) of this vector. @@ -168,7 +168,7 @@ This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula. </description> </method> - <method name="lerp" qualifiers="const"> + <method name="lerp" qualifiers="const" keywords="interpolate"> <return type="Vector4" /> <param index="0" name="to" type="Vector4" /> <param index="1" name="weight" type="float" /> diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml index ded5d6f3ef..f8a0026066 100644 --- a/doc/classes/Vector4i.xml +++ b/doc/classes/Vector4i.xml @@ -72,7 +72,7 @@ Returns the distance between this vector and [param to]. </description> </method> - <method name="length" qualifiers="const"> + <method name="length" qualifiers="const" keywords="size"> <return type="float" /> <description> Returns the length (magnitude) of this vector. diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml index 27b07821b1..c7ee160174 100644 --- a/doc/classes/WorldEnvironment.xml +++ b/doc/classes/WorldEnvironment.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WorldEnvironment" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="WorldEnvironment" inherits="Node" keywords="background, sky" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Default environment properties for the entire scene (post-processing effects, lighting and background settings). </brief_description> diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 6517b4e91b..8c92737374 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -1955,48 +1955,44 @@ RDD::CommandQueueID RenderingDeviceDriverD3D12::command_queue_create(CommandQueu return CommandQueueID(command_queue); } -Error RenderingDeviceDriverD3D12::command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) { +Error RenderingDeviceDriverD3D12::command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) { CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id); for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) { const SemaphoreInfo *semaphore = (const SemaphoreInfo *)(p_wait_semaphores[i].id); command_queue->d3d_queue->Wait(semaphore->d3d_fence.Get(), semaphore->fence_value); } - thread_local LocalVector<ID3D12CommandList *> command_lists; - command_lists.resize(p_cmd_buffers.size()); - for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) { - const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffers[i].id); - command_lists[i] = cmd_buf_info->cmd_list.Get(); - } + if (p_cmd_buffers.size() > 0) { + thread_local LocalVector<ID3D12CommandList *> command_lists; + command_lists.resize(p_cmd_buffers.size()); + for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) { + const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffers[i].id); + command_lists[i] = cmd_buf_info->cmd_list.Get(); + } - command_queue->d3d_queue->ExecuteCommandLists(command_lists.size(), command_lists.ptr()); + command_queue->d3d_queue->ExecuteCommandLists(command_lists.size(), command_lists.ptr()); - for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) { - SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_signal_semaphores[i].id); - semaphore->fence_value++; - command_queue->d3d_queue->Signal(semaphore->d3d_fence.Get(), semaphore->fence_value); - } + for (uint32_t i = 0; i < p_cmd_semaphores.size(); i++) { + SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_cmd_semaphores[i].id); + semaphore->fence_value++; + command_queue->d3d_queue->Signal(semaphore->d3d_fence.Get(), semaphore->fence_value); + } - if (p_signal_fence) { - FenceInfo *fence = (FenceInfo *)(p_signal_fence.id); - fence->fence_value++; - command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value); - fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle); + if (p_cmd_fence) { + FenceInfo *fence = (FenceInfo *)(p_cmd_fence.id); + fence->fence_value++; + command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value); + fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle); + } } - return OK; -} - -Error RenderingDeviceDriverD3D12::command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) { - // D3D12 does not require waiting for the command queue's semaphores to handle presentation. - // We just present the swap chains that were specified and ignore the command queue and the semaphores. HRESULT res; bool any_present_failed = false; for (uint32_t i = 0; i < p_swap_chains.size(); i++) { SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); res = swap_chain->d3d_swap_chain->Present(swap_chain->sync_interval, swap_chain->present_flags); if (!SUCCEEDED(res)) { - print_verbose("D3D12: Presenting swapchain failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); + print_verbose(vformat("D3D12: Presenting swapchain failed with error 0x%08ux.", (uint64_t)res)); any_present_failed = true; } } diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 595ee30966..06d5cb65c4 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -413,8 +413,7 @@ private: public: virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override; - virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) override; - virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) override; + virtual Error command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) override; virtual void command_queue_free(CommandQueueID p_cmd_queue) override; private: diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 14ef0f40cf..da2320c23d 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -194,6 +194,11 @@ typedef void(GLAPIENTRY *DebugMessageCallbackARB)(DEBUGPROCARB callback, const v void RasterizerGLES3::initialize() { Engine::get_singleton()->print_header(vformat("OpenGL API %s - Compatibility - Using Device: %s - %s", RS::get_singleton()->get_video_adapter_api_version(), RS::get_singleton()->get_video_adapter_vendor(), RS::get_singleton()->get_video_adapter_name())); + + // FLIP XY Bug: Are more devices affected? + // Confirmed so far: all Adreno 3xx + // ok on some tested Adreno devices: 4xx, 5xx and 6xx + flip_xy_bugfix = GLES3::Config::get_singleton()->adreno_3xx_compatibility; } void RasterizerGLES3::finalize() { @@ -398,8 +403,18 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display } Vector2i screen_rect_end = p_screen_rect.get_end(); + + // Adreno (TM) 3xx devices have a bug that create wrong Landscape rotation of 180 degree + // Reversing both the X and Y axis is equivalent to rotating 180 degrees + bool flip_x = false; + if (flip_xy_bugfix && screen_rect_end.x > screen_rect_end.y) { + flip_y = !flip_y; + flip_x = !flip_x; + } + glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, - p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y, screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y, + flip_x ? screen_rect_end.x : p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y, + flip_x ? p_screen_rect.position.x : screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (read_fbo != 0) { diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index fc1315035b..8d52dc2365 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -55,6 +55,7 @@ private: float delta = 0; double time_total = 0.0; + bool flip_xy_bugfix = false; static bool gles_over_gl; diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 80e28cf9fc..8da7d7dc80 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -187,8 +187,31 @@ void main() { #endif // !USE_INSTANCING #else // !USE_ATTRIBUTES - vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0)); - vec2 vertex_base = vertex_base_arr[gl_VertexID % 6]; + + // crash on Adreno 320/330 + //vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0)); + //vec2 vertex_base = vertex_base_arr[gl_VertexID % 6]; + //----------------------------------------- + // ID | 0 | 1 | 2 | 3 | 4 | 5 | + //----------------------------------------- + // X | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | + // Y | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 | + //----------------------------------------- + // no crash or freeze on all Adreno 3xx with 'if / else if' and slightly faster! + int vertex_id = gl_VertexID % 6; + vec2 vertex_base; + if (vertex_id == 0) + vertex_base = vec2(0.0, 0.0); + else if (vertex_id == 1) + vertex_base = vec2(0.0, 1.0); + else if (vertex_id == 2) + vertex_base = vec2(1.0, 1.0); + else if (vertex_id == 3) + vertex_base = vec2(1.0, 0.0); + else if (vertex_id == 4) + vertex_base = vec2(0.0, 0.0); + else if (vertex_id == 5) + vertex_base = vec2(1.0, 1.0); vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy); vec4 color = read_draw_data_modulation; @@ -475,16 +498,12 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { uint blend_mode = light_array[light_base].flags & LIGHT_FLAGS_BLEND_MASK; - switch (blend_mode) { - case LIGHT_FLAGS_BLEND_MODE_ADD: { - color.rgb += light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_SUB: { - color.rgb -= light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_MIX: { - color.rgb = mix(color.rgb, light_color.rgb, light_color.a); - } break; + if (blend_mode == LIGHT_FLAGS_BLEND_MODE_ADD) { + color.rgb += light_color.rgb * light_color.a; + } else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_SUB) { + color.rgb -= light_color.rgb * light_color.a; + } else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_MIX) { + color.rgb = mix(color.rgb, light_color.rgb, light_color.a); } } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 27c292d163..a6db90c3f5 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1200,7 +1200,10 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f vec3 spot_dir = spot_lights[idx].direction; float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle); float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation); + + mediump float cone_attenuation = spot_lights[idx].cone_attenuation; + spot_attenuation *= 1.0 - pow(spot_rim, cone_attenuation); + vec3 color = spot_lights[idx].color; float size_A = 0.0; diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 5d01ab0346..1a41b60836 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -166,6 +166,11 @@ Config::Config() { max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements"); max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights"); max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object"); + + //Adreno 3xx Compatibility + const String rendering_device_name = String::utf8((const char *)glGetString(GL_RENDERER)); + //TODO: Check the number between 300 and 399(?) + adreno_3xx_compatibility = (rendering_device_name.left(13) == "Adreno (TM) 3"); } Config::~Config() { diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index 1c0a5178bd..c3ab65f0bc 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -91,6 +91,8 @@ public: bool rt_msaa_multiview_supported = false; bool multiview_supported = false; + bool adreno_3xx_compatibility = false; + #ifdef ANDROID_ENABLED PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr; PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr; diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index f48e6eb7ed..21cf54b4be 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -1113,12 +1113,12 @@ void RenderingDeviceDriverVulkan::_set_object_name(VkObjectType p_object_type, u } Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t p_frame_count) { - // Frame count is not required for the Vulkan driver, so we just ignore it. - context_device = context_driver->device_get(p_device_index); physical_device = context_driver->physical_device_get(p_device_index); vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); + frame_count = p_frame_count; + // Copy the queue family properties the context already retrieved. uint32_t queue_family_count = context_driver->queue_family_get_count(p_device_index); queue_family_properties.resize(queue_family_count); @@ -2131,21 +2131,18 @@ RDD::CommandQueueID RenderingDeviceDriverVulkan::command_queue_create(CommandQue return CommandQueueID(command_queue); } -Error RenderingDeviceDriverVulkan::command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) { +Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) { DEV_ASSERT(p_cmd_queue.id != 0); + VkResult err; CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); Queue &device_queue = queue_families[command_queue->queue_family][command_queue->queue_index]; - Fence *fence = (Fence *)(p_signal_fence.id); + Fence *fence = (Fence *)(p_cmd_fence.id); VkFence vk_fence = (fence != nullptr) ? fence->vk_fence : VK_NULL_HANDLE; - thread_local LocalVector<VkCommandBuffer> command_buffers; thread_local LocalVector<VkSemaphore> wait_semaphores; - thread_local LocalVector<VkSemaphore> signal_semaphores; thread_local LocalVector<VkPipelineStageFlags> wait_semaphores_stages; - command_buffers.clear(); wait_semaphores.clear(); - signal_semaphores.clear(); wait_semaphores_stages.clear(); if (!command_queue->pending_semaphores_for_execute.is_empty()) { @@ -2158,117 +2155,142 @@ Error RenderingDeviceDriverVulkan::command_queue_execute(CommandQueueID p_cmd_qu command_queue->pending_semaphores_for_execute.clear(); } - for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) { - command_buffers.push_back(VkCommandBuffer(p_cmd_buffers[i].id)); - } - for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) { // FIXME: Allow specifying the stage mask in more detail. wait_semaphores.push_back(VkSemaphore(p_wait_semaphores[i].id)); wait_semaphores_stages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); } - for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) { - signal_semaphores.push_back(VkSemaphore(p_signal_semaphores[i].id)); - } - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.waitSemaphoreCount = wait_semaphores.size(); - submit_info.pWaitSemaphores = wait_semaphores.ptr(); - submit_info.pWaitDstStageMask = wait_semaphores_stages.ptr(); - submit_info.commandBufferCount = command_buffers.size(); - submit_info.pCommandBuffers = command_buffers.ptr(); - submit_info.signalSemaphoreCount = signal_semaphores.size(); - submit_info.pSignalSemaphores = signal_semaphores.ptr(); + if (p_cmd_buffers.size() > 0) { + thread_local LocalVector<VkCommandBuffer> command_buffers; + thread_local LocalVector<VkSemaphore> signal_semaphores; + command_buffers.clear(); + signal_semaphores.clear(); - device_queue.submit_mutex.lock(); - VkResult err = vkQueueSubmit(device_queue.queue, 1, &submit_info, vk_fence); - device_queue.submit_mutex.unlock(); - ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); - - if (fence != nullptr && !command_queue->pending_semaphores_for_fence.is_empty()) { - fence->queue_signaled_from = command_queue; + for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) { + command_buffers.push_back(VkCommandBuffer(p_cmd_buffers[i].id)); + } - // Indicate to the fence that it should release the semaphores that were waited on this submission the next time the fence is waited on. - for (uint32_t i = 0; i < command_queue->pending_semaphores_for_fence.size(); i++) { - command_queue->image_semaphores_for_fences.push_back({ fence, command_queue->pending_semaphores_for_fence[i] }); + for (uint32_t i = 0; i < p_cmd_semaphores.size(); i++) { + signal_semaphores.push_back(VkSemaphore(p_cmd_semaphores[i].id)); } - command_queue->pending_semaphores_for_fence.clear(); - } + VkSemaphore present_semaphore = VK_NULL_HANDLE; + if (p_swap_chains.size() > 0) { + if (command_queue->present_semaphores.is_empty()) { + // Create the semaphores used for presentation if they haven't been created yet. + VkSemaphore semaphore = VK_NULL_HANDLE; + VkSemaphoreCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + for (uint32_t i = 0; i < frame_count; i++) { + err = vkCreateSemaphore(vk_device, &create_info, nullptr, &semaphore); + ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + command_queue->present_semaphores.push_back(semaphore); + } + } - return OK; -} + // If a presentation semaphore is required, cycle across the ones available on the queue. It is technically possible + // and valid to reuse the same semaphore for this particular operation, but we create multiple ones anyway in case + // some hardware expects multiple semaphores to be used. + present_semaphore = command_queue->present_semaphores[command_queue->present_semaphore_index]; + signal_semaphores.push_back(present_semaphore); + command_queue->present_semaphore_index = (command_queue->present_semaphore_index + 1) % command_queue->present_semaphores.size(); + } -Error RenderingDeviceDriverVulkan::command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) { - DEV_ASSERT(p_cmd_queue.id != 0); + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.waitSemaphoreCount = wait_semaphores.size(); + submit_info.pWaitSemaphores = wait_semaphores.ptr(); + submit_info.pWaitDstStageMask = wait_semaphores_stages.ptr(); + submit_info.commandBufferCount = command_buffers.size(); + submit_info.pCommandBuffers = command_buffers.ptr(); + submit_info.signalSemaphoreCount = signal_semaphores.size(); + submit_info.pSignalSemaphores = signal_semaphores.ptr(); + + device_queue.submit_mutex.lock(); + err = vkQueueSubmit(device_queue.queue, 1, &submit_info, vk_fence); + device_queue.submit_mutex.unlock(); + ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + + if (fence != nullptr && !command_queue->pending_semaphores_for_fence.is_empty()) { + fence->queue_signaled_from = command_queue; + + // Indicate to the fence that it should release the semaphores that were waited on this submission the next time the fence is waited on. + for (uint32_t i = 0; i < command_queue->pending_semaphores_for_fence.size(); i++) { + command_queue->image_semaphores_for_fences.push_back({ fence, command_queue->pending_semaphores_for_fence[i] }); + } - CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); - Queue &device_queue = queue_families[command_queue->queue_family][command_queue->queue_index]; + command_queue->pending_semaphores_for_fence.clear(); + } - thread_local LocalVector<VkSwapchainKHR> swapchains; - thread_local LocalVector<uint32_t> image_indices; - thread_local LocalVector<VkSemaphore> wait_semaphores; - thread_local LocalVector<VkResult> results; - swapchains.clear(); - image_indices.clear(); - for (uint32_t i = 0; i < p_swap_chains.size(); i++) { - SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); - swapchains.push_back(swap_chain->vk_swapchain); - DEV_ASSERT(swap_chain->image_index < swap_chain->images.size()); - image_indices.push_back(swap_chain->image_index); + if (present_semaphore != VK_NULL_HANDLE) { + // If command buffers were executed, swap chains must wait on the present semaphore used by the command queue. + wait_semaphores.clear(); + wait_semaphores.push_back(present_semaphore); + } } - wait_semaphores.clear(); - for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) { - wait_semaphores.push_back(VkSemaphore(p_wait_semaphores[i].id)); - } + if (p_swap_chains.size() > 0) { + thread_local LocalVector<VkSwapchainKHR> swapchains; + thread_local LocalVector<uint32_t> image_indices; + thread_local LocalVector<VkResult> results; + swapchains.clear(); + image_indices.clear(); - results.resize(swapchains.size()); - - VkPresentInfoKHR present_info = {}; - present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present_info.waitSemaphoreCount = wait_semaphores.size(); - present_info.pWaitSemaphores = wait_semaphores.ptr(); - present_info.swapchainCount = swapchains.size(); - present_info.pSwapchains = swapchains.ptr(); - present_info.pImageIndices = image_indices.ptr(); - present_info.pResults = results.ptr(); - device_queue.submit_mutex.lock(); - VkResult err = device_functions.QueuePresentKHR(device_queue.queue, &present_info); - device_queue.submit_mutex.unlock(); - - // Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired. - bool any_result_is_out_of_date = false; - for (uint32_t i = 0; i < p_swap_chains.size(); i++) { - SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); - swap_chain->image_index = UINT_MAX; - if (results[i] == VK_ERROR_OUT_OF_DATE_KHR) { - context_driver->surface_set_needs_resize(swap_chain->surface, true); - any_result_is_out_of_date = true; + for (uint32_t i = 0; i < p_swap_chains.size(); i++) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); + swapchains.push_back(swap_chain->vk_swapchain); + DEV_ASSERT(swap_chain->image_index < swap_chain->images.size()); + image_indices.push_back(swap_chain->image_index); } - } - if (any_result_is_out_of_date || err == VK_ERROR_OUT_OF_DATE_KHR) { - // It is possible for presentation to fail with out of date while acquire might've succeeded previously. This case - // will be considered a silent failure as it can be triggered easily by resizing a window in the OS natively. - return FAILED; - } + results.resize(swapchains.size()); + + VkPresentInfoKHR present_info = {}; + present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_info.waitSemaphoreCount = wait_semaphores.size(); + present_info.pWaitSemaphores = wait_semaphores.ptr(); + present_info.swapchainCount = swapchains.size(); + present_info.pSwapchains = swapchains.ptr(); + present_info.pImageIndices = image_indices.ptr(); + present_info.pResults = results.ptr(); + + device_queue.submit_mutex.lock(); + err = device_functions.QueuePresentKHR(device_queue.queue, &present_info); + device_queue.submit_mutex.unlock(); + + // Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired. + bool any_result_is_out_of_date = false; + for (uint32_t i = 0; i < p_swap_chains.size(); i++) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); + swap_chain->image_index = UINT_MAX; + if (results[i] == VK_ERROR_OUT_OF_DATE_KHR) { + context_driver->surface_set_needs_resize(swap_chain->surface, true); + any_result_is_out_of_date = true; + } + } - // Handling VK_SUBOPTIMAL_KHR the same as VK_SUCCESS is completely intentional. - // - // Godot does not currently support native rotation in Android when creating the swap chain. It intentionally uses - // VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR instead of the current transform bits available in the surface capabilities. - // Choosing the transform that leads to optimal presentation leads to distortion that makes the application unusable, - // as the rotation of all the content is not handled at the moment. - // - // VK_SUBOPTIMAL_KHR is accepted as a successful case even if it's not the most efficient solution to work around this - // problem. This behavior should not be changed unless the swap chain recreation uses the current transform bits, as - // it'll lead to very low performance in Android by entering an endless loop where it'll always resize the swap chain - // every frame. + if (any_result_is_out_of_date || err == VK_ERROR_OUT_OF_DATE_KHR) { + // It is possible for presentation to fail with out of date while acquire might've succeeded previously. This case + // will be considered a silent failure as it can be triggered easily by resizing a window in the OS natively. + return FAILED; + } - ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, FAILED); + // Handling VK_SUBOPTIMAL_KHR the same as VK_SUCCESS is completely intentional. + // + // Godot does not currently support native rotation in Android when creating the swap chain. It intentionally uses + // VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR instead of the current transform bits available in the surface capabilities. + // Choosing the transform that leads to optimal presentation leads to distortion that makes the application unusable, + // as the rotation of all the content is not handled at the moment. + // + // VK_SUBOPTIMAL_KHR is accepted as a successful case even if it's not the most efficient solution to work around this + // problem. This behavior should not be changed unless the swap chain recreation uses the current transform bits, as + // it'll lead to very low performance in Android by entering an endless loop where it'll always resize the swap chain + // every frame. + + ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, FAILED); + } return OK; } @@ -2278,6 +2300,11 @@ void RenderingDeviceDriverVulkan::command_queue_free(CommandQueueID p_cmd_queue) CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); + // Erase all the semaphores used for presentation. + for (VkSemaphore semaphore : command_queue->present_semaphores) { + vkDestroySemaphore(vk_device, semaphore, nullptr); + } + // Erase all the semaphores used for image acquisition. for (VkSemaphore semaphore : command_queue->image_semaphores) { vkDestroySemaphore(vk_device, semaphore, nullptr); diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 4abaeecd11..70c4cebba5 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -115,6 +115,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { VkDevice vk_device = VK_NULL_HANDLE; RenderingContextDriverVulkan *context_driver = nullptr; RenderingContextDriver::Device context_device = {}; + uint32_t frame_count = 1; VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkPhysicalDeviceProperties physical_device_properties = {}; VkPhysicalDeviceFeatures physical_device_features = {}; @@ -276,6 +277,7 @@ public: // ----- QUEUE ----- private: struct CommandQueue { + LocalVector<VkSemaphore> present_semaphores; LocalVector<VkSemaphore> image_semaphores; LocalVector<SwapChain *> image_semaphores_swap_chains; LocalVector<uint32_t> pending_semaphores_for_execute; @@ -284,12 +286,12 @@ private: LocalVector<Pair<Fence *, uint32_t>> image_semaphores_for_fences; uint32_t queue_family = 0; uint32_t queue_index = 0; + uint32_t present_semaphore_index = 0; }; public: virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override final; - virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) override final; - virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) override final; + virtual Error command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) override final; virtual void command_queue_free(CommandQueueID p_cmd_queue) override final; private: diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index e7d2f2bda7..d3872349e9 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -39,6 +39,8 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/separator.h" #include "scene/resources/font.h" void GotoLineDialog::popup_find_line(CodeEdit *p_edit) { @@ -763,6 +765,8 @@ FindReplaceBar::FindReplaceBar() { /*** CODE EDITOR ****/ +static constexpr float ZOOM_FACTOR_PRESETS[7] = { 0.25f, 0.5f, 0.75f, 1.0f, 1.5f, 2.0f, 3.0f }; + // This function should be used to handle shortcuts that could otherwise // be handled too late if they weren't handled here. void CodeTextEditor::input(const Ref<InputEvent> &event) { @@ -827,18 +831,21 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) { if (mb->is_pressed() && mb->is_command_or_control_pressed()) { if (mb->get_button_index() == MouseButton::WHEEL_UP) { _zoom_in(); - } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN) { + accept_event(); + return; + } + if (mb->get_button_index() == MouseButton::WHEEL_DOWN) { _zoom_out(); + accept_event(); + return; } } } Ref<InputEventMagnifyGesture> magnify_gesture = p_event; if (magnify_gesture.is_valid()) { - font_size = text_editor->get_theme_font_size(SNAME("font_size")); - font_size *= powf(magnify_gesture->get_factor(), 0.25); - - _add_font_size((int)font_size - text_editor->get_theme_font_size(SNAME("font_size"))); + _zoom_to(zoom_factor * powf(magnify_gesture->get_factor(), 0.25f)); + accept_event(); return; } @@ -849,40 +856,22 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) { if (ED_IS_SHORTCUT("script_editor/zoom_in", p_event)) { _zoom_in(); accept_event(); + return; } if (ED_IS_SHORTCUT("script_editor/zoom_out", p_event)) { _zoom_out(); accept_event(); + return; } if (ED_IS_SHORTCUT("script_editor/reset_zoom", p_event)) { - _reset_zoom(); + _zoom_to(1); accept_event(); + return; } } } } -void CodeTextEditor::_zoom_in() { - font_resize_val += MAX(EDSCALE, 1.0f); - _zoom_changed(); -} - -void CodeTextEditor::_zoom_out() { - font_resize_val -= MAX(EDSCALE, 1.0f); - _zoom_changed(); -} - -void CodeTextEditor::_zoom_changed() { - if (font_resize_timer->get_time_left() == 0) { - font_resize_timer->start(); - } -} - -void CodeTextEditor::_reset_zoom() { - EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14); - text_editor->add_theme_font_size_override("font_size", 14 * EDSCALE); -} - void CodeTextEditor::_line_col_changed() { if (!code_complete_timer->is_stopped() && code_complete_timer_line != text_editor->get_caret_line()) { code_complete_timer->stop(); @@ -904,9 +893,6 @@ void CodeTextEditor::_line_col_changed() { sb.append(" : "); sb.append(itos(positional_column + 1).lpad(3)); - sb.append(" | "); - sb.append(text_editor->is_indent_using_spaces() ? TTR("Spaces", "Indentation") : TTR("Tabs", "Indentation")); - line_and_col_txt->set_text(sb.as_string()); if (find_replace_bar) { @@ -1010,24 +996,6 @@ Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptLanguage::CodeCo return tex; } -void CodeTextEditor::_font_resize_timeout() { - if (_add_font_size(font_resize_val)) { - font_resize_val = 0; - } -} - -bool CodeTextEditor::_add_font_size(int p_delta) { - int old_size = text_editor->get_theme_font_size(SNAME("font_size")); - int new_size = CLAMP(old_size + p_delta, 8 * EDSCALE, 96 * EDSCALE); - - if (new_size != old_size) { - EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE); - text_editor->add_theme_font_size_override("font_size", new_size); - } - - return true; -} - void CodeTextEditor::update_editor_settings() { // Theme: Highlighting completion_font_color = EDITOR_GET("text_editor/theme/highlighting/completion_font_color"); @@ -1068,12 +1036,16 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_drag_and_drop_selection_enabled(EDITOR_GET("text_editor/behavior/navigation/drag_and_drop_selection")); // Behavior: indent - text_editor->set_indent_using_spaces(EDITOR_GET("text_editor/behavior/indent/type")); + set_indent_using_spaces(EDITOR_GET("text_editor/behavior/indent/type")); text_editor->set_indent_size(EDITOR_GET("text_editor/behavior/indent/size")); text_editor->set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent")); // Completion text_editor->set_auto_brace_completion_enabled(EDITOR_GET("text_editor/completion/auto_brace_complete")); + text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line")); + code_complete_enabled = EDITOR_GET("text_editor/completion/code_complete_enabled"); + code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay")); + idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay")); // Appearance: Guidelines if (EDITOR_GET("text_editor/appearance/guidelines/show_line_length_guidelines")) { @@ -1086,6 +1058,9 @@ void CodeTextEditor::update_editor_settings() { } else { text_editor->set_line_length_guidelines(TypedArray<int>()); } + + _update_font_ligatures(); + set_zoom_factor(zoom_factor); } void CodeTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) { @@ -1203,6 +1178,11 @@ void CodeTextEditor::convert_case(CaseStyle p_case) { text_editor->end_complex_operation(); } +void CodeTextEditor::set_indent_using_spaces(bool p_use_spaces) { + text_editor->set_indent_using_spaces(p_use_spaces); + indentation_txt->set_text(p_use_spaces ? TTR("Spaces", "Indentation") : TTR("Tabs", "Indentation")); +} + void CodeTextEditor::move_lines_up() { text_editor->begin_complex_operation(); @@ -1703,41 +1683,38 @@ void CodeTextEditor::goto_error() { } void CodeTextEditor::_update_text_editor_theme() { + if (!EditorThemeManager::is_generated_theme_outdated()) { + return; + } + emit_signal(SNAME("load_theme_settings")); - error->begin_bulk_theme_override(); - error->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts))); - error->add_theme_font_size_override(SNAME("font_size"), get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts))); - error->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("error_color"), EditorStringName(Editor))); + error_button->set_icon(get_editor_theme_icon(SNAME("StatusError"))); + warning_button->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); Ref<Font> status_bar_font = get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts)); int status_bar_font_size = get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts)); - error->add_theme_font_override("font", status_bar_font); - error->add_theme_font_size_override("font_size", status_bar_font_size); - error->end_bulk_theme_override(); int count = status_bar->get_child_count(); for (int i = 0; i < count; i++) { Control *n = Object::cast_to<Control>(status_bar->get_child(i)); if (n) { - n->add_theme_font_override("font", status_bar_font); - n->add_theme_font_size_override("font_size", status_bar_font_size); + n->add_theme_font_override(SNAME("font"), status_bar_font); + n->add_theme_font_size_override(SNAME("font_size"), status_bar_font_size); } } -} -void CodeTextEditor::_on_settings_change() { - if (EditorThemeManager::is_generated_theme_outdated() || - EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") || - EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/completion")) { - _apply_settings_change(); - } -} + const Color &error_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor)); + const Color &warning_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor)); -void CodeTextEditor::_apply_settings_change() { - _update_text_editor_theme(); + error->add_theme_color_override(SNAME("font_color"), error_color); + error_button->add_theme_color_override(SNAME("font_color"), error_color); + warning_button->add_theme_color_override(SNAME("font_color"), warning_color); + + _update_font_ligatures(); +} - font_size = EDITOR_GET("interface/editor/code_font_size"); +void CodeTextEditor::_update_font_ligatures() { int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures"); Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font")); @@ -1768,12 +1745,6 @@ void CodeTextEditor::_apply_settings_change() { } break; } } - - text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line")); - - code_complete_enabled = EDITOR_GET("text_editor/completion/code_complete_enabled"); - code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay")); - idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay")); } void CodeTextEditor::_text_changed_idle_timeout() { @@ -1795,6 +1766,10 @@ void CodeTextEditor::_warning_button_pressed() { _set_show_errors_panel(false); } +void CodeTextEditor::_zoom_popup_id_pressed(int p_idx) { + _zoom_to(zoom_button->get_popup()->get_item_metadata(p_idx)); +} + void CodeTextEditor::_set_show_errors_panel(bool p_show) { is_errors_panel_opened = p_show; emit_signal(SNAME("show_errors_panel"), p_show); @@ -1833,32 +1808,9 @@ void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) { } } -void CodeTextEditor::_update_status_bar_theme() { - error_button->set_icon(get_editor_theme_icon(SNAME("StatusError"))); - warning_button->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); - - error_button->begin_bulk_theme_override(); - error_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - error_button->add_theme_font_override("font", get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts))); - error_button->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts))); - error_button->end_bulk_theme_override(); - - warning_button->begin_bulk_theme_override(); - warning_button->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); - warning_button->add_theme_font_override("font", get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts))); - warning_button->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts))); - warning_button->end_bulk_theme_override(); - - line_and_col_txt->begin_bulk_theme_override(); - line_and_col_txt->add_theme_font_override("font", get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts))); - line_and_col_txt->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts))); - line_and_col_txt->end_bulk_theme_override(); -} - void CodeTextEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - _update_status_bar_theme(); if (toggle_scripts_button->is_visible()) { update_toggle_scripts_button(); } @@ -1966,11 +1918,54 @@ void CodeTextEditor::remove_all_bookmarks() { text_editor->clear_bookmarked_lines(); } +void CodeTextEditor::_zoom_in() { + int s = text_editor->get_theme_font_size("font_size"); + _zoom_to(zoom_factor * (s + MAX(1.0f, EDSCALE)) / s); +} + +void CodeTextEditor::_zoom_out() { + int s = text_editor->get_theme_font_size("font_size"); + _zoom_to(zoom_factor * (s - MAX(1.0f, EDSCALE)) / s); +} + +void CodeTextEditor::_zoom_to(float p_zoom_factor) { + if (zoom_factor == p_zoom_factor) { + return; + } + + float old_zoom_factor = zoom_factor; + + set_zoom_factor(p_zoom_factor); + + if (old_zoom_factor != zoom_factor) { + emit_signal(SNAME("zoomed"), zoom_factor); + } +} + +void CodeTextEditor::set_zoom_factor(float p_zoom_factor) { + int preset_count = sizeof(ZOOM_FACTOR_PRESETS) / sizeof(float); + zoom_factor = CLAMP(p_zoom_factor, ZOOM_FACTOR_PRESETS[0], ZOOM_FACTOR_PRESETS[preset_count - 1]); + int neutral_font_size = int(EDITOR_GET("interface/editor/code_font_size")) * EDSCALE; + int new_font_size = Math::round(zoom_factor * neutral_font_size); + + zoom_button->set_text(itos(Math::round(zoom_factor * 100)) + " %"); + + if (text_editor->has_theme_font_size_override("font_size")) { + text_editor->remove_theme_font_size_override("font_size"); + } + text_editor->add_theme_font_size_override("font_size", new_font_size); +} + +float CodeTextEditor::get_zoom_factor() { + return zoom_factor; +} + void CodeTextEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("validate_script")); ADD_SIGNAL(MethodInfo("load_theme_settings")); ADD_SIGNAL(MethodInfo("show_errors_panel")); ADD_SIGNAL(MethodInfo("show_warnings_panel")); + ADD_SIGNAL(MethodInfo("zoomed", PropertyInfo(Variant::FLOAT, "p_zoom_factor"))); } void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud) { @@ -2004,36 +1999,6 @@ CodeTextEditor::CodeTextEditor() { text_editor->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_GDSCRIPT); text_editor->set_draw_bookmarks_gutter(true); - int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures"); - Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font")); - if (fc.is_valid()) { - switch (ot_mode) { - case 1: { // Disable ligatures. - Dictionary ftrs; - ftrs[TS->name_to_tag("calt")] = 0; - fc->set_opentype_features(ftrs); - } break; - case 2: { // Custom. - Vector<String> subtag = String(EDITOR_GET("interface/editor/code_font_custom_opentype_features")).split(","); - Dictionary ftrs; - for (int i = 0; i < subtag.size(); i++) { - Vector<String> subtag_a = subtag[i].split("="); - if (subtag_a.size() == 2) { - ftrs[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_int(); - } else if (subtag_a.size() == 1) { - ftrs[TS->name_to_tag(subtag_a[0])] = 1; - } - } - fc->set_opentype_features(ftrs); - } break; - default: { // Enabled. - Dictionary ftrs; - ftrs[TS->name_to_tag("calt")] = 1; - fc->set_opentype_features(ftrs); - } break; - } - } - text_editor->set_draw_line_numbers(true); text_editor->set_highlight_matching_braces_enabled(true); text_editor->set_auto_indent_enabled(true); @@ -2047,19 +2012,18 @@ CodeTextEditor::CodeTextEditor() { idle = memnew(Timer); add_child(idle); idle->set_one_shot(true); - idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay")); code_complete_enabled = EDITOR_GET("text_editor/completion/code_complete_enabled"); code_complete_timer = memnew(Timer); add_child(code_complete_timer); code_complete_timer->set_one_shot(true); - code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay")); error_line = 0; error_column = 0; toggle_scripts_button = memnew(Button); toggle_scripts_button->set_flat(true); + toggle_scripts_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); toggle_scripts_button->connect("pressed", callable_mp(this, &CodeTextEditor::_toggle_scripts_pressed)); status_bar->add_child(toggle_scripts_button); toggle_scripts_button->hide(); @@ -2097,6 +2061,29 @@ CodeTextEditor::CodeTextEditor() { warning_button->set_tooltip_text(TTR("Warnings")); set_warning_count(0); + status_bar->add_child(memnew(VSeparator)); + + // Zoom + zoom_button = memnew(MenuButton); + status_bar->add_child(zoom_button); + zoom_button->set_flat(true); + zoom_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); + zoom_button->set_tooltip_text(TTR("Zoom factor")); + zoom_button->set_text("100 %"); + + PopupMenu *zoom_menu = zoom_button->get_popup(); + int preset_count = sizeof(ZOOM_FACTOR_PRESETS) / sizeof(float); + + for (int i = 0; i < preset_count; i++) { + float z = ZOOM_FACTOR_PRESETS[i]; + zoom_menu->add_item(itos(Math::round(z * 100)) + " %"); + zoom_menu->set_item_metadata(i, z); + } + + zoom_menu->connect("id_pressed", callable_mp(this, &CodeTextEditor::_zoom_popup_id_pressed)); + + status_bar->add_child(memnew(VSeparator)); + // Line and column line_and_col_txt = memnew(Label); status_bar->add_child(line_and_col_txt); @@ -2104,6 +2091,15 @@ CodeTextEditor::CodeTextEditor() { line_and_col_txt->set_tooltip_text(TTR("Line and column numbers.")); line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP); + status_bar->add_child(memnew(VSeparator)); + + // Indentation + indentation_txt = memnew(Label); + status_bar->add_child(indentation_txt); + indentation_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); + indentation_txt->set_tooltip_text(TTR("Indentation")); + indentation_txt->set_mouse_filter(MOUSE_FILTER_STOP); + text_editor->connect("gui_input", callable_mp(this, &CodeTextEditor::_text_editor_gui_input)); text_editor->connect("caret_changed", callable_mp(this, &CodeTextEditor::_line_col_changed)); text_editor->connect("text_changed", callable_mp(this, &CodeTextEditor::_text_changed)); @@ -2122,14 +2118,5 @@ CodeTextEditor::CodeTextEditor() { code_complete_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_code_complete_timer_timeout)); - font_resize_val = 0; - font_size = EDITOR_GET("interface/editor/code_font_size"); - font_resize_timer = memnew(Timer); - add_child(font_resize_timer); - font_resize_timer->set_one_shot(true); - font_resize_timer->set_wait_time(0.07); - font_resize_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_font_resize_timeout)); - - EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CodeTextEditor::_on_settings_change)); add_theme_constant_override("separation", 4 * EDSCALE); } diff --git a/editor/code_editor.h b/editor/code_editor.h index 9d8a3a2229..c888619ac0 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -40,6 +40,8 @@ #include "scene/gui/line_edit.h" #include "scene/main/timer.h" +class MenuButton; + class GotoLineDialog : public ConfirmationDialog { GDCLASS(GotoLineDialog, ConfirmationDialog); @@ -156,7 +158,9 @@ class CodeTextEditor : public VBoxContainer { Button *error_button = nullptr; Button *warning_button = nullptr; + MenuButton *zoom_button = nullptr; Label *line_and_col_txt = nullptr; + Label *indentation_txt = nullptr; Label *info = nullptr; Timer *idle = nullptr; @@ -164,29 +168,19 @@ class CodeTextEditor : public VBoxContainer { Timer *code_complete_timer = nullptr; int code_complete_timer_line = 0; - Timer *font_resize_timer = nullptr; - int font_resize_val; - real_t font_size; + float zoom_factor = 1.0f; Label *error = nullptr; int error_line; int error_column; - void _on_settings_change(); - void _apply_settings_change(); - void _update_text_editor_theme(); + void _update_font_ligatures(); void _complete_request(); Ref<Texture2D> _get_completion_icon(const ScriptLanguage::CodeCompletionOption &p_option); - void _font_resize_timeout(); - bool _add_font_size(int p_delta); virtual void input(const Ref<InputEvent> &event) override; void _text_editor_gui_input(const Ref<InputEvent> &p_event); - void _zoom_in(); - void _zoom_out(); - void _zoom_changed(); - void _reset_zoom(); Color completion_font_color; Color completion_string_color; @@ -195,13 +189,17 @@ class CodeTextEditor : public VBoxContainer { CodeTextEditorCodeCompleteFunc code_complete_func; void *code_complete_ud = nullptr; + void _zoom_in(); + void _zoom_out(); + void _zoom_to(float p_zoom_factor); + void _error_button_pressed(); void _warning_button_pressed(); void _set_show_errors_panel(bool p_show); void _set_show_warnings_panel(bool p_show); void _error_pressed(const Ref<InputEvent> &p_event); - void _update_status_bar_theme(); + void _zoom_popup_id_pressed(int p_idx); void _toggle_scripts_pressed(); @@ -234,6 +232,8 @@ public: }; void convert_case(CaseStyle p_case); + void set_indent_using_spaces(bool p_use_spaces); + void move_lines_up(); void move_lines_down(); void delete_lines(); @@ -273,6 +273,9 @@ public: void goto_prev_bookmark(); void remove_all_bookmarks(); + void set_zoom_factor(float p_zoom_factor); + float get_zoom_factor(); + void set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud); void validate_script(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 04944a9143..cc0e954087 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -669,6 +669,8 @@ void EditorNode::_notification(int p_what) { callable_mp(this, &EditorNode::_begin_first_scan).call_deferred(); + DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_update_theme)); + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -773,6 +775,9 @@ void EditorNode::_notification(int p_what) { EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int()); } + follow_system_theme = EDITOR_GET("interface/theme/follow_system_theme"); + use_system_accent_color = EDITOR_GET("interface/theme/use_system_accent_color"); + if (EditorThemeManager::is_generated_theme_outdated()) { _update_theme(); _build_icon_type_cache(); @@ -3130,6 +3135,35 @@ void EditorNode::_save_screenshot(NodePath p_path) { ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'."); } +void EditorNode::_check_system_theme_changed() { + DisplayServer *display_server = DisplayServer::get_singleton(); + + bool system_theme_changed = false; + + if (follow_system_theme) { + if (display_server->get_base_color() != last_system_base_color) { + system_theme_changed = true; + last_system_base_color = display_server->get_base_color(); + } + + if (display_server->is_dark_mode_supported() && display_server->is_dark_mode() != last_dark_mode_state) { + system_theme_changed = true; + last_dark_mode_state = display_server->is_dark_mode(); + } + } + + if (use_system_accent_color) { + if (display_server->get_accent_color() != last_system_accent_color) { + system_theme_changed = true; + last_system_accent_color = display_server->get_accent_color(); + } + } + + if (system_theme_changed) { + _update_theme(); + } +} + void EditorNode::_tool_menu_option(int p_idx) { switch (tool_menu->get_item_id(p_idx)) { case TOOLS_ORPHAN_RESOURCES: { @@ -7372,7 +7406,7 @@ EditorNode::EditorNode() { vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel(); vcs_actions_menu->set_name("Version Control"); vcs_actions_menu->connect("index_pressed", callable_mp(this, &EditorNode::_version_control_menu_option)); - vcs_actions_menu->add_item(TTR("Create Version Control Metadata..."), RUN_VCS_METADATA); + vcs_actions_menu->add_item(TTR("Create/Override Version Control Metadata..."), RUN_VCS_METADATA); vcs_actions_menu->add_item(TTR("Version Control Settings..."), RUN_VCS_SETTINGS); project_menu->add_child(vcs_actions_menu); project_menu->set_item_submenu(project_menu->get_item_index(VCS_MENU), "Version Control"); @@ -7568,6 +7602,15 @@ EditorNode::EditorNode() { String exec = OS::get_singleton()->get_executable_path(); // Save editor executable path for third-party tools. EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); + + follow_system_theme = EDITOR_GET("interface/theme/follow_system_theme"); + use_system_accent_color = EDITOR_GET("interface/theme/use_system_accent_color"); + system_theme_timer = memnew(Timer); + system_theme_timer->set_wait_time(1.0); + system_theme_timer->connect("timeout", callable_mp(this, &EditorNode::_check_system_theme_changed)); + add_child(system_theme_timer); + system_theme_timer->set_owner(get_owner()); + system_theme_timer->set_autostart(true); } EditorNode::~EditorNode() { diff --git a/editor/editor_node.h b/editor/editor_node.h index 8a880a00cc..2aa743343e 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -358,6 +358,13 @@ private: Ref<Theme> theme; + Timer *system_theme_timer = nullptr; + bool follow_system_theme = false; + bool use_system_accent_color = false; + bool last_dark_mode_state = false; + Color last_system_base_color = Color(0, 0, 0, 0); + Color last_system_accent_color = Color(0, 0, 0, 0); + PopupMenu *recent_scenes = nullptr; String _recent_scene; List<String> previous_scenes; @@ -538,6 +545,8 @@ private: void _screenshot(bool p_use_utc = false); void _save_screenshot(NodePath p_path); + void _check_system_theme_changed(); + void _tool_menu_option(int p_idx); void _export_as_menu_option(int p_idx); void _update_file_menu_opened(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index f5b8d04444..9b883f7661 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -780,9 +780,19 @@ void EditorPropertyDictionary::_add_key_value() { } Dictionary dict = object->get_dict().duplicate(); - dict[object->get_new_item_key()] = object->get_new_item_value(); - object->set_new_item_key(Variant()); - object->set_new_item_value(Variant()); + Variant new_key = object->get_new_item_key(); + Variant new_value = object->get_new_item_value(); + dict[new_key] = new_value; + + Variant::Type type = new_key.get_type(); + new_key.zero(); + VariantInternal::initialize(&new_key, type); + object->set_new_item_key(new_key); + + type = new_value.get_type(); + new_value.zero(); + VariantInternal::initialize(&new_value, type); + object->set_new_item_value(new_value); emit_changed(get_edited_property(), dict, "", false); update_property(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 8192ac2eb4..94e55f347a 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -489,11 +489,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle") // Theme + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_ENUM, "interface/theme/follow_system_theme", false, "") EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom") EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/spacing_preset", "Default", "Compact,Default,Spacious,Custom") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "") + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/use_system_accent_color", false, "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/contrast", 0.3, "-1,1,0.01") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/draw_extra_borders", false, "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/icon_saturation", 1.0, "0,2,0.01") @@ -766,8 +768,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/shader_editor/behavior/files/restore_shaders_on_load", true); // Visual editors + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "editors/visual_editors/color_theme", "Default", "Default,Legacy,Custom") + + _load_default_visual_shader_editor_theme(); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/lines_curvature", 0.5, "0.0,1.0,0.01") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/visual_editors/grid_pattern", 1, "Lines,Dots") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visual_shader/port_preview_size", 160, "100,400,0.01") /* Run */ @@ -903,6 +910,30 @@ void EditorSettings::_load_godot2_text_editor_theme() { _initial_set("text_editor/theme/highlighting/search_result_border_color", Color(0.41, 0.61, 0.91, 0.38)); } +void EditorSettings::_load_default_visual_shader_editor_theme() { + // Connection type colors + _initial_set("editors/visual_editors/connection_colors/scalar_color", Color(0.55, 0.55, 0.55)); + _initial_set("editors/visual_editors/connection_colors/vector2_color", Color(0.44, 0.43, 0.64)); + _initial_set("editors/visual_editors/connection_colors/vector3_color", Color(0.337, 0.314, 0.71)); + _initial_set("editors/visual_editors/connection_colors/vector4_color", Color(0.7, 0.65, 0.147)); + _initial_set("editors/visual_editors/connection_colors/boolean_color", Color(0.243, 0.612, 0.349)); + _initial_set("editors/visual_editors/connection_colors/transform_color", Color(0.71, 0.357, 0.64)); + _initial_set("editors/visual_editors/connection_colors/sampler_color", Color(0.659, 0.4, 0.137)); + + // Node category colors (used for the node headers) + _initial_set("editors/visual_editors/category_colors/output_color", Color(0.26, 0.10, 0.15)); + _initial_set("editors/visual_editors/category_colors/color_color", Color(0.5, 0.5, 0.1)); + _initial_set("editors/visual_editors/category_colors/conditional_color", Color(0.208, 0.522, 0.298)); + _initial_set("editors/visual_editors/category_colors/input_color", Color(0.502, 0.2, 0.204)); + _initial_set("editors/visual_editors/category_colors/scalar_color", Color(0.1, 0.5, 0.6)); + _initial_set("editors/visual_editors/category_colors/textures_color", Color(0.5, 0.3, 0.1)); + _initial_set("editors/visual_editors/category_colors/transform_color", Color(0.5, 0.3, 0.5)); + _initial_set("editors/visual_editors/category_colors/utility_color", Color(0.2, 0.2, 0.2)); + _initial_set("editors/visual_editors/category_colors/vector_color", Color(0.2, 0.2, 0.5)); + _initial_set("editors/visual_editors/category_colors/special_color", Color(0.098, 0.361, 0.294)); + _initial_set("editors/visual_editors/category_colors/particle_color", Color(0.12, 0.358, 0.8)); +} + bool EditorSettings::_save_text_editor_theme(String p_file) { String theme_section = "color_theme"; Ref<ConfigFile> cf = memnew(ConfigFile); // hex is better? diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 87ce0cfd57..5783bac770 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -110,6 +110,7 @@ private: void _load_defaults(Ref<ConfigFile> p_extra_config = Ref<ConfigFile>()); void _load_godot2_text_editor_theme(); + void _load_default_visual_shader_editor_theme(); bool _save_text_editor_theme(String p_file); bool _is_default_text_editor_theme(String p_theme_name); const String _get_project_metadata_path() const; diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 13e3c41e3b..c339bbf365 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -71,6 +71,8 @@ void EditorSettingsDialog::_settings_property_edited(const String &p_name) { EditorSettings::get_singleton()->set_manually("interface/theme/spacing_preset", "Custom"); } else if (full_name.begins_with("text_editor/theme/highlighting")) { EditorSettings::get_singleton()->set_manually("text_editor/theme/color_theme", "Custom"); + } else if (full_name.begins_with("editors/visual_editors/connection_colors") || full_name.begins_with("editors/visual_editors/category_colors")) { + EditorSettings::get_singleton()->set_manually("editors/visual_editors/color_theme", "Custom"); } } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index a007411d29..15a9cfad22 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -646,6 +646,18 @@ void Node3DEditorViewport::cancel_transform() { continue; } + if (se && se->gizmo.is_valid()) { + Vector<int> ids; + Vector<Transform3D> restore; + + for (const KeyValue<int, Transform3D> &GE : se->subgizmos) { + ids.push_back(GE.key); + restore.push_back(GE.value); + } + + se->gizmo->commit_subgizmos(ids, restore, true); + } + sp->set_global_transform(se->original); } @@ -2666,10 +2678,6 @@ void Node3DEditorPlugin::edited_scene_changed() { } void Node3DEditorViewport::_project_settings_changed() { - if (!EditorSettings::get_singleton()->check_changed_settings_in_group("rendering")) { - return; - } - // Update shadow atlas if changed. int shadowmap_size = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_size"); bool shadowmap_16_bits = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_16_bits"); @@ -8075,6 +8083,7 @@ void Node3DEditor::_bind_methods() { ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons); ClassDB::bind_method("update_all_gizmos", &Node3DEditor::update_all_gizmos); + ClassDB::bind_method("update_transform_gizmo", &Node3DEditor::update_transform_gizmo); ADD_SIGNAL(MethodInfo("transform_key_request")); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index ed42e8e5ab..61b1d38cfc 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -509,7 +509,7 @@ public: RID sbox_instance_xray; RID sbox_instance_xray_offset; Ref<EditorNode3DGizmo> gizmo; - HashMap<int, Transform3D> subgizmos; // map ID -> initial transform + HashMap<int, Transform3D> subgizmos; // Key: Subgizmo ID, Value: Initial subgizmo transform. Node3DEditorSelectedItem() { sp = nullptr; diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 6fe1949382..ffdc06ceee 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -200,22 +200,6 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - // Primary handles: position. - if (!p_secondary) { - // Special cas for primary handle, the handle id equals control point id. - const int idx = p_id; - if (p_cancel) { - c->set_point_position(idx, p_restore); - return; - } - ur->create_action(TTR("Set Curve Point Position")); - ur->add_do_method(c.ptr(), "set_point_position", idx, c->get_point_position(idx)); - ur->add_undo_method(c.ptr(), "set_point_position", idx, p_restore); - ur->commit_action(); - - return; - } - // Secondary handles: in, out, tilt. const HandleInfo info = _secondary_handles_info[p_id]; const int idx = info.point_idx; @@ -235,6 +219,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res ur->add_do_method(c.ptr(), "set_point_in", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_out(idx) : (-c->get_point_out(idx).normalized() * orig_in_length)); ur->add_undo_method(c.ptr(), "set_point_in", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_in_length)); } + ur->commit_action(); break; } @@ -252,6 +237,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res ur->add_do_method(c.ptr(), "set_point_out", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_in(idx) : (-c->get_point_in(idx).normalized() * orig_out_length)); ur->add_undo_method(c.ptr(), "set_point_out", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_out_length)); } + ur->commit_action(); break; } @@ -263,6 +249,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res ur->create_action(TTR("Set Curve Point Tilt")); ur->add_do_method(c.ptr(), "set_point_tilt", idx, c->get_point_tilt(idx)); ur->add_undo_method(c.ptr(), "set_point_tilt", idx, p_restore); + ur->commit_action(); break; } @@ -275,7 +262,7 @@ void Path3DGizmo::redraw() { Ref<StandardMaterial3D> path_material = gizmo_plugin->get_material("path_material", this); Ref<StandardMaterial3D> path_thin_material = gizmo_plugin->get_material("path_thin_material", this); Ref<StandardMaterial3D> path_tilt_material = gizmo_plugin->get_material("path_tilt_material", this); - Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles"); + Ref<StandardMaterial3D> path_tilt_muted_material = gizmo_plugin->get_material("path_tilt_muted_material", this); Ref<StandardMaterial3D> sec_handles_material = gizmo_plugin->get_material("sec_handles"); Ref<Curve3D> c = path->get_curve(); @@ -353,48 +340,57 @@ void Path3DGizmo::redraw() { if (Path3DEditorPlugin::singleton->get_edited_path() == path) { PackedVector3Array handle_lines; PackedVector3Array tilt_handle_lines; - PackedVector3Array primary_handle_points; PackedVector3Array secondary_handle_points; PackedInt32Array collected_secondary_handle_ids; // Avoid shadowing member on Node3DEditorGizmo. _secondary_handles_info.resize(c->get_point_count() * 3); for (int idx = 0; idx < c->get_point_count(); idx++) { - // Collect primary-handles. const Vector3 pos = c->get_point_position(idx); - primary_handle_points.append(pos); + bool is_current_point_selected = is_subgizmo_selected(idx); + bool is_previous_point_selected = is_subgizmo_selected(idx - 1); + bool is_following_point_selected = is_subgizmo_selected(idx + 1); HandleInfo info; info.point_idx = idx; // Collect in-handles except for the first point. - if (idx > 0) { - info.type = HandleType::HANDLE_TYPE_IN; - const int handle_idx = idx * 3 + 0; - collected_secondary_handle_ids.append(handle_idx); - _secondary_handles_info.write[handle_idx] = info; - + if (idx > 0 && (is_current_point_selected || is_previous_point_selected)) { const Vector3 in = c->get_point_in(idx); - secondary_handle_points.append(pos + in); - handle_lines.append(pos); - handle_lines.append(pos + in); + + // Display in-handles only when they are "initialized". + if (in.length_squared() > 0) { + info.type = HandleType::HANDLE_TYPE_IN; + const int handle_idx = idx * 3 + 0; + collected_secondary_handle_ids.append(handle_idx); + _secondary_handles_info.write[handle_idx] = info; + + secondary_handle_points.append(pos + in); + handle_lines.append(pos); + handle_lines.append(pos + in); + } } // Collect out-handles except for the last point. - if (idx < c->get_point_count() - 1) { - info.type = HandleType::HANDLE_TYPE_OUT; - const int handle_idx = idx * 3 + 1; - collected_secondary_handle_ids.append(handle_idx); - _secondary_handles_info.write[handle_idx] = info; - + if (idx < c->get_point_count() - 1 && (is_current_point_selected || is_following_point_selected)) { const Vector3 out = c->get_point_out(idx); - secondary_handle_points.append(pos + out); - handle_lines.append(pos); - handle_lines.append(pos + out); + + // Display out-handles only when they are "initialized". + if (out.length_squared() > 0) { + info.type = HandleType::HANDLE_TYPE_OUT; + const int handle_idx = idx * 3 + 1; + collected_secondary_handle_ids.append(handle_idx); + _secondary_handles_info.write[handle_idx] = info; + + secondary_handle_points.append(pos + out); + handle_lines.append(pos); + handle_lines.append(pos + out); + } } // Collect tilt-handles. - { + if (is_current_point_selected || is_previous_point_selected || is_following_point_selected) { + // Tilt handle. { info.type = HandleType::HANDLE_TYPE_TILT; const int handle_idx = idx * 3 + 2; @@ -423,7 +419,7 @@ void Path3DGizmo::redraw() { const Vector3 edge = sin(a) * side + cos(a) * up; disk.append(pos + edge * disk_size); } - add_vertices(disk, path_tilt_material, Mesh::PRIMITIVE_LINE_STRIP); + add_vertices(disk, is_current_point_selected ? path_tilt_material : path_tilt_muted_material, Mesh::PRIMITIVE_LINE_STRIP); } } } @@ -436,21 +432,27 @@ void Path3DGizmo::redraw() { add_lines(tilt_handle_lines, path_tilt_material); } - if (primary_handle_points.size()) { - add_handles(primary_handle_points, handles_material); - } if (secondary_handle_points.size()) { add_handles(secondary_handle_points, sec_handles_material, collected_secondary_handle_ids, false, true); } + // Draw the gizmo plugin manually, because handles are registered. In which case, the caller code skips drawing the gizmo plugin. + gizmo_plugin->redraw(this); } } +void Path3DGizmo::_update_transform_gizmo() { + Node3DEditor::get_singleton()->update_transform_gizmo(); +} + Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) { path = p_path; disk_size = p_disk_size; set_node_3d(p_path); orig_in_length = 0; orig_out_length = 0; + + // Connecting to a signal once, rather than plaguing the implementation with calls to `Node3DEditor::update_transform_gizmo`. + path->connect("curve_changed", callable_mp(this, &Path3DGizmo::_update_transform_gizmo)); } EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { @@ -819,10 +821,130 @@ Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) { return ref; } +bool Path3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to<Path3D>(p_spatial) != nullptr; +} + String Path3DGizmoPlugin::get_gizmo_name() const { return "Path3D"; } +void Path3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d()); + ERR_FAIL_NULL(path); + + Ref<Curve3D> curve = path->get_curve(); + + Ref<StandardMaterial3D> handle_material = get_material("handles", p_gizmo); + PackedVector3Array handles; + + for (int idx = 0; idx < curve->get_point_count(); ++idx) { + // Collect handles. + const Vector3 pos = curve->get_point_position(idx); + + handles.append(pos); + } + + if (handles.size()) { + p_gizmo->add_vertices(handles, handle_material, Mesh::PRIMITIVE_POINTS); + } +} + +int Path3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const { + Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d()); + ERR_FAIL_NULL_V(path, -1); + Ref<Curve3D> curve = path->get_curve(); + ERR_FAIL_COND_V(curve.is_null(), -1); + + for (int idx = 0; idx < curve->get_point_count(); ++idx) { + Vector3 pos = path->get_global_transform().xform(curve->get_point_position(idx)); + if (p_camera->unproject_position(pos).distance_to(p_point) < 20) { + return idx; + } + } + return -1; +} + +Vector<int> Path3DGizmoPlugin::subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const { + Vector<int> contained_points; + + Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d()); + ERR_FAIL_NULL_V(path, contained_points); + Ref<Curve3D> curve = path->get_curve(); + ERR_FAIL_COND_V(curve.is_null(), contained_points); + + for (int idx = 0; idx < curve->get_point_count(); ++idx) { + Vector3 pos = path->get_global_transform().xform(curve->get_point_position(idx)); + bool is_contained_in_frustum = true; + for (int i = 0; i < p_frustum.size(); ++i) { + if (p_frustum[i].distance_to(pos) > 0) { + is_contained_in_frustum = false; + break; + } + } + + if (is_contained_in_frustum) { + contained_points.push_back(idx); + } + } + + return contained_points; +} + +Transform3D Path3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const { + Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d()); + ERR_FAIL_NULL_V(path, Transform3D()); + Ref<Curve3D> curve = path->get_curve(); + ERR_FAIL_COND_V(curve.is_null(), Transform3D()); + ERR_FAIL_INDEX_V(p_id, curve->get_point_count(), Transform3D()); + + Basis basis = transformation_locked_basis.has(p_id) ? transformation_locked_basis[p_id] : curve->get_point_baked_posture(p_id, true); + Vector3 pos = curve->get_point_position(p_id); + + Transform3D t = Transform3D(basis, pos); + return t; +} + +void Path3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) { + Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d()); + ERR_FAIL_NULL(path); + Ref<Curve3D> curve = path->get_curve(); + ERR_FAIL_COND(curve.is_null()); + ERR_FAIL_INDEX(p_id, curve->get_point_count()); + + if (!transformation_locked_basis.has(p_id)) { + transformation_locked_basis[p_id] = Basis(curve->get_point_baked_posture(p_id, true)); + } + curve->set_point_position(p_id, p_transform.origin); +} + +void Path3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) { + Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d()); + ERR_FAIL_NULL(path); + Ref<Curve3D> curve = path->get_curve(); + ERR_FAIL_COND(curve.is_null()); + + transformation_locked_basis.clear(); + + if (p_cancel) { + for (int i = 0; i < p_ids.size(); ++i) { + curve->set_point_position(p_ids[i], p_restore[i].origin); + } + return; + } + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + + undo_redo->create_action(TTR("Set Curve Point Position")); + + for (int i = 0; i < p_ids.size(); ++i) { + const int idx = p_ids[i]; + undo_redo->add_do_method(curve.ptr(), "set_point_position", idx, curve->get_point_position(idx)); + undo_redo->add_undo_method(curve.ptr(), "set_point_position", idx, p_restore[i].origin); + } + undo_redo->commit_action(); +} + int Path3DGizmoPlugin::get_priority() const { return -1; } @@ -835,6 +957,7 @@ Path3DGizmoPlugin::Path3DGizmoPlugin(float p_disk_size) { create_material("path_material", path_color); create_material("path_thin_material", Color(0.6, 0.6, 0.6)); create_material("path_tilt_material", path_tilt_color); + create_material("path_tilt_muted_material", path_tilt_color * 0.7); create_handle_material("handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons))); create_handle_material("sec_handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorCurveHandle"), EditorStringName(EditorIcons))); } diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h index 5a5f76b015..931ac7128c 100644 --- a/editor/plugins/path_3d_editor_plugin.h +++ b/editor/plugins/path_3d_editor_plugin.h @@ -63,6 +63,8 @@ class Path3DGizmo : public EditorNode3DGizmo { // Cache information of secondary handles. Vector<HandleInfo> _secondary_handles_info; + void _update_transform_gizmo(); + public: virtual String get_handle_name(int p_id, bool p_secondary) const override; virtual Variant get_handle_value(int p_id, bool p_secondary) const override; @@ -78,11 +80,25 @@ class Path3DGizmoPlugin : public EditorNode3DGizmoPlugin { float disk_size = 0.8; + // Locking basis is meant to ensure a predictable behavior during translation of the curve points in "local space transform mode". + // Without the locking, the gizmo/point, in "local space transform mode", wouldn't follow a straight path and would curve and twitch in an unpredictable way. + HashMap<int, Basis> transformation_locked_basis; + protected: Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial) override; public: + virtual bool has_gizmo(Node3D *p_spatial) override; String get_gizmo_name() const override; + + virtual void redraw(EditorNode3DGizmo *p_gizmo) override; + + virtual int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override; + virtual Vector<int> subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const override; + virtual Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override; + virtual void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override; + virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false) override; + int get_priority() const override; Path3DGizmoPlugin(float p_disk_size); }; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index d1d858b4db..32dae74ba4 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/version.h" +#include "editor/code_editor.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_command_palette.h" @@ -1639,7 +1640,7 @@ void ScriptEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop)); - _editor_settings_changed(); + _apply_editor_settings(); [[fallthrough]]; } @@ -2481,6 +2482,12 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col, se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested)); se->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method)); + CodeTextEditor *cte = se->get_code_editor(); + if (cte) { + cte->set_zoom_factor(zoom_factor); + cte->connect("zoomed", callable_mp(this, &ScriptEditor::_set_zoom_factor)); + } + //test for modification, maybe the script was not edited but was loaded _test_script_times_on_disk(p_resource); @@ -2779,11 +2786,16 @@ void ScriptEditor::_save_layout() { } void ScriptEditor::_editor_settings_changed() { - if (!EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor") && + if (!EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") && + !EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor") && !EditorSettings::get_singleton()->check_changed_settings_in_group("docks/filesystem")) { return; } + _apply_editor_settings(); +} + +void ScriptEditor::_apply_editor_settings() { textfile_extensions.clear(); const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false); for (const String &E : textfile_ext) { @@ -2808,6 +2820,11 @@ void ScriptEditor::_editor_settings_changed() { EditorSettings::get_singleton()->load_text_editor_theme(); } + _update_script_colors(); + _update_script_names(); + + ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save")); + for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); if (!se) { @@ -2816,10 +2833,6 @@ void ScriptEditor::_editor_settings_changed() { se->update_settings(); } - _update_script_colors(); - _update_script_names(); - - ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save")); } void ScriptEditor::_filesystem_changed() { @@ -3322,6 +3335,8 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { } } + _set_zoom_factor(p_layout->get_value("ScriptEditor", "zoom_factor", 1.0f)); + restoring_layout = false; _update_script_names(); @@ -3371,6 +3386,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { p_layout->set_value("ScriptEditor", "open_help", helps); p_layout->set_value("ScriptEditor", "script_split_offset", script_split->get_split_offset()); p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset()); + p_layout->set_value("ScriptEditor", "zoom_factor", zoom_factor); // Save the cache. script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg")); @@ -3806,6 +3822,24 @@ void ScriptEditor::_on_find_in_files_modified_files(PackedStringArray paths) { _update_modified_scripts_for_external_editor(); } +void ScriptEditor::_set_zoom_factor(float p_zoom_factor) { + if (zoom_factor == p_zoom_factor) { + return; + } + zoom_factor = p_zoom_factor; + for (int i = 0; i < tab_container->get_tab_count(); i++) { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); + if (se) { + CodeTextEditor *cte = se->get_code_editor(); + if (cte) { + if (zoom_factor != cte->get_zoom_factor()) { + cte->set_zoom_factor(zoom_factor); + } + } + } + } +} + void ScriptEditor::_window_changed(bool p_visible) { make_floating->set_visible(!p_visible); is_floating = p_visible; diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 68eb23c838..752c1a6a05 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -38,6 +38,7 @@ #include "scene/resources/syntax_highlighter.h" #include "scene/resources/text_file.h" +class CodeTextEditor; class EditorFileDialog; class EditorHelpSearch; class FindReplaceBar; @@ -192,6 +193,7 @@ public: virtual void set_find_replace_bar(FindReplaceBar *p_bar) = 0; virtual Control *get_base_editor() const = 0; + virtual CodeTextEditor *get_code_editor() const = 0; virtual void validate() = 0; @@ -306,6 +308,8 @@ class ScriptEditor : public PanelContainer { String current_theme; + float zoom_factor = 1.0f; + TextureRect *script_icon = nullptr; Label *script_name_label = nullptr; @@ -420,6 +424,7 @@ class ScriptEditor : public PanelContainer { void _save_editor_state(ScriptEditorBase *p_editor); void _save_layout(); void _editor_settings_changed(); + void _apply_editor_settings(); void _filesystem_changed(); void _files_moved(const String &p_old_file, const String &p_new_file); void _file_removed(const String &p_file); @@ -491,6 +496,8 @@ class ScriptEditor : public PanelContainer { void _start_find_in_files(bool with_replace); void _on_find_in_files_modified_files(PackedStringArray paths); + void _set_zoom_factor(float p_zoom_factor); + void _window_changed(bool p_visible); static void _open_script_request(const String &p_path); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 9fbeab494e..ce5535432c 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1393,11 +1393,11 @@ void ScriptTextEditor::_edit_option(int p_op) { trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { - tx->set_indent_using_spaces(true); + code_editor->set_indent_using_spaces(true); convert_indent(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { - tx->set_indent_using_spaces(false); + code_editor->set_indent_using_spaces(false); convert_indent(); } break; case EDIT_PICK_COLOR: { @@ -1691,6 +1691,10 @@ Control *ScriptTextEditor::get_base_editor() const { return code_editor->get_text_editor(); } +CodeTextEditor *ScriptTextEditor::get_code_editor() const { + return code_editor; +} + Variant ScriptTextEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { return Variant(); } @@ -2374,8 +2378,6 @@ ScriptTextEditor::ScriptTextEditor() { update_settings(); - code_editor->get_text_editor()->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line")); - code_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true); code_editor->get_text_editor()->set_context_menu_enabled(false); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 8c0ba6d7e6..820e86df61 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -256,6 +256,7 @@ public: static void register_editor(); virtual Control *get_base_editor() const override; + virtual CodeTextEditor *get_code_editor() const override; virtual void validate() override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index f8e2bd0915..cce1f160b2 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -143,7 +143,6 @@ void ShaderEditorPlugin::edit(Object *p_object) { es.shader_editor = memnew(TextShaderEditor); es.shader_editor->edit(si); shader_tabs->add_child(es.shader_editor); - es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list)); } else { Shader *s = Object::cast_to<Shader>(p_object); for (uint32_t i = 0; i < edited_shaders.size(); i++) { @@ -163,7 +162,16 @@ void ShaderEditorPlugin::edit(Object *p_object) { es.shader_editor = memnew(TextShaderEditor); shader_tabs->add_child(es.shader_editor); es.shader_editor->edit(s); - es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list)); + } + } + + if (es.shader_editor) { + es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list)); + + CodeTextEditor *cte = es.shader_editor->get_code_editor(); + if (cte) { + cte->set_zoom_factor(text_shader_zoom_factor); + cte->connect("zoomed", callable_mp(this, &ShaderEditorPlugin::_set_text_shader_zoom_factor)); } } @@ -244,6 +252,8 @@ void ShaderEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { _update_shader_list(); _shader_selected(selected_shader_idx); + + _set_text_shader_zoom_factor(p_layout->get_value("ShaderEditor", "text_shader_zoom_factor", 1.0f)); } void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { @@ -290,6 +300,7 @@ void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { p_layout->set_value("ShaderEditor", "open_shaders", shaders); p_layout->set_value("ShaderEditor", "split_offset", main_split->get_split_offset()); p_layout->set_value("ShaderEditor", "selected_shader", selected_shader); + p_layout->set_value("ShaderEditor", "text_shader_zoom_factor", text_shader_zoom_factor); } String ShaderEditorPlugin::get_unsaved_status(const String &p_for_scene) const { @@ -590,6 +601,20 @@ void ShaderEditorPlugin::_window_changed(bool p_visible) { make_floating->set_visible(!p_visible); } +void ShaderEditorPlugin::_set_text_shader_zoom_factor(float p_zoom_factor) { + if (text_shader_zoom_factor != p_zoom_factor) { + text_shader_zoom_factor = p_zoom_factor; + for (const EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader_editor) { + CodeTextEditor *cte = edited_shader.shader_editor->get_code_editor(); + if (cte && cte->get_zoom_factor() != text_shader_zoom_factor) { + cte->set_zoom_factor(text_shader_zoom_factor); + } + } + } + } +} + void ShaderEditorPlugin::_file_removed(const String &p_removed_file) { for (uint32_t i = 0; i < edited_shaders.size(); i++) { if (edited_shaders[i].path == p_removed_file) { diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index ea50d62b8f..84c5a620a7 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -86,6 +86,8 @@ class ShaderEditorPlugin : public EditorPlugin { ShaderCreateDialog *shader_create_dialog = nullptr; + float text_shader_zoom_factor = 1.0f; + void _update_shader_list(); void _shader_selected(int p_index); void _shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index); @@ -106,6 +108,8 @@ class ShaderEditorPlugin : public EditorPlugin { void _window_changed(bool p_visible); + void _set_text_shader_zoom_factor(float p_zoom_factor); + protected: void _notification(int p_what); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index c9a0cbd2de..465785a3b7 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -150,6 +150,10 @@ Control *TextEditor::get_base_editor() const { return code_editor->get_text_editor(); } +CodeTextEditor *TextEditor::get_code_editor() const { + return code_editor; +} + PackedInt32Array TextEditor::get_breakpoints() { return PackedInt32Array(); } @@ -419,11 +423,11 @@ void TextEditor::_edit_option(int p_op) { trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { - tx->set_indent_using_spaces(true); + code_editor->set_indent_using_spaces(true); convert_indent(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { - tx->set_indent_using_spaces(false); + code_editor->set_indent_using_spaces(false); convert_indent(); } break; case EDIT_TO_UPPERCASE: { diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index a4ec2d882b..38dca9eb28 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -152,6 +152,7 @@ public: virtual void validate() override; virtual Control *get_base_editor() const override; + virtual CodeTextEditor *get_code_editor() const override; static void register_editor(); diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 17b48118ac..ad64e1d1d7 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -628,100 +628,100 @@ ShaderTextEditor::ShaderTextEditor() { /*** SCRIPT EDITOR ******/ void TextShaderEditor::_menu_option(int p_option) { - shader_editor->get_text_editor()->apply_ime(); + code_editor->get_text_editor()->apply_ime(); switch (p_option) { case EDIT_UNDO: { - shader_editor->get_text_editor()->undo(); + code_editor->get_text_editor()->undo(); } break; case EDIT_REDO: { - shader_editor->get_text_editor()->redo(); + code_editor->get_text_editor()->redo(); } break; case EDIT_CUT: { - shader_editor->get_text_editor()->cut(); + code_editor->get_text_editor()->cut(); } break; case EDIT_COPY: { - shader_editor->get_text_editor()->copy(); + code_editor->get_text_editor()->copy(); } break; case EDIT_PASTE: { - shader_editor->get_text_editor()->paste(); + code_editor->get_text_editor()->paste(); } break; case EDIT_SELECT_ALL: { - shader_editor->get_text_editor()->select_all(); + code_editor->get_text_editor()->select_all(); } break; case EDIT_MOVE_LINE_UP: { - shader_editor->move_lines_up(); + code_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - shader_editor->move_lines_down(); + code_editor->move_lines_down(); } break; case EDIT_INDENT: { if (shader.is_null() && shader_inc.is_null()) { return; } - shader_editor->get_text_editor()->indent_lines(); + code_editor->get_text_editor()->indent_lines(); } break; case EDIT_UNINDENT: { if (shader.is_null() && shader_inc.is_null()) { return; } - shader_editor->get_text_editor()->unindent_lines(); + code_editor->get_text_editor()->unindent_lines(); } break; case EDIT_DELETE_LINE: { - shader_editor->delete_lines(); + code_editor->delete_lines(); } break; case EDIT_DUPLICATE_SELECTION: { - shader_editor->duplicate_selection(); + code_editor->duplicate_selection(); } break; case EDIT_DUPLICATE_LINES: { - shader_editor->get_text_editor()->duplicate_lines(); + code_editor->get_text_editor()->duplicate_lines(); } break; case EDIT_TOGGLE_WORD_WRAP: { - TextEdit::LineWrappingMode wrap = shader_editor->get_text_editor()->get_line_wrapping_mode(); - shader_editor->get_text_editor()->set_line_wrapping_mode(wrap == TextEdit::LINE_WRAPPING_BOUNDARY ? TextEdit::LINE_WRAPPING_NONE : TextEdit::LINE_WRAPPING_BOUNDARY); + TextEdit::LineWrappingMode wrap = code_editor->get_text_editor()->get_line_wrapping_mode(); + code_editor->get_text_editor()->set_line_wrapping_mode(wrap == TextEdit::LINE_WRAPPING_BOUNDARY ? TextEdit::LINE_WRAPPING_NONE : TextEdit::LINE_WRAPPING_BOUNDARY); } break; case EDIT_TOGGLE_COMMENT: { if (shader.is_null() && shader_inc.is_null()) { return; } - shader_editor->toggle_inline_comment("//"); + code_editor->toggle_inline_comment("//"); } break; case EDIT_COMPLETE: { - shader_editor->get_text_editor()->request_code_completion(); + code_editor->get_text_editor()->request_code_completion(); } break; case SEARCH_FIND: { - shader_editor->get_find_replace_bar()->popup_search(); + code_editor->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - shader_editor->get_find_replace_bar()->search_next(); + code_editor->get_find_replace_bar()->search_next(); } break; case SEARCH_FIND_PREV: { - shader_editor->get_find_replace_bar()->search_prev(); + code_editor->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - shader_editor->get_find_replace_bar()->popup_replace(); + code_editor->get_find_replace_bar()->popup_replace(); } break; case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(shader_editor->get_text_editor()); + goto_line_dialog->popup_find_line(code_editor->get_text_editor()); } break; case BOOKMARK_TOGGLE: { - shader_editor->toggle_bookmark(); + code_editor->toggle_bookmark(); } break; case BOOKMARK_GOTO_NEXT: { - shader_editor->goto_next_bookmark(); + code_editor->goto_next_bookmark(); } break; case BOOKMARK_GOTO_PREV: { - shader_editor->goto_prev_bookmark(); + code_editor->goto_prev_bookmark(); } break; case BOOKMARK_REMOVE_ALL: { - shader_editor->remove_all_bookmarks(); + code_editor->remove_all_bookmarks(); } break; case HELP_DOCS: { OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/shader_reference/index.html", VERSION_DOCS_URL)); } break; } if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { - callable_mp((Control *)shader_editor->get_text_editor(), &Control::grab_focus).call_deferred(); + callable_mp((Control *)code_editor->get_text_editor(), &Control::grab_focus).call_deferred(); } } @@ -740,14 +740,16 @@ void TextShaderEditor::_notification(int p_what) { } void TextShaderEditor::_editor_settings_changed() { - if (!EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor")) { + if (!EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") && + !EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor")) { return; } - shader_editor->update_editor_settings(); - shader_editor->get_text_editor()->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing")); - shader_editor->get_text_editor()->set_draw_breakpoints_gutter(false); - shader_editor->get_text_editor()->set_draw_executing_lines_gutter(false); + _apply_editor_settings(); +} + +void TextShaderEditor::_apply_editor_settings() { + code_editor->update_editor_settings(); trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save"); } @@ -758,7 +760,7 @@ void TextShaderEditor::_show_warnings_panel(bool p_show) { void TextShaderEditor::_warning_clicked(Variant p_line) { if (p_line.get_type() == Variant::INT) { - shader_editor->get_text_editor()->set_caret_line(p_line.operator int64_t()); + code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t()); } } @@ -773,7 +775,7 @@ void TextShaderEditor::ensure_select_current() { } void TextShaderEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - shader_editor->goto_line_selection(p_line, p_begin, p_end); + code_editor->goto_line_selection(p_line, p_begin, p_end); } void TextShaderEditor::_project_settings_changed() { @@ -812,8 +814,8 @@ void TextShaderEditor::_update_warnings(bool p_validate) { saved_warning_flags = (uint32_t)ShaderWarning::get_flags_from_codemap(saved_warnings); } - if (p_validate && changed && shader_editor && shader_editor->get_edited_shader().is_valid()) { - shader_editor->validate_script(); + if (p_validate && changed && code_editor && code_editor->get_edited_shader().is_valid()) { + code_editor->validate_script(); } } @@ -848,22 +850,22 @@ void TextShaderEditor::_reload_shader_from_disk() { Ref<Shader> rel_shader = ResourceLoader::load(shader->get_path(), shader->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); ERR_FAIL_COND(!rel_shader.is_valid()); - shader_editor->set_block_shader_changed(true); + code_editor->set_block_shader_changed(true); shader->set_code(rel_shader->get_code()); - shader_editor->set_block_shader_changed(false); + code_editor->set_block_shader_changed(false); shader->set_last_modified_time(rel_shader->get_last_modified_time()); - shader_editor->reload_text(); + code_editor->reload_text(); } void TextShaderEditor::_reload_shader_include_from_disk() { Ref<ShaderInclude> rel_shader_include = ResourceLoader::load(shader_inc->get_path(), shader_inc->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); ERR_FAIL_COND(!rel_shader_include.is_valid()); - shader_editor->set_block_shader_changed(true); + code_editor->set_block_shader_changed(true); shader_inc->set_code(rel_shader_include->get_code()); - shader_editor->set_block_shader_changed(false); + code_editor->set_block_shader_changed(false); shader_inc->set_last_modified_time(rel_shader_include->get_last_modified_time()); - shader_editor->reload_text(); + code_editor->reload_text(); } void TextShaderEditor::_reload() { @@ -886,7 +888,7 @@ void TextShaderEditor::edit(const Ref<Shader> &p_shader) { shader = p_shader; shader_inc = Ref<ShaderInclude>(); - shader_editor->set_edited_shader(shader); + code_editor->set_edited_shader(shader); } void TextShaderEditor::edit(const Ref<ShaderInclude> &p_shader_inc) { @@ -901,7 +903,7 @@ void TextShaderEditor::edit(const Ref<ShaderInclude> &p_shader_inc) { shader_inc = p_shader_inc; shader = Ref<Shader>(); - shader_editor->set_edited_shader_include(p_shader_inc); + code_editor->set_edited_shader_include(p_shader_inc); } void TextShaderEditor::save_external_data(const String &p_str) { @@ -916,7 +918,7 @@ void TextShaderEditor::save_external_data(const String &p_str) { apply_shaders(); - Ref<Shader> edited_shader = shader_editor->get_edited_shader(); + Ref<Shader> edited_shader = code_editor->get_edited_shader(); if (edited_shader.is_valid()) { ResourceSaver::save(edited_shader); } @@ -924,56 +926,56 @@ void TextShaderEditor::save_external_data(const String &p_str) { ResourceSaver::save(shader); } - Ref<ShaderInclude> edited_shader_inc = shader_editor->get_edited_shader_include(); + Ref<ShaderInclude> edited_shader_inc = code_editor->get_edited_shader_include(); if (edited_shader_inc.is_valid()) { ResourceSaver::save(edited_shader_inc); } if (shader_inc.is_valid() && shader_inc != edited_shader_inc) { ResourceSaver::save(shader_inc); } - shader_editor->get_text_editor()->tag_saved_version(); + code_editor->get_text_editor()->tag_saved_version(); disk_changed->hide(); } void TextShaderEditor::trim_trailing_whitespace() { - shader_editor->trim_trailing_whitespace(); + code_editor->trim_trailing_whitespace(); } void TextShaderEditor::validate_script() { - shader_editor->_validate_script(); + code_editor->_validate_script(); } bool TextShaderEditor::is_unsaved() const { - return shader_editor->get_text_editor()->get_saved_version() != shader_editor->get_text_editor()->get_version(); + return code_editor->get_text_editor()->get_saved_version() != code_editor->get_text_editor()->get_version(); } void TextShaderEditor::tag_saved_version() { - shader_editor->get_text_editor()->tag_saved_version(); + code_editor->get_text_editor()->tag_saved_version(); } void TextShaderEditor::apply_shaders() { - String editor_code = shader_editor->get_text_editor()->get_text(); + String editor_code = code_editor->get_text_editor()->get_text(); if (shader.is_valid()) { String shader_code = shader->get_code(); - if (shader_code != editor_code || dependencies_version != shader_editor->get_dependencies_version()) { - shader_editor->set_block_shader_changed(true); + if (shader_code != editor_code || dependencies_version != code_editor->get_dependencies_version()) { + code_editor->set_block_shader_changed(true); shader->set_code(editor_code); - shader_editor->set_block_shader_changed(false); + code_editor->set_block_shader_changed(false); shader->set_edited(true); } } if (shader_inc.is_valid()) { String shader_inc_code = shader_inc->get_code(); - if (shader_inc_code != editor_code || dependencies_version != shader_editor->get_dependencies_version()) { - shader_editor->set_block_shader_changed(true); + if (shader_inc_code != editor_code || dependencies_version != code_editor->get_dependencies_version()) { + code_editor->set_block_shader_changed(true); shader_inc->set_code(editor_code); - shader_editor->set_block_shader_changed(false); + code_editor->set_block_shader_changed(false); shader_inc->set_edited(true); } } - dependencies_version = shader_editor->get_dependencies_version(); + dependencies_version = code_editor->get_dependencies_version(); } void TextShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { @@ -981,7 +983,7 @@ void TextShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { - CodeEdit *tx = shader_editor->get_text_editor(); + CodeEdit *tx = code_editor->get_text_editor(); tx->apply_ime(); @@ -1014,7 +1016,7 @@ void TextShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { Ref<InputEventKey> k = ev; if (k.is_valid() && k->is_pressed() && k->is_action("ui_menu", true)) { - CodeEdit *tx = shader_editor->get_text_editor(); + CodeEdit *tx = code_editor->get_text_editor(); tx->adjust_viewport_to_caret(); _make_context_menu(tx->has_selection(), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->get_caret_draw_pos())); context_menu->grab_focus(); @@ -1029,7 +1031,7 @@ void TextShaderEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - PackedInt32Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines(); + PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } @@ -1037,7 +1039,7 @@ void TextShaderEditor::_update_bookmark_list() { bookmarks_menu->add_separator(); for (int i = 0; i < bookmark_list.size(); i++) { - String line = shader_editor->get_text_editor()->get_line(bookmark_list[i]).strip_edges(); + String line = code_editor->get_text_editor()->get_line(bookmark_list[i]).strip_edges(); // Limit the size of the line if too big. if (line.length() > 50) { line = line.substr(0, 50); @@ -1052,7 +1054,7 @@ void TextShaderEditor::_bookmark_item_pressed(int p_idx) { if (p_idx < 4) { // Any item before the separator. _menu_option(bookmarks_menu->get_item_id(p_idx)); } else { - shader_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx)); + code_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx)); } } @@ -1083,26 +1085,26 @@ void TextShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) TextShaderEditor::TextShaderEditor() { _update_warnings(false); - shader_editor = memnew(ShaderTextEditor); + code_editor = memnew(ShaderTextEditor); - shader_editor->connect("script_validated", callable_mp(this, &TextShaderEditor::_script_validated)); + code_editor->connect("script_validated", callable_mp(this, &TextShaderEditor::_script_validated)); - shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); - shader_editor->add_theme_constant_override("separation", 0); - shader_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + code_editor->add_theme_constant_override("separation", 0); + code_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); - shader_editor->connect("show_warnings_panel", callable_mp(this, &TextShaderEditor::_show_warnings_panel)); - shader_editor->connect("script_changed", callable_mp(this, &TextShaderEditor::apply_shaders)); + code_editor->connect("show_warnings_panel", callable_mp(this, &TextShaderEditor::_show_warnings_panel)); + code_editor->connect("script_changed", callable_mp(this, &TextShaderEditor::apply_shaders)); EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextShaderEditor::_editor_settings_changed)); ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextShaderEditor::_project_settings_changed)); - shader_editor->get_text_editor()->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line")); - - shader_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true); - shader_editor->get_text_editor()->set_context_menu_enabled(false); - shader_editor->get_text_editor()->connect("gui_input", callable_mp(this, &TextShaderEditor::_text_edit_gui_input)); + code_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true); + code_editor->get_text_editor()->set_context_menu_enabled(false); + code_editor->get_text_editor()->set_draw_breakpoints_gutter(false); + code_editor->get_text_editor()->set_draw_executing_lines_gutter(false); + code_editor->get_text_editor()->connect("gui_input", callable_mp(this, &TextShaderEditor::_text_edit_gui_input)); - shader_editor->update_editor_settings(); + code_editor->update_editor_settings(); context_menu = memnew(PopupMenu); add_child(context_menu); @@ -1184,12 +1186,12 @@ TextShaderEditor::TextShaderEditor() { main_container->add_child(editor_box); editor_box->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); - editor_box->add_child(shader_editor); + editor_box->add_child(code_editor); FindReplaceBar *bar = memnew(FindReplaceBar); main_container->add_child(bar); bar->hide(); - shader_editor->set_find_replace_bar(bar); + code_editor->set_find_replace_bar(bar); warnings_panel = memnew(RichTextLabel); warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); @@ -1201,7 +1203,7 @@ TextShaderEditor::TextShaderEditor() { warnings_panel->hide(); warnings_panel->connect("meta_clicked", callable_mp(this, &TextShaderEditor::_warning_clicked)); editor_box->add_child(warnings_panel); - shader_editor->set_warnings_panel(warnings_panel); + code_editor->set_warnings_panel(warnings_panel); goto_line_dialog = memnew(GotoLineDialog); add_child(goto_line_dialog); @@ -1221,8 +1223,6 @@ TextShaderEditor::TextShaderEditor() { disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); disk_changed->connect("custom_action", callable_mp(this, &TextShaderEditor::save_external_data)); - trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save"); - add_child(disk_changed); _editor_settings_changed(); diff --git a/editor/plugins/text_shader_editor.h b/editor/plugins/text_shader_editor.h index eba2ec0bb9..a1b45d1b2e 100644 --- a/editor/plugins/text_shader_editor.h +++ b/editor/plugins/text_shader_editor.h @@ -148,7 +148,7 @@ class TextShaderEditor : public MarginContainer { ConfirmationDialog *erase_tab_confirm = nullptr; ConfirmationDialog *disk_changed = nullptr; - ShaderTextEditor *shader_editor = nullptr; + ShaderTextEditor *code_editor = nullptr; bool compilation_success = true; void _menu_option(int p_option); @@ -156,6 +156,7 @@ class TextShaderEditor : public MarginContainer { mutable Ref<ShaderInclude> shader_inc; void _editor_settings_changed(); + void _apply_editor_settings(); void _project_settings_changed(); void _check_for_external_edit(); @@ -197,6 +198,7 @@ public: void validate_script(); bool is_unsaved() const; void tag_saved_version(); + ShaderTextEditor *get_code_editor() { return code_editor; } virtual Size2 get_minimum_size() const override { return Size2(0, 200); } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 4750179473..acca5810a9 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -104,6 +104,7 @@ void VisualShaderNodePlugin::_bind_methods() { /////////////////// VisualShaderGraphPlugin::VisualShaderGraphPlugin() { + vs_msdf_fonts_theme.instantiate(); } void VisualShaderGraphPlugin::_bind_methods() { @@ -358,6 +359,13 @@ void VisualShaderGraphPlugin::update_theme() { vector_expanded_color[1] = editor->get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)); // green vector_expanded_color[2] = editor->get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor)); // blue vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), EditorStringName(Editor)); // alpha + + Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorFonts)); + Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorFonts)); + vs_msdf_fonts_theme->set_font("font", "Label", label_font); + vs_msdf_fonts_theme->set_font("font", "GraphNodeTitleLabel", label_bold_font); + vs_msdf_fonts_theme->set_font("font", "LineEdit", label_font); + vs_msdf_fonts_theme->set_font("font", "Button", label_font); } bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const { @@ -398,34 +406,35 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool Control *offset; - static const Color type_color[] = { - Color(0.38, 0.85, 0.96), // scalar (float) - Color(0.49, 0.78, 0.94), // scalar (int) - Color(0.20, 0.88, 0.67), // scalar (uint) - Color(0.74, 0.57, 0.95), // vector2 - Color(0.84, 0.49, 0.93), // vector3 - Color(1.0, 0.125, 0.95), // vector4 - Color(0.55, 0.65, 0.94), // boolean - Color(0.96, 0.66, 0.43), // transform - Color(1.0, 1.0, 0.0), // sampler + const Color type_color[] = { + EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"), + EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"), + EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"), + EDITOR_GET("editors/visual_editors/connection_colors/vector2_color"), + EDITOR_GET("editors/visual_editors/connection_colors/vector3_color"), + EDITOR_GET("editors/visual_editors/connection_colors/vector4_color"), + EDITOR_GET("editors/visual_editors/connection_colors/boolean_color"), + EDITOR_GET("editors/visual_editors/connection_colors/transform_color"), + EDITOR_GET("editors/visual_editors/connection_colors/sampler_color"), }; - static const String vector_expanded_name[4] = { - "red", - "green", - "blue", - "alpha" + // Keep in sync with VisualShaderNode::Category. + const Color category_color[VisualShaderNode::Category::CATEGORY_MAX] = { + Color(0.0, 0.0, 0.0), // None (default, not used) + EDITOR_GET("editors/visual_editors/category_colors/output_color"), + EDITOR_GET("editors/visual_editors/category_colors/color_color"), + EDITOR_GET("editors/visual_editors/category_colors/conditional_color"), + EDITOR_GET("editors/visual_editors/category_colors/input_color"), + EDITOR_GET("editors/visual_editors/category_colors/scalar_color"), + EDITOR_GET("editors/visual_editors/category_colors/textures_color"), + EDITOR_GET("editors/visual_editors/category_colors/transform_color"), + EDITOR_GET("editors/visual_editors/category_colors/utility_color"), + EDITOR_GET("editors/visual_editors/category_colors/vector_color"), + EDITOR_GET("editors/visual_editors/category_colors/special_color"), + EDITOR_GET("editors/visual_editors/category_colors/particle_color"), }; - // Visual shader specific theme for MSDF font. - Ref<Theme> vstheme; - vstheme.instantiate(); - Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorFonts)); - Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorFonts)); - vstheme->set_font("font", "Label", label_font); - vstheme->set_font("font", "GraphNodeTitleLabel", label_bold_font); - vstheme->set_font("font", "LineEdit", label_font); - vstheme->set_font("font", "Button", label_font); + static const String vector_expanded_name[4] = { "red", "green", "blue", "alpha" }; Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id); @@ -457,7 +466,18 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool node->connect("delete_request", callable_mp(editor, &VisualShaderEditor::_delete_node_request).bind(p_type, p_id), CONNECT_DEFERRED); } graph->add_child(node); - node->set_theme(vstheme); + node->set_theme(vs_msdf_fonts_theme); + + // Set the node's titlebar color based on its category. + if (vsnode->get_category() != VisualShaderNode::CATEGORY_NONE) { + Ref<StyleBoxFlat> sb_colored = editor->get_theme_stylebox("titlebar", "GraphNode")->duplicate(); + sb_colored->set_bg_color(category_color[vsnode->get_category()]); + node->add_theme_style_override("titlebar", sb_colored); + + Ref<StyleBoxFlat> sb_colored_selected = editor->get_theme_stylebox("titlebar_selected", "GraphNode")->duplicate(); + sb_colored_selected->set_bg_color(category_color[vsnode->get_category()].lightened(0.2)); + node->add_theme_style_override("titlebar_selected", sb_colored_selected); + } if (p_just_update) { Link &link = links[p_id]; @@ -506,6 +526,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool port_offset += 1; } + // Set the minimum width of a node based on the preview size to avoid a resize when toggling the preview. + Ref<StyleBoxFlat> graph_node_stylebox = graph->get_theme_stylebox("panel", "GraphNode"); + int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size"); + node->set_custom_minimum_size(Size2((Math::ceil(graph_node_stylebox->get_minimum_size().width) + port_preview_size) * EDSCALE, 0)); + Ref<VisualShaderNodeParticleEmit> emit = vsnode; if (emit.is_valid()) { node->set_custom_minimum_size(Size2(200 * EDSCALE, 0)); @@ -4313,7 +4338,9 @@ void VisualShaderEditor::_notification(int p_what) { } if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/visual_editors")) { graph->set_minimap_opacity(EDITOR_GET("editors/visual_editors/minimap_opacity")); + graph->set_grid_pattern((GraphEdit::GridPattern) int(EDITOR_GET("editors/visual_editors/grid_pattern"))); graph->set_connection_lines_curvature(EDITOR_GET("editors/visual_editors/lines_curvature")); + _update_graph(); } } break; @@ -5424,6 +5451,9 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_menu_hbox()->set_h_size_flags(SIZE_EXPAND_FILL); graph->set_v_size_flags(SIZE_EXPAND_FILL); graph->set_h_size_flags(SIZE_EXPAND_FILL); + graph->set_grid_pattern(GraphEdit::GridPattern::GRID_PATTERN_DOTS); + int grid_pattern = EDITOR_GET("editors/visual_editors/grid_pattern"); + graph->set_grid_pattern((GraphEdit::GridPattern)grid_pattern); graph->set_show_zoom_label(true); add_child(graph); SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 39e721f226..2575866b10 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -99,6 +99,9 @@ private: Color vector_expanded_color[4]; + // Visual shader specific theme for using MSDF fonts (on GraphNodes) which reduce aliasing at higher zoom levels. + Ref<Theme> vs_msdf_fonts_theme; + protected: static void _bind_methods(); diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index 052b19478c..4a67bd6b31 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -39,6 +39,7 @@ #include "editor/themes/editor_icons.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme.h" +#include "scene/gui/graph_edit.h" #include "scene/resources/image_texture.h" #include "scene/resources/style_box_flat.h" #include "scene/resources/style_box_line.h" @@ -213,6 +214,7 @@ Ref<EditorTheme> EditorThemeManager::_create_base_theme(const Ref<EditorTheme> & _populate_standard_styles(theme, config); _populate_editor_styles(theme, config); _populate_text_editor_styles(theme, config); + _populate_visual_shader_styles(theme, config); OS::get_singleton()->benchmark_end_measure(get_benchmark_key(), "Create Base Theme"); return theme; @@ -252,6 +254,29 @@ EditorThemeManager::ThemeConfiguration EditorThemeManager::_create_theme_config( // Handle main theme preset. { + const bool follow_system_theme = EDITOR_GET("interface/theme/follow_system_theme"); + const bool use_system_accent_color = EDITOR_GET("interface/theme/use_system_accent_color"); + DisplayServer *display_server = DisplayServer::get_singleton(); + Color system_base_color = display_server->get_base_color(); + Color system_accent_color = display_server->get_accent_color(); + + if (follow_system_theme) { + String dark_theme = "Default"; + String light_theme = "Light"; + + config.preset = light_theme; // Assume light theme if we can't detect system theme attributes. + + if (system_base_color == Color(0, 0, 0, 0)) { + if (display_server->is_dark_mode_supported() && display_server->is_dark_mode()) { + config.preset = dark_theme; + } + } else { + if (system_base_color.get_luminance() < 0.5) { + config.preset = dark_theme; + } + } + } + if (config.preset != "Custom") { Color preset_accent_color; Color preset_base_color; @@ -308,6 +333,16 @@ EditorThemeManager::ThemeConfiguration EditorThemeManager::_create_theme_config( EditorSettings::get_singleton()->set_initial_value("interface/theme/draw_extra_borders", config.draw_extra_borders); } + if (follow_system_theme && system_base_color != Color(0, 0, 0, 0)) { + config.base_color = system_base_color; + config.preset = "Custom"; + } + + if (use_system_accent_color && system_accent_color != Color(0, 0, 0, 0)) { + config.accent_color = system_accent_color; + config.preset = "Custom"; + } + // Enforce values in case they were adjusted or overridden. EditorSettings::get_singleton()->set_manually("interface/theme/preset", config.preset); EditorSettings::get_singleton()->set_manually("interface/theme/accent_color", config.accent_color); @@ -1432,13 +1467,22 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_stylebox("panel", "GraphEdit", p_config.tree_panel_style); p_theme->set_stylebox("menu_panel", "GraphEdit", make_flat_stylebox(p_config.dark_color_1 * Color(1, 1, 1, 0.6), 4, 2, 4, 2, 3)); - if (p_config.dark_theme) { - p_theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.1)); - p_theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.05)); - } else { - p_theme->set_color("grid_major", "GraphEdit", Color(0.0, 0.0, 0.0, 0.15)); - p_theme->set_color("grid_minor", "GraphEdit", Color(0.0, 0.0, 0.0, 0.07)); + float grid_base_brightness = p_config.dark_theme ? 1.0 : 0.0; + GraphEdit::GridPattern grid_pattern = (GraphEdit::GridPattern) int(EDITOR_GET("editors/visual_editors/grid_pattern")); + switch (grid_pattern) { + case GraphEdit::GRID_PATTERN_LINES: + p_theme->set_color("grid_major", "GraphEdit", Color(grid_base_brightness, grid_base_brightness, grid_base_brightness, 0.10)); + p_theme->set_color("grid_minor", "GraphEdit", Color(grid_base_brightness, grid_base_brightness, grid_base_brightness, 0.05)); + break; + case GraphEdit::GRID_PATTERN_DOTS: + p_theme->set_color("grid_major", "GraphEdit", Color(grid_base_brightness, grid_base_brightness, grid_base_brightness, 0.07)); + p_theme->set_color("grid_minor", "GraphEdit", Color(grid_base_brightness, grid_base_brightness, grid_base_brightness, 0.07)); + break; + default: + WARN_PRINT("Unknown grid pattern."); + break; } + p_theme->set_color("selection_fill", "GraphEdit", p_theme->get_color(SNAME("box_selection_fill_color"), EditorStringName(Editor))); p_theme->set_color("selection_stroke", "GraphEdit", p_theme->get_color(SNAME("box_selection_stroke_color"), EditorStringName(Editor))); p_theme->set_color("activity", "GraphEdit", p_config.dark_theme ? Color(1, 1, 1) : Color(0, 0, 0)); @@ -1489,31 +1533,48 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the const int gn_margin_side = 2; const int gn_margin_bottom = 2; + const int gn_corner_radius = 3; + const Color gn_bg_color = p_config.dark_theme ? p_config.dark_color_3 : p_config.dark_color_1.lerp(p_config.mono_color, 0.09); - const Color gn_selected_border_color = gn_bg_color.lerp(p_config.accent_color, 0.275); + const Color gn_selected_border_color = p_config.dark_theme ? Color(1, 1, 1) : Color(0, 0, 0); const Color gn_frame_bg = gn_bg_color.lerp(p_config.tree_panel_style->get_bg_color(), 0.3); - Ref<StyleBoxFlat> gn_panel_style = make_flat_stylebox(gn_frame_bg, gn_margin_side, gn_margin_top, gn_margin_side, gn_margin_bottom, p_config.corner_radius); - gn_panel_style->set_border_width_all(p_config.border_width); - gn_panel_style->set_border_color(gn_bg_color); - gn_panel_style->set_corner_radius_individual(0, 0, p_config.corner_radius * EDSCALE, p_config.corner_radius * EDSCALE); - gn_panel_style->set_expand_margin(SIDE_TOP, 17 * EDSCALE); + const bool high_contrast_borders = p_config.draw_extra_borders && p_config.dark_theme; - Ref<StyleBoxFlat> gn_panel_selected_style = make_flat_stylebox(gn_frame_bg, gn_margin_side, gn_margin_top, gn_margin_side, gn_margin_bottom, p_config.corner_radius); - gn_panel_selected_style->set_border_width_all(2 * EDSCALE + p_config.border_width); + Ref<StyleBoxFlat> gn_panel_style = make_flat_stylebox(gn_frame_bg, gn_margin_side, gn_margin_top, gn_margin_side, gn_margin_bottom, p_config.corner_radius); + gn_panel_style->set_border_width(SIDE_BOTTOM, 2 * EDSCALE); + gn_panel_style->set_border_width(SIDE_LEFT, 2 * EDSCALE); + gn_panel_style->set_border_width(SIDE_RIGHT, 2 * EDSCALE); + gn_panel_style->set_border_color(high_contrast_borders ? gn_bg_color.lightened(0.2) : gn_bg_color.darkened(0.3)); + gn_panel_style->set_corner_radius_individual(0, 0, gn_corner_radius * EDSCALE, gn_corner_radius * EDSCALE); + gn_panel_style->set_anti_aliased(true); + + Ref<StyleBoxFlat> gn_panel_selected_style = gn_panel_style->duplicate(); + gn_panel_selected_style->set_bg_color(p_config.dark_theme ? gn_bg_color.lightened(0.15) : gn_bg_color.darkened(0.15)); + gn_panel_selected_style->set_border_width(SIDE_TOP, 0); + gn_panel_selected_style->set_border_width(SIDE_BOTTOM, 2 * EDSCALE); + gn_panel_selected_style->set_border_width(SIDE_LEFT, 2 * EDSCALE); + gn_panel_selected_style->set_border_width(SIDE_RIGHT, 2 * EDSCALE); gn_panel_selected_style->set_border_color(gn_selected_border_color); - gn_panel_selected_style->set_corner_radius_individual(0, 0, p_config.corner_radius * EDSCALE, p_config.corner_radius * EDSCALE); - gn_panel_selected_style->set_expand_margin(SIDE_TOP, 17 * EDSCALE); - const int gn_titlebar_margin_left = 12; - const int gn_titlebar_margin_right = 4; // The rest is for the close button. + const int gn_titlebar_margin_top = 8; + const int gn_titlebar_margin_side = 12; + const int gn_titlebar_margin_bottom = 8; - Ref<StyleBoxFlat> gn_titlebar_style = make_flat_stylebox(gn_bg_color, gn_titlebar_margin_left, gn_margin_top, gn_titlebar_margin_right, 0, p_config.corner_radius); + Ref<StyleBoxFlat> gn_titlebar_style = make_flat_stylebox(gn_bg_color, gn_titlebar_margin_side, gn_titlebar_margin_top, gn_titlebar_margin_side, gn_titlebar_margin_bottom, p_config.corner_radius); + gn_titlebar_style->set_border_width(SIDE_TOP, 2 * EDSCALE); + gn_titlebar_style->set_border_width(SIDE_LEFT, 2 * EDSCALE); + gn_titlebar_style->set_border_width(SIDE_RIGHT, 2 * EDSCALE); + gn_titlebar_style->set_border_color(high_contrast_borders ? gn_bg_color.lightened(0.2) : gn_bg_color.darkened(0.3)); gn_titlebar_style->set_expand_margin(SIDE_TOP, 2 * EDSCALE); - gn_titlebar_style->set_corner_radius_individual(p_config.corner_radius * EDSCALE, p_config.corner_radius * EDSCALE, 0, 0); - - Ref<StyleBoxFlat> gn_titlebar_selected_style = make_flat_stylebox(gn_selected_border_color, gn_titlebar_margin_left, gn_margin_top, gn_titlebar_margin_right, 0, p_config.corner_radius); - gn_titlebar_selected_style->set_corner_radius_individual(p_config.corner_radius * EDSCALE, p_config.corner_radius * EDSCALE, 0, 0); + gn_titlebar_style->set_corner_radius_individual(gn_corner_radius * EDSCALE, gn_corner_radius * EDSCALE, 0, 0); + gn_titlebar_style->set_anti_aliased(true); + + Ref<StyleBoxFlat> gn_titlebar_selected_style = gn_titlebar_style->duplicate(); + gn_titlebar_selected_style->set_border_color(gn_selected_border_color); + gn_titlebar_selected_style->set_border_width(SIDE_TOP, 2 * EDSCALE); + gn_titlebar_selected_style->set_border_width(SIDE_LEFT, 2 * EDSCALE); + gn_titlebar_selected_style->set_border_width(SIDE_RIGHT, 2 * EDSCALE); gn_titlebar_selected_style->set_expand_margin(SIDE_TOP, 2 * EDSCALE); Color gn_decoration_color = p_config.dark_color_1.inverted(); @@ -1540,7 +1601,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_color("resizer_color", "GraphNode", gn_decoration_color); - p_theme->set_constant("port_h_offset", "GraphNode", 0); + p_theme->set_constant("port_h_offset", "GraphNode", 1); p_theme->set_constant("separation", "GraphNode", 1 * EDSCALE); Ref<ImageTexture> port_icon = p_theme->get_icon(SNAME("GuiGraphNodePort"), EditorStringName(EditorIcons)); @@ -1551,7 +1612,11 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the // GraphNode's title Label. p_theme->set_type_variation("GraphNodeTitleLabel", "Label"); p_theme->set_stylebox("normal", "GraphNodeTitleLabel", make_empty_stylebox(0, 0, 0, 0)); - p_theme->set_color("font_color", "GraphNodeTitleLabel", p_config.font_color); + p_theme->set_color("font_color", "GraphNodeTitleLabel", p_config.dark_theme ? p_config.font_color : Color(1, 1, 1)); // Also use a bright font color for light themes. + p_theme->set_color("font_shadow_color", "GraphNodeTitleLabel", Color(0, 0, 0, 0.35)); + p_theme->set_constant("shadow_outline_size", "GraphNodeTitleLabel", 4); + p_theme->set_constant("shadow_offset_x", "GraphNodeTitleLabel", 0); + p_theme->set_constant("shadow_offset_y", "GraphNodeTitleLabel", 1); p_theme->set_constant("line_spacing", "GraphNodeTitleLabel", 3 * EDSCALE); } } @@ -2306,6 +2371,59 @@ void EditorThemeManager::_populate_text_editor_styles(const Ref<EditorTheme> &p_ /* clang-format on */ } +void EditorThemeManager::_populate_visual_shader_styles(const Ref<EditorTheme> &p_theme, ThemeConfiguration &p_config) { + EditorSettings *ed_settings = EditorSettings::get_singleton(); + String visual_shader_color_theme = ed_settings->get("editors/visual_editors/color_theme"); + if (visual_shader_color_theme == "Default") { + // Connection type colors + ed_settings->set_initial_value("editors/visual_editors/connection_colors/scalar_color", Color(0.55, 0.55, 0.55), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/vector2_color", Color(0.44, 0.43, 0.64), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/vector3_color", Color(0.337, 0.314, 0.71), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/vector4_color", Color(0.7, 0.65, 0.147), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/boolean_color", Color(0.243, 0.612, 0.349), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/transform_color", Color(0.71, 0.357, 0.64), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/sampler_color", Color(0.659, 0.4, 0.137), true); + + // Node category colors (used for the node headers) + ed_settings->set_initial_value("editors/visual_editors/category_colors/output_color", Color(0.26, 0.10, 0.15), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/color_color", Color(0.5, 0.5, 0.1), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/conditional_color", Color(0.208, 0.522, 0.298), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/input_color", Color(0.502, 0.2, 0.204), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/scalar_color", Color(0.1, 0.5, 0.6), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/textures_color", Color(0.5, 0.3, 0.1), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/transform_color", Color(0.5, 0.3, 0.5), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/utility_color", Color(0.2, 0.2, 0.2), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/vector_color", Color(0.2, 0.2, 0.5), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/special_color", Color(0.098, 0.361, 0.294), true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/particle_color", Color(0.12, 0.358, 0.8), true); + + } else if (visual_shader_color_theme == "Legacy") { + // Connection type colors + ed_settings->set_initial_value("editors/visual_editors/connection_colors/scalar_color", Color(0.38, 0.85, 0.96), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/vector2_color", Color(0.74, 0.57, 0.95), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/vector3_color", Color(0.84, 0.49, 0.93), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/vector4_color", Color(1.0, 0.125, 0.95), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/boolean_color", Color(0.55, 0.65, 0.94), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/transform_color", Color(0.96, 0.66, 0.43), true); + ed_settings->set_initial_value("editors/visual_editors/connection_colors/sampler_color", Color(1.0, 1.0, 0.0), true); + + // Node category colors (used for the node headers) + Ref<StyleBoxFlat> gn_panel_style = p_theme->get_stylebox("panel", "GraphNode"); + Color gn_bg_color = gn_panel_style->get_bg_color(); + ed_settings->set_initial_value("editors/visual_editors/category_colors/output_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/color_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/conditional_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/input_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/scalar_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/textures_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/transform_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/utility_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/vector_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/special_color", gn_bg_color, true); + ed_settings->set_initial_value("editors/visual_editors/category_colors/particle_color", gn_bg_color, true); + } +} + void EditorThemeManager::_reset_dirty_flag() { outdated_cache_dirty = true; } @@ -2348,6 +2466,7 @@ bool EditorThemeManager::is_generated_theme_outdated() { EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font") || EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/increase_scrollbar_touch_area") || EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/scale_gizmo_handles") || + EditorSettings::get_singleton()->check_changed_settings_in_group("editors/visual_editors") || EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") || EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/help/help") || EditorSettings::get_singleton()->check_changed_settings_in_group("docks/property_editor/subresource_hue_tint") || diff --git a/editor/themes/editor_theme_manager.h b/editor/themes/editor_theme_manager.h index de088a1011..3eb1dd5ffd 100644 --- a/editor/themes/editor_theme_manager.h +++ b/editor/themes/editor_theme_manager.h @@ -156,6 +156,7 @@ class EditorThemeManager { static void _generate_text_editor_defaults(ThemeConfiguration &p_config); static void _populate_text_editor_styles(const Ref<EditorTheme> &p_theme, ThemeConfiguration &p_config); + static void _populate_visual_shader_styles(const Ref<EditorTheme> &p_theme, ThemeConfiguration &p_config); static void _reset_dirty_flag(); diff --git a/main/main.cpp b/main/main.cpp index 4c9c159f47..c520ebecd3 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -74,7 +74,9 @@ #include "servers/navigation_server_3d.h" #include "servers/navigation_server_3d_dummy.h" #include "servers/physics_server_2d.h" +#ifndef _3D_DISABLED #include "servers/physics_server_3d.h" +#endif // _3D_DISABLED #include "servers/register_server_types.h" #include "servers/rendering/rendering_server_default.h" #include "servers/text/text_server_dummy.h" @@ -144,8 +146,10 @@ static RenderingServer *rendering_server = nullptr; static CameraServer *camera_server = nullptr; static XRServer *xr_server = nullptr; static TextServerManager *tsman = nullptr; +#ifndef _3D_DISABLED static PhysicsServer3DManager *physics_server_3d_manager = nullptr; static PhysicsServer3D *physics_server_3d = nullptr; +#endif // _3D_DISABLED static PhysicsServer2DManager *physics_server_2d_manager = nullptr; static PhysicsServer2D *physics_server_2d = nullptr; static NavigationServer3D *navigation_server_3d = nullptr; @@ -293,6 +297,7 @@ static Vector<String> get_files_with_extension(const String &p_root, const Strin // FIXME: Could maybe be moved to have less code in main.cpp. void initialize_physics() { +#ifndef _3D_DISABLED /// 3D Physics Server physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server( GLOBAL_GET(PhysicsServer3DManager::setting_property_name)); @@ -302,6 +307,7 @@ void initialize_physics() { } ERR_FAIL_NULL(physics_server_3d); physics_server_3d->init(); +#endif // _3D_DISABLED // 2D Physics server physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server( @@ -315,8 +321,10 @@ void initialize_physics() { } void finalize_physics() { +#ifndef _3D_DISABLED physics_server_3d->finish(); memdelete(physics_server_3d); +#endif // _3D_DISABLED physics_server_2d->finish(); memdelete(physics_server_2d); @@ -655,7 +663,9 @@ Error Main::test_setup() { tsman->add_interface(ts); } +#ifndef _3D_DISABLED physics_server_3d_manager = memnew(PhysicsServer3DManager); +#endif // _3D_DISABLED physics_server_2d_manager = memnew(PhysicsServer2DManager); // From `Main::setup2()`. @@ -783,9 +793,11 @@ void Main::test_cleanup() { if (tsman) { memdelete(tsman); } +#ifndef _3D_DISABLED if (physics_server_3d_manager) { memdelete(physics_server_3d_manager); } +#endif // _3D_DISABLED if (physics_server_2d_manager) { memdelete(physics_server_2d_manager); } @@ -2561,7 +2573,9 @@ Error Main::setup2() { tsman->add_interface(ts); } +#ifndef _3D_DISABLED physics_server_3d_manager = memnew(PhysicsServer3DManager); +#endif // _3D_DISABLED physics_server_2d_manager = memnew(PhysicsServer2DManager); register_server_types(); @@ -3925,14 +3939,18 @@ bool Main::iteration() { uint64_t physics_begin = OS::get_singleton()->get_ticks_usec(); +#ifndef _3D_DISABLED PhysicsServer3D::get_singleton()->sync(); PhysicsServer3D::get_singleton()->flush_queries(); +#endif // _3D_DISABLED PhysicsServer2D::get_singleton()->sync(); PhysicsServer2D::get_singleton()->flush_queries(); if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) { +#ifndef _3D_DISABLED PhysicsServer3D::get_singleton()->end_sync(); +#endif // _3D_DISABLED PhysicsServer2D::get_singleton()->end_sync(); exit = true; @@ -3948,8 +3966,10 @@ bool Main::iteration() { message_queue->flush(); +#ifndef _3D_DISABLED PhysicsServer3D::get_singleton()->end_sync(); PhysicsServer3D::get_singleton()->step(physics_step * time_scale); +#endif // _3D_DISABLED PhysicsServer2D::get_singleton()->end_sync(); PhysicsServer2D::get_singleton()->step(physics_step * time_scale); @@ -4194,9 +4214,11 @@ void Main::cleanup(bool p_force) { if (tsman) { memdelete(tsman); } +#ifndef _3D_DISABLED if (physics_server_3d_manager) { memdelete(physics_server_3d_manager); } +#endif // _3D_DISABLED if (physics_server_2d_manager) { memdelete(physics_server_2d_manager); } diff --git a/main/performance.cpp b/main/performance.cpp index b5f1a45b9a..aff26c20a3 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -180,12 +180,22 @@ double Performance::get_monitor(Monitor p_monitor) const { return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_COLLISION_PAIRS); case PHYSICS_2D_ISLAND_COUNT: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ISLAND_COUNT); +#ifdef _3D_DISABLED + case PHYSICS_3D_ACTIVE_OBJECTS: + return 0; + case PHYSICS_3D_COLLISION_PAIRS: + return 0; + case PHYSICS_3D_ISLAND_COUNT: + return 0; +#else case PHYSICS_3D_ACTIVE_OBJECTS: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ACTIVE_OBJECTS); case PHYSICS_3D_COLLISION_PAIRS: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_COLLISION_PAIRS); case PHYSICS_3D_ISLAND_COUNT: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ISLAND_COUNT); +#endif // _3D_DISABLED + case AUDIO_OUTPUT_LATENCY: return AudioServer::get_singleton()->get_output_latency(); case NAVIGATION_ACTIVE_MAPS: diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp index 41de62b20b..72e7977eef 100644 --- a/modules/basis_universal/image_compress_basisu.cpp +++ b/modules/basis_universal/image_compress_basisu.cpp @@ -154,9 +154,12 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { // Get supported compression formats. bool bptc_supported = RS::get_singleton()->has_os_feature("bptc"); + bool astc_supported = RS::get_singleton()->has_os_feature("astc"); bool s3tc_supported = RS::get_singleton()->has_os_feature("s3tc"); bool etc2_supported = RS::get_singleton()->has_os_feature("etc2"); + bool needs_ra_rg_swap = false; + switch (*(uint32_t *)(src_ptr)) { case BASIS_DECOMPRESS_RG: { // RGTC transcoding is currently performed with RG_AS_RA, fail. @@ -166,6 +169,9 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { if (bptc_supported) { basisu_format = basist::transcoder_texture_format::cTFBC7_M6_OPAQUE_ONLY; image_format = Image::FORMAT_BPTC_RGBA; + } else if (astc_supported) { + basisu_format = basist::transcoder_texture_format::cTFASTC_4x4_RGBA; + image_format = Image::FORMAT_ASTC_4x4; } else if (s3tc_supported) { basisu_format = basist::transcoder_texture_format::cTFBC1; image_format = Image::FORMAT_DXT1; @@ -183,6 +189,9 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { if (bptc_supported) { basisu_format = basist::transcoder_texture_format::cTFBC7_M5; image_format = Image::FORMAT_BPTC_RGBA; + } else if (astc_supported) { + basisu_format = basist::transcoder_texture_format::cTFASTC_4x4_RGBA; + image_format = Image::FORMAT_ASTC_4x4; } else if (s3tc_supported) { basisu_format = basist::transcoder_texture_format::cTFBC3; image_format = Image::FORMAT_DXT5; @@ -206,6 +215,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { // No supported VRAM compression formats, decompress. basisu_format = basist::transcoder_texture_format::cTFRGBA32; image_format = Image::FORMAT_RGBA8; + needs_ra_rg_swap = true; } } break; } @@ -221,6 +231,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { basist::basisu_image_info basisu_info; transcoder.get_image_info(src_ptr, src_size, basisu_info, 0); + // Create the buffer for transcoded/decompressed data. Vector<uint8_t> out_data; out_data.resize(Image::get_image_data_size(basisu_info.m_width, basisu_info.m_height, image_format, basisu_info.m_total_levels > 1)); @@ -232,8 +243,10 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { basist::basisu_image_level_info basisu_level; transcoder.get_image_level_info(src_ptr, src_size, basisu_level, 0, i); + uint32_t mip_block_or_pixel_count = image_format >= Image::FORMAT_DXT1 ? basisu_level.m_total_blocks : basisu_level.m_orig_width * basisu_level.m_orig_height; int ofs = Image::get_image_mipmap_offset(basisu_info.m_width, basisu_info.m_height, image_format, i); - bool result = transcoder.transcode_image_level(src_ptr, src_size, 0, i, dst + ofs, basisu_level.m_total_blocks, basisu_format); + + bool result = transcoder.transcode_image_level(src_ptr, src_size, 0, i, dst + ofs, mip_block_or_pixel_count, basisu_format); if (!result) { print_line(vformat("BasisUniversal cannot unpack level %d.", i)); @@ -243,6 +256,11 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { image = Image::create_from_data(basisu_info.m_width, basisu_info.m_height, basisu_info.m_total_levels > 1, image_format, out_data); + if (needs_ra_rg_swap) { + // Swap uncompressed RA-as-RG texture's color channels. + image->convert_ra_rgba8_to_rg(); + } + return image; } diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 5cfbd3f9dd..4b009f1866 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -209,7 +209,7 @@ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID. </description> </method> - <method name="range" qualifiers="vararg"> + <method name="range" qualifiers="vararg" keywords="seq"> <return type="Array" /> <description> Returns an array with the given range. [method range] can be called in three ways: diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h index 5acf436e42..b2289ef9cc 100644 --- a/modules/gdscript/tests/gdscript_test_runner_suite.h +++ b/modules/gdscript/tests/gdscript_test_runner_suite.h @@ -37,6 +37,8 @@ namespace GDScriptTests { +// TODO: Handle some cases failing on release builds. See: https://github.com/godotengine/godot/pull/88452 +#ifdef TOOLS_ENABLED TEST_SUITE("[Modules][GDScript]") { TEST_CASE("Script compilation and runtime") { bool print_filenames = OS::get_singleton()->get_cmdline_args().find("--print-filenames") != nullptr; @@ -68,6 +70,7 @@ func _init(): ref_counted->set_script(gdscript); CHECK_MESSAGE(int(ref_counted->get_meta("result")) == 42, "The script should assign object metadata successfully."); } +#endif // TOOLS_ENABLED TEST_CASE("[Modules][GDScript] Validate built-in API") { GDScriptLanguage *lang = GDScriptLanguage::get_singleton(); diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index 653a394ebb..1c82430abf 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -39,7 +39,7 @@ </method> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)" keywords="colour"> The [Color] of the light. Defaults to white. A black color causes the light to have no effect. </member> <member name="inner_cone_angle" type="float" setter="set_inner_cone_angle" getter="get_inner_cone_angle" default="0.0"> diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index da11cd216f..7aeecef980 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GridMap" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> +<class name="GridMap" inherits="Node3D" keywords="tilemap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Node for 3D tile-based maps. </brief_description> diff --git a/modules/ktx/SCsub b/modules/ktx/SCsub index b160f7a287..acdb829979 100644 --- a/modules/ktx/SCsub +++ b/modules/ktx/SCsub @@ -16,10 +16,12 @@ thirdparty_sources = [ "lib/filestream.c", "lib/hashlist.c", "lib/memstream.c", + "lib/miniz_wrapper.cpp", "lib/swap.c", "lib/texture.c", "lib/texture1.c", "lib/texture2.c", + "lib/vkformat_check.c", "lib/dfdutils/createdfd.c", "lib/dfdutils/colourspaces.c", "lib/dfdutils/interpretdfd.c", @@ -33,7 +35,11 @@ env_ktx.Prepend(CPPPATH=[thirdparty_dir + "include"]) env_ktx.Prepend(CPPPATH=[thirdparty_dir + "utils"]) env_ktx.Prepend(CPPPATH=[thirdparty_dir + "lib"]) env_ktx.Prepend(CPPPATH=[thirdparty_dir + "other_include"]) + env_ktx.Prepend(CPPPATH=["#thirdparty/basis_universal"]) +if env.editor_build: + # We already build miniz in the basis_universal module (editor only). + env_ktx.Append(CPPDEFINES=["MINIZ_HEADER_FILE_ONLY"]) if env["vulkan"]: env_ktx.Prepend(CPPPATH=["#thirdparty/vulkan/include"]) diff --git a/modules/multiplayer/doc_classes/MultiplayerSpawner.xml b/modules/multiplayer/doc_classes/MultiplayerSpawner.xml index 482db3e8b5..3da245f806 100644 --- a/modules/multiplayer/doc_classes/MultiplayerSpawner.xml +++ b/modules/multiplayer/doc_classes/MultiplayerSpawner.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerSpawner" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> +<class name="MultiplayerSpawner" inherits="Node" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Automatically replicates spawnable nodes from the authority to other multiplayer peers. </brief_description> diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml index df2644767d..c2d879962c 100644 --- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml +++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerSynchronizer" inherits="Node" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> +<class name="MultiplayerSynchronizer" inherits="Node" keywords="network" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Synchronizes properties from the multiplayer authority to the remote peers. </brief_description> diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 14c72f3db4..a3b23da6b6 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -121,13 +121,13 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) { if (p_active) { if (!map_is_active(p_map)) { active_maps.push_back(map); - active_maps_update_id.push_back(map->get_map_update_id()); + active_maps_iteration_id.push_back(map->get_iteration_id()); } } else { int map_index = active_maps.find(map); ERR_FAIL_COND(map_index < 0); active_maps.remove_at(map_index); - active_maps_update_id.remove_at(map_index); + active_maps_iteration_id.remove_at(map_index); } } @@ -1131,7 +1131,11 @@ void GodotNavigationServer::bake_from_source_geometry_data_async(const Ref<Navig } bool GodotNavigationServer::is_baking_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) const { +#ifdef _3D_DISABLED + return false; +#else return NavMeshGenerator3D::get_singleton()->is_baking(p_navigation_mesh); +#endif // _3D_DISABLED } COMMAND_1(free, RID, p_object) { @@ -1165,7 +1169,7 @@ COMMAND_1(free, RID, p_object) { int map_index = active_maps.find(map); if (map_index >= 0) { active_maps.remove_at(map_index); - active_maps_update_id.remove_at(map_index); + active_maps_iteration_id.remove_at(map_index); } map_owner.free(p_object); @@ -1258,6 +1262,13 @@ void GodotNavigationServer::map_force_update(RID p_map) { map->sync(); } +uint32_t GodotNavigationServer::map_get_iteration_id(RID p_map) const { + NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_NULL_V(map, 0); + + return map->get_iteration_id(); +} + void GodotNavigationServer::sync() { #ifndef _3D_DISABLED if (navmesh_generator_3d) { @@ -1300,10 +1311,10 @@ void GodotNavigationServer::process(real_t p_delta_time) { _new_pm_edge_free_count += active_maps[i]->get_pm_edge_free_count(); // Emit a signal if a map changed. - const uint32_t new_map_update_id = active_maps[i]->get_map_update_id(); - if (new_map_update_id != active_maps_update_id[i]) { + const uint32_t new_map_iteration_id = active_maps[i]->get_iteration_id(); + if (new_map_iteration_id != active_maps_iteration_id[i]) { emit_signal(SNAME("map_changed"), active_maps[i]->get_self()); - active_maps_update_id[i] = new_map_update_id; + active_maps_iteration_id[i] = new_map_iteration_id; } } diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index f3bc1185d8..8af0eb1874 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -80,7 +80,7 @@ class GodotNavigationServer : public NavigationServer3D { bool active = true; LocalVector<NavMap *> active_maps; - LocalVector<uint32_t> active_maps_update_id; + LocalVector<uint32_t> active_maps_iteration_id; #ifndef _3D_DISABLED NavMeshGenerator3D *navmesh_generator_3d = nullptr; @@ -142,6 +142,7 @@ public: virtual TypedArray<RID> map_get_obstacles(RID p_map) const override; virtual void map_force_update(RID p_map) override; + virtual uint32_t map_get_iteration_id(RID p_map) const override; virtual Vector3 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override; diff --git a/modules/navigation/godot_navigation_server_2d.cpp b/modules/navigation/godot_navigation_server_2d.cpp index 5bd4a37fd7..28bcd16310 100644 --- a/modules/navigation/godot_navigation_server_2d.cpp +++ b/modules/navigation/godot_navigation_server_2d.cpp @@ -222,7 +222,11 @@ void GodotNavigationServer2D::bake_from_source_geometry_data_async(const Ref<Nav } bool GodotNavigationServer2D::is_baking_navigation_polygon(Ref<NavigationPolygon> p_navigation_polygon) const { +#ifdef CLIPPER2_ENABLED return NavMeshGenerator2D::get_singleton()->is_baking(p_navigation_polygon); +#else + return false; +#endif } GodotNavigationServer2D::GodotNavigationServer2D() {} @@ -253,6 +257,10 @@ void GodotNavigationServer2D::map_force_update(RID p_map) { NavigationServer3D::get_singleton()->map_force_update(p_map); } +uint32_t GodotNavigationServer2D::map_get_iteration_id(RID p_map) const { + return NavigationServer3D::get_singleton()->map_get_iteration_id(p_map); +} + void FORWARD_2(map_set_cell_size, RID, p_map, real_t, p_cell_size, rid_to_rid, real_to_real); real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid); diff --git a/modules/navigation/godot_navigation_server_2d.h b/modules/navigation/godot_navigation_server_2d.h index 08f1730441..225fd8f3a6 100644 --- a/modules/navigation/godot_navigation_server_2d.h +++ b/modules/navigation/godot_navigation_server_2d.h @@ -77,6 +77,7 @@ public: virtual TypedArray<RID> map_get_obstacles(RID p_map) const override; virtual void map_force_update(RID p_map) override; virtual Vector2 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override; + virtual uint32_t map_get_iteration_id(RID p_map) const override; virtual RID region_create() override; virtual void region_set_enabled(RID p_region, bool p_enabled) override; diff --git a/modules/navigation/nav_agent.cpp b/modules/navigation/nav_agent.cpp index 5a87ff6c4b..2dbe57eb4a 100644 --- a/modules/navigation/nav_agent.cpp +++ b/modules/navigation/nav_agent.cpp @@ -111,8 +111,8 @@ void NavAgent::set_map(NavMap *p_map) { bool NavAgent::is_map_changed() { if (map) { - bool is_changed = map->get_map_update_id() != map_update_id; - map_update_id = map->get_map_update_id(); + bool is_changed = map->get_iteration_id() != last_map_iteration_id; + last_map_iteration_id = map->get_iteration_id(); return is_changed; } else { return false; diff --git a/modules/navigation/nav_agent.h b/modules/navigation/nav_agent.h index 9ab6f55544..00b5bc13ab 100644 --- a/modules/navigation/nav_agent.h +++ b/modules/navigation/nav_agent.h @@ -72,7 +72,7 @@ class NavAgent : public NavRid { bool agent_dirty = true; - uint32_t map_update_id = 0; + uint32_t last_map_iteration_id = 0; bool paused = false; public: diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 9482da39ef..a3f2ee2e61 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -54,6 +54,15 @@ r_path_owners->push_back(poly->owner->get_owner_id()); \ } +#ifdef DEBUG_ENABLED +#define NAVMAP_ITERATION_ZERO_ERROR_MSG() \ + ERR_PRINT_ONCE("NavigationServer navigation map query failed because it was made before first map synchronization.\n\ + NavigationServer 'map_changed' signal can be used to receive update notifications.\n\ + NavigationServer 'map_get_iteration_id()' can be used to check if a map has finished its newest iteration."); +#else +#define NAVMAP_ITERATION_ZERO_ERROR_MSG() +#endif // DEBUG_ENABLED + void NavMap::set_up(Vector3 p_up) { if (up == p_up) { return; @@ -128,8 +137,9 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const { Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const { RWLockRead read_lock(map_rwlock); - if (map_update_id == 0) { - ERR_FAIL_V_MSG(Vector<Vector3>(), "NavigationServer map query failed because it was made before first map synchronization."); + if (iteration_id == 0) { + NAVMAP_ITERATION_ZERO_ERROR_MSG(); + return Vector<Vector3>(); } // Clear metadata outputs. @@ -592,8 +602,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { RWLockRead read_lock(map_rwlock); - if (map_update_id == 0) { - ERR_FAIL_V_MSG(Vector3(), "NavigationServer map query failed because it was made before first map synchronization."); + if (iteration_id == 0) { + NAVMAP_ITERATION_ZERO_ERROR_MSG(); + return Vector3(); } bool use_collision = p_use_collision; @@ -644,8 +655,9 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector Vector3 NavMap::get_closest_point(const Vector3 &p_point) const { RWLockRead read_lock(map_rwlock); - if (map_update_id == 0) { - ERR_FAIL_V_MSG(Vector3(), "NavigationServer map query failed because it was made before first map synchronization."); + if (iteration_id == 0) { + NAVMAP_ITERATION_ZERO_ERROR_MSG(); + return Vector3(); } gd::ClosestPointQueryResult cp = get_closest_point_info(p_point); return cp.point; @@ -653,8 +665,9 @@ Vector3 NavMap::get_closest_point(const Vector3 &p_point) const { Vector3 NavMap::get_closest_point_normal(const Vector3 &p_point) const { RWLockRead read_lock(map_rwlock); - if (map_update_id == 0) { - ERR_FAIL_V_MSG(Vector3(), "NavigationServer map query failed because it was made before first map synchronization."); + if (iteration_id == 0) { + NAVMAP_ITERATION_ZERO_ERROR_MSG(); + return Vector3(); } gd::ClosestPointQueryResult cp = get_closest_point_info(p_point); return cp.normal; @@ -662,8 +675,9 @@ Vector3 NavMap::get_closest_point_normal(const Vector3 &p_point) const { RID NavMap::get_closest_point_owner(const Vector3 &p_point) const { RWLockRead read_lock(map_rwlock); - if (map_update_id == 0) { - ERR_FAIL_V_MSG(RID(), "NavigationServer map query failed because it was made before first map synchronization."); + if (iteration_id == 0) { + NAVMAP_ITERATION_ZERO_ERROR_MSG(); + return RID(); } gd::ClosestPointQueryResult cp = get_closest_point_info(p_point); return cp.owner; @@ -1160,9 +1174,8 @@ void NavMap::sync() { } } - // Update the update ID. - // Some code treats 0 as a failure case, so we avoid returning 0. - map_update_id = map_update_id % 9999999 + 1; + // Some code treats 0 as a failure case, so we avoid returning 0 and modulo wrap UINT32_MAX manually. + iteration_id = iteration_id % UINT32_MAX + 1; } // Do we have modified obstacle positions? diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index 311a265e0c..d6215ea57f 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -108,7 +108,7 @@ class NavMap : public NavRid { real_t deltatime = 0.0; /// Change the id each time the map is updated. - uint32_t map_update_id = 0; + uint32_t iteration_id = 0; bool use_threads = true; bool avoidance_use_multiple_threads = true; @@ -128,6 +128,8 @@ public: NavMap(); ~NavMap(); + uint32_t get_iteration_id() const { return iteration_id; } + void set_up(Vector3 p_up); Vector3 get_up() const { return up; @@ -199,10 +201,6 @@ public: return obstacles; } - uint32_t get_map_update_id() const { - return map_update_id; - } - Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const; void sync(); diff --git a/modules/navigation/nav_mesh_generator_2d.cpp b/modules/navigation/nav_mesh_generator_2d.cpp index 0cb0648906..836dee8178 100644 --- a/modules/navigation/nav_mesh_generator_2d.cpp +++ b/modules/navigation/nav_mesh_generator_2d.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#ifdef CLIPPER2_ENABLED + #include "nav_mesh_generator_2d.h" #include "core/config/project_settings.h" @@ -902,3 +904,5 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation p_navigation_mesh->add_polygon(new_polygons[i]); } } + +#endif // CLIPPER2_ENABLED diff --git a/modules/navigation/nav_mesh_generator_2d.h b/modules/navigation/nav_mesh_generator_2d.h index 4ec582bd51..b606f3f6fc 100644 --- a/modules/navigation/nav_mesh_generator_2d.h +++ b/modules/navigation/nav_mesh_generator_2d.h @@ -31,6 +31,8 @@ #ifndef NAV_MESH_GENERATOR_2D_H #define NAV_MESH_GENERATOR_2D_H +#ifdef CLIPPER2_ENABLED + #include "core/object/class_db.h" #include "core/object/worker_thread_pool.h" @@ -98,4 +100,6 @@ public: ~NavMeshGenerator2D(); }; +#endif // CLIPPER2_ENABLED + #endif // NAV_MESH_GENERATOR_2D_H diff --git a/modules/navigation/nav_obstacle.cpp b/modules/navigation/nav_obstacle.cpp index 34e5f7aa85..14dfd4eae3 100644 --- a/modules/navigation/nav_obstacle.cpp +++ b/modules/navigation/nav_obstacle.cpp @@ -149,8 +149,8 @@ void NavObstacle::set_vertices(const Vector<Vector3> &p_vertices) { bool NavObstacle::is_map_changed() { if (map) { - bool is_changed = map->get_map_update_id() != map_update_id; - map_update_id = map->get_map_update_id(); + bool is_changed = map->get_iteration_id() != last_map_iteration_id; + last_map_iteration_id = map->get_iteration_id(); return is_changed; } else { return false; diff --git a/modules/navigation/nav_obstacle.h b/modules/navigation/nav_obstacle.h index eb44f63d03..e231e83836 100644 --- a/modules/navigation/nav_obstacle.h +++ b/modules/navigation/nav_obstacle.h @@ -55,7 +55,7 @@ class NavObstacle : public NavRid { bool obstacle_dirty = true; - uint32_t map_update_id = 0; + uint32_t last_map_iteration_id = 0; bool paused = false; public: diff --git a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java index ef97aaeab9..bd8c58ad69 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java @@ -1673,7 +1673,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mWantRenderNotification = true; mRequestRender = true; mRenderComplete = false; - mFinishDrawingRunnable = finishDrawing; + + // fix lost old callback when continuous call requestRenderAndNotify + // + // If continuous call requestRenderAndNotify before trigger old + // callback, old callback will lose, cause VRI will wait for SV's + // draw to finish forever not calling finishDraw. + // https://android.googlesource.com/platform/frameworks/base/+/044fce0b826f2da3a192aac56785b5089143e693%5E%21/ + //+++++++++++++++++++++++++++++++++++++++++++++++++++ + final Runnable oldCallback = mFinishDrawingRunnable; + mFinishDrawingRunnable = () -> { + if (oldCallback != null) { + oldCallback.run(); + } + if (finishDrawing != null) { + finishDrawing.run(); + } + }; + //---------------------------------------------------- sGLThreadManager.notifyAll(); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index 01ee41e30b..1f0d8592b3 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -66,11 +66,15 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory { GLUtils.checkEglError(TAG, "Before eglCreateContext", egl); EGLContext context; + int[] debug_attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; if (mUseDebugOpengl) { - int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; - context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, debug_attrib_list); + if (context == null || context == EGL10.EGL_NO_CONTEXT) { + Log.w(TAG, "creating 'OpenGL Debug' context failed"); + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + } } else { - int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); } GLUtils.checkEglError(TAG, "After eglCreateContext", egl); diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index bc052f9034..8b2542b34e 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -1360,6 +1360,7 @@ void TileMapLayer::_build_runtime_update_tile_data() { if (!forced_cleanup) { if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) { if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) { + _runtime_update_needs_all_cells_cleaned_up = true; for (KeyValue<Vector2i, CellData> &E : tile_map) { _build_runtime_update_tile_data_for_cell(E.value); } @@ -1414,14 +1415,24 @@ void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_dat } void TileMapLayer::_clear_runtime_update_tile_data() { - for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { - CellData &cell_data = *cell_data_list_element->self(); - - // Clear the runtime tile data. - if (cell_data.runtime_tile_data_cache) { - memdelete(cell_data.runtime_tile_data_cache); - cell_data.runtime_tile_data_cache = nullptr; + if (_runtime_update_needs_all_cells_cleaned_up) { + for (KeyValue<Vector2i, CellData> &E : tile_map) { + _clear_runtime_update_tile_data_for_cell(E.value); } + _runtime_update_needs_all_cells_cleaned_up = false; + } else { + for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &r_cell_data = *cell_data_list_element->self(); + _clear_runtime_update_tile_data_for_cell(r_cell_data); + } + } +} + +void TileMapLayer::_clear_runtime_update_tile_data_for_cell(CellData &r_cell_data) { + // Clear the runtime tile data. + if (r_cell_data.runtime_tile_data_cache) { + memdelete(r_cell_data.runtime_tile_data_cache); + r_cell_data.runtime_tile_data_cache = nullptr; } } @@ -1632,7 +1643,7 @@ void TileMapLayer::_deferred_internal_update() { void TileMapLayer::_internal_update() { // Find TileData that need a runtime modification. - // This may add cells to the dirty list is a runtime modification has been notified. + // This may add cells to the dirty list if a runtime modification has been notified. _build_runtime_update_tile_data(); // Update all subsystems. diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index 6cf432bc24..ac03f3155f 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -283,7 +283,9 @@ private: bool _runtime_update_tile_data_was_cleaned_up = false; void _build_runtime_update_tile_data(); void _build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list = false); + bool _runtime_update_needs_all_cells_cleaned_up = false; void _clear_runtime_update_tile_data(); + void _clear_runtime_update_tile_data_for_cell(CellData &r_cell_data); // Per-system methods. #ifdef DEBUG_ENABLED diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index d83d55d121..35baf81e89 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -493,6 +493,23 @@ void MeshInstance3D::create_debug_tangents() { } } +bool MeshInstance3D::_property_can_revert(const StringName &p_name) const { + HashMap<StringName, int>::ConstIterator E = blend_shape_properties.find(p_name); + if (E) { + return true; + } + return false; +} + +bool MeshInstance3D::_property_get_revert(const StringName &p_name, Variant &r_property) const { + HashMap<StringName, int>::ConstIterator E = blend_shape_properties.find(p_name); + if (E) { + r_property = 0.0f; + return true; + } + return false; +} + void MeshInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshInstance3D::set_mesh); ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance3D::get_mesh); diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index 0a7ffa0bee..add6bfe15e 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -62,6 +62,9 @@ protected: void _notification(int p_what); static void _bind_methods(); + bool _property_can_revert(const StringName &p_name) const; + bool _property_get_revert(const StringName &p_name, Variant &r_property) const; + public: void set_mesh(const Ref<Mesh> &p_mesh); Ref<Mesh> get_mesh() const; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index de7948dca7..1b9a9e812d 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -1403,6 +1403,7 @@ String AnimationNodeBlendTree::get_caption() const { double AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node; node_state.connections = nodes[SceneStringNames::get_singleton()->output].connections; + ERR_FAIL_COND_V(output.is_null(), 0); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0; diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index 87ac0bf5c8..0ee47ee0fe 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -693,6 +693,9 @@ bool AnimationMixer::_update_caches() { track_value->init_value = anim->track_get_key_value(i, 0); track_value->init_value.zero(); + // Can't interpolate them, need to convert. + track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value); + // If there is a Reset Animation, it takes precedence by overwriting. if (has_reset_anim) { int rt = reset_anim->find_track(path, track_src_type); @@ -1414,7 +1417,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { bool is_value = ttype == Animation::TYPE_VALUE; bool is_discrete = is_value && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE; bool force_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS; - if (!is_discrete || force_continuous) { + if (t->is_variant_interpolatable && (!is_discrete || force_continuous)) { Variant value = is_value ? a->value_track_interpolate(i, time, is_discrete && force_continuous ? backward : false) : Variant(a->bezier_track_interpolate(i, time)); value = post_process_key_value(a, i, value, t->object_id); if (value == Variant()) { @@ -1727,7 +1730,7 @@ void AnimationMixer::_blend_apply() { case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); - if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete) { + if (!t->is_variant_interpolatable || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) { break; // Don't overwrite the value set by UPDATE_DISCRETE. } diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index 7808ec788c..5f7e6c5429 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -224,6 +224,7 @@ protected: Vector<StringName> subpath; bool use_discrete = false; bool is_using_angle = false; + bool is_variant_interpolatable = true; Variant element_size; TrackCacheValue(const TrackCacheValue &p_other) : @@ -233,6 +234,7 @@ protected: subpath(p_other.subpath), use_discrete(p_other.use_discrete), is_using_angle(p_other.is_using_angle), + is_variant_interpolatable(p_other.is_variant_interpolatable), element_size(p_other.element_size) {} TrackCacheValue() { type = Animation::TYPE_VALUE; } diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 2b7c47c869..2c2d8387f3 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -140,6 +140,7 @@ double AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_pl } Ref<AnimationNode> node = blend_tree->get_node(node_name); + ERR_FAIL_COND_V(node.is_null(), 0); real_t activity = 0.0; Vector<AnimationTree::Activity> *activity_ptr = process_state->tree->input_activity_map.getptr(node_state.base_path); @@ -153,12 +154,13 @@ double AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_pl } double AnimationNode::blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) { + ERR_FAIL_COND_V(p_node.is_null(), 0); + p_node->node_state.connections.clear(); return _blend_node(p_node, p_subpath, this, p_playback_info, p_filter, p_sync, p_test_only, nullptr); } double AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only, real_t *r_activity) { - ERR_FAIL_COND_V(!p_node.is_valid(), 0); ERR_FAIL_NULL_V(process_state, 0); int blend_count = node_state.track_weights.size(); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index c23d21775f..b7118d595f 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -52,6 +52,7 @@ constexpr int MINIMAP_PADDING = 5; constexpr int MIN_DRAG_DISTANCE_FOR_VALID_CONNECTION = 20; constexpr int MAX_CONNECTION_LINE_CURVE_TESSELATION_STAGES = 5; constexpr int GRID_MINOR_STEPS_PER_MAJOR_LINE = 10; +constexpr int GRID_MINOR_STEPS_PER_MAJOR_DOT = 5; constexpr int GRID_MIN_SNAPPING_DISTANCE = 2; constexpr int GRID_MAX_SNAPPING_DISTANCE = 100; @@ -1349,13 +1350,13 @@ void GraphEdit::_draw_grid() { } break; case GRID_PATTERN_DOTS: { Color transparent_grid_minor = theme_cache.grid_minor; - transparent_grid_minor.a *= CLAMP(2 * (zoom - 0.4), 0, 1); + transparent_grid_minor.a *= CLAMP(1.0 * (zoom - 0.4), 0, 1); for (int i = from_pos.x; i < from_pos.x + len.x; i++) { for (int j = from_pos.y; j < from_pos.y + len.y; j++) { Color color = transparent_grid_minor; - if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_LINE == 0 && ABS(j) % GRID_MINOR_STEPS_PER_MAJOR_LINE == 0) { + if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_DOT == 0 && ABS(j) % GRID_MINOR_STEPS_PER_MAJOR_DOT == 0) { color = theme_cache.grid_major; } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 0da5093ab8..fda909af79 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1808,6 +1808,11 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { return; } + String submenu_name_safe = p_submenu.replace("@", "_"); // Allow special characters for auto-generated names. + if (submenu_name_safe.validate_node_name() != submenu_name_safe) { + ERR_FAIL_MSG(vformat("Invalid node name '%s' for a submenu, the following characters are not allowed:\n%s", p_submenu, String::get_invalid_node_name_characters(true))); + } + if (!global_menu_name.is_empty()) { if (items[p_idx].submenu_bound) { PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(items[p_idx].submenu)); diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index f87bccdfe7..d20fef8164 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -627,6 +627,10 @@ void TabBar::set_tab_count(int p_count) { offset = MIN(offset, p_count - 1); max_drawn_tab = MIN(max_drawn_tab, p_count - 1); current = MIN(current, p_count - 1); + // Fix range if unable to deselect. + if (current == -1 && !_can_deselect()) { + current = 0; + } _update_cache(); _ensure_no_over_offset(); @@ -1557,10 +1561,7 @@ bool TabBar::_can_deselect() const { } void TabBar::ensure_tab_visible(int p_idx) { - if (!is_inside_tree() || !buttons_visible) { - return; - } - if (p_idx == -1 && _can_deselect()) { + if (p_idx == -1 || !is_inside_tree() || !buttons_visible) { return; } ERR_FAIL_INDEX(p_idx, tabs.size()); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 6b3b2d6260..a29311af43 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -60,7 +60,9 @@ #include "servers/display_server.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" +#ifndef _3D_DISABLED #include "servers/physics_server_3d.h" +#endif // _3D_DISABLED #include "window.h" #include <stdio.h> #include <stdlib.h> @@ -884,7 +886,9 @@ void SceneTree::set_pause(bool p_enabled) { return; } paused = p_enabled; +#ifndef _3D_DISABLED PhysicsServer3D::get_singleton()->set_active(!p_enabled); +#endif // _3D_DISABLED PhysicsServer2D::get_singleton()->set_active(!p_enabled); if (get_root()) { get_root()->_propagate_pause_notification(p_enabled); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 483c6e4c60..9c2509404c 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1194,10 +1194,7 @@ void Window::_update_viewport_size() { } } - if (old_size != size) { - old_size = size; - notification(NOTIFICATION_WM_SIZE_CHANGED); - } + notification(NOTIFICATION_WM_SIZE_CHANGED); if (embedder) { embedder->_sub_window_update(this); diff --git a/scene/main/window.h b/scene/main/window.h index 70ee744344..e37a98bd2d 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -116,7 +116,6 @@ private: mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE); mutable Size2i min_size; mutable Size2i max_size; - mutable Size2i old_size = size; mutable Vector<Vector2> mpath; mutable Mode mode = MODE_WINDOWED; mutable bool flags[FLAG_MAX] = {}; diff --git a/scene/property_list_helper.cpp b/scene/property_list_helper.cpp index 2d3179d9fd..d9a80011b0 100644 --- a/scene/property_list_helper.cpp +++ b/scene/property_list_helper.cpp @@ -111,12 +111,7 @@ bool PropertyListHelper::property_set_value(const String &p_property, const Vari bool PropertyListHelper::property_can_revert(const String &p_property) const { int index; - const Property *property = _get_property(p_property, &index); - - if (property) { - return _call_getter(property->getter, index) != property->default_value; - } - return false; + return _get_property(p_property, &index) != nullptr; } bool PropertyListHelper::property_get_revert(const String &p_property, Variant &r_value) const { diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 218ca6322a..c7c2ddbb18 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -403,6 +403,11 @@ String VisualShaderNode::get_warning(Shader::Mode p_mode, VisualShader::Type p_t return String(); } +VisualShaderNode::Category VisualShaderNode::get_category() const { + WARN_PRINT(get_caption() + " is missing a category."); + return CATEGORY_NONE; +} + bool VisualShaderNode::is_input_port_default(int p_port, Shader::Mode p_mode) const { return false; } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index d4d77e7609..09ea9a8890 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -255,6 +255,37 @@ VARIANT_ENUM_CAST(VisualShader::VaryingType) class VisualShaderNode : public Resource { GDCLASS(VisualShaderNode, Resource); +public: + enum PortType { + PORT_TYPE_SCALAR, + PORT_TYPE_SCALAR_INT, + PORT_TYPE_SCALAR_UINT, + PORT_TYPE_VECTOR_2D, + PORT_TYPE_VECTOR_3D, + PORT_TYPE_VECTOR_4D, + PORT_TYPE_BOOLEAN, + PORT_TYPE_TRANSFORM, + PORT_TYPE_SAMPLER, + PORT_TYPE_MAX, + }; + + enum Category { + CATEGORY_NONE, + CATEGORY_OUTPUT, + CATEGORY_COLOR, + CATEGORY_CONDITIONAL, + CATEGORY_INPUT, + CATEGORY_SCALAR, + CATEGORY_TEXTURES, + CATEGORY_TRANSFORM, + CATEGORY_UTILITY, + CATEGORY_VECTOR, + CATEGORY_SPECIAL, + CATEGORY_PARTICLE, + CATEGORY_MAX + }; + +private: int port_preview = -1; HashMap<int, bool> connected_input_ports; @@ -270,19 +301,6 @@ protected: static void _bind_methods(); public: - enum PortType { - PORT_TYPE_SCALAR, - PORT_TYPE_SCALAR_INT, - PORT_TYPE_SCALAR_UINT, - PORT_TYPE_VECTOR_2D, - PORT_TYPE_VECTOR_3D, - PORT_TYPE_VECTOR_4D, - PORT_TYPE_BOOLEAN, - PORT_TYPE_TRANSFORM, - PORT_TYPE_SAMPLER, - PORT_TYPE_MAX, - }; - bool is_simple_decl() const; virtual String get_caption() const = 0; @@ -348,6 +366,8 @@ public: virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const; + virtual Category get_category() const; + VisualShaderNode(); }; @@ -507,6 +527,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_INPUT; } + VisualShaderNodeInput(); }; @@ -546,6 +568,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_OUTPUT; } + VisualShaderNodeOutput(); }; @@ -589,6 +613,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; + virtual Category get_category() const override { return CATEGORY_INPUT; } + VisualShaderNodeParameter(); }; @@ -661,6 +687,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_INPUT; } + VisualShaderNodeParameterRef(); }; @@ -713,6 +741,8 @@ public: void set_description(const String &p_description); String get_description() const; + virtual Category get_category() const override { return CATEGORY_SPECIAL; } + VisualShaderNodeComment(); }; @@ -781,6 +811,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_SPECIAL; } + VisualShaderNodeGroupBase(); }; @@ -887,6 +919,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_OUTPUT; } + VisualShaderNodeVaryingSetter(); }; @@ -907,6 +941,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_INPUT; } + VisualShaderNodeVaryingGetter(); }; diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 67e2c4633d..05c8fbd16c 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -76,6 +76,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_VECTOR; } + VisualShaderNodeVectorBase(); }; @@ -101,6 +103,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override = 0; + virtual Category get_category() const override { return CATEGORY_INPUT; } + VisualShaderNodeConstant(); }; @@ -437,6 +441,8 @@ public: virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeTexture(); }; @@ -473,6 +479,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; virtual bool is_use_prop_slots() const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeCurveTexture(); }; @@ -543,6 +551,8 @@ public: virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeSample3D(); }; @@ -671,8 +681,11 @@ public: virtual bool has_output_port_preview(int p_port) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeLinearSceneDepth(); }; @@ -695,6 +708,8 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeWorldPositionFromDepth(); }; @@ -717,6 +732,8 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeScreenNormalWorldSpace(); }; @@ -765,6 +782,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_SCALAR; } + VisualShaderNodeFloatOp(); }; @@ -957,6 +976,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_COLOR; } + VisualShaderNodeColorOp(); }; @@ -1006,6 +1027,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_TRANSFORM; } + VisualShaderNodeTransformOp(); }; @@ -1050,6 +1073,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_TRANSFORM; } + VisualShaderNodeTransformVecMult(); }; @@ -1122,6 +1147,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_SCALAR; } + VisualShaderNodeFloatFunc(); }; @@ -1166,6 +1193,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_SCALAR; } + VisualShaderNodeIntFunc(); }; @@ -1208,6 +1237,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_SCALAR; } + VisualShaderNodeUIntFunc(); }; @@ -1327,6 +1358,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_COLOR; } + VisualShaderNodeColorFunc(); }; @@ -1369,6 +1402,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_TRANSFORM; } + VisualShaderNodeTransformFunc(); }; @@ -1414,6 +1449,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeUVFunc(); }; @@ -1440,6 +1477,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TEXTURES; } + VisualShaderNodeUVPolarCoord(); }; @@ -1620,6 +1659,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeDerivativeFunc(); }; @@ -1669,6 +1710,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TRANSFORM; } + VisualShaderNodeOuterProduct(); }; @@ -1714,6 +1757,14 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { + if (op_type == OP_TYPE_SCALAR) { + return CATEGORY_SCALAR; + } else { + return CATEGORY_VECTOR; + } + } + VisualShaderNodeStep(); }; @@ -1761,6 +1812,14 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { + if (op_type == OP_TYPE_SCALAR) { + return CATEGORY_SCALAR; + } else { + return CATEGORY_VECTOR; + } + } + VisualShaderNodeSmoothStep(); }; @@ -1852,6 +1911,14 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { + if (op_type == OP_TYPE_SCALAR) { + return CATEGORY_SCALAR; + } else { + return CATEGORY_VECTOR; + } + } + VisualShaderNodeMix(); }; @@ -1898,6 +1965,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TRANSFORM; } + VisualShaderNodeTransformCompose(); }; @@ -1921,6 +1990,8 @@ public: virtual void set_op_type(OpType p_op_type) override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_VECTOR; } + VisualShaderNodeVectorDecompose(); }; @@ -1942,6 +2013,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_TRANSFORM; } + VisualShaderNodeTransformDecompose(); }; @@ -2584,6 +2657,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_CONDITIONAL; } + VisualShaderNodeIf(); }; @@ -2630,6 +2705,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_CONDITIONAL; } + VisualShaderNodeSwitch(); }; @@ -2698,6 +2775,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_CONDITIONAL; } + VisualShaderNodeIs(); }; @@ -2772,6 +2851,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; + virtual Category get_category() const override { return CATEGORY_CONDITIONAL; } + VisualShaderNodeCompare(); }; @@ -2815,6 +2896,14 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { + if (op_type == OP_TYPE_SCALAR) { + return CATEGORY_SCALAR; + } else { + return CATEGORY_VECTOR; + } + } + VisualShaderNodeMultiplyAdd(); }; @@ -2862,6 +2951,8 @@ public: virtual Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeBillboard(); }; @@ -2888,6 +2979,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeDistanceFade(); }; @@ -2909,6 +3002,8 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeProximityFade(); }; @@ -2929,6 +3024,8 @@ public: virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeRandomRange(); }; @@ -2948,6 +3045,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeRemap(); }; @@ -2968,6 +3067,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_UTILITY; } + VisualShaderNodeRotationByAxis(); }; diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h index 652b5dff03..23d06d4b7c 100644 --- a/scene/resources/visual_shader_particle_nodes.h +++ b/scene/resources/visual_shader_particle_nodes.h @@ -57,6 +57,8 @@ public: virtual HashMap<StringName, String> get_editable_properties_names() const override; bool is_show_prop_names() const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleEmitter(); }; @@ -73,6 +75,8 @@ public: virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleSphereEmitter(); }; @@ -90,6 +94,8 @@ public: virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleBoxEmitter(); }; @@ -106,6 +112,8 @@ public: virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleRingEmitter(); }; @@ -158,6 +166,8 @@ public: HashMap<StringName, String> get_editable_properties_names() const override; Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleMeshEmitter(); }; @@ -187,6 +197,8 @@ public: bool is_degrees_mode() const; Vector<StringName> get_editable_properties() const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleMultiplyByAxisAngle(); }; @@ -207,6 +219,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleConeVelocity(); }; @@ -248,6 +262,8 @@ public: void set_op_type(OpType p_type); OpType get_op_type() const; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleRandomness(); }; @@ -290,6 +306,8 @@ public: void set_mode(Mode p_mode); Mode get_mode() const; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleAccelerator(); }; @@ -352,6 +370,8 @@ public: virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + virtual Category get_category() const override { return CATEGORY_PARTICLE; } + VisualShaderNodeParticleEmit(); }; diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index 32c77195f8..d87ac00e32 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -58,6 +58,7 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("map_get_obstacles", "map"), &NavigationServer2D::map_get_obstacles); ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer2D::map_force_update); + ClassDB::bind_method(D_METHOD("map_get_iteration_id", "map"), &NavigationServer2D::map_get_iteration_id); ClassDB::bind_method(D_METHOD("map_get_random_point", "map", "navigation_layers", "uniformly"), &NavigationServer2D::map_get_random_point); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index c7d97c004b..d7dc9d6526 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -102,6 +102,7 @@ public: virtual TypedArray<RID> map_get_obstacles(RID p_map) const = 0; virtual void map_force_update(RID p_map) = 0; + virtual uint32_t map_get_iteration_id(RID p_map) const = 0; virtual Vector2 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const = 0; diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h index 3ec6d11352..94c6dfd6a7 100644 --- a/servers/navigation_server_2d_dummy.h +++ b/servers/navigation_server_2d_dummy.h @@ -59,6 +59,7 @@ public: TypedArray<RID> map_get_obstacles(RID p_map) const override { return TypedArray<RID>(); } void map_force_update(RID p_map) override {} Vector2 map_get_random_point(RID p_map, uint32_t p_naviation_layers, bool p_uniformly) const override { return Vector2(); }; + uint32_t map_get_iteration_id(RID p_map) const override { return 0; } RID region_create() override { return RID(); } void region_set_enabled(RID p_region, bool p_enabled) override {} diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 7fc027284b..00db1440f6 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -65,6 +65,7 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("map_get_obstacles", "map"), &NavigationServer3D::map_get_obstacles); ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer3D::map_force_update); + ClassDB::bind_method(D_METHOD("map_get_iteration_id", "map"), &NavigationServer3D::map_get_iteration_id); ClassDB::bind_method(D_METHOD("map_get_random_point", "map", "navigation_layers", "uniformly"), &NavigationServer3D::map_get_random_point); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 552e318586..975ffdee94 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -116,6 +116,7 @@ public: virtual TypedArray<RID> map_get_obstacles(RID p_map) const = 0; virtual void map_force_update(RID p_map) = 0; + virtual uint32_t map_get_iteration_id(RID p_map) const = 0; virtual Vector3 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const = 0; diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h index d595fcde7e..9ba9b20d00 100644 --- a/servers/navigation_server_3d_dummy.h +++ b/servers/navigation_server_3d_dummy.h @@ -66,6 +66,8 @@ public: TypedArray<RID> map_get_agents(RID p_map) const override { return TypedArray<RID>(); } TypedArray<RID> map_get_obstacles(RID p_map) const override { return TypedArray<RID>(); } void map_force_update(RID p_map) override {} + uint32_t map_get_iteration_id(RID p_map) const override { return 0; } + RID region_create() override { return RID(); } void region_set_enabled(RID p_region, bool p_enabled) override {} bool region_get_enabled(RID p_region) const override { return false; } @@ -92,6 +94,7 @@ public: Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override { return Vector3(); } Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector3(); } Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector3(); } + RID link_create() override { return RID(); } void link_set_map(RID p_link, RID p_map) override {} RID link_get_map(RID p_link) const override { return RID(); } @@ -111,6 +114,7 @@ public: real_t link_get_travel_cost(RID p_link) const override { return 0; } void link_set_owner_id(RID p_link, ObjectID p_owner_id) override {} ObjectID link_get_owner_id(RID p_link) const override { return ObjectID(); } + RID agent_create() override { return RID(); } void agent_set_map(RID p_agent, RID p_map) override {} RID agent_get_map(RID p_agent) const override { return RID(); } @@ -148,6 +152,7 @@ public: uint32_t agent_get_avoidance_mask(RID p_agent) const override { return 0; } void agent_set_avoidance_priority(RID p_agent, real_t p_priority) override {} real_t agent_get_avoidance_priority(RID p_agent) const override { return 0; } + RID obstacle_create() override { return RID(); } void obstacle_set_map(RID p_obstacle, RID p_map) override {} RID obstacle_get_map(RID p_obstacle) const override { return RID(); } @@ -169,6 +174,7 @@ public: Vector<Vector3> obstacle_get_vertices(RID p_obstacle) const override { return Vector<Vector3>(); } void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override {} uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override { return 0; } + void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override {} void bake_from_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override {} void bake_from_source_geometry_data_async(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override {} @@ -180,8 +186,10 @@ public: void init() override {} void sync() override {} void finish() override {} + NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override { return NavigationUtilities::PathQueryResult(); } int get_process_info(ProcessInfo p_info) const override { return 0; } + void set_debug_enabled(bool p_enabled) {} bool get_debug_enabled() const { return false; } }; diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 150c155f1a..66843aaad8 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -60,14 +60,6 @@ #include "movie_writer/movie_writer.h" #include "movie_writer/movie_writer_mjpeg.h" #include "movie_writer/movie_writer_pngwav.h" -#include "navigation_server_2d.h" -#include "navigation_server_3d.h" -#include "physics_2d/godot_physics_server_2d.h" -#include "physics_3d/godot_physics_server_3d.h" -#include "physics_server_2d.h" -#include "physics_server_2d_wrap_mt.h" -#include "physics_server_3d.h" -#include "physics_server_3d_wrap_mt.h" #include "rendering/renderer_compositor.h" #include "rendering/renderer_rd/framebuffer_cache_rd.h" #include "rendering/renderer_rd/storage_rd/render_data_rd.h" @@ -80,8 +72,6 @@ #include "rendering/storage/render_scene_buffers.h" #include "rendering/storage/render_scene_data.h" #include "rendering_server.h" -#include "servers/extensions/physics_server_2d_extension.h" -#include "servers/extensions/physics_server_3d_extension.h" #include "servers/rendering/shader_types.h" #include "text/text_server_dummy.h" #include "text/text_server_extension.h" @@ -92,8 +82,25 @@ #include "xr/xr_positional_tracker.h" #include "xr_server.h" +// 2D physics and navigation. +#include "navigation_server_2d.h" +#include "physics_2d/godot_physics_server_2d.h" +#include "physics_server_2d.h" +#include "physics_server_2d_wrap_mt.h" +#include "servers/extensions/physics_server_2d_extension.h" + +// 3D physics and navigation (3D navigation is needed for 2D). +#include "navigation_server_3d.h" +#ifndef _3D_DISABLED +#include "physics_3d/godot_physics_server_3d.h" +#include "physics_server_3d.h" +#include "physics_server_3d_wrap_mt.h" +#include "servers/extensions/physics_server_3d_extension.h" +#endif // _3D_DISABLED + ShaderTypes *shader_types = nullptr; +#ifndef _3D_DISABLED static PhysicsServer3D *_createGodotPhysics3DCallback() { #ifdef THREADS_ENABLED bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread"); @@ -105,6 +112,7 @@ static PhysicsServer3D *_createGodotPhysics3DCallback() { return memnew(PhysicsServer3DWrapMT(physics_server_3d, using_threads)); } +#endif // _3D_DISABLED static PhysicsServer2D *_createGodotPhysics2DCallback() { #ifdef THREADS_ENABLED @@ -152,34 +160,6 @@ void register_server_types() { GDREGISTER_ABSTRACT_CLASS(RenderingServer); GDREGISTER_CLASS(AudioServer); - GDREGISTER_CLASS(PhysicsServer2DManager); - Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2DManager", PhysicsServer2DManager::get_singleton(), "PhysicsServer2DManager")); - - GDREGISTER_ABSTRACT_CLASS(PhysicsServer2D); - GDREGISTER_VIRTUAL_CLASS(PhysicsServer2DExtension); - GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2DExtension); - GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2DExtension); - - GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionRayResult, "Vector2 position;Vector2 normal;RID rid;ObjectID collider_id;Object *collider;int shape"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeRestInfo, "Vector2 point;Vector2 normal;RID rid;ObjectID collider_id;int shape;Vector2 linear_velocity"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape"); - - GDREGISTER_CLASS(PhysicsServer3DManager); - Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager")); - - GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D); - GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension); - GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension); - GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState3DExtension) - GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DRenderingServerHandler) - - GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionRayResult, "Vector3 position;Vector3 normal;RID rid;ObjectID collider_id;Object *collider;int shape;int face_index"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionShapeRestInfo, "Vector3 point;Vector3 normal;RID rid;ObjectID collider_id;int shape;Vector3 linear_velocity"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionCollision, "Vector3 position;Vector3 normal;Vector3 collider_velocity;Vector3 collider_angular_velocity;real_t depth;int local_shape;ObjectID collider_id;RID collider;int collider_shape"); - GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionResult, "Vector3 travel;Vector3 remainder;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;PhysicsServer3DExtensionMotionCollision collisions[32];int collision_count"); - GDREGISTER_ABSTRACT_CLASS(NavigationServer2D); GDREGISTER_ABSTRACT_CLASS(NavigationServer3D); GDREGISTER_CLASS(NavigationPathQueryParameters2D); @@ -285,6 +265,24 @@ void register_server_types() { GDREGISTER_CLASS(CameraFeed); + GDREGISTER_VIRTUAL_CLASS(MovieWriter); + + ServersDebugger::initialize(); + + // Physics 2D + GDREGISTER_CLASS(PhysicsServer2DManager); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2DManager", PhysicsServer2DManager::get_singleton(), "PhysicsServer2DManager")); + + GDREGISTER_ABSTRACT_CLASS(PhysicsServer2D); + GDREGISTER_VIRTUAL_CLASS(PhysicsServer2DExtension); + GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2DExtension); + GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2DExtension); + + GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionRayResult, "Vector2 position;Vector2 normal;RID rid;ObjectID collider_id;Object *collider;int shape"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeRestInfo, "Vector2 point;Vector2 normal;RID rid;ObjectID collider_id;int shape;Vector2 linear_velocity"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape"); + GDREGISTER_ABSTRACT_CLASS(PhysicsDirectBodyState2D); GDREGISTER_ABSTRACT_CLASS(PhysicsDirectSpaceState2D); GDREGISTER_CLASS(PhysicsRayQueryParameters2D); @@ -293,6 +291,28 @@ void register_server_types() { GDREGISTER_CLASS(PhysicsTestMotionParameters2D); GDREGISTER_CLASS(PhysicsTestMotionResult2D); + GLOBAL_DEF(PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"), "DEFAULT"); + + PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback)); + PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D"); + +#ifndef _3D_DISABLED + // Physics 3D + GDREGISTER_CLASS(PhysicsServer3DManager); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager")); + + GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D); + GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension); + GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension); + GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState3DExtension) + GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DRenderingServerHandler) + + GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionRayResult, "Vector3 position;Vector3 normal;RID rid;ObjectID collider_id;Object *collider;int shape;int face_index"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionShapeRestInfo, "Vector3 point;Vector3 normal;RID rid;ObjectID collider_id;int shape;Vector3 linear_velocity"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionCollision, "Vector3 position;Vector3 normal;Vector3 collider_velocity;Vector3 collider_angular_velocity;real_t depth;int local_shape;ObjectID collider_id;RID collider;int collider_shape"); + GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionResult, "Vector3 travel;Vector3 remainder;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;PhysicsServer3DExtensionMotionCollision collisions[32];int collision_count"); + GDREGISTER_ABSTRACT_CLASS(PhysicsDirectBodyState3D); GDREGISTER_ABSTRACT_CLASS(PhysicsDirectSpaceState3D); GDREGISTER_CLASS(PhysicsRayQueryParameters3D); @@ -301,21 +321,11 @@ void register_server_types() { GDREGISTER_CLASS(PhysicsTestMotionParameters3D); GDREGISTER_CLASS(PhysicsTestMotionResult3D); - GDREGISTER_VIRTUAL_CLASS(MovieWriter); - - ServersDebugger::initialize(); - - // Physics 2D - GLOBAL_DEF(PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"), "DEFAULT"); - - PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback)); - PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D"); - - // Physics 3D GLOBAL_DEF(PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"), "DEFAULT"); PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback)); PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D"); +#endif // _3D_DISABLED writer_mjpeg = memnew(MovieWriterMJPEG); MovieWriter::add_writer(writer_mjpeg); diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index 46fb0a75d6..bdd687d9f4 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -899,10 +899,9 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende int y_groups = p_ssil_buffers.buffer_height; RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1); - if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { - RD::get_singleton()->compute_list_add_barrier(compute_list); - } } + + RD::get_singleton()->compute_list_add_barrier(compute_list); } RD::get_singleton()->draw_command_end_label(); // Blur @@ -1285,9 +1284,7 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.buffer_width, p_ssao_buffers.buffer_height, 1); } - if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { - RD::get_singleton()->compute_list_add_barrier(compute_list); - } + RD::get_singleton()->compute_list_add_barrier(compute_list); } RD::get_singleton()->draw_command_end_label(); // Blur } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 3b51f5274a..2cfee25f91 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -2853,17 +2853,6 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner)); - if (_texture_make_mutable(texture, texture_id)) { - // The texture must be mutable as a layout transition will be required. - draw_graph.add_synchronization(); - } - - if (texture->draw_tracker != nullptr) { - bool depth_stencil_read = (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - draw_trackers.push_back(texture->draw_tracker); - draw_trackers_usage.push_back(depth_stencil_read ? RDG::RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ : RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ); - } - driver_uniform.ids.push_back(texture->driver_id); } } break; @@ -3185,7 +3174,7 @@ Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_scre uint32_t to_present_index = 0; while (to_present_index < frames[frame].swap_chains_to_present.size()) { if (frames[frame].swap_chains_to_present[to_present_index] == it->value) { - driver->command_queue_present(present_queue, it->value, {}); + driver->command_queue_execute_and_present(present_queue, {}, {}, {}, {}, it->value); frames[frame].swap_chains_to_present.remove_at(to_present_index); } else { to_present_index++; @@ -4717,7 +4706,6 @@ void RenderingDevice::swap_buffers() { _end_frame(); _execute_frame(true); - _present_frame(); // Advance to the next frame and begin recording again. frame = (frame + 1) % frames.size(); @@ -4890,17 +4878,21 @@ void RenderingDevice::_end_frame() { driver->end_segment(); } -void RenderingDevice::_execute_frame(bool p_signal_for_present) { - const bool frame_can_present = !frames[frame].swap_chains_to_present.is_empty(); - const VectorView<RDD::SemaphoreID> execute_draw_semaphore = p_signal_for_present && frame_can_present ? frames[frame].draw_semaphore : VectorView<RDD::SemaphoreID>(); - driver->command_queue_execute(main_queue, frames[frame].setup_command_buffer, {}, frames[frame].setup_semaphore, {}); - driver->command_queue_execute(main_queue, frames[frame].draw_command_buffer, frames[frame].setup_semaphore, execute_draw_semaphore, frames[frame].draw_fence); +void RenderingDevice::_execute_frame(bool p_present) { + const bool frame_can_present = p_present && !frames[frame].swap_chains_to_present.is_empty(); + const bool separate_present_queue = main_queue != present_queue; + const VectorView<RDD::SemaphoreID> execute_draw_semaphore = frame_can_present && separate_present_queue ? frames[frame].draw_semaphore : VectorView<RDD::SemaphoreID>(); + const VectorView<RDD::SwapChainID> execute_draw_swap_chains = frame_can_present && !separate_present_queue ? frames[frame].swap_chains_to_present : VectorView<RDD::SwapChainID>(); + driver->command_queue_execute_and_present(main_queue, {}, frames[frame].setup_command_buffer, frames[frame].setup_semaphore, {}, {}); + driver->command_queue_execute_and_present(main_queue, frames[frame].setup_semaphore, frames[frame].draw_command_buffer, execute_draw_semaphore, frames[frame].draw_fence, execute_draw_swap_chains); frames[frame].draw_fence_signaled = true; -} -void RenderingDevice::_present_frame() { - if (!frames[frame].swap_chains_to_present.is_empty()) { - driver->command_queue_present(present_queue, frames[frame].swap_chains_to_present, frames[frame].draw_semaphore); + if (frame_can_present) { + if (separate_present_queue) { + // Issue the presentation separately if the presentation queue is different from the main queue. + driver->command_queue_execute_and_present(present_queue, frames[frame].draw_semaphore, {}, {}, {}, frames[frame].swap_chains_to_present); + } + frames[frame].swap_chains_to_present.clear(); } } diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index f4b7683d6e..ce7128d564 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1291,8 +1291,7 @@ private: void _free_internal(RID p_id); void _begin_frame(); void _end_frame(); - void _execute_frame(bool p_signal_for_present); - void _present_frame(); + void _execute_frame(bool p_present); void _stall_for_previous_frames(); void _flush_and_stall_for_all_frames(); diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 753b3668bc..9706d3219a 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -408,8 +408,7 @@ public: // ----- QUEUE ----- virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) = 0; - virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) = 0; - virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) = 0; + virtual Error command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) = 0; virtual void command_queue_free(CommandQueueID p_cmd_queue) = 0; // ----- POOL ----- diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index 3e4890e866..4b85d1c2bf 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -53,8 +53,6 @@ bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) { case RESOURCE_USAGE_INDEX_BUFFER_READ: case RESOURCE_USAGE_TEXTURE_SAMPLE: case RESOURCE_USAGE_STORAGE_IMAGE_READ: - case RESOURCE_USAGE_ATTACHMENT_COLOR_READ: - case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ: return false; case RESOURCE_USAGE_TRANSFER_TO: case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE: @@ -80,11 +78,8 @@ RDD::TextureLayout RenderingDeviceGraph::_usage_to_image_layout(ResourceUsage p_ case RESOURCE_USAGE_STORAGE_IMAGE_READ: case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE: return RDD::TEXTURE_LAYOUT_GENERAL; - case RESOURCE_USAGE_ATTACHMENT_COLOR_READ: case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE: return RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ: - return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE: return RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; case RESOURCE_USAGE_NONE: @@ -123,12 +118,8 @@ RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage return RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; case RESOURCE_USAGE_INDEX_BUFFER_READ: return RDD::BARRIER_ACCESS_INDEX_READ_BIT; - case RESOURCE_USAGE_ATTACHMENT_COLOR_READ: - return RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT; case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE: return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ: - return RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE: return RDD::BarrierAccessBits(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); default: diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h index 9bb109ea0e..3bc63bb297 100644 --- a/servers/rendering/rendering_device_graph.h +++ b/servers/rendering/rendering_device_graph.h @@ -142,9 +142,7 @@ public: RESOURCE_USAGE_TEXTURE_SAMPLE, RESOURCE_USAGE_STORAGE_IMAGE_READ, RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE, - RESOURCE_USAGE_ATTACHMENT_COLOR_READ, RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE, - RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ, RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE }; diff --git a/tests/core/config/test_project_settings.h b/tests/core/config/test_project_settings.h index 9bd072f511..8fc2489f8b 100644 --- a/tests/core/config/test_project_settings.h +++ b/tests/core/config/test_project_settings.h @@ -45,6 +45,8 @@ public: namespace TestProjectSettings { +// TODO: Handle some cases failing on release builds. See: https://github.com/godotengine/godot/pull/88452 +#ifdef TOOLS_ENABLED TEST_CASE("[ProjectSettings] Get existing setting") { CHECK(ProjectSettings::get_singleton()->has_setting("application/config/name")); @@ -64,6 +66,7 @@ TEST_CASE("[ProjectSettings] Default value is ignored if setting exists") { String name = variant; CHECK_EQ(name, "GDScript Integration Test Suite"); } +#endif // TOOLS_ENABLED TEST_CASE("[ProjectSettings] Non existing setting is null") { CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting")); diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h index 945a7e1ba3..35d182f50c 100644 --- a/tests/core/io/test_image.h +++ b/tests/core/io/test_image.h @@ -88,11 +88,14 @@ TEST_CASE("[Image] Saving and loading") { err == OK, "The image should be saved successfully as a .png file."); + // Only available on editor builds. +#ifdef TOOLS_ENABLED // Save EXR err = image->save_exr(save_path_exr, false); CHECK_MESSAGE( err == OK, "The image should be saved successfully as an .exr file."); +#endif // TOOLS_ENABLED // Load using load() Ref<Image> image_load = memnew(Image()); diff --git a/tests/core/os/test_os.h b/tests/core/os/test_os.h index ef8216685f..1a5d360f57 100644 --- a/tests/core/os/test_os.h +++ b/tests/core/os/test_os.h @@ -93,6 +93,7 @@ TEST_CASE("[OS] Ticks") { } TEST_CASE("[OS] Feature tags") { +#ifdef TOOLS_ENABLED CHECK_MESSAGE( OS::get_singleton()->has_feature("editor"), "The binary has the \"editor\" feature tag."); @@ -105,6 +106,29 @@ TEST_CASE("[OS] Feature tags") { CHECK_MESSAGE( !OS::get_singleton()->has_feature("template_release"), "The binary does not have the \"template_release\" feature tag."); +#else + CHECK_MESSAGE( + !OS::get_singleton()->has_feature("editor"), + "The binary does not have the \"editor\" feature tag."); + CHECK_MESSAGE( + OS::get_singleton()->has_feature("template"), + "The binary has the \"template\" feature tag."); +#ifdef DEBUG_ENABLED + CHECK_MESSAGE( + OS::get_singleton()->has_feature("template_debug"), + "The binary has the \"template_debug\" feature tag."); + CHECK_MESSAGE( + !OS::get_singleton()->has_feature("template_release"), + "The binary does not have the \"template_release\" feature tag."); +#else + CHECK_MESSAGE( + !OS::get_singleton()->has_feature("template_debug"), + "The binary does not have the \"template_debug\" feature tag."); + CHECK_MESSAGE( + OS::get_singleton()->has_feature("template_release"), + "The binary has the \"template_release\" feature tag."); +#endif // DEBUG_ENABLED +#endif // TOOLS_ENABLED } TEST_CASE("[OS] Process ID") { diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 8a11491bb2..8d2607b874 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -1300,39 +1300,54 @@ TEST_CASE("[String] Capitalize against many strings") { input = "snake_case_function( snake_case_arg )"; output = "Snake Case Function( Snake Case Arg )"; CHECK(input.capitalize() == output); + + input = U"словоСлово_слово слово"; + output = U"Слово Слово Слово Слово"; + CHECK(input.capitalize() == output); + + input = U"λέξηΛέξη_λέξη λέξη"; + output = U"Λέξη Λέξη Λέξη Λέξη"; + CHECK(input.capitalize() == output); + + input = U"բառԲառ_բառ բառ"; + output = U"Բառ Բառ Բառ Բառ"; + CHECK(input.capitalize() == output); } struct StringCasesTestCase { - const char *input; - const char *camel_case; - const char *pascal_case; - const char *snake_case; + const char32_t *input; + const char32_t *camel_case; + const char32_t *pascal_case; + const char32_t *snake_case; }; TEST_CASE("[String] Checking case conversion methods") { StringCasesTestCase test_cases[] = { /* clang-format off */ - { "2D", "2d", "2d", "2d" }, - { "2d", "2d", "2d", "2d" }, - { "2db", "2Db", "2Db", "2_db" }, - { "Vector3", "vector3", "Vector3", "vector_3" }, - { "sha256", "sha256", "Sha256", "sha_256" }, - { "Node2D", "node2d", "Node2d", "node_2d" }, - { "RichTextLabel", "richTextLabel", "RichTextLabel", "rich_text_label" }, - { "HTML5", "html5", "Html5", "html_5" }, - { "Node2DPosition", "node2dPosition", "Node2dPosition", "node_2d_position" }, - { "Number2Digits", "number2Digits", "Number2Digits", "number_2_digits" }, - { "get_property_list", "getPropertyList", "GetPropertyList", "get_property_list" }, - { "get_camera_2d", "getCamera2d", "GetCamera2d", "get_camera_2d" }, - { "_physics_process", "physicsProcess", "PhysicsProcess", "_physics_process" }, - { "bytes2var", "bytes2Var", "Bytes2Var", "bytes_2_var" }, - { "linear2db", "linear2Db", "Linear2Db", "linear_2_db" }, - { "sha256sum", "sha256Sum", "Sha256Sum", "sha_256_sum" }, - { "camelCase", "camelCase", "CamelCase", "camel_case" }, - { "PascalCase", "pascalCase", "PascalCase", "pascal_case" }, - { "snake_case", "snakeCase", "SnakeCase", "snake_case" }, - { "Test TEST test", "testTestTest", "TestTestTest", "test_test_test" }, - { nullptr, nullptr, nullptr, nullptr }, + { U"2D", U"2d", U"2d", U"2d" }, + { U"2d", U"2d", U"2d", U"2d" }, + { U"2db", U"2Db", U"2Db", U"2_db" }, + { U"Vector3", U"vector3", U"Vector3", U"vector_3" }, + { U"sha256", U"sha256", U"Sha256", U"sha_256" }, + { U"Node2D", U"node2d", U"Node2d", U"node_2d" }, + { U"RichTextLabel", U"richTextLabel", U"RichTextLabel", U"rich_text_label" }, + { U"HTML5", U"html5", U"Html5", U"html_5" }, + { U"Node2DPosition", U"node2dPosition", U"Node2dPosition", U"node_2d_position" }, + { U"Number2Digits", U"number2Digits", U"Number2Digits", U"number_2_digits" }, + { U"get_property_list", U"getPropertyList", U"GetPropertyList", U"get_property_list" }, + { U"get_camera_2d", U"getCamera2d", U"GetCamera2d", U"get_camera_2d" }, + { U"_physics_process", U"physicsProcess", U"PhysicsProcess", U"_physics_process" }, + { U"bytes2var", U"bytes2Var", U"Bytes2Var", U"bytes_2_var" }, + { U"linear2db", U"linear2Db", U"Linear2Db", U"linear_2_db" }, + { U"sha256sum", U"sha256Sum", U"Sha256Sum", U"sha_256_sum" }, + { U"camelCase", U"camelCase", U"CamelCase", U"camel_case" }, + { U"PascalCase", U"pascalCase", U"PascalCase", U"pascal_case" }, + { U"snake_case", U"snakeCase", U"SnakeCase", U"snake_case" }, + { U"Test TEST test", U"testTestTest", U"TestTestTest", U"test_test_test" }, + { U"словоСлово_слово слово", U"словоСловоСловоСлово", U"СловоСловоСловоСлово", U"слово_слово_слово_слово" }, + { U"λέξηΛέξη_λέξη λέξη", U"λέξηΛέξηΛέξηΛέξη", U"ΛέξηΛέξηΛέξηΛέξη", U"λέξη_λέξη_λέξη_λέξη" }, + { U"բառԲառ_բառ բառ", U"բառԲառԲառԲառ", U"ԲառԲառԲառԲառ", U"բառ_բառ_բառ_բառ" }, + { nullptr, nullptr, nullptr, nullptr }, /* clang-format on */ }; diff --git a/tests/core/string/test_translation.h b/tests/core/string/test_translation.h index bf9674d6b1..acdd851b29 100644 --- a/tests/core/string/test_translation.h +++ b/tests/core/string/test_translation.h @@ -129,6 +129,7 @@ TEST_CASE("[TranslationPO] Plural messages") { CHECK(vformat(translation->get_plural_message("There are %d apples", "", 2), 2) == "Il y a 2 pommes"); } +#ifdef TOOLS_ENABLED TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages") { Ref<Translation> translation = memnew(Translation); translation->set_locale("fr"); @@ -150,7 +151,6 @@ TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages") CHECK(messages.size() == 0); } -#ifdef TOOLS_ENABLED TEST_CASE("[TranslationCSV] CSV import") { Ref<ResourceImporterCSVTranslation> import_csv_translation = memnew(ResourceImporterCSVTranslation); diff --git a/tests/test_main.cpp b/tests/test_main.cpp index bac5c3dd7c..47c8e9732d 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -144,7 +144,9 @@ #include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" +#ifndef _3D_DISABLED #include "servers/physics_server_3d.h" +#endif // _3D_DISABLED #include "servers/rendering/rendering_server_default.h" int test_main(int argc, char *argv[]) { @@ -219,7 +221,9 @@ struct GodotTestCaseListener : public doctest::IReporter { SignalWatcher *signal_watcher = nullptr; +#ifndef _3D_DISABLED PhysicsServer3D *physics_server_3d = nullptr; +#endif // _3D_DISABLED PhysicsServer2D *physics_server_2d = nullptr; NavigationServer3D *navigation_server_3d = nullptr; NavigationServer2D *navigation_server_2d = nullptr; @@ -254,8 +258,10 @@ struct GodotTestCaseListener : public doctest::IReporter { ThemeDB::get_singleton()->finalize_theme(); ThemeDB::get_singleton()->initialize_theme_noproject(); +#ifndef _3D_DISABLED physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server(); physics_server_3d->init(); +#endif // _3D_DISABLED physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server(); physics_server_2d->init(); @@ -334,11 +340,13 @@ struct GodotTestCaseListener : public doctest::IReporter { navigation_server_2d = nullptr; } +#ifndef _3D_DISABLED if (physics_server_3d) { physics_server_3d->finish(); memdelete(physics_server_3d); physics_server_3d = nullptr; } +#endif // _3D_DISABLED if (physics_server_2d) { physics_server_2d->finish(); diff --git a/thirdparty/README.md b/thirdparty/README.md index 2e99abc622..8a11cc9447 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -426,19 +426,21 @@ Files extracted from upstream source: ## libktx - Upstream: https://github.com/KhronosGroup/KTX-Software -- Version: 4.1.0 (d7255fe73cd53b856731ceb9f2c279181d0dbbca, 2023) +- Version: 4.3.1 (c0214158d551cfc779624b0f84130bcbbefef59a, 2024) - License: Apache-2.0 Files extracted from upstream source: - `LICENSE.md` - `include/*` -- `lib/dfdutils/{LICENSES/Apache-2.0.txt,KHR,*.c,*.h,*.inl}` -- `lib/{basis_sgd.h,basis_transcode.cpp,checkheader.c,filestream.*,formatsize.h,gl_format.h,hashlist.c,ktxint.h,memstream.*,swap.c,texture*,uthash.h,vk_format.h,vkformat_enum.h}` -- `utils/unused.h` +- `lib/dfdutils/LICENSE.adoc` as `LICENSE.dfdutils.adoc` (in root) +- `lib/dfdutils/LICENSES/Apache-2.0.txt` as `Apache-2.0.txt` (in root) +- `lib/dfdutils/{KHR/*,dfd.h,colourspaces.c,createdfd.c,interpretdfd.c,printdfd.c,queries.c,dfd2vk.inl,vk2dfd.*}` +- `lib/{basis_sgd.h,formatsize.h,gl_format.h,ktxint.h,uthash.h,vk_format.h,vkformat_enum.h,checkheader.c,swap.c,hashlist.c,vkformat_check.c,basis_transcode.cpp,miniz_wrapper.cpp,filestream.*,memstream.*,texture*}` - `other_include/KHR/*` +- `utils/unused.h` -Some Godot-specific changes are applied via `godot.patch`. +Some Godot-specific changes are applied via patches included in the `patches` folder. ## libogg diff --git a/thirdparty/libktx/godot.patch b/thirdparty/libktx/godot.patch deleted file mode 100644 index 8a492ee27d..0000000000 --- a/thirdparty/libktx/godot.patch +++ /dev/null @@ -1,45 +0,0 @@ ---- thirdparty/libktx/lib/gl_format.h -+++ thirdparty/libktx/lib/gl_format.h -@@ -92,7 +92,9 @@ - #include "vkformat_enum.h" - - #if defined(_WIN32) && !defined(__MINGW32__) -+#ifndef NOMINMAX - #define NOMINMAX -+#endif - #ifndef __cplusplus - #undef inline - #define inline __inline ---- thirdparty/libktx/lib/basis_transcode.cpp -+++ thirdparty/libktx/lib/basis_transcode.cpp -@@ -29,9 +29,9 @@ - #include "vkformat_enum.h" - #include "vk_format.h" - #include "basis_sgd.h" --#include "basisu/transcoder/basisu_file_headers.h" --#include "basisu/transcoder/basisu_transcoder.h" --#include "basisu/transcoder/basisu_transcoder_internal.h" -+#include "transcoder/basisu_file_headers.h" -+#include "transcoder/basisu_transcoder.h" -+#include "transcoder/basisu_transcoder_internal.h" - - #undef DECLARE_PRIVATE - #undef DECLARE_PROTECTED ---- thirdparty/libktx/lib/dfdutils/vk2dfd.inl -+++ thirdparty/libktx/lib/dfdutils/vk2dfd.inl -@@ -298,6 +298,7 @@ - case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SFLOAT); - case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SFLOAT); - case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SFLOAT); -+#if 0 - case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_UNORM); - case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SRGB); - case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SFLOAT); -@@ -328,6 +329,7 @@ - case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_UNORM); - case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SRGB); - case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SFLOAT); -+#endif - case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: { - int channels[] = {2,1,0,3}; int bits[] = {4,4,4,4}; - return createDFDPacked(0, 4, bits, channels, s_UNORM); diff --git a/thirdparty/libktx/include/KHR/khr_df.h b/thirdparty/libktx/include/KHR/khr_df.h index bbd0d14bd9..c0d03aa763 100644 --- a/thirdparty/libktx/include/KHR/khr_df.h +++ b/thirdparty/libktx/include/KHR/khr_df.h @@ -17,6 +17,11 @@ #ifndef _KHR_DATA_FORMAT_H_ #define _KHR_DATA_FORMAT_H_ +/** @file khr_df.h + + @brief Data Format enums and macros. +*/ + /* Accessors */ typedef enum _khr_word_e { KHR_DF_WORD_VENDORID = 0U, @@ -217,41 +222,42 @@ typedef enum _khr_df_versionnumber_e { KHR_DF_VERSIONNUMBER_MAX = 0xFFFFU } khr_df_versionnumber_e; -/* Model in which the color coordinate space is defined. +/** @~English + @brief Model in which the color coordinate space is defined. There is no requirement that a color format use all the channel types that are defined in the color model. */ typedef enum _khr_df_model_e { - /* No interpretation of color channels defined */ + /** No interpretation of color channels defined */ KHR_DF_MODEL_UNSPECIFIED = 0U, - /* Color primaries (red, green, blue) + alpha, depth and stencil */ + /** Color primaries (red, green, blue) + alpha, depth and stencil */ KHR_DF_MODEL_RGBSDA = 1U, - /* Color differences (Y', Cb, Cr) + alpha, depth and stencil */ + /** Color differences (Y', Cb, Cr) + alpha, depth and stencil */ KHR_DF_MODEL_YUVSDA = 2U, - /* Color differences (Y', I, Q) + alpha, depth and stencil */ + /** Color differences (Y', I, Q) + alpha, depth and stencil */ KHR_DF_MODEL_YIQSDA = 3U, - /* Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ + /** Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ KHR_DF_MODEL_LABSDA = 4U, - /* Subtractive colors (cyan, magenta, yellow, black) + alpha */ + /** Subtractive colors (cyan, magenta, yellow, black) + alpha */ KHR_DF_MODEL_CMYKA = 5U, - /* Non-color coordinate data (X, Y, Z, W) */ + /** Non-color coordinate data (X, Y, Z, W) */ KHR_DF_MODEL_XYZW = 6U, - /* Hue, saturation, value, hue angle on color circle, plus alpha */ + /** Hue, saturation, value, hue angle on color circle, plus alpha */ KHR_DF_MODEL_HSVA_ANG = 7U, - /* Hue, saturation, lightness, hue angle on color circle, plus alpha */ + /** Hue, saturation, lightness, hue angle on color circle, plus alpha */ KHR_DF_MODEL_HSLA_ANG = 8U, - /* Hue, saturation, value, hue on color hexagon, plus alpha */ + /** Hue, saturation, value, hue on color hexagon, plus alpha */ KHR_DF_MODEL_HSVA_HEX = 9U, - /* Hue, saturation, lightness, hue on color hexagon, plus alpha */ + /** Hue, saturation, lightness, hue on color hexagon, plus alpha */ KHR_DF_MODEL_HSLA_HEX = 10U, - /* Lightweight approximate color difference (luma, orange, green) */ + /** Lightweight approximate color difference (luma, orange, green) */ KHR_DF_MODEL_YCGCOA = 11U, - /* ITU BT.2020 constant luminance YcCbcCrc */ + /** ITU BT.2020 constant luminance YcCbcCrc */ KHR_DF_MODEL_YCCBCCRC = 12U, - /* ITU BT.2100 constant intensity ICtCp */ + /** ITU BT.2100 constant intensity ICtCp */ KHR_DF_MODEL_ICTCP = 13U, - /* CIE 1931 XYZ color coordinates (X, Y, Z) */ + /** CIE 1931 XYZ color coordinates (X, Y, Z) */ KHR_DF_MODEL_CIEXYZ = 14U, - /* CIE 1931 xyY color coordinates (X, Y, Y) */ + /** CIE 1931 xyY color coordinates (X, Y, Y) */ KHR_DF_MODEL_CIEXYY = 15U, /* Compressed formats start at 128. */ @@ -260,51 +266,54 @@ typedef enum _khr_df_model_e { channels are used to distinguish formats, these should be cosited. */ /* Direct3D (and S3) compressed formats */ /* Note that premultiplied status is recorded separately */ - /* DXT1 "channels" are RGB (0), Alpha (1) */ - /* DXT1/BC1 with one channel is opaque */ - /* DXT1/BC1 with a cosited alpha sample is transparent */ + /** DXT1 "channels" are RGB (0), Alpha (1) + DXT1/BC1 with one channel is opaque + DXT1/BC1 with a cosited alpha sample is transparent */ KHR_DF_MODEL_DXT1A = 128U, KHR_DF_MODEL_BC1A = 128U, - /* DXT2/DXT3/BC2, with explicit 4-bit alpha */ + /** DXT2/DXT3/BC2, with explicit 4-bit alpha */ KHR_DF_MODEL_DXT2 = 129U, KHR_DF_MODEL_DXT3 = 129U, KHR_DF_MODEL_BC2 = 129U, - /* DXT4/DXT5/BC3, with interpolated alpha */ + /** DXT4/DXT5/BC3, with interpolated alpha */ KHR_DF_MODEL_DXT4 = 130U, KHR_DF_MODEL_DXT5 = 130U, KHR_DF_MODEL_BC3 = 130U, - /* BC4 - single channel interpolated 8-bit data */ - /* (The UNORM/SNORM variation is recorded in the channel data) */ + /** BC4 - single channel interpolated 8-bit data + (The UNORM/SNORM variation is recorded in the channel data) */ KHR_DF_MODEL_BC4 = 131U, - /* BC5 - two channel interpolated 8-bit data */ - /* (The UNORM/SNORM variation is recorded in the channel data) */ + /** BC5 - two channel interpolated 8-bit data + (The UNORM/SNORM variation is recorded in the channel data) */ KHR_DF_MODEL_BC5 = 132U, - /* BC6H - DX11 format for 16-bit float channels */ + /** BC6H - DX11 format for 16-bit float channels */ KHR_DF_MODEL_BC6H = 133U, - /* BC7 - DX11 format */ + /** BC7 - DX11 format */ KHR_DF_MODEL_BC7 = 134U, /* Gap left for future desktop expansion */ /* Mobile compressed formats follow */ - /* A format of ETC1 indicates that the format shall be decodable - by an ETC1-compliant decoder and not rely on ETC2 features */ + /** A format of ETC1 indicates that the format shall be decodable + by an ETC1-compliant decoder and not rely on ETC2 features */ KHR_DF_MODEL_ETC1 = 160U, - /* A format of ETC2 is permitted to use ETC2 encodings on top of - the baseline ETC1 specification */ - /* The ETC2 format has channels "red", "green", "RGB" and "alpha", - which should be cosited samples */ - /* Punch-through alpha can be distinguished from full alpha by - the plane size in bytes required for the texel block */ + /** A format of ETC2 is permitted to use ETC2 encodings on top of + the baseline ETC1 specification. + The ETC2 format has channels "red", "green", "RGB" and "alpha", + which should be cosited samples. + Punch-through alpha can be distinguished from full alpha by + the plane size in bytes required for the texel block */ KHR_DF_MODEL_ETC2 = 161U, - /* Adaptive Scalable Texture Compression */ - /* ASTC HDR vs LDR is determined by the float flag in the channel */ - /* ASTC block size can be distinguished by texel block size */ + /** Adaptive Scalable Texture Compression */ + /** ASTC HDR vs LDR is determined by the float flag in the channel */ + /** ASTC block size can be distinguished by texel block size */ KHR_DF_MODEL_ASTC = 162U, - /* ETC1S is a simplified subset of ETC1 */ + /** ETC1S is a simplified subset of ETC1 */ KHR_DF_MODEL_ETC1S = 163U, - /* PowerVR Texture Compression */ + /** PowerVR Texture Compression v1 */ KHR_DF_MODEL_PVRTC = 164U, + /** PowerVR Texture Compression v2 */ KHR_DF_MODEL_PVRTC2 = 165U, + /** UASTC is a transcodable subset of ASTC + with additions to support the transcoding. */ KHR_DF_MODEL_UASTC = 166U, /* Proprietary formats (ATITC, etc.) should follow */ KHR_DF_MODEL_MAX = 0xFFU @@ -520,86 +529,88 @@ typedef enum _khr_df_model_channels_e { KHR_DF_CHANNEL_COMMON_A = 15U } khr_df_model_channels_e; -/* Definition of the primary colors in color coordinates. +/** @~English + @brief Definition of the primary colors in color coordinates. This is implicitly responsible for defining the conversion between RGB an YUV color spaces. LAB and related absolute color models should use KHR_DF_PRIMARIES_CIEXYZ. */ typedef enum _khr_df_primaries_e { - /* No color primaries defined */ + /** No color primaries defined */ KHR_DF_PRIMARIES_UNSPECIFIED = 0U, - /* Color primaries of ITU-R BT.709 and sRGB */ + /** Color primaries of ITU-R BT.709 and sRGB */ KHR_DF_PRIMARIES_BT709 = 1U, - /* Synonym for KHR_DF_PRIMARIES_BT709 */ + /** Synonym for KHR_DF_PRIMARIES_BT709 */ KHR_DF_PRIMARIES_SRGB = 1U, - /* Color primaries of ITU-R BT.601 (625-line EBU variant) */ + /** Color primaries of ITU-R BT.601 (625-line EBU variant) */ KHR_DF_PRIMARIES_BT601_EBU = 2U, - /* Color primaries of ITU-R BT.601 (525-line SMPTE C variant) */ + /** Color primaries of ITU-R BT.601 (525-line SMPTE C variant) */ KHR_DF_PRIMARIES_BT601_SMPTE = 3U, - /* Color primaries of ITU-R BT.2020 */ + /** Color primaries of ITU-R BT.2020 */ KHR_DF_PRIMARIES_BT2020 = 4U, - /* CIE theoretical color coordinate space */ + /** CIE theoretical color coordinate space */ KHR_DF_PRIMARIES_CIEXYZ = 5U, - /* Academy Color Encoding System primaries */ + /** Academy Color Encoding System primaries */ KHR_DF_PRIMARIES_ACES = 6U, - /* Color primaries of ACEScc */ + /** Color primaries of ACEScc */ KHR_DF_PRIMARIES_ACESCC = 7U, - /* Legacy NTSC 1953 primaries */ + /** Legacy NTSC 1953 primaries */ KHR_DF_PRIMARIES_NTSC1953 = 8U, - /* Legacy PAL 525-line primaries */ + /** Legacy PAL 525-line primaries */ KHR_DF_PRIMARIES_PAL525 = 9U, - /* Color primaries of Display P3 */ + /** Color primaries of Display P3 */ KHR_DF_PRIMARIES_DISPLAYP3 = 10U, - /* Color primaries of Adobe RGB (1998) */ + /** Color primaries of Adobe RGB (1998) */ KHR_DF_PRIMARIES_ADOBERGB = 11U, KHR_DF_PRIMARIES_MAX = 0xFFU } khr_df_primaries_e; -/* Definition of the optical to digital transfer function +/** @~English + @brief Definition of the optical to digital transfer function ("gamma correction"). Most transfer functions are not a pure power function and also include a linear element. LAB and related absolute color representations should use KHR_DF_TRANSFER_UNSPECIFIED. */ typedef enum _khr_df_transfer_e { - /* No transfer function defined */ + /** No transfer function defined */ KHR_DF_TRANSFER_UNSPECIFIED = 0U, - /* Linear transfer function (value proportional to intensity) */ + /** Linear transfer function (value proportional to intensity) */ KHR_DF_TRANSFER_LINEAR = 1U, - /* Perceptually-linear transfer function of sRGH (~2.4) */ + /** Perceptually-linear transfer function of sRGH (~2.4) */ KHR_DF_TRANSFER_SRGB = 2U, - /* Perceptually-linear transfer function of ITU BT.601, BT.709 and BT.2020 (~1/.45) */ + /** Perceptually-linear transfer function of ITU BT.601, BT.709 and BT.2020 (~1/.45) */ KHR_DF_TRANSFER_ITU = 3U, - /* SMTPE170M (digital NTSC) defines an alias for the ITU transfer function (~1/.45) */ + /** SMTPE170M (digital NTSC) defines an alias for the ITU transfer function (~1/.45) */ KHR_DF_TRANSFER_SMTPE170M = 3U, - /* Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */ + /** Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */ KHR_DF_TRANSFER_NTSC = 4U, - /* Sony S-log used by Sony video cameras */ + /** Sony S-log used by Sony video cameras */ KHR_DF_TRANSFER_SLOG = 5U, - /* Sony S-log 2 used by Sony video cameras */ + /** Sony S-log 2 used by Sony video cameras */ KHR_DF_TRANSFER_SLOG2 = 6U, - /* ITU BT.1886 EOTF */ + /** ITU BT.1886 EOTF */ KHR_DF_TRANSFER_BT1886 = 7U, - /* ITU BT.2100 HLG OETF */ + /** ITU BT.2100 HLG OETF */ KHR_DF_TRANSFER_HLG_OETF = 8U, - /* ITU BT.2100 HLG EOTF */ + /** ITU BT.2100 HLG EOTF */ KHR_DF_TRANSFER_HLG_EOTF = 9U, - /* ITU BT.2100 PQ EOTF */ + /** ITU BT.2100 PQ EOTF */ KHR_DF_TRANSFER_PQ_EOTF = 10U, - /* ITU BT.2100 PQ OETF */ + /** ITU BT.2100 PQ OETF */ KHR_DF_TRANSFER_PQ_OETF = 11U, - /* DCI P3 transfer function */ + /** DCI P3 transfer function */ KHR_DF_TRANSFER_DCIP3 = 12U, - /* Legacy PAL OETF */ + /** Legacy PAL OETF */ KHR_DF_TRANSFER_PAL_OETF = 13U, - /* Legacy PAL 625-line EOTF */ + /** Legacy PAL 625-line EOTF */ KHR_DF_TRANSFER_PAL625_EOTF = 14U, - /* Legacy ST240 transfer function */ + /** Legacy ST240 transfer function */ KHR_DF_TRANSFER_ST240 = 15U, - /* ACEScc transfer function */ + /** ACEScc transfer function */ KHR_DF_TRANSFER_ACESCC = 16U, - /* ACEScct transfer function */ + /** ACEScct transfer function */ KHR_DF_TRANSFER_ACESCCT = 17U, - /* Adobe RGB (1998) transfer function */ + /** Adobe RGB (1998) transfer function */ KHR_DF_TRANSFER_ADOBERGB = 18U, KHR_DF_TRANSFER_MAX = 0xFFU } khr_df_transfer_e; diff --git a/thirdparty/libktx/include/ktx.h b/thirdparty/libktx/include/ktx.h index 0af87f2519..dcf5dae42a 100644 --- a/thirdparty/libktx/include/ktx.h +++ b/thirdparty/libktx/include/ktx.h @@ -25,6 +25,7 @@ * @snippet{doc} version.h API version */ +#include <limits.h> #include <stdio.h> #include <stdbool.h> #include <sys/types.h> @@ -156,6 +157,7 @@ extern "C" { * @brief Required unpack alignment */ #define KTX_GL_UNPACK_ALIGNMENT 4 +#define KTX_FACESLICE_WHOLE_LEVEL UINT_MAX #define KTX_TRUE true #define KTX_FALSE false @@ -176,15 +178,17 @@ typedef enum ktx_error_code_e { KTX_FILE_WRITE_ERROR, /*!< An error occurred while writing to the file. */ KTX_GL_ERROR, /*!< GL operations resulted in an error. */ KTX_INVALID_OPERATION, /*!< The operation is not allowed in the current state. */ - KTX_INVALID_VALUE, /*!< A parameter value was not valid */ - KTX_NOT_FOUND, /*!< Requested key was not found */ + KTX_INVALID_VALUE, /*!< A parameter value was not valid. */ + KTX_NOT_FOUND, /*!< Requested metadata key or required dynamically loaded GPU function was not found. */ KTX_OUT_OF_MEMORY, /*!< Not enough memory to complete the operation. */ KTX_TRANSCODE_FAILED, /*!< Transcoding of block compressed texture failed. */ KTX_UNKNOWN_FILE_FORMAT, /*!< The file not a KTX file */ KTX_UNSUPPORTED_TEXTURE_TYPE, /*!< The KTX file specifies an unsupported texture type. */ KTX_UNSUPPORTED_FEATURE, /*!< Feature not included in in-use library or not yet implemented. */ KTX_LIBRARY_NOT_LINKED, /*!< Library dependency (OpenGL or Vulkan) not linked into application. */ - KTX_ERROR_MAX_ENUM = KTX_LIBRARY_NOT_LINKED /*!< For safety checks. */ + KTX_DECOMPRESS_LENGTH_ERROR, /*!< Decompressed byte count does not match expected byte size */ + KTX_DECOMPRESS_CHECKSUM_ERROR, /*!< Checksum mismatch when decompressing */ + KTX_ERROR_MAX_ENUM = KTX_DECOMPRESS_CHECKSUM_ERROR /*!< For safety checks. */ } ktx_error_code_e; /** * @deprecated @@ -672,8 +676,9 @@ typedef enum ktxSupercmpScheme { KTX_SS_NONE = 0, /*!< No supercompression. */ KTX_SS_BASIS_LZ = 1, /*!< Basis LZ supercompression. */ KTX_SS_ZSTD = 2, /*!< ZStd supercompression. */ + KTX_SS_ZLIB = 3, /*!< ZLIB supercompression. */ KTX_SS_BEGIN_RANGE = KTX_SS_NONE, - KTX_SS_END_RANGE = KTX_SS_ZSTD, + KTX_SS_END_RANGE = KTX_SS_ZLIB, KTX_SS_BEGIN_VENDOR_RANGE = 0x10000, KTX_SS_END_VENDOR_RANGE = 0x1ffff, KTX_SS_BEGIN_RESERVED = 0x20000, @@ -703,15 +708,21 @@ typedef struct ktxTexture2 { struct ktxTexture2_private* _private; /*!< Private data. */ } ktxTexture2; +/** + * @brief Helper for casting ktxTexture1 and ktxTexture2 to ktxTexture. + * + * Use with caution. + */ #define ktxTexture(t) ((ktxTexture*)t) /** * @memberof ktxTexture * @~English - * @brief Structure for passing texture information to ktxTexture1_Create() and - * ktxTexture2_Create(). + * @brief Structure for passing texture information to ktxTexture1\_Create() and + * ktxTexture2\_Create(). * - * @sa ktxTexture1_Create() and ktxTexture2_Create(). + * @sa @ref ktxTexture1::ktxTexture1\_Create() "ktxTexture1_Create()" + * @sa @ref ktxTexture2::ktxTexture2\_Create() "ktxTexture2_Create()" */ typedef struct { @@ -766,9 +777,12 @@ enum ktxTextureCreateFlagBits { KTX_TEXTURE_CREATE_RAW_KVDATA_BIT = 0x02, /*!< Load the raw key-value data instead of creating a @c ktxHashList from it. */ - KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT = 0x04 + KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT = 0x04, /*!< Skip any key-value data. This overrides the RAW_KVDATA_BIT. */ + KTX_TEXTURE_CREATE_CHECK_GLTF_BASISU_BIT = 0x08 + /*!< Load texture compatible with the rules + of KHR_texture_basisu glTF extension */ }; /** * @memberof ktxTexture @@ -1053,6 +1067,9 @@ ktxTexture2_CompressBasis(ktxTexture2* This, ktx_uint32_t quality); KTX_API KTX_error_code KTX_APIENTRY ktxTexture2_DeflateZstd(ktxTexture2* This, ktx_uint32_t level); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_DeflateZLIB(ktxTexture2* This, ktx_uint32_t level); + KTX_API void KTX_APIENTRY ktxTexture2_GetComponentInfo(ktxTexture2* This, ktx_uint32_t* numComponents, ktx_uint32_t* componentByteLength); @@ -1682,6 +1699,19 @@ KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForStdioStream(FILE* stdioStream KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForNamedFile(const char* const filename); KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForMemory(const ktx_uint8_t* bytes, ktx_size_t size); +/*===========================================================* + * Utilities for printing info about a KTX2 file. * + *===========================================================*/ + +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForMemory(const ktx_uint8_t* bytes, ktx_size_t size); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForNamedFile(const char* const filename); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForStdioStream(FILE* stdioStream); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoTextForStream(ktxStream* stream); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForMemory(const ktx_uint8_t* bytes, ktx_size_t size, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForNamedFile(const char* const filename, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForStdioStream(FILE* stdioStream, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); +KTX_API KTX_error_code KTX_APIENTRY ktxPrintKTX2InfoJSONForStream(ktxStream* stream, ktx_uint32_t base_indent, ktx_uint32_t indent_width, bool minified); + #ifdef __cplusplus } #endif @@ -1709,6 +1739,9 @@ KTX_API KTX_error_code KTX_APIENTRY ktxPrintInfoForMemory(const ktx_uint8_t* byt @~English @page libktx_history Revision History +No longer updated. Kept to preserve ancient history. For more recent history see the repo log at +https://github.com/KhronosGroup/KTX-Software. See also the Release Notes in the repo. + @section v8 Version 4.0 Added: @li Support for KTX Version 2. diff --git a/thirdparty/libktx/include/ktxvulkan.h b/thirdparty/libktx/include/ktxvulkan.h index e695ee6863..2162b1fc59 100644 --- a/thirdparty/libktx/include/ktxvulkan.h +++ b/thirdparty/libktx/include/ktxvulkan.h @@ -23,8 +23,6 @@ * alternative is duplicating unattractively large parts of it. * * @author Mark Callow, Edgewise Consulting - * - * $Date$ */ #include <ktx.h> @@ -116,8 +114,9 @@ typedef struct ktxVulkanTexture VkImageLayout imageLayout; /*!< Layout of the created image. Has the same value as @p layout parameter passed to the loader. */ - VkDeviceMemory deviceMemory; /*!< The memory allocated for the image on - the Vulkan device. */ + VkDeviceMemory deviceMemory; /*!< The memory (sub)allocation for the + image on the Vulkan device. Will not be + used with suballocators.*/ VkImageViewType viewType; /*!< ViewType corresponding to @p image. Reflects the dimensionality, cubeness and arrayness of the image. */ @@ -126,15 +125,41 @@ typedef struct ktxVulkanTexture uint32_t depth; /*!< The depth of the image. */ uint32_t levelCount; /*!< The number of MIP levels in the image. */ uint32_t layerCount; /*!< The number of array layers in the image. */ + uint64_t allocationId; /*!< An id referencing suballocation(s). */ } ktxVulkanTexture; +typedef uint64_t(*ktxVulkanTexture_subAllocatorAllocMemFuncPtr)(VkMemoryAllocateInfo* allocInfo, VkMemoryRequirements* memReq, uint64_t* pageCount); +typedef VkResult(*ktxVulkanTexture_subAllocatorBindBufferFuncPtr)(VkBuffer buffer, uint64_t allocId); +typedef VkResult(*ktxVulkanTexture_subAllocatorBindImageFuncPtr)(VkImage image, uint64_t allocId); +typedef VkResult(*ktxVulkanTexture_subAllocatorMemoryMapFuncPtr)(uint64_t allocId, uint64_t pageNumber, VkDeviceSize *mapLength, void** dataPtr); +typedef void (*ktxVulkanTexture_subAllocatorMemoryUnmapFuncPtr)(uint64_t allocId, uint64_t pageNumber); +typedef void (*ktxVulkanTexture_subAllocatorFreeMemFuncPtr)(uint64_t allocId); +/** + * @class ktxVulkanTexture_subAllocatorCallbacks + * @~English + * @brief Struct that contains all callbacks necessary for suballocation. + * + * These pointers must all be provided for upload or destroy to occur using suballocator callbacks. + */ +typedef struct { + ktxVulkanTexture_subAllocatorAllocMemFuncPtr allocMemFuncPtr; /*!< Pointer to the memory procurement function. Can suballocate one or more pages. */ + ktxVulkanTexture_subAllocatorBindBufferFuncPtr bindBufferFuncPtr; /*!< Pointer to bind-buffer-to-suballocation(s) function. */ + ktxVulkanTexture_subAllocatorBindImageFuncPtr bindImageFuncPtr; /*!< Pointer to bind-image-to-suballocation(s) function. */ + ktxVulkanTexture_subAllocatorMemoryMapFuncPtr memoryMapFuncPtr; /*!< Pointer to function for mapping the memory of a specific page. */ + ktxVulkanTexture_subAllocatorMemoryUnmapFuncPtr memoryUnmapFuncPtr; /*!< Pointer to function for unmapping the memory of a specific page. */ + ktxVulkanTexture_subAllocatorFreeMemFuncPtr freeMemFuncPtr; /*!< Pointer to the free procurement function. */ +} ktxVulkanTexture_subAllocatorCallbacks; + +KTX_API ktx_error_code_e KTX_APIENTRY +ktxVulkanTexture_Destruct_WithSuballocator(ktxVulkanTexture* This, VkDevice device, + const VkAllocationCallbacks* pAllocator, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); + KTX_API void KTX_APIENTRY ktxVulkanTexture_Destruct(ktxVulkanTexture* This, VkDevice device, const VkAllocationCallbacks* pAllocator); - - /** * @class ktxVulkanDeviceInfo * @~English @@ -210,6 +235,13 @@ ktxVulkanDeviceInfo_Destruct(ktxVulkanDeviceInfo* This); KTX_API void KTX_APIENTRY ktxVulkanDeviceInfo_Destroy(ktxVulkanDeviceInfo* This); KTX_API KTX_error_code KTX_APIENTRY +ktxTexture_VkUploadEx_WithSuballocator(ktxTexture* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); +KTX_API KTX_error_code KTX_APIENTRY ktxTexture_VkUploadEx(ktxTexture* This, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture* vkTexture, VkImageTiling tiling, @@ -219,6 +251,13 @@ KTX_API KTX_error_code KTX_APIENTRY ktxTexture_VkUpload(ktxTexture* texture, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture *vkTexture); KTX_API KTX_error_code KTX_APIENTRY +ktxTexture1_VkUploadEx_WithSuballocator(ktxTexture1* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); +KTX_API KTX_error_code KTX_APIENTRY ktxTexture1_VkUploadEx(ktxTexture1* This, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture* vkTexture, VkImageTiling tiling, @@ -228,6 +267,13 @@ KTX_API KTX_error_code KTX_APIENTRY ktxTexture1_VkUpload(ktxTexture1* texture, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture *vkTexture); KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_VkUploadEx_WithSuballocator(ktxTexture2* This, ktxVulkanDeviceInfo* vdi, + ktxVulkanTexture* vkTexture, + VkImageTiling tiling, + VkImageUsageFlags usageFlags, + VkImageLayout finalLayout, + ktxVulkanTexture_subAllocatorCallbacks* subAllocatorCallbacks); +KTX_API KTX_error_code KTX_APIENTRY ktxTexture2_VkUploadEx(ktxTexture2* This, ktxVulkanDeviceInfo* vdi, ktxVulkanTexture* vkTexture, VkImageTiling tiling, diff --git a/thirdparty/libktx/lib/basis_sgd.h b/thirdparty/libktx/lib/basis_sgd.h index 6c55909652..15804e8d26 100644 --- a/thirdparty/libktx/lib/basis_sgd.h +++ b/thirdparty/libktx/lib/basis_sgd.h @@ -28,7 +28,7 @@ extern "C" { // This must be the same value as cSliceDescFlagsFrameIsIFrame so we can just // invert the bit when passing back & forth. As FrameIsIFrame is within // a C namespace it can't easily be accessed from a c header. -enum bu_image_flags__bits_e { eBUImageIsPframe = 0x02 }; +enum bu_image_flags__bits_e { ETC1S_P_FRAME = 0x02 }; typedef uint32_t buFlags; diff --git a/thirdparty/libktx/lib/basis_transcode.cpp b/thirdparty/libktx/lib/basis_transcode.cpp index 8df65bcb68..d7ecb7a0fd 100644 --- a/thirdparty/libktx/lib/basis_transcode.cpp +++ b/thirdparty/libktx/lib/basis_transcode.cpp @@ -372,6 +372,12 @@ ktxTexture2_transcodeUastc(ktxTexture2* This, This->dataSize = prototype->dataSize; prototype->pData = 0; prototype->dataSize = 0; + // Free SGD data + This->_private->_sgdByteLength = 0; + if (This->_private->_supercompressionGlobalData) { + free(This->_private->_supercompressionGlobalData); + This->_private->_supercompressionGlobalData = NULL; + } } ktxTexture2_Destroy(prototype); return result; diff --git a/thirdparty/libktx/lib/checkheader.c b/thirdparty/libktx/lib/checkheader.c index 07e5d919c8..cee47ce341 100644 --- a/thirdparty/libktx/lib/checkheader.c +++ b/thirdparty/libktx/lib/checkheader.c @@ -1,7 +1,7 @@ /* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ -/* $Id: ee6f7be4d43390de78e1815ed158012c78ddeff1 $ */ +/* $Id$ */ /* * Copyright 2010-2020 The Khronos Group Inc. @@ -27,6 +27,10 @@ #include "ktx.h" #include "ktxint.h" +#include "vkformat_enum.h" + +bool isProhibitedFormat(VkFormat format); +bool isValidFormat(VkFormat format); /** * @internal @@ -112,7 +116,7 @@ KTX_error_code ktxCheckHeader1_(KTX_header* pHeader, if (pHeader->numberOfArrayElements > 0) { /* No 3D array textures yet. */ - return KTX_UNSUPPORTED_TEXTURE_TYPE; + return KTX_UNSUPPORTED_FEATURE; } pSuppInfo->textureDimension = 3; } @@ -192,6 +196,20 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, return KTX_UNKNOWN_FILE_FORMAT; } + /* Check format */ + if (isProhibitedFormat(pHeader->vkFormat)) + { + return KTX_FILE_DATA_ERROR; + } + if (!isValidFormat(pHeader->vkFormat)) + { + return KTX_UNSUPPORTED_FEATURE; + } + if (pHeader->supercompressionScheme == KTX_SS_BASIS_LZ && pHeader->vkFormat != VK_FORMAT_UNDEFINED) + { + return KTX_FILE_DATA_ERROR; + } + /* Check texture dimensions. KTX files can store 8 types of textures: 1D, 2D, 3D, cube, and array variants of these. There is currently no extension for 3D array textures in any 3D API. */ @@ -208,7 +226,7 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, if (pHeader->layerCount > 0) { /* No 3D array textures yet. */ - return KTX_UNSUPPORTED_TEXTURE_TYPE; + return KTX_UNSUPPORTED_FEATURE; } pSuppInfo->textureDimension = 3; } @@ -228,6 +246,16 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, /* cube map needs 2D faces */ return KTX_FILE_DATA_ERROR; } + if (pHeader->pixelDepth != 0) + { + /* cube map cannot have depth */ + return KTX_FILE_DATA_ERROR; + } + if (pHeader->pixelWidth != pHeader->pixelHeight) + { + /* cube map needs square faces */ + return KTX_FILE_DATA_ERROR; + } } else if (pHeader->faceCount != 1) { @@ -246,6 +274,18 @@ KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader, pSuppInfo->generateMipmaps = 0; } + // Check supercompression + switch (pHeader->supercompressionScheme) { + case KTX_SS_NONE: + case KTX_SS_BASIS_LZ: + case KTX_SS_ZSTD: + case KTX_SS_ZLIB: + break; + default: + // Unsupported supercompression + return KTX_UNSUPPORTED_FEATURE; + } + // This test works for arrays too because height or depth will be 0. max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); if (max_dim < ((ktx_uint32_t)1 << (pHeader->levelCount - 1))) diff --git a/thirdparty/libktx/lib/dfdutils/colourspaces.c b/thirdparty/libktx/lib/dfdutils/colourspaces.c index 0d998a71aa..8e934746bf 100644 --- a/thirdparty/libktx/lib/dfdutils/colourspaces.c +++ b/thirdparty/libktx/lib/dfdutils/colourspaces.c @@ -36,7 +36,7 @@ sPrimaryMapping primaryMap[] = { * @param[in] latitude tolerance to use while matching. A suitable value might be 0.002 * but it depends on the application. */ -khr_df_primaries_e findMapping(Primaries *p, float latitude) { +khr_df_primaries_e findMapping(const Primaries *p, float latitude) { unsigned int i; for (i = 0; i < sizeof(primaryMap)/sizeof(sPrimaryMapping); ++i) { if (primaryMap[i].primaries.Rx - p->Rx <= latitude && p->Rx - primaryMap[i].primaries.Rx <= latitude && @@ -49,3 +49,23 @@ khr_df_primaries_e findMapping(Primaries *p, float latitude) { /* No match */ return KHR_DF_PRIMARIES_UNSPECIFIED; } + +/** + * @brief Get the primaries corresponding to a KDFS primaries enum. + * + * @param[in] primaries the enum identifying the KDFS primaries. + * @param[out] p pointer to a Primaries struct that will + * be filled with the primary values. + */ +bool getPrimaries(khr_df_primaries_e primaries, Primaries *p) { + unsigned int i; + for (i = 0; i < sizeof(primaryMap)/sizeof(sPrimaryMapping); ++i) { + if (primaryMap[i].dfPrimaryEnum == primaries) { + *p = primaryMap[i].primaries; + return true; + } + } + + /* No match */ + return false; +} diff --git a/thirdparty/libktx/lib/dfdutils/createdfd.c b/thirdparty/libktx/lib/dfdutils/createdfd.c index ea00d8d745..2a5af00c7e 100644 --- a/thirdparty/libktx/lib/dfdutils/createdfd.c +++ b/thirdparty/libktx/lib/dfdutils/createdfd.c @@ -15,7 +15,9 @@ * Author: Andrew Garrard */ +#include <assert.h> #include <stdlib.h> +#include <string.h> #include <KHR/khr_df.h> #include "dfd.h" @@ -228,6 +230,8 @@ uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, * @param bits[] An array of length numChannels. * Each entry is the number of bits composing the channel, in * order starting at bit 0 of the packed type. + * @param paddings[] An array of length numChannels. + * Each entry is the number of padding bits after each channel. * @param channels[] An array of length numChannels. * Each entry enumerates the channel type: 0 = red, 1 = green, * 2 = blue, 15 = alpha, in order starting at bit 0 of the @@ -239,9 +243,9 @@ uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, * @return A data format descriptor in malloc'd data. The caller is responsible * for freeing the descriptor. **/ -uint32_t *createDFDPacked(int bigEndian, int numChannels, - int bits[], int channels[], - enum VkSuffix suffix) +uint32_t *createDFDPackedPadded(int bigEndian, int numChannels, + int bits[], int paddings[], int channels[], + enum VkSuffix suffix) { uint32_t *DFD = 0; if (numChannels == 6) { @@ -287,7 +291,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, int sampleCounter; for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { beChannelStart[channelCounter] = totalBits; - totalBits += bits[channelCounter]; + totalBits += bits[channelCounter] + paddings[channelCounter]; } BEMask = (totalBits - 1) & 0x18; for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { @@ -297,7 +301,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter; numSamples++; } - bitOffset += bits[channelCounter]; + bitOffset += bits[channelCounter] + paddings[channelCounter]; } DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR); @@ -339,7 +343,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, int totalBits = 0; int bitOffset = 0; for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { - totalBits += bits[sampleCounter]; + totalBits += bits[sampleCounter] + paddings[sampleCounter]; } /* One sample per channel */ @@ -348,12 +352,98 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, writeSample(DFD, sampleCounter, channels[sampleCounter], bits[sampleCounter], bitOffset, 1, 1, suffix); - bitOffset += bits[sampleCounter]; + bitOffset += bits[sampleCounter] + paddings[sampleCounter]; } } return DFD; } +/** + * @~English + * @brief Create a Data Format Descriptor for a packed format. + * + * @param bigEndian Big-endian flag: Set to 1 for big-endian byte ordering and + * 0 for little-endian byte ordering. + * @param numChannels The number of color channels. + * @param bits[] An array of length numChannels. + * Each entry is the number of bits composing the channel, in + * order starting at bit 0 of the packed type. + * @param channels[] An array of length numChannels. + * Each entry enumerates the channel type: 0 = red, 1 = green, + * 2 = blue, 15 = alpha, in order starting at bit 0 of the + * packed type. These values match channel IDs for RGBSDA in + * the Khronos Data Format header. To simplify iteration + * through channels, channel id 3 is a synonym for alpha. + * @param suffix Indicates the format suffix for the type. + * + * @return A data format descriptor in malloc'd data. The caller is responsible + * for freeing the descriptor. + **/ +uint32_t *createDFDPacked(int bigEndian, int numChannels, + int bits[], int channels[], + enum VkSuffix suffix) { + assert(numChannels <= 6); + int paddings[] = {0, 0, 0, 0, 0, 0}; + return createDFDPackedPadded(bigEndian, numChannels, bits, paddings, channels, suffix); +} + +uint32_t *createDFD422(int bigEndian, int numSamples, + int bits[], int paddings[], int channels[], + int position_xs[], int position_ys[], + enum VkSuffix suffix) { + assert(!bigEndian); (void) bigEndian; + assert(suffix == s_UNORM); (void) suffix; + + int totalBits = 0; + for (int i = 0; i < numSamples; ++i) + totalBits += bits[i] + paddings[i]; + assert(totalBits % 8 == 0); + + uint32_t BDFDSize = sizeof(uint32_t) * (KHR_DF_WORD_SAMPLESTART + numSamples * KHR_DF_WORD_SAMPLEWORDS); + uint32_t DFDSize = sizeof(uint32_t) + BDFDSize; + uint32_t *DFD = (uint32_t *) malloc(DFDSize); + memset(DFD, 0, DFDSize); + DFD[0] = DFDSize; + uint32_t *BDFD = DFD + 1; + KHR_DFDSETVAL(BDFD, VENDORID, KHR_DF_VENDORID_KHRONOS); + KHR_DFDSETVAL(BDFD, DESCRIPTORTYPE, KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT); + KHR_DFDSETVAL(BDFD, VERSIONNUMBER, KHR_DF_VERSIONNUMBER_LATEST); + KHR_DFDSETVAL(BDFD, DESCRIPTORBLOCKSIZE, BDFDSize); + KHR_DFDSETVAL(BDFD, MODEL, KHR_DF_MODEL_YUVSDA); + KHR_DFDSETVAL(BDFD, PRIMARIES, KHR_DF_PRIMARIES_UNSPECIFIED); + KHR_DFDSETVAL(BDFD, TRANSFER, KHR_DF_TRANSFER_LINEAR); + KHR_DFDSETVAL(BDFD, FLAGS, KHR_DF_FLAG_ALPHA_STRAIGHT); + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION0, 2 - 1); // 422 contains 2 x 1 blocks + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION1, 1 - 1); + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION2, 1 - 1); + KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION3, 1 - 1); + KHR_DFDSETVAL(BDFD, BYTESPLANE0, totalBits / 8); + KHR_DFDSETVAL(BDFD, BYTESPLANE1, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE2, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE3, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE4, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE5, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE6, 0); + KHR_DFDSETVAL(BDFD, BYTESPLANE7, 0); + + int bitOffset = 0; + for (int i = 0; i < numSamples; ++i) { + KHR_DFDSETSVAL(BDFD, i, BITOFFSET, bitOffset); + KHR_DFDSETSVAL(BDFD, i, BITLENGTH, bits[i] - 1); + KHR_DFDSETSVAL(BDFD, i, CHANNELID, channels[i]); + KHR_DFDSETSVAL(BDFD, i, QUALIFIERS, 0); // None of: FLOAT, SIGNED, EXPONENT, LINEAR + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION0, position_xs[i]); + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION1, position_ys[i]); + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION2, 0); + KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION3, 0); + KHR_DFDSETSVAL(BDFD, i, SAMPLELOWER, 0); + KHR_DFDSETSVAL(BDFD, i, SAMPLEUPPER, (1u << bits[i]) - 1u); + bitOffset += bits[i] + paddings[i]; + } + + return DFD; +} + static khr_df_model_e compModelMapping[] = { KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, no alpha. */ KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, punch-through alpha. */ @@ -657,3 +747,39 @@ uint32_t *createDFDDepthStencil(int depthBits, } return DFD; } + +/** + * @~English + * @brief Create a Data Format Descriptor for an alpha-only format. + * + * @param bigEndian Set to 1 for big-endian byte ordering and + 0 for little-endian byte ordering. + * @param bytes The number of bytes per channel. + * @param suffix Indicates the format suffix for the type. + * + * @return A data format descriptor in malloc'd data. The caller is responsible + * for freeing the descriptor. + **/ +uint32_t *createDFDAlpha(int bigEndian, int bytes, + enum VkSuffix suffix) { + uint32_t *DFD; + int channel = 3; /* alpha channel */ + if (bigEndian) { + int channelByte; + /* Number of samples = number of channels * bytes per channel */ + DFD = writeHeader(bytes, bytes, suffix, i_COLOR); + /* Loop over the bytes that constitute a channel */ + for (channelByte = 0; channelByte < bytes; ++channelByte) { + writeSample(DFD, channelByte, channel, + 8, 8 * (bytes - channelByte - 1), + channelByte == bytes-1, channelByte == 0, suffix); + } + } else { /* Little-endian */ + /* One sample per channel */ + DFD = writeHeader(1, bytes, suffix, i_COLOR); + writeSample(DFD, 0, channel, + 8 * bytes, 0, + 1, 1, suffix); + } + return DFD; +} diff --git a/thirdparty/libktx/lib/dfdutils/dfd.h b/thirdparty/libktx/lib/dfdutils/dfd.h index 3ba0249dbb..7f1fb74a6b 100644 --- a/thirdparty/libktx/lib/dfdutils/dfd.h +++ b/thirdparty/libktx/lib/dfdutils/dfd.h @@ -19,6 +19,7 @@ #define _DFD_H_ #include <KHR/khr_df.h> +#include <stdbool.h> #ifdef __cplusplus extern "C" { @@ -72,11 +73,22 @@ uint32_t* vk2dfd(enum VkFormat format); uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, int redBlueSwap, enum VkSuffix suffix); +/* Create a Data Format Descriptor for a packed padded format. */ +uint32_t *createDFDPackedPadded(int bigEndian, int numChannels, + int bits[], int paddings[], int channels[], + enum VkSuffix suffix); + /* Create a Data Format Descriptor for a packed format. */ uint32_t *createDFDPacked(int bigEndian, int numChannels, int bits[], int channels[], enum VkSuffix suffix); +/* Create a Data Format Descriptor for a 4:2:2 format. */ +uint32_t *createDFD422(int bigEndian, int numChannels, + int bits[], int paddings[], int channels[], + int position_xs[], int position_ys[], + enum VkSuffix suffix); + /* Create a Data Format Descriptor for a compressed format. */ uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth, @@ -87,16 +99,22 @@ uint32_t *createDFDDepthStencil(int depthBits, int stencilBits, int sizeBytes); +/* Create a Data Format Descriptor for an alpha-only format */ +uint32_t *createDFDAlpha(int bigEndian, int bytes, + enum VkSuffix suffix); + /** @brief Result of interpreting the data format descriptor. */ enum InterpretDFDResult { i_LITTLE_ENDIAN_FORMAT_BIT = 0, /*!< Confirmed little-endian (default for 8bpc). */ - i_BIG_ENDIAN_FORMAT_BIT = 1, /*!< Confirmed big-endian. */ - i_PACKED_FORMAT_BIT = 2, /*!< Packed format. */ - i_SRGB_FORMAT_BIT = 4, /*!< sRGB transfer function. */ - i_NORMALIZED_FORMAT_BIT = 8, /*!< Normalized (UNORM or SNORM). */ - i_SIGNED_FORMAT_BIT = 16, /*!< Format is signed. */ - i_FLOAT_FORMAT_BIT = 32, /*!< Format is floating point. */ - i_UNSUPPORTED_ERROR_BIT = 64, /*!< Format not successfully interpreted. */ + i_BIG_ENDIAN_FORMAT_BIT = 1u << 0u, /*!< Confirmed big-endian. */ + i_PACKED_FORMAT_BIT = 1u << 1u, /*!< Packed format. */ + i_SRGB_FORMAT_BIT = 1u << 2u, /*!< sRGB transfer function. */ + i_NORMALIZED_FORMAT_BIT = 1u << 3u, /*!< Normalized (UNORM or SNORM). */ + i_SIGNED_FORMAT_BIT = 1u << 4u, /*!< Format is signed. */ + i_FLOAT_FORMAT_BIT = 1u << 5u, /*!< Format is floating point. */ + i_COMPRESSED_FORMAT_BIT = 1u << 6u, /*!< Format is block compressed (422). */ + i_YUVSDA_FORMAT_BIT = 1u << 7u, /*!< Color model is YUVSDA. */ + i_UNSUPPORTED_ERROR_BIT = 1u << 8u, /*!< Format not successfully interpreted. */ /** "NONTRIVIAL_ENDIANNESS" means not big-endian, not little-endian * (a channel has bits that are not consecutive in either order). **/ i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS = i_UNSUPPORTED_ERROR_BIT, @@ -109,7 +127,9 @@ enum InterpretDFDResult { i_UNSUPPORTED_CHANNEL_TYPES = i_UNSUPPORTED_ERROR_BIT + 3, /** Only channels with the same flags are supported * (e.g. we don't support float red with integer green). */ - i_UNSUPPORTED_MIXED_CHANNELS = i_UNSUPPORTED_ERROR_BIT + 4 + i_UNSUPPORTED_MIXED_CHANNELS = i_UNSUPPORTED_ERROR_BIT + 4, + /** Only 2x1 block is supported for YUVSDA model. */ + i_UNSUPPORTED_BLOCK_DIMENSIONS = i_UNSUPPORTED_ERROR_BIT + 5, }; /** @brief Interpretation of a channel from the data format descriptor. */ @@ -126,8 +146,47 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD, InterpretedDFDChannel *A, uint32_t *wordBytes); +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringVendorID(khr_df_vendorid_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringDescriptorType(khr_df_khr_descriptortype_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringVersionNumber(khr_df_versionnumber_e value); + +/* Returns the string representation of a bit in a khr_df_flags_e. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringFlagsBit(uint32_t bit_index, bool bit_value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringTransferFunction(khr_df_transfer_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringColorPrimaries(khr_df_primaries_e value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringColorModel(khr_df_model_e value); + +/* Returns the string representation of a bit in a khr_df_sample_datatype_qualifiers_e. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringSampleDatatypeQualifiersBit(uint32_t bit_index, bool bit_value); + +/* Returns the string representation. + * If there is no direct match or the value is invalid returns NULL */ +const char* dfdToStringChannelId(khr_df_model_e model, khr_df_model_channels_e value); + /* Print a human-readable interpretation of a data format descriptor. */ -void printDFD(uint32_t *DFD); +void printDFD(uint32_t *DFD, uint32_t dataSize); + +/* Print a JSON interpretation of a data format descriptor. */ +void printDFDJSON(uint32_t *DFD, uint32_t dataSize, uint32_t base_indent, uint32_t indent_width, bool minified); /* Get the number of components & component size from a DFD for an * unpacked format. @@ -161,7 +220,8 @@ typedef struct _Primaries { float Wy; /*!< White y. */ } Primaries; -khr_df_primaries_e findMapping(Primaries *p, float latitude); +khr_df_primaries_e findMapping(const Primaries *p, float latitude); +bool getPrimaries(khr_df_primaries_e primaries, Primaries *p); #ifdef __cplusplus } diff --git a/thirdparty/libktx/lib/dfdutils/dfd2vk.inl b/thirdparty/libktx/lib/dfdutils/dfd2vk.inl index cfed9140e9..8b4de41597 100644 --- a/thirdparty/libktx/lib/dfdutils/dfd2vk.inl +++ b/thirdparty/libktx/lib/dfdutils/dfd2vk.inl @@ -51,6 +51,7 @@ if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) { } else { /* Four channels, one-bit alpha */ if (B.offset == 0) return VK_FORMAT_A1R5G5B5_UNORM_PACK16; if (B.offset == 1) return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + if (B.offset == 10) return VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR; return VK_FORMAT_B5G5R5A1_UNORM_PACK16; } } else if (wordBytes == 4) { /* PACK32 */ @@ -74,6 +75,9 @@ if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) { } } else { /* Not a packed format */ if (wordBytes == 1) { + if (A.size > 8 && R.size == 0 && G.size == 0 && B.size == 0 && (r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) { + return VK_FORMAT_A8_UNORM_KHR; + } if (A.size > 0) { /* 4 channels */ if (R.offset == 0) { /* RGBA */ if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_SRGB; diff --git a/thirdparty/libktx/lib/dfdutils/interpretdfd.c b/thirdparty/libktx/lib/dfdutils/interpretdfd.c index 273410a18c..6d25f33a1b 100644 --- a/thirdparty/libktx/lib/dfdutils/interpretdfd.c +++ b/thirdparty/libktx/lib/dfdutils/interpretdfd.c @@ -17,6 +17,14 @@ #include <KHR/khr_df.h> #include "dfd.h" +static uint32_t bit_ceil(uint32_t x) { + x -= 1; + for (uint32_t i = 0; i < sizeof(x) * 8; ++i) + if (1u << i > x) + return 1u << i; + return 0; +} + /** * @~English * @brief Interpret a Data Format Descriptor for a simple format. @@ -25,8 +33,8 @@ described as 32-bit words in native endianness. Note that this is the whole descriptor, not just the basic descriptor block. - * @param R Information about the decoded red channel, if any. - * @param G Information about the decoded green channel, if any. + * @param R Information about the decoded red channel or the depth channel, if any. + * @param G Information about the decoded green channel or the stencil channel, if any. * @param B Information about the decoded blue channel, if any. * @param A Information about the decoded alpha channel, if any. * @param wordBytes Byte size of the channels (unpacked) or total size (packed). @@ -54,14 +62,14 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD, const uint32_t *BDFDB = DFD+1; uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); + if (numSamples == 0) + return i_UNSUPPORTED_CHANNEL_TYPES; - uint32_t sampleCounter; int determinedEndianness = 0; - int determinedNormalizedness = 0; - int determinedSignedness = 0; - int determinedFloatness = 0; enum InterpretDFDResult result = 0; /* Build this up incrementally. */ + bool isDepthStencil = false; + /* Clear these so following code doesn't get confused. */ R->offset = R->size = 0; G->offset = G->size = 0; @@ -76,270 +84,322 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD, if ((BDFDB[KHR_DF_WORD_BYTESPLANE0] & ~KHR_DF_MASK_BYTESPLANE0) || BDFDB[KHR_DF_WORD_BYTESPLANE4]) return i_UNSUPPORTED_MULTIPLE_PLANES; - /* Only support the RGB color model. */ - /* We could expand this to allow "UNSPECIFIED" as well. */ - if (KHR_DFDVAL(BDFDB, MODEL) != KHR_DF_MODEL_RGBSDA) return i_UNSUPPORTED_CHANNEL_TYPES; - - /* We only pay attention to sRGB. */ - if (KHR_DFDVAL(BDFDB, TRANSFER) == KHR_DF_TRANSFER_SRGB) result |= i_SRGB_FORMAT_BIT; - - /* We only support samples at coordinate 0,0,0,0. */ - /* (We could confirm this from texel_block_dimensions in 1.2, but */ - /* the interpretation might change in later versions.) */ - for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { - if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEPOSITION_ALL)) - return i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS; - } - - /* Set flags and check for consistency. */ - for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { - /* Note: We're ignoring 9995, which is weird and worth special-casing */ - /* rather than trying to generalise to all float formats. */ - if (!determinedFloatness) { - if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) - & KHR_DF_SAMPLE_DATATYPE_FLOAT) { - result |= i_FLOAT_FORMAT_BIT; - determinedFloatness = 1; - } - } else { - /* Check whether we disagree with our predetermined floatness. */ - /* Note that this could justifiably happen with (say) D24S8. */ - if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) - & KHR_DF_SAMPLE_DATATYPE_FLOAT) { - if (!(result & i_FLOAT_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; - } else { - if ((result & i_FLOAT_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; - } - } - if (!determinedSignedness) { - if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) - & KHR_DF_SAMPLE_DATATYPE_SIGNED) { - result |= i_SIGNED_FORMAT_BIT; - determinedSignedness = 1; - } - } else { - /* Check whether we disagree with our predetermined signedness. */ - if (KHR_DFDSVAL(BDFDB, sampleCounter, QUALIFIERS) - & KHR_DF_SAMPLE_DATATYPE_SIGNED) { - if (!(result & i_SIGNED_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; - } else { - if ((result & i_SIGNED_FORMAT_BIT)) return i_UNSUPPORTED_MIXED_CHANNELS; - } - } - /* We define "unnormalized" as "sample_upper = 1". */ - /* We don't check whether any non-1 normalization value is correct */ - /* (i.e. set to the maximum bit value, and check min value) on */ - /* the assumption that we're looking at a format which *came* from */ - /* an API we can support. */ - if (!determinedNormalizedness) { - /* The ambiguity here is if the bottom bit is a single-bit value, */ - /* as in RGBA 5:5:5:1, so we defer the decision if the channel only has one bit. */ - if (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) > 0) { - if ((result & i_FLOAT_FORMAT_BIT)) { - if (*(float *)(void *)&BDFDB[KHR_DF_WORD_SAMPLESTART + - KHR_DF_WORD_SAMPLEWORDS * sampleCounter + - KHR_DF_SAMPLEWORD_SAMPLEUPPER] != 1.0f) { - result |= i_NORMALIZED_FORMAT_BIT; - } - } else { - if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEUPPER) != 1U) { - result |= i_NORMALIZED_FORMAT_BIT; - } - } - determinedNormalizedness = 1; - } - } - /* Note: We don't check for inconsistent normalization, because */ - /* channels composed of multiple samples will have 0 in the */ - /* lower/upper range. */ - /* This heuristic should handle 64-bit integers, too. */ - } - /* If this is a packed format, we work out our offsets differently. */ /* We assume a packed format has channels that aren't byte-aligned. */ /* If we have a format in which every channel is byte-aligned *and* packed, */ /* we have the RGBA/ABGR ambiguity; we *probably* don't want the packed */ /* version in this case, and if hardware has to pack it and swizzle, */ /* that's up to the hardware to special-case. */ - for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { - if (KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET) & 0x7U) { + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t offset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); + uint32_t length = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; + if ((offset & 0x7U) || ((offset + length) & 0x7U)) { result |= i_PACKED_FORMAT_BIT; /* Once we're packed, we're packed, no need to keep checking. */ break; } } - /* Remember: the canonical ordering of samples is to start with */ - /* the lowest bit of the channel/location which touches bit 0 of */ - /* the data, when the latter is concatenated in little-endian order, */ - /* and then progress until all the bits of that channel/location */ - /* have been processed. Multiple channels sharing the same source */ - /* bits are processed in channel ID order. (I should clarify this */ - /* for partially-shared data, but it doesn't really matter so long */ - /* as everything is consecutive, except to make things canonical.) */ - /* Note: For standard formats we could determine big/little-endianness */ - /* simply from whether the first sample starts in bit 0; technically */ - /* it's possible to have a format with unaligned channels wherein the */ - /* first channel starts at bit 0 and is one byte, yet other channels */ - /* take more bytes or aren't aligned (e.g. D24S8), but this should be */ - /* irrelevant for the formats that we support. */ - if ((result & i_PACKED_FORMAT_BIT)) { - /* A packed format. */ - uint32_t currentChannel = ~0U; /* Don't start matched. */ - uint32_t currentBitOffset = 0; - uint32_t currentByteOffset = 0; - uint32_t currentBitLength = 0; - *wordBytes = (BDFDB[KHR_DF_WORD_BYTESPLANE0] & 0xFFU); - for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { - uint32_t sampleBitOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); - uint32_t sampleByteOffset = sampleBitOffset >> 3U; - /* The sample bitLength field stores the bit length - 1. */ - uint32_t sampleBitLength = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; - uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); - InterpretedDFDChannel *sampleChannelPtr; - switch (sampleChannel) { - case KHR_DF_CHANNEL_RGBSDA_RED: - sampleChannelPtr = R; - break; - case KHR_DF_CHANNEL_RGBSDA_GREEN: - sampleChannelPtr = G; - break; - case KHR_DF_CHANNEL_RGBSDA_BLUE: - sampleChannelPtr = B; + // Check data types. + bool hasSigned = false; + bool hasFloat = false; + bool hasNormalized = false; + + // Note: We're ignoring 9995, which is weird and worth special-casing + // rather than trying to generalise to all float formats. + for (uint32_t i = 0; i < numSamples; ++i) { + const bool isSigned = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED) != 0; + const bool isFloat = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) != 0; + + // We define "unnormalized" as "sample_upper = 1" or "sample_upper = 1.0f". + // We don't check whether any non-1 normalization value is correct + // (i.e. set to the maximum bit value, and check min value) on + // the assumption that we're looking at a format which *came* from + // an API we can support. + const bool isNormalized = isFloat ? + *(float*) (void*) &BDFDB[KHR_DF_WORD_SAMPLESTART + + KHR_DF_WORD_SAMPLEWORDS * i + + KHR_DF_SAMPLEWORD_SAMPLEUPPER] != 1.0f : + KHR_DFDSVAL(BDFDB, i, SAMPLEUPPER) != 1U; + + hasSigned |= isSigned; + hasFloat |= isFloat; + // By our definition the normalizedness of a single bit channel (like in RGBA 5:5:5:1) + // is ambiguous. Ignore these during normalized checks. + if (KHR_DFDSVAL(BDFDB, i, BITLENGTH) > 0) + hasNormalized |= isNormalized; + } + result |= hasSigned ? i_SIGNED_FORMAT_BIT : 0; + result |= hasFloat ? i_FLOAT_FORMAT_BIT : 0; + result |= hasNormalized ? i_NORMALIZED_FORMAT_BIT : 0; + + // Checks based on color model + if (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_YUVSDA) { + result |= i_NORMALIZED_FORMAT_BIT; + result |= i_COMPRESSED_FORMAT_BIT; + result |= i_YUVSDA_FORMAT_BIT; + + for (uint32_t i = 0; i < numSamples; ++i) { + switch (KHR_DFDSVAL(BDFDB, i, CHANNELID)) { + case KHR_DF_CHANNEL_YUVSDA_Y: + case KHR_DF_CHANNEL_YUVSDA_U: + case KHR_DF_CHANNEL_YUVSDA_V: + case KHR_DF_CHANNEL_YUVSDA_A: break; - case KHR_DF_CHANNEL_RGBSDA_ALPHA: - sampleChannelPtr = A; + case KHR_DF_CHANNEL_YUVSDA_DEPTH: + case KHR_DF_CHANNEL_YUVSDA_STENCIL: + isDepthStencil = true; break; default: return i_UNSUPPORTED_CHANNEL_TYPES; } - if (sampleChannel == currentChannel) { - /* Continuation of the same channel. */ - /* Since a big (>32-bit) channel isn't "packed", */ - /* this should only happen in big-endian, or if */ - /* we have a wacky format that we won't support. */ - if (sampleByteOffset == currentByteOffset - 1U && /* One byte earlier */ - ((currentBitOffset + currentBitLength) & 7U) == 0 && /* Already at the end of a byte */ - (sampleBitOffset & 7U) == 0) { /* Start at the beginning of the byte */ - /* All is good, continue big-endian. */ - /* N.B. We shouldn't be here if we decided we were little-endian, */ - /* so we don't bother to check that disagreement. */ - result |= i_BIG_ENDIAN_FORMAT_BIT; - determinedEndianness = 1; - } else { - /* Oh dear. */ - /* We could be little-endian, but not with any standard format. */ - /* More likely we've got something weird that we can't support. */ - return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; - } - /* Remember where we are. */ - currentBitOffset = sampleBitOffset; - currentByteOffset = sampleByteOffset; - currentBitLength = sampleBitLength; - /* Accumulate the bit length. */ - sampleChannelPtr->size += sampleBitLength; - } else { - /* Everything is new. Hopefully. */ - currentChannel = sampleChannel; - currentBitOffset = sampleBitOffset; - currentByteOffset = sampleByteOffset; - currentBitLength = sampleBitLength; - if (sampleChannelPtr->size) { - /* Uh-oh, we've seen this channel before. */ - return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; - } - /* For now, record the bit offset in little-endian terms, */ - /* because we may not know to reverse it yet. */ - sampleChannelPtr->offset = sampleBitOffset; - sampleChannelPtr->size = sampleBitLength; - } } - if ((result & i_BIG_ENDIAN_FORMAT_BIT)) { - /* Our bit offsets to bit 0 of each channel are in little-endian terms. */ - /* We need to do a byte swap to work out where they should be. */ - /* We assume, for sanity, that byte sizes are a power of two for this. */ - uint32_t offsetMask = (*wordBytes - 1U) << 3U; - R->offset ^= offsetMask; - G->offset ^= offsetMask; - B->offset ^= offsetMask; - A->offset ^= offsetMask; + + // Determine wordBytes + uint32_t largestSampleSize = 0; + for (uint32_t i = 0; i < numSamples; ++i) { + uint32_t length = KHR_DFDSVAL(BDFDB, i, BITLENGTH) + 1; + if (largestSampleSize < length) + largestSampleSize = length; } - } else { - /* Not a packed format. */ - /* Everything is byte-aligned. */ - /* Question is whether there multiple samples per channel. */ - uint32_t currentChannel = ~0U; /* Don't start matched. */ - uint32_t currentByteOffset = 0; - uint32_t currentByteLength = 0; - for (sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { - uint32_t sampleByteOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET) >> 3U; - uint32_t sampleByteLength = (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1) >> 3U; - uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); - InterpretedDFDChannel *sampleChannelPtr; - switch (sampleChannel) { - case KHR_DF_CHANNEL_RGBSDA_RED: - sampleChannelPtr = R; - break; - case KHR_DF_CHANNEL_RGBSDA_GREEN: - sampleChannelPtr = G; - break; - case KHR_DF_CHANNEL_RGBSDA_BLUE: - sampleChannelPtr = B; - break; - case KHR_DF_CHANNEL_RGBSDA_ALPHA: - sampleChannelPtr = A; + *wordBytes = ((result & i_PACKED_FORMAT_BIT) ? 4 : 1) * bit_ceil(largestSampleSize) / 8; + + } else if (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_RGBSDA) { + /* We only pay attention to sRGB. */ + if (KHR_DFDVAL(BDFDB, TRANSFER) == KHR_DF_TRANSFER_SRGB) result |= i_SRGB_FORMAT_BIT; + + /* We only support samples at coordinate 0,0,0,0. */ + /* (We could confirm this from texel_block_dimensions in 1.2, but */ + /* the interpretation might change in later versions.) */ + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEPOSITION_ALL)) + return i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS; + } + + /* For Depth/Stencil formats mixed channels are allowed */ + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + switch (KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID)) { + case KHR_DF_CHANNEL_RGBSDA_DEPTH: + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + isDepthStencil = true; break; default: - return i_UNSUPPORTED_CHANNEL_TYPES; + break; } - if (sampleChannel == currentChannel) { - /* Continuation of the same channel. */ - /* Either big-endian, or little-endian with a very large channel. */ - if (sampleByteOffset == currentByteOffset - 1) { /* One byte earlier */ - if (determinedEndianness && !(result & i_BIG_ENDIAN_FORMAT_BIT)) { + } + + // Check for mixed channels + if (!isDepthStencil) { + for (uint32_t i = 0; i < numSamples; ++i) { + const bool isSigned = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED) != 0; + const bool isFloat = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) != 0; + + if (isSigned != hasSigned) + return i_UNSUPPORTED_MIXED_CHANNELS; + if (isFloat != hasFloat) + return i_UNSUPPORTED_MIXED_CHANNELS; + + // Note: We don't check for inconsistent normalization, because + // channels composed of multiple samples will have 0 in the + // lower/upper range. Single bit channels are also ambiguous. + // This heuristic should handle 64-bit integers, too. + } + } + + /* Remember: the canonical ordering of samples is to start with */ + /* the lowest bit of the channel/location which touches bit 0 of */ + /* the data, when the latter is concatenated in little-endian order, */ + /* and then progress until all the bits of that channel/location */ + /* have been processed. Multiple channels sharing the same source */ + /* bits are processed in channel ID order. (I should clarify this */ + /* for partially-shared data, but it doesn't really matter so long */ + /* as everything is consecutive, except to make things canonical.) */ + /* Note: For standard formats we could determine big/little-endianness */ + /* simply from whether the first sample starts in bit 0; technically */ + /* it's possible to have a format with unaligned channels wherein the */ + /* first channel starts at bit 0 and is one byte, yet other channels */ + /* take more bytes or aren't aligned (e.g. D24S8), but this should be */ + /* irrelevant for the formats that we support. */ + if ((result & i_PACKED_FORMAT_BIT)) { + /* A packed format. */ + uint32_t currentChannel = ~0U; /* Don't start matched. */ + uint32_t currentBitOffset = 0; + uint32_t currentByteOffset = 0; + uint32_t currentBitLength = 0; + *wordBytes = (BDFDB[KHR_DF_WORD_BYTESPLANE0] & 0xFFU); + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleBitOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); + uint32_t sampleByteOffset = sampleBitOffset >> 3U; + /* The sample bitLength field stores the bit length - 1. */ + uint32_t sampleBitLength = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; + uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); + InterpretedDFDChannel *sampleChannelPtr; + switch (sampleChannel) { + case KHR_DF_CHANNEL_RGBSDA_RED: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_GREEN: + sampleChannelPtr = G; + break; + case KHR_DF_CHANNEL_RGBSDA_BLUE: + sampleChannelPtr = B; + break; + case KHR_DF_CHANNEL_RGBSDA_DEPTH: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + sampleChannelPtr = G; + break; + case KHR_DF_CHANNEL_RGBSDA_ALPHA: + sampleChannelPtr = A; + break; + default: + return i_UNSUPPORTED_CHANNEL_TYPES; + } + if (sampleChannel == currentChannel) { + /* Continuation of the same channel. */ + /* Since a big (>32-bit) channel isn't "packed", */ + /* this should only happen in big-endian, or if */ + /* we have a wacky format that we won't support. */ + if (sampleByteOffset == currentByteOffset - 1U && /* One byte earlier */ + ((currentBitOffset + currentBitLength) & 7U) == 0 && /* Already at the end of a byte */ + (sampleBitOffset & 7U) == 0) { /* Start at the beginning of the byte */ + /* All is good, continue big-endian. */ + /* N.B. We shouldn't be here if we decided we were little-endian, */ + /* so we don't bother to check that disagreement. */ + result |= i_BIG_ENDIAN_FORMAT_BIT; + determinedEndianness = 1; + } else { + /* Oh dear. */ + /* We could be little-endian, but not with any standard format. */ + /* More likely we've got something weird that we can't support. */ return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; } - /* All is good, continue big-endian. */ - result |= i_BIG_ENDIAN_FORMAT_BIT; - determinedEndianness = 1; - /* Update the start */ - sampleChannelPtr->offset = sampleByteOffset; - } else if (sampleByteOffset == currentByteOffset + currentByteLength) { - if (determinedEndianness && (result & i_BIG_ENDIAN_FORMAT_BIT)) { + /* Remember where we are. */ + currentBitOffset = sampleBitOffset; + currentByteOffset = sampleByteOffset; + currentBitLength = sampleBitLength; + /* Accumulate the bit length. */ + sampleChannelPtr->size += sampleBitLength; + } else { + /* Everything is new. Hopefully. */ + currentChannel = sampleChannel; + currentBitOffset = sampleBitOffset; + currentByteOffset = sampleByteOffset; + currentBitLength = sampleBitLength; + if (sampleChannelPtr->size) { + /* Uh-oh, we've seen this channel before. */ return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; } - /* All is good, continue little-endian. */ - determinedEndianness = 1; - } else { - /* Oh dear. */ - /* We could be little-endian, but not with any standard format. */ - /* More likely we've got something weird that we can't support. */ - return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + /* For now, record the bit offset in little-endian terms, */ + /* because we may not know to reverse it yet. */ + sampleChannelPtr->offset = sampleBitOffset; + sampleChannelPtr->size = sampleBitLength; } - /* Remember where we are. */ - currentByteOffset = sampleByteOffset; - currentByteLength = sampleByteLength; - /* Accumulate the byte length. */ - sampleChannelPtr->size += sampleByteLength; - /* Assume these are all the same. */ - *wordBytes = sampleChannelPtr->size; - } else { - /* Everything is new. Hopefully. */ - currentChannel = sampleChannel; - currentByteOffset = sampleByteOffset; - currentByteLength = sampleByteLength; - if (sampleChannelPtr->size) { - /* Uh-oh, we've seen this channel before. */ - return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + if ((result & i_BIG_ENDIAN_FORMAT_BIT)) { + /* Our bit offsets to bit 0 of each channel are in little-endian terms. */ + /* We need to do a byte swap to work out where they should be. */ + /* We assume, for sanity, that byte sizes are a power of two for this. */ + uint32_t offsetMask = (*wordBytes - 1U) << 3U; + R->offset ^= offsetMask; + G->offset ^= offsetMask; + B->offset ^= offsetMask; + A->offset ^= offsetMask; + } + } else { + /* Not a packed format. */ + /* Everything is byte-aligned. */ + /* Question is whether there multiple samples per channel. */ + uint32_t currentChannel = ~0U; /* Don't start matched. */ + uint32_t currentByteOffset = 0; + uint32_t currentByteLength = 0; + for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { + uint32_t sampleByteOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET) >> 3U; + uint32_t sampleByteLength = (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1) >> 3U; + uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); + InterpretedDFDChannel *sampleChannelPtr; + switch (sampleChannel) { + case KHR_DF_CHANNEL_RGBSDA_RED: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_GREEN: + sampleChannelPtr = G; + break; + case KHR_DF_CHANNEL_RGBSDA_BLUE: + sampleChannelPtr = B; + break; + case KHR_DF_CHANNEL_RGBSDA_DEPTH: + sampleChannelPtr = R; + break; + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + sampleChannelPtr = G; + break; + case KHR_DF_CHANNEL_RGBSDA_ALPHA: + sampleChannelPtr = A; + break; + default: + return i_UNSUPPORTED_CHANNEL_TYPES; + } + if (sampleChannel == currentChannel) { + /* Continuation of the same channel. */ + /* Either big-endian, or little-endian with a very large channel. */ + if (sampleByteOffset == currentByteOffset - 1) { /* One byte earlier */ + if (determinedEndianness && !(result & i_BIG_ENDIAN_FORMAT_BIT)) { + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* All is good, continue big-endian. */ + result |= i_BIG_ENDIAN_FORMAT_BIT; + determinedEndianness = 1; + /* Update the start */ + sampleChannelPtr->offset = sampleByteOffset; + } else if (sampleByteOffset == currentByteOffset + currentByteLength) { + if (determinedEndianness && (result & i_BIG_ENDIAN_FORMAT_BIT)) { + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* All is good, continue little-endian. */ + determinedEndianness = 1; + } else { + /* Oh dear. */ + /* We could be little-endian, but not with any standard format. */ + /* More likely we've got something weird that we can't support. */ + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* Remember where we are. */ + currentByteOffset = sampleByteOffset; + currentByteLength = sampleByteLength; + /* Accumulate the byte length. */ + sampleChannelPtr->size += sampleByteLength; + /* Assume these are all the same. */ + *wordBytes = sampleChannelPtr->size; + } else { + /* Everything is new. Hopefully. */ + currentChannel = sampleChannel; + currentByteOffset = sampleByteOffset; + currentByteLength = sampleByteLength; + if (sampleChannelPtr->size) { + /* Uh-oh, we've seen this channel before. */ + return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; + } + /* For now, record the byte offset in little-endian terms, */ + /* because we may not know to reverse it yet. */ + sampleChannelPtr->offset = sampleByteOffset; + sampleChannelPtr->size = sampleByteLength; + /* Assume these are all the same. */ + *wordBytes = sampleByteLength; } - /* For now, record the byte offset in little-endian terms, */ - /* because we may not know to reverse it yet. */ - sampleChannelPtr->offset = sampleByteOffset; - sampleChannelPtr->size = sampleByteLength; - /* Assume these are all the same. */ - *wordBytes = sampleByteLength; } } + } else { + return i_UNSUPPORTED_CHANNEL_TYPES; + } + + if (isDepthStencil) { + /* For Depth/Stencil formats wordBytes is determined by the required alignment of */ + /* the larger channel. */ + uint32_t largerSize = R->size > G->size ? R->size : G->size; + *wordBytes = bit_ceil(largerSize); } + return result; } diff --git a/thirdparty/libktx/lib/dfdutils/printdfd.c b/thirdparty/libktx/lib/dfdutils/printdfd.c index 36d3d2c50d..bfdd33ba04 100644 --- a/thirdparty/libktx/lib/dfdutils/printdfd.c +++ b/thirdparty/libktx/lib/dfdutils/printdfd.c @@ -15,83 +15,1011 @@ * Author: Andrew Garrard */ +#include <assert.h> +#include <stdbool.h> #include <stdio.h> +#include <string.h> #include <KHR/khr_df.h> #include "dfd.h" +enum { + // These constraints are not mandated by the spec and only used as a + // reasonable upper limit to stop parsing garbage data during print + MAX_NUM_BDFD_SAMPLES = 16, + MAX_NUM_DFD_BLOCKS = 10, +}; + +const char* dfdToStringVendorID(khr_df_vendorid_e value) { + switch (value) { + case KHR_DF_VENDORID_KHRONOS: + return "KHR_DF_VENDORID_KHRONOS"; + + case KHR_DF_VENDORID_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringDescriptorType(khr_df_khr_descriptortype_e value) { + switch (value) { + case KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT: + return "KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT"; + case KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES: + return "KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES"; + case KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS: + return "KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS"; + + case KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_WRITE_BIT: + case KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_DECODE_BIT: + case KHR_DF_KHR_DESCRIPTORTYPE_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringVersionNumber(khr_df_versionnumber_e value) { + switch (value) { + case KHR_DF_VERSIONNUMBER_1_1: + // case KHR_DF_VERSIONNUMBER_1_0: // Fallthrough, Matching values + return "KHR_DF_VERSIONNUMBER_1_1"; + case KHR_DF_VERSIONNUMBER_1_2: + return "KHR_DF_VERSIONNUMBER_1_2"; + case KHR_DF_VERSIONNUMBER_1_3: + return "KHR_DF_VERSIONNUMBER_1_3"; + + // case KHR_DF_VERSIONNUMBER_LATEST: // Fallthrough, Matching values + case KHR_DF_VERSIONNUMBER_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringFlagsBit(uint32_t bit_index, bool bit_value) { + switch (bit_index) { + case 0: + return bit_value ? "KHR_DF_FLAG_ALPHA_PREMULTIPLIED" : "KHR_DF_FLAG_ALPHA_STRAIGHT"; + default: + return NULL; + } +} + +const char* dfdToStringTransferFunction(khr_df_transfer_e value) { + switch (value) { + case KHR_DF_TRANSFER_UNSPECIFIED: + return "KHR_DF_TRANSFER_UNSPECIFIED"; + case KHR_DF_TRANSFER_LINEAR: + return "KHR_DF_TRANSFER_LINEAR"; + case KHR_DF_TRANSFER_SRGB: + return "KHR_DF_TRANSFER_SRGB"; + case KHR_DF_TRANSFER_ITU: + return "KHR_DF_TRANSFER_ITU"; + case KHR_DF_TRANSFER_NTSC: + // case KHR_DF_TRANSFER_SMTPE170M: // Fallthrough, Matching values + return "KHR_DF_TRANSFER_NTSC"; + case KHR_DF_TRANSFER_SLOG: + return "KHR_DF_TRANSFER_SLOG"; + case KHR_DF_TRANSFER_SLOG2: + return "KHR_DF_TRANSFER_SLOG2"; + case KHR_DF_TRANSFER_BT1886: + return "KHR_DF_TRANSFER_BT1886"; + case KHR_DF_TRANSFER_HLG_OETF: + return "KHR_DF_TRANSFER_HLG_OETF"; + case KHR_DF_TRANSFER_HLG_EOTF: + return "KHR_DF_TRANSFER_HLG_EOTF"; + case KHR_DF_TRANSFER_PQ_EOTF: + return "KHR_DF_TRANSFER_PQ_EOTF"; + case KHR_DF_TRANSFER_PQ_OETF: + return "KHR_DF_TRANSFER_PQ_OETF"; + case KHR_DF_TRANSFER_DCIP3: + return "KHR_DF_TRANSFER_DCIP3"; + case KHR_DF_TRANSFER_PAL_OETF: + return "KHR_DF_TRANSFER_PAL_OETF"; + case KHR_DF_TRANSFER_PAL625_EOTF: + return "KHR_DF_TRANSFER_PAL625_EOTF"; + case KHR_DF_TRANSFER_ST240: + return "KHR_DF_TRANSFER_ST240"; + case KHR_DF_TRANSFER_ACESCC: + return "KHR_DF_TRANSFER_ACESCC"; + case KHR_DF_TRANSFER_ACESCCT: + return "KHR_DF_TRANSFER_ACESCCT"; + case KHR_DF_TRANSFER_ADOBERGB: + return "KHR_DF_TRANSFER_ADOBERGB"; + + case KHR_DF_TRANSFER_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringColorPrimaries(khr_df_primaries_e value) { + switch (value) { + case KHR_DF_PRIMARIES_UNSPECIFIED: + return "KHR_DF_PRIMARIES_UNSPECIFIED"; + case KHR_DF_PRIMARIES_BT709: + // case KHR_DF_PRIMARIES_SRGB: // Fallthrough, Matching values + return "KHR_DF_PRIMARIES_BT709"; + case KHR_DF_PRIMARIES_BT601_EBU: + return "KHR_DF_PRIMARIES_BT601_EBU"; + case KHR_DF_PRIMARIES_BT601_SMPTE: + return "KHR_DF_PRIMARIES_BT601_SMPTE"; + case KHR_DF_PRIMARIES_BT2020: + return "KHR_DF_PRIMARIES_BT2020"; + case KHR_DF_PRIMARIES_CIEXYZ: + return "KHR_DF_PRIMARIES_CIEXYZ"; + case KHR_DF_PRIMARIES_ACES: + return "KHR_DF_PRIMARIES_ACES"; + case KHR_DF_PRIMARIES_ACESCC: + return "KHR_DF_PRIMARIES_ACESCC"; + case KHR_DF_PRIMARIES_NTSC1953: + return "KHR_DF_PRIMARIES_NTSC1953"; + case KHR_DF_PRIMARIES_PAL525: + return "KHR_DF_PRIMARIES_PAL525"; + case KHR_DF_PRIMARIES_DISPLAYP3: + return "KHR_DF_PRIMARIES_DISPLAYP3"; + case KHR_DF_PRIMARIES_ADOBERGB: + return "KHR_DF_PRIMARIES_ADOBERGB"; + + case KHR_DF_PRIMARIES_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringColorModel(khr_df_model_e value) { + switch (value) { + case KHR_DF_MODEL_UNSPECIFIED: + return "KHR_DF_MODEL_UNSPECIFIED"; + case KHR_DF_MODEL_RGBSDA: + return "KHR_DF_MODEL_RGBSDA"; + case KHR_DF_MODEL_YUVSDA: + return "KHR_DF_MODEL_YUVSDA"; + case KHR_DF_MODEL_YIQSDA: + return "KHR_DF_MODEL_YIQSDA"; + case KHR_DF_MODEL_LABSDA: + return "KHR_DF_MODEL_LABSDA"; + case KHR_DF_MODEL_CMYKA: + return "KHR_DF_MODEL_CMYKA"; + case KHR_DF_MODEL_XYZW: + return "KHR_DF_MODEL_XYZW"; + case KHR_DF_MODEL_HSVA_ANG: + return "KHR_DF_MODEL_HSVA_ANG"; + case KHR_DF_MODEL_HSLA_ANG: + return "KHR_DF_MODEL_HSLA_ANG"; + case KHR_DF_MODEL_HSVA_HEX: + return "KHR_DF_MODEL_HSVA_HEX"; + case KHR_DF_MODEL_HSLA_HEX: + return "KHR_DF_MODEL_HSLA_HEX"; + case KHR_DF_MODEL_YCGCOA: + return "KHR_DF_MODEL_YCGCOA"; + case KHR_DF_MODEL_YCCBCCRC: + return "KHR_DF_MODEL_YCCBCCRC"; + case KHR_DF_MODEL_ICTCP: + return "KHR_DF_MODEL_ICTCP"; + case KHR_DF_MODEL_CIEXYZ: + return "KHR_DF_MODEL_CIEXYZ"; + case KHR_DF_MODEL_CIEXYY: + return "KHR_DF_MODEL_CIEXYY"; + case KHR_DF_MODEL_BC1A: + // case KHR_DF_MODEL_DXT1A: // Fallthrough, Matching values + return "KHR_DF_MODEL_BC1A"; + case KHR_DF_MODEL_BC2: + // case KHR_DF_MODEL_DXT2: // Fallthrough, Matching values + // case KHR_DF_MODEL_DXT3: // Fallthrough, Matching values + return "KHR_DF_MODEL_BC2"; + case KHR_DF_MODEL_BC3: + // case KHR_DF_MODEL_DXT4: // Fallthrough, Matching values + // case KHR_DF_MODEL_DXT5: // Fallthrough, Matching values + return "KHR_DF_MODEL_BC3"; + case KHR_DF_MODEL_BC4: + return "KHR_DF_MODEL_BC4"; + case KHR_DF_MODEL_BC5: + return "KHR_DF_MODEL_BC5"; + case KHR_DF_MODEL_BC6H: + return "KHR_DF_MODEL_BC6H"; + case KHR_DF_MODEL_BC7: + return "KHR_DF_MODEL_BC7"; + case KHR_DF_MODEL_ETC1: + return "KHR_DF_MODEL_ETC1"; + case KHR_DF_MODEL_ETC2: + return "KHR_DF_MODEL_ETC2"; + case KHR_DF_MODEL_ASTC: + return "KHR_DF_MODEL_ASTC"; + case KHR_DF_MODEL_ETC1S: + return "KHR_DF_MODEL_ETC1S"; + case KHR_DF_MODEL_PVRTC: + return "KHR_DF_MODEL_PVRTC"; + case KHR_DF_MODEL_PVRTC2: + return "KHR_DF_MODEL_PVRTC2"; + case KHR_DF_MODEL_UASTC: + return "KHR_DF_MODEL_UASTC"; + + case KHR_DF_MODEL_MAX: + // These enum values are not meant for string representation. Ignore + break; + } + return NULL; +} + +const char* dfdToStringSampleDatatypeQualifiers(uint32_t bit_index, bool bit_value) { + if (!bit_value) + return NULL; + + switch (1u << bit_index) { + case KHR_DF_SAMPLE_DATATYPE_LINEAR: + return "KHR_DF_SAMPLE_DATATYPE_LINEAR"; + case KHR_DF_SAMPLE_DATATYPE_EXPONENT: + return "KHR_DF_SAMPLE_DATATYPE_EXPONENT"; + case KHR_DF_SAMPLE_DATATYPE_SIGNED: + return "KHR_DF_SAMPLE_DATATYPE_SIGNED"; + case KHR_DF_SAMPLE_DATATYPE_FLOAT: + return "KHR_DF_SAMPLE_DATATYPE_FLOAT"; + } + return NULL; +} + +const char* dfdToStringChannelId(khr_df_model_e model, khr_df_model_channels_e value) { + switch (model) { + case KHR_DF_MODEL_RGBSDA: + switch (value) { + case KHR_DF_CHANNEL_RGBSDA_RED: + return "KHR_DF_CHANNEL_RGBSDA_RED"; + case KHR_DF_CHANNEL_RGBSDA_GREEN: + return "KHR_DF_CHANNEL_RGBSDA_GREEN"; + case KHR_DF_CHANNEL_RGBSDA_BLUE: + return "KHR_DF_CHANNEL_RGBSDA_BLUE"; + case KHR_DF_CHANNEL_RGBSDA_STENCIL: + return "KHR_DF_CHANNEL_RGBSDA_STENCIL"; + case KHR_DF_CHANNEL_RGBSDA_DEPTH: + return "KHR_DF_CHANNEL_RGBSDA_DEPTH"; + case KHR_DF_CHANNEL_RGBSDA_ALPHA: + return "KHR_DF_CHANNEL_RGBSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_YUVSDA: + switch (value) { + case KHR_DF_CHANNEL_YUVSDA_Y: + return "KHR_DF_CHANNEL_YUVSDA_Y"; + case KHR_DF_CHANNEL_YUVSDA_U: + return "KHR_DF_CHANNEL_YUVSDA_U"; + case KHR_DF_CHANNEL_YUVSDA_V: + return "KHR_DF_CHANNEL_YUVSDA_V"; + case KHR_DF_CHANNEL_YUVSDA_STENCIL: + return "KHR_DF_CHANNEL_YUVSDA_STENCIL"; + case KHR_DF_CHANNEL_YUVSDA_DEPTH: + return "KHR_DF_CHANNEL_YUVSDA_DEPTH"; + case KHR_DF_CHANNEL_YUVSDA_ALPHA: + return "KHR_DF_CHANNEL_YUVSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_YIQSDA: + switch (value) { + case KHR_DF_CHANNEL_YIQSDA_Y: + return "KHR_DF_CHANNEL_YIQSDA_Y"; + case KHR_DF_CHANNEL_YIQSDA_I: + return "KHR_DF_CHANNEL_YIQSDA_I"; + case KHR_DF_CHANNEL_YIQSDA_Q: + return "KHR_DF_CHANNEL_YIQSDA_Q"; + case KHR_DF_CHANNEL_YIQSDA_STENCIL: + return "KHR_DF_CHANNEL_YIQSDA_STENCIL"; + case KHR_DF_CHANNEL_YIQSDA_DEPTH: + return "KHR_DF_CHANNEL_YIQSDA_DEPTH"; + case KHR_DF_CHANNEL_YIQSDA_ALPHA: + return "KHR_DF_CHANNEL_YIQSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_LABSDA: + switch (value) { + case KHR_DF_CHANNEL_LABSDA_L: + return "KHR_DF_CHANNEL_LABSDA_L"; + case KHR_DF_CHANNEL_LABSDA_A: + return "KHR_DF_CHANNEL_LABSDA_A"; + case KHR_DF_CHANNEL_LABSDA_B: + return "KHR_DF_CHANNEL_LABSDA_B"; + case KHR_DF_CHANNEL_LABSDA_STENCIL: + return "KHR_DF_CHANNEL_LABSDA_STENCIL"; + case KHR_DF_CHANNEL_LABSDA_DEPTH: + return "KHR_DF_CHANNEL_LABSDA_DEPTH"; + case KHR_DF_CHANNEL_LABSDA_ALPHA: + return "KHR_DF_CHANNEL_LABSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_CMYKA: + switch (value) { + case KHR_DF_CHANNEL_CMYKSDA_CYAN: + return "KHR_DF_CHANNEL_CMYKSDA_CYAN"; + case KHR_DF_CHANNEL_CMYKSDA_MAGENTA: + return "KHR_DF_CHANNEL_CMYKSDA_MAGENTA"; + case KHR_DF_CHANNEL_CMYKSDA_YELLOW: + return "KHR_DF_CHANNEL_CMYKSDA_YELLOW"; + case KHR_DF_CHANNEL_CMYKSDA_BLACK: + return "KHR_DF_CHANNEL_CMYKSDA_BLACK"; + case KHR_DF_CHANNEL_CMYKSDA_ALPHA: + return "KHR_DF_CHANNEL_CMYKSDA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_XYZW: + switch (value) { + case KHR_DF_CHANNEL_XYZW_X: + return "KHR_DF_CHANNEL_XYZW_X"; + case KHR_DF_CHANNEL_XYZW_Y: + return "KHR_DF_CHANNEL_XYZW_Y"; + case KHR_DF_CHANNEL_XYZW_Z: + return "KHR_DF_CHANNEL_XYZW_Z"; + case KHR_DF_CHANNEL_XYZW_W: + return "KHR_DF_CHANNEL_XYZW_W"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSVA_ANG: + switch (value) { + case KHR_DF_CHANNEL_HSVA_ANG_VALUE: + return "KHR_DF_CHANNEL_HSVA_ANG_VALUE"; + case KHR_DF_CHANNEL_HSVA_ANG_SATURATION: + return "KHR_DF_CHANNEL_HSVA_ANG_SATURATION"; + case KHR_DF_CHANNEL_HSVA_ANG_HUE: + return "KHR_DF_CHANNEL_HSVA_ANG_HUE"; + case KHR_DF_CHANNEL_HSVA_ANG_ALPHA: + return "KHR_DF_CHANNEL_HSVA_ANG_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSLA_ANG: + switch (value) { + case KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS: + return "KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS"; + case KHR_DF_CHANNEL_HSLA_ANG_SATURATION: + return "KHR_DF_CHANNEL_HSLA_ANG_SATURATION"; + case KHR_DF_CHANNEL_HSLA_ANG_HUE: + return "KHR_DF_CHANNEL_HSLA_ANG_HUE"; + case KHR_DF_CHANNEL_HSLA_ANG_ALPHA: + return "KHR_DF_CHANNEL_HSLA_ANG_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSVA_HEX: + switch (value) { + case KHR_DF_CHANNEL_HSVA_HEX_VALUE: + return "KHR_DF_CHANNEL_HSVA_HEX_VALUE"; + case KHR_DF_CHANNEL_HSVA_HEX_SATURATION: + return "KHR_DF_CHANNEL_HSVA_HEX_SATURATION"; + case KHR_DF_CHANNEL_HSVA_HEX_HUE: + return "KHR_DF_CHANNEL_HSVA_HEX_HUE"; + case KHR_DF_CHANNEL_HSVA_HEX_ALPHA: + return "KHR_DF_CHANNEL_HSVA_HEX_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_HSLA_HEX: + switch (value) { + case KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS: + return "KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS"; + case KHR_DF_CHANNEL_HSLA_HEX_SATURATION: + return "KHR_DF_CHANNEL_HSLA_HEX_SATURATION"; + case KHR_DF_CHANNEL_HSLA_HEX_HUE: + return "KHR_DF_CHANNEL_HSLA_HEX_HUE"; + case KHR_DF_CHANNEL_HSLA_HEX_ALPHA: + return "KHR_DF_CHANNEL_HSLA_HEX_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_YCGCOA: + switch (value) { + case KHR_DF_CHANNEL_YCGCOA_Y: + return "KHR_DF_CHANNEL_YCGCOA_Y"; + case KHR_DF_CHANNEL_YCGCOA_CG: + return "KHR_DF_CHANNEL_YCGCOA_CG"; + case KHR_DF_CHANNEL_YCGCOA_CO: + return "KHR_DF_CHANNEL_YCGCOA_CO"; + case KHR_DF_CHANNEL_YCGCOA_ALPHA: + return "KHR_DF_CHANNEL_YCGCOA_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_CIEXYZ: + switch (value) { + case KHR_DF_CHANNEL_CIEXYZ_X: + return "KHR_DF_CHANNEL_CIEXYZ_X"; + case KHR_DF_CHANNEL_CIEXYZ_Y: + return "KHR_DF_CHANNEL_CIEXYZ_Y"; + case KHR_DF_CHANNEL_CIEXYZ_Z: + return "KHR_DF_CHANNEL_CIEXYZ_Z"; + default: + return NULL; + } + + case KHR_DF_MODEL_CIEXYY: + switch (value) { + case KHR_DF_CHANNEL_CIEXYY_X: + return "KHR_DF_CHANNEL_CIEXYY_X"; + case KHR_DF_CHANNEL_CIEXYY_YCHROMA: + return "KHR_DF_CHANNEL_CIEXYY_YCHROMA"; + case KHR_DF_CHANNEL_CIEXYY_YLUMA: + return "KHR_DF_CHANNEL_CIEXYY_YLUMA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC1A: + switch (value) { + case KHR_DF_CHANNEL_BC1A_COLOR: + return "KHR_DF_CHANNEL_BC1A_COLOR"; + case KHR_DF_CHANNEL_BC1A_ALPHA: + return "KHR_DF_CHANNEL_BC1A_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC2: + switch (value) { + case KHR_DF_CHANNEL_BC2_COLOR: + return "KHR_DF_CHANNEL_BC2_COLOR"; + case KHR_DF_CHANNEL_BC2_ALPHA: + return "KHR_DF_CHANNEL_BC2_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC3: + switch (value) { + case KHR_DF_CHANNEL_BC3_COLOR: + return "KHR_DF_CHANNEL_BC3_COLOR"; + case KHR_DF_CHANNEL_BC3_ALPHA: + return "KHR_DF_CHANNEL_BC3_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC4: + switch (value) { + case KHR_DF_CHANNEL_BC4_DATA: + return "KHR_DF_CHANNEL_BC4_DATA"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC5: + switch (value) { + case KHR_DF_CHANNEL_BC5_RED: + return "KHR_DF_CHANNEL_BC5_RED"; + case KHR_DF_CHANNEL_BC5_GREEN: + return "KHR_DF_CHANNEL_BC5_GREEN"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC6H: + switch (value) { + case KHR_DF_CHANNEL_BC6H_COLOR: + return "KHR_DF_CHANNEL_BC6H_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_BC7: + switch (value) { + case KHR_DF_CHANNEL_BC7_COLOR: + return "KHR_DF_CHANNEL_BC7_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_ETC1: + switch (value) { + case KHR_DF_CHANNEL_ETC1_COLOR: + return "KHR_DF_CHANNEL_ETC1_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_ETC2: + switch (value) { + case KHR_DF_CHANNEL_ETC2_RED: + return "KHR_DF_CHANNEL_ETC2_RED"; + case KHR_DF_CHANNEL_ETC2_GREEN: + return "KHR_DF_CHANNEL_ETC2_GREEN"; + case KHR_DF_CHANNEL_ETC2_COLOR: + return "KHR_DF_CHANNEL_ETC2_COLOR"; + case KHR_DF_CHANNEL_ETC2_ALPHA: + return "KHR_DF_CHANNEL_ETC2_ALPHA"; + default: + return NULL; + } + + case KHR_DF_MODEL_ASTC: + switch (value) { + case KHR_DF_CHANNEL_ASTC_DATA: + return "KHR_DF_CHANNEL_ASTC_DATA"; + default: + return NULL; + } + + case KHR_DF_MODEL_ETC1S: + switch (value) { + case KHR_DF_CHANNEL_ETC1S_RGB: + return "KHR_DF_CHANNEL_ETC1S_RGB"; + case KHR_DF_CHANNEL_ETC1S_RRR: + return "KHR_DF_CHANNEL_ETC1S_RRR"; + case KHR_DF_CHANNEL_ETC1S_GGG: + return "KHR_DF_CHANNEL_ETC1S_GGG"; + case KHR_DF_CHANNEL_ETC1S_AAA: + return "KHR_DF_CHANNEL_ETC1S_AAA"; + default: + return NULL; + } + + case KHR_DF_MODEL_PVRTC: + switch (value) { + case KHR_DF_CHANNEL_PVRTC_COLOR: + return "KHR_DF_CHANNEL_PVRTC_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_PVRTC2: + switch (value) { + case KHR_DF_CHANNEL_PVRTC2_COLOR: + return "KHR_DF_CHANNEL_PVRTC2_COLOR"; + default: + return NULL; + } + + case KHR_DF_MODEL_UASTC: + switch (value) { + case KHR_DF_CHANNEL_UASTC_RGB: + return "KHR_DF_CHANNEL_UASTC_RGB"; + case KHR_DF_CHANNEL_UASTC_RGBA: + return "KHR_DF_CHANNEL_UASTC_RGBA"; + case KHR_DF_CHANNEL_UASTC_RRR: + return "KHR_DF_CHANNEL_UASTC_RRR"; + case KHR_DF_CHANNEL_UASTC_RRRG: + return "KHR_DF_CHANNEL_UASTC_RRRG"; + case KHR_DF_CHANNEL_UASTC_RG: + return "KHR_DF_CHANNEL_UASTC_RG"; + default: + return NULL; + } + + default: + break; + } + + switch (value) { + case KHR_DF_CHANNEL_UNSPECIFIED_0: + return "KHR_DF_CHANNEL_UNSPECIFIED_0"; + case KHR_DF_CHANNEL_UNSPECIFIED_1: + return "KHR_DF_CHANNEL_UNSPECIFIED_1"; + case KHR_DF_CHANNEL_UNSPECIFIED_2: + return "KHR_DF_CHANNEL_UNSPECIFIED_2"; + case KHR_DF_CHANNEL_UNSPECIFIED_3: + return "KHR_DF_CHANNEL_UNSPECIFIED_3"; + case KHR_DF_CHANNEL_UNSPECIFIED_4: + return "KHR_DF_CHANNEL_UNSPECIFIED_4"; + case KHR_DF_CHANNEL_UNSPECIFIED_5: + return "KHR_DF_CHANNEL_UNSPECIFIED_5"; + case KHR_DF_CHANNEL_UNSPECIFIED_6: + return "KHR_DF_CHANNEL_UNSPECIFIED_6"; + case KHR_DF_CHANNEL_UNSPECIFIED_7: + return "KHR_DF_CHANNEL_UNSPECIFIED_7"; + case KHR_DF_CHANNEL_UNSPECIFIED_8: + return "KHR_DF_CHANNEL_UNSPECIFIED_8"; + case KHR_DF_CHANNEL_UNSPECIFIED_9: + return "KHR_DF_CHANNEL_UNSPECIFIED_9"; + case KHR_DF_CHANNEL_UNSPECIFIED_10: + return "KHR_DF_CHANNEL_UNSPECIFIED_10"; + case KHR_DF_CHANNEL_UNSPECIFIED_11: + return "KHR_DF_CHANNEL_UNSPECIFIED_11"; + case KHR_DF_CHANNEL_UNSPECIFIED_12: + return "KHR_DF_CHANNEL_UNSPECIFIED_12"; + case KHR_DF_CHANNEL_UNSPECIFIED_13: + return "KHR_DF_CHANNEL_UNSPECIFIED_13"; + case KHR_DF_CHANNEL_UNSPECIFIED_14: + return "KHR_DF_CHANNEL_UNSPECIFIED_14"; + case KHR_DF_CHANNEL_UNSPECIFIED_15: + return "KHR_DF_CHANNEL_UNSPECIFIED_15"; + default: + break; + } + + return NULL; +} + +/** + * @internal + */ +static void printFlagBits(uint32_t flags, const char*(*toStringFn)(uint32_t, bool)) { + bool first = true; + for (uint32_t bit_index = 0; bit_index < 32; ++bit_index) { + uint32_t bit_mask = 1u << bit_index; + bool bit_value = (bit_mask & (uint32_t) flags) != 0; + + const char* comma = first ? "" : ", "; + const char* str = toStringFn(bit_index, bit_value); + if (str) { + printf("%s%s", comma, str); + first = false; + } else if (bit_value) { + printf("%s%u", comma, bit_mask); + first = false; + } + } +} + +/** + * @internal + */ +static void printFlagBitsJSON(uint32_t indent, const char* nl, uint32_t flags, const char*(*toStringFn)(uint32_t, bool)) { + bool first = true; + for (uint32_t bit_index = 0; bit_index < 32; ++bit_index) { + uint32_t bit_mask = 1u << bit_index; + bool bit_value = (bit_mask & (uint32_t) flags) != 0; + + const char* str = toStringFn(bit_index, bit_value); + if (str) { + printf("%s%s%*s\"%s\"", first ? "" : ",", first ? "" : nl, indent, "", str); + first = false; + } else if (bit_value) { + printf("%s%s%*s%u", first ? "" : ",", first ? "" : nl, indent, "", bit_mask); + first = false; + } + } + if (!first) + printf("%s", nl); +} + /** * @~English * @brief Print a human-readable interpretation of a data format descriptor. * * @param DFD Pointer to a data format descriptor. + * @param dataSize The maximum size that can be considered as part of the DFD. + **/ +void printDFD(uint32_t *DFD, uint32_t dataSize) +{ +#define PRINT_ENUM(VALUE, TO_STRING_FN) { \ + int value = VALUE; \ + const char* str = TO_STRING_FN(value); \ + if (str) \ + printf("%s", str); \ + else \ + printf("%u", value); \ + } + + const uint32_t sizeof_dfdTotalSize = sizeof(uint32_t); + const uint32_t sizeof_DFDBHeader = sizeof(uint32_t) * 2; + const uint32_t sizeof_BDFD = sizeof(uint32_t) * KHR_DF_WORD_SAMPLESTART; + const uint32_t sizeof_BDFDSample = sizeof(uint32_t) * KHR_DF_WORD_SAMPLEWORDS; + + uint32_t dfdTotalSize = dataSize >= sizeof_dfdTotalSize ? DFD[0] : 0; + uint32_t remainingSize = dfdTotalSize < dataSize ? dfdTotalSize : dataSize; + if (remainingSize < sizeof_dfdTotalSize) + return; // Invalid DFD: dfdTotalSize must be present + + uint32_t* block = DFD + 1; + remainingSize -= sizeof_dfdTotalSize; + + printf("DFD total bytes: %u\n", dfdTotalSize); + + for (int i = 0; i < MAX_NUM_DFD_BLOCKS; ++i) { // At most only iterate MAX_NUM_DFD_BLOCKS block + if (remainingSize < sizeof_DFDBHeader) + break; // Invalid DFD: Missing or partial block header + + const khr_df_vendorid_e vendorID = KHR_DFDVAL(block, VENDORID); + const khr_df_khr_descriptortype_e descriptorType = KHR_DFDVAL(block, DESCRIPTORTYPE); + const khr_df_versionnumber_e versionNumber = KHR_DFDVAL(block, VERSIONNUMBER); + const uint32_t blockSize = KHR_DFDVAL(block, DESCRIPTORBLOCKSIZE); + + printf("Vendor ID: "); + PRINT_ENUM(vendorID, dfdToStringVendorID); + printf("\nDescriptor type: "); + PRINT_ENUM(descriptorType, dfdToStringDescriptorType); + printf("\nVersion: "); + PRINT_ENUM(versionNumber, dfdToStringVersionNumber); + printf("\nDescriptor block size: %u", blockSize); + printf("\n"); + + if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT) { + if (remainingSize < sizeof_BDFD) + break; // Invalid DFD: Missing or partial basic DFD block + + const int model = KHR_DFDVAL(block, MODEL); + + khr_df_flags_e flags = KHR_DFDVAL(block, FLAGS); + printf("Flags: 0x%X (", flags); + printFlagBits(flags, dfdToStringFlagsBit); + printf(")\nTransfer: "); + PRINT_ENUM(KHR_DFDVAL(block, TRANSFER), dfdToStringTransferFunction); + printf("\nPrimaries: "); + PRINT_ENUM(KHR_DFDVAL(block, PRIMARIES), dfdToStringColorPrimaries); + printf("\nModel: "); + PRINT_ENUM(model, dfdToStringColorModel); + printf("\n"); + + printf("Dimensions: %u, %u, %u, %u\n", + KHR_DFDVAL(block, TEXELBLOCKDIMENSION0) + 1, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION1) + 1, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION2) + 1, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION3) + 1); + printf("Plane bytes: %u, %u, %u, %u, %u, %u, %u, %u\n", + KHR_DFDVAL(block, BYTESPLANE0), + KHR_DFDVAL(block, BYTESPLANE1), + KHR_DFDVAL(block, BYTESPLANE2), + KHR_DFDVAL(block, BYTESPLANE3), + KHR_DFDVAL(block, BYTESPLANE4), + KHR_DFDVAL(block, BYTESPLANE5), + KHR_DFDVAL(block, BYTESPLANE6), + KHR_DFDVAL(block, BYTESPLANE7)); + + int samples = (blockSize - sizeof_BDFD) / sizeof_BDFDSample; + if (samples > MAX_NUM_BDFD_SAMPLES) + samples = MAX_NUM_BDFD_SAMPLES; // Too many BDFD samples + for (int sample = 0; sample < samples; ++sample) { + if (remainingSize < sizeof_BDFD + (sample + 1) * sizeof_BDFDSample) + break; // Invalid DFD: Missing or partial basic DFD sample + + khr_df_model_channels_e channelType = KHR_DFDSVAL(block, sample, CHANNELID); + printf("Sample %u:\n", sample); + + khr_df_sample_datatype_qualifiers_e qualifiers = KHR_DFDSVAL(block, sample, QUALIFIERS); + printf(" Qualifiers: 0x%X (", qualifiers); + printFlagBits(qualifiers, dfdToStringSampleDatatypeQualifiers); + printf(")\n"); + printf(" Channel Type: 0x%X", channelType); + { + const char* str = dfdToStringChannelId(model, channelType); + if (str) + printf(" (%s)\n", str); + else + printf(" (%u)\n", channelType); + } + printf(" Length: %u bits Offset: %u\n", + KHR_DFDSVAL(block, sample, BITLENGTH) + 1, + KHR_DFDSVAL(block, sample, BITOFFSET)); + printf(" Position: %u, %u, %u, %u\n", + KHR_DFDSVAL(block, sample, SAMPLEPOSITION0), + KHR_DFDSVAL(block, sample, SAMPLEPOSITION1), + KHR_DFDSVAL(block, sample, SAMPLEPOSITION2), + KHR_DFDSVAL(block, sample, SAMPLEPOSITION3)); + printf(" Lower: 0x%08x\n Upper: 0x%08x\n", + KHR_DFDSVAL(block, sample, SAMPLELOWER), + KHR_DFDSVAL(block, sample, SAMPLEUPPER)); + } + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS) { + // TODO: Implement DFD print for ADDITIONAL_DIMENSIONS + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES) { + // TODO: Implement DFD print for ADDITIONAL_PLANES + } else { + printf("Unknown block\n"); + } + + const uint32_t advance = sizeof_DFDBHeader > blockSize ? sizeof_DFDBHeader : blockSize; + if (advance > remainingSize) + break; + remainingSize -= advance; + block += advance / 4; + } +#undef PRINT_ENUM +} + +/** + * @~English + * @brief Print a JSON interpretation of a data format descriptor. + * + * @param DFD Pointer to a data format descriptor. + * @param dataSize The maximum size that can be considered as part of the DFD. + * @param base_indent The number of indentations to include at the front of every line + * @param indent_width The number of spaces to add with each nested scope + * @param minified Specifies whether the JSON output should be minified **/ -void printDFD(uint32_t *DFD) +void printDFDJSON(uint32_t* DFD, uint32_t dataSize, uint32_t base_indent, uint32_t indent_width, bool minified) { - uint32_t *BDB = DFD+1; - int samples = (KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE) - 4 * KHR_DF_WORD_SAMPLESTART) / (4 * KHR_DF_WORD_SAMPLEWORDS); - int sample; - int model = KHR_DFDVAL(BDB, MODEL); - printf("DFD total bytes: %d\n", DFD[0]); - printf("BDB descriptor type 0x%04x vendor id = 0x%05x\n", - KHR_DFDVAL(BDB, DESCRIPTORTYPE), - KHR_DFDVAL(BDB, VENDORID)); - printf("Descriptor block size %d (%d samples) versionNumber = 0x%04x\n", - KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE), - samples, - KHR_DFDVAL(BDB, VERSIONNUMBER)); - printf("Flags 0x%02x Xfer %02d Primaries %02d Model %03d\n", - KHR_DFDVAL(BDB, FLAGS), - KHR_DFDVAL(BDB, TRANSFER), - KHR_DFDVAL(BDB, PRIMARIES), - model); - printf("Dimensions: %d,%d,%d,%d\n", - KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION0) + 1, - KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION1) + 1, - KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION2) + 1, - KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION3) + 1); - printf("Plane bytes: %d,%d,%d,%d,%d,%d,%d,%d\n", - KHR_DFDVAL(BDB, BYTESPLANE0), - KHR_DFDVAL(BDB, BYTESPLANE1), - KHR_DFDVAL(BDB, BYTESPLANE2), - KHR_DFDVAL(BDB, BYTESPLANE3), - KHR_DFDVAL(BDB, BYTESPLANE4), - KHR_DFDVAL(BDB, BYTESPLANE5), - KHR_DFDVAL(BDB, BYTESPLANE6), - KHR_DFDVAL(BDB, BYTESPLANE7)); - for (sample = 0; sample < samples; ++sample) { - int channelId = KHR_DFDSVAL(BDB, sample, CHANNELID); - printf(" Sample %d\n", sample); - printf("Qualifiers %x", KHR_DFDSVAL(BDB, sample, QUALIFIERS) >> 4); - printf(" Channel 0x%x", channelId); - if (model == KHR_DF_MODEL_UASTC) { - printf(" (%s)", - channelId == KHR_DF_CHANNEL_UASTC_RRRG ? "RRRG" - : channelId == KHR_DF_CHANNEL_UASTC_RGBA ? "RGBA" - : channelId == KHR_DF_CHANNEL_UASTC_RRR ? "RRR" - : channelId == KHR_DF_CHANNEL_UASTC_RGB ? "RGB" - : channelId == KHR_DF_CHANNEL_UASTC_RG ? "RG" - : "unknown"); - } else if (model == KHR_DF_MODEL_ETC1S) { - printf(" (%s)", - channelId == KHR_DF_CHANNEL_ETC1S_AAA ? "AAA" - : channelId == KHR_DF_CHANNEL_ETC1S_GGG ? "GGG" - : channelId == KHR_DF_CHANNEL_ETC1S_RRR ? "RRR" - : channelId == KHR_DF_CHANNEL_ETC1S_RGB ? "RGB" - : "unknown"); + if (minified) { + base_indent = 0; + indent_width = 0; + } + const char* space = minified ? "" : " "; + const char* nl = minified ? "" : "\n"; + +#define LENGTH_OF_INDENT(INDENT) ((base_indent + INDENT) * indent_width) + +/** Prints an enum as string or number */ +#define PRINT_ENUM(INDENT, NAME, VALUE, TO_STRING_FN, COMMA) { \ + int value = VALUE; \ + printf("%*s\"" NAME "\":%s", LENGTH_OF_INDENT(INDENT), "", space); \ + const char* str = TO_STRING_FN(value); \ + if (str) \ + printf("\"%s\"", str); \ + else \ + printf("%u", value); \ + printf(COMMA "%s", nl); \ + } + +/** Prints an enum as string or number if the to string function fails with a trailing comma*/ +#define PRINT_ENUM_C(INDENT, NAME, VALUE, TO_STRING_FN) \ + PRINT_ENUM(INDENT, NAME, VALUE, TO_STRING_FN, ",") + +/** Prints an enum as string or number if the to string function fails without a trailing comma*/ +#define PRINT_ENUM_E(INDENT, NAME, VALUE, TO_STRING_FN) \ + PRINT_ENUM(INDENT, NAME, VALUE, TO_STRING_FN, "") + +#define PRINT_INDENT(INDENT, FMT, ...) { \ + printf("%*s" FMT, LENGTH_OF_INDENT(INDENT), "", __VA_ARGS__); \ + } + +#define PRINT_INDENT_NOARG(INDENT, FMT) { \ + printf("%*s" FMT, LENGTH_OF_INDENT(INDENT), ""); \ + } + + const uint32_t sizeof_dfdTotalSize = sizeof(uint32_t); + const uint32_t sizeof_DFDBHeader = sizeof(uint32_t) * 2; + const uint32_t sizeof_BDFD = sizeof(uint32_t) * KHR_DF_WORD_SAMPLESTART; + const uint32_t sizeof_BDFDSample = sizeof(uint32_t) * KHR_DF_WORD_SAMPLEWORDS; + + uint32_t dfdTotalSize = dataSize >= sizeof_dfdTotalSize ? DFD[0] : 0; + PRINT_INDENT(0, "\"totalSize\":%s%u,%s", space, dfdTotalSize, nl) + + uint32_t remainingSize = dfdTotalSize < dataSize ? dfdTotalSize : dataSize; + if (remainingSize < sizeof_dfdTotalSize) { + PRINT_INDENT(0, "\"blocks\":%s[]%s", space, nl) // Print empty blocks to confirm to the json scheme + return; // Invalid DFD: dfdTotalSize must be present + } + + uint32_t* block = DFD + 1; + remainingSize -= sizeof_dfdTotalSize; + PRINT_INDENT(0, "\"blocks\":%s[", space) + + for (int i = 0; i < MAX_NUM_DFD_BLOCKS; ++i) { // At most only iterate MAX_NUM_DFD_BLOCKS block + if (remainingSize < sizeof_DFDBHeader) + break; // Invalid DFD: Missing or partial block header + + const khr_df_vendorid_e vendorID = KHR_DFDVAL(block, VENDORID); + const khr_df_khr_descriptortype_e descriptorType = KHR_DFDVAL(block, DESCRIPTORTYPE); + const khr_df_versionnumber_e versionNumber = KHR_DFDVAL(block, VERSIONNUMBER); + const uint32_t blockSize = KHR_DFDVAL(block, DESCRIPTORBLOCKSIZE); + + const int model = KHR_DFDVAL(block, MODEL); + + if (i == 0) { + printf("%s", nl); } else { - printf(" (%c)", - "RGB3456789abcdeA"[channelId]); - } - printf(" Length %d bits Offset %d\n", - KHR_DFDSVAL(BDB, sample, BITLENGTH) + 1, - KHR_DFDSVAL(BDB, sample, BITOFFSET)); - printf("Position: %d,%d,%d,%d\n", - KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION0), - KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION1), - KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION2), - KHR_DFDSVAL(BDB, sample, SAMPLEPOSITION3)); - printf("Lower 0x%08x\nUpper 0x%08x\n", - KHR_DFDSVAL(BDB, sample, SAMPLELOWER), - KHR_DFDSVAL(BDB, sample, SAMPLEUPPER)); + printf(",%s", nl); + } + PRINT_INDENT(1, "{%s", nl) + PRINT_ENUM_C(2, "vendorId", vendorID, dfdToStringVendorID); + PRINT_ENUM_C(2, "descriptorType", descriptorType, dfdToStringDescriptorType); + PRINT_ENUM_C(2, "versionNumber", versionNumber, dfdToStringVersionNumber); + PRINT_INDENT(2, "\"descriptorBlockSize\":%s%u", space, blockSize) + + if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT) { + if (remainingSize < sizeof_BDFD) { + // Invalid DFD: Missing or partial basic DFD block + printf("%s", nl); + PRINT_INDENT(1, "}%s", nl) // End of block + break; + } + + printf(",%s", nl); + PRINT_INDENT(2, "\"flags\":%s[%s", space, nl) + khr_df_flags_e flags = KHR_DFDVAL(block, FLAGS); + printFlagBitsJSON(LENGTH_OF_INDENT(3), nl, flags, dfdToStringFlagsBit); + PRINT_INDENT(2, "],%s", nl) + + PRINT_ENUM_C(2, "transferFunction", KHR_DFDVAL(block, TRANSFER), dfdToStringTransferFunction); + PRINT_ENUM_C(2, "colorPrimaries", KHR_DFDVAL(block, PRIMARIES), dfdToStringColorPrimaries); + PRINT_ENUM_C(2, "colorModel", model, dfdToStringColorModel); + PRINT_INDENT(2, "\"texelBlockDimension\":%s[%u,%s%u,%s%u,%s%u],%s", space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION0) + 1, space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION1) + 1, space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION2) + 1, space, + KHR_DFDVAL(block, TEXELBLOCKDIMENSION3) + 1, nl) + PRINT_INDENT(2, "\"bytesPlane\":%s[%u,%s%u,%s%u,%s%u,%s%u,%s%u,%s%u,%s%u],%s", space, + KHR_DFDVAL(block, BYTESPLANE0), space, + KHR_DFDVAL(block, BYTESPLANE1), space, + KHR_DFDVAL(block, BYTESPLANE2), space, + KHR_DFDVAL(block, BYTESPLANE3), space, + KHR_DFDVAL(block, BYTESPLANE4), space, + KHR_DFDVAL(block, BYTESPLANE5), space, + KHR_DFDVAL(block, BYTESPLANE6), space, + KHR_DFDVAL(block, BYTESPLANE7), nl) + + PRINT_INDENT(2, "\"samples\":%s[%s", space, nl) + int samples = (blockSize - sizeof_BDFD) / sizeof_BDFDSample; + if (samples > MAX_NUM_BDFD_SAMPLES) + samples = MAX_NUM_BDFD_SAMPLES; + for (int sample = 0; sample < samples; ++sample) { + if (remainingSize < sizeof_BDFD + (sample + 1) * sizeof_BDFDSample) + break; // Invalid DFD: Missing or partial basic DFD sample + + if (sample != 0) + printf(",%s", nl); + PRINT_INDENT(3, "{%s", nl) + + khr_df_sample_datatype_qualifiers_e qualifiers = KHR_DFDSVAL(block, sample, QUALIFIERS); + if (qualifiers == 0) { + PRINT_INDENT(4, "\"qualifiers\":%s[],%s", space, nl) + + } else { + PRINT_INDENT(4, "\"qualifiers\":%s[%s", space, nl) + printFlagBitsJSON(LENGTH_OF_INDENT(5), nl, qualifiers, dfdToStringSampleDatatypeQualifiers); + PRINT_INDENT(4, "],%s", nl) + } + + khr_df_model_channels_e channelType = KHR_DFDSVAL(block, sample, CHANNELID); + const char* channelStr = dfdToStringChannelId(model, channelType); + if (channelStr) + PRINT_INDENT(4, "\"channelType\":%s\"%s\",%s", space, channelStr, nl) + else + PRINT_INDENT(4, "\"channelType\":%s%u,%s", space, channelType, nl) + + PRINT_INDENT(4, "\"bitLength\":%s%u,%s", space, KHR_DFDSVAL(block, sample, BITLENGTH), nl) + PRINT_INDENT(4, "\"bitOffset\":%s%u,%s", space, KHR_DFDSVAL(block, sample, BITOFFSET), nl) + PRINT_INDENT(4, "\"samplePosition\":%s[%u,%s%u,%s%u,%s%u],%s", space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION0), space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION1), space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION2), space, + KHR_DFDSVAL(block, sample, SAMPLEPOSITION3), nl) + + if (qualifiers & KHR_DF_SAMPLE_DATATYPE_SIGNED) { + PRINT_INDENT(4, "\"sampleLower\":%s%d,%s", space, KHR_DFDSVAL(block, sample, SAMPLELOWER), nl) + PRINT_INDENT(4, "\"sampleUpper\":%s%d%s", space, KHR_DFDSVAL(block, sample, SAMPLEUPPER), nl) + } else { + PRINT_INDENT(4, "\"sampleLower\":%s%u,%s", space, (unsigned int) KHR_DFDSVAL(block, sample, SAMPLELOWER), nl) + PRINT_INDENT(4, "\"sampleUpper\":%s%u%s", space, (unsigned int) KHR_DFDSVAL(block, sample, SAMPLEUPPER), nl) + } + + PRINT_INDENT_NOARG(3, "}") + } + printf("%s", nl); + PRINT_INDENT(2, "]%s", nl) // End of samples + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS) { + printf("%s", nl); + // printf(",%s", nl); // If there is extra member printed + // TODO: Implement DFD print for ADDITIONAL_DIMENSIONS + } else if (vendorID == KHR_DF_VENDORID_KHRONOS && descriptorType == KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES) { + printf("%s", nl); + // printf(",%s", nl); // If there is extra member printed + // TODO: Implement DFD print for ADDITIONAL_PLANES + } else { + printf("%s", nl); + // printf(",%s", nl); // If there is extra member printed + // TODO: What to do with unknown blocks for json? + // Unknown block data in binary? + } + + PRINT_INDENT_NOARG(1, "}") // End of block + + const uint32_t advance = sizeof_DFDBHeader > blockSize ? sizeof_DFDBHeader : blockSize; + if (advance > remainingSize) + break; + remainingSize -= advance; + block += advance / 4; } + printf("%s", nl); + PRINT_INDENT(0, "]%s", nl) // End of blocks + +#undef PRINT_ENUM +#undef PRINT_ENUM_C +#undef PRINT_ENUM_E +#undef PRINT_INDENT +#undef PRINT_INDENT_NOARG } diff --git a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl index 4ae1e6d5e1..25c7a2c238 100644 --- a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl +++ b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl @@ -5,9 +5,6 @@ Automatically generated by makevk2dfd.pl. *************************************************************************/ -/* Vulkan combined depth & stencil formats are not included here - * because they do not exist outside a Vulkan device. - */ case VK_FORMAT_R4G4_UNORM_PACK8: { int channels[] = {1,0}; int bits[] = {4,4}; return createDFDPacked(0, 2, bits, channels, s_UNORM); @@ -222,6 +219,9 @@ case VK_FORMAT_D16_UNORM: return createDFDDepthStencil(16,0,2); case VK_FORMAT_X8_D24_UNORM_PACK32: return createDFDDepthStencil(24,0,4); case VK_FORMAT_D32_SFLOAT: return createDFDDepthStencil(32,0,4); case VK_FORMAT_S8_UINT: return createDFDDepthStencil(0,8,1); +case VK_FORMAT_D16_UNORM_S8_UINT: return createDFDDepthStencil(16,8,4); +case VK_FORMAT_D24_UNORM_S8_UINT: return createDFDDepthStencil(24,8,4); +case VK_FORMAT_D32_SFLOAT_S8_UINT: return createDFDDepthStencil(32,8,8); case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_UNORM); case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_SRGB); case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGBA, 4, 4, 1, s_UNORM); @@ -276,6 +276,92 @@ case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 10 case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SRGB); case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_UNORM); case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SRGB); +case VK_FORMAT_G8B8G8R8_422_UNORM: { + int channels[] = {0, 1, 0, 2}; int bits[] = {8, 8, 8, 8}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B8G8R8G8_422_UNORM: { + int channels[] = {1, 0, 2, 0}; int bits[] = {8, 8, 8, 8}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_R10X6_UNORM_PACK16: { + int channels[] = {0}; int bits[] = {10}; int paddings[] = {6}; + return createDFDPackedPadded(0, 1, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: { + int channels[] = {0, 1}; int bits[] = {10, 10}; int paddings[] = {6, 6}; + return createDFDPackedPadded(0, 2, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: { + int channels[] = {0, 1, 2, 3}; int bits[] = {10, 10, 10, 10}; int paddings[] = {6, 6, 6, 6}; + return createDFDPackedPadded(0, 4, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: { + int channels[] = {0, 1, 0, 2}; int bits[] = {10, 10, 10, 10}; int paddings[] = {6, 6, 6, 6}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: { + int channels[] = {1, 0, 2, 0}; int bits[] = {10, 10, 10, 10}; int paddings[] = {6, 6, 6, 6}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_R12X4_UNORM_PACK16: { + int channels[] = {0}; int bits[] = {12}; int paddings[] = {4}; + return createDFDPackedPadded(0, 1, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: { + int channels[] = {0, 1}; int bits[] = {12, 12}; int paddings[] = {4, 4}; + return createDFDPackedPadded(0, 2, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: { + int channels[] = {0, 1, 2, 3}; int bits[] = {12, 12, 12, 12}; int paddings[] = {4, 4, 4, 4}; + return createDFDPackedPadded(0, 4, bits, paddings, channels, s_UNORM); +} +case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: { + int channels[] = {0, 1, 0, 2}; int bits[] = {12, 12, 12, 12}; int paddings[] = {4, 4, 4, 4}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: { + int channels[] = {1, 0, 2, 0}; int bits[] = {12, 12, 12, 12}; int paddings[] = {4, 4, 4, 4}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_G16B16G16R16_422_UNORM: { + int channels[] = {0, 1, 0, 2}; int bits[] = {16, 16, 16, 16}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 192, 64}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_B16G16R16G16_422_UNORM: { + int channels[] = {1, 0, 2, 0}; int bits[] = {16, 16, 16, 16}; int paddings[] = {0, 0, 0, 0}; + int position_xs[] = {64, 64, 64, 192}; int position_ys[] = {128, 128, 128, 128}; + return createDFD422(0, 4, bits, paddings, channels, position_xs, position_ys, s_UNORM); +} +case VK_FORMAT_A4R4G4B4_UNORM_PACK16: { + int channels[] = {2,1,0,3}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_A4B4G4R4_UNORM_PACK16: { + int channels[] = {0,1,2,3}; int bits[] = {4,4,4,4}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +} +case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 4, 4, 1, s_SFLOAT); +case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 5, 4, 1, s_SFLOAT); +case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 5, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 6, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 6, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 8, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 8, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 8, 8, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 5, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 6, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 8, 1, s_SFLOAT); +case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SFLOAT); +case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SFLOAT); +case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SFLOAT); case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8, 4, 1, s_UNORM); case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_UNORM); case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_UNORM); @@ -284,20 +370,6 @@ case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8 case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_SRGB); case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_SRGB); case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 4, 4, 1, s_SRGB); -case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 4, 4, 1, s_SFLOAT); -case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 4, 1, s_SFLOAT); -case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 5, 5, 1, s_SFLOAT); -case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 5, 1, s_SFLOAT); -case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 1, s_SFLOAT); -case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 8, 5, 1, s_SFLOAT); -case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 8, 6, 1, s_SFLOAT); -case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 8, 8, 1, s_SFLOAT); -case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 5, 1, s_SFLOAT); -case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 6, 1, s_SFLOAT); -case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 8, 1, s_SFLOAT); -case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SFLOAT); -case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SFLOAT); -case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SFLOAT); #if 0 case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_UNORM); case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SRGB); @@ -330,11 +402,8 @@ case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SRGB); case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SFLOAT); #endif -case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: { - int channels[] = {2,1,0,3}; int bits[] = {4,4,4,4}; - return createDFDPacked(0, 4, bits, channels, s_UNORM); -} -case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: { - int channels[] = {0,1,2,3}; int bits[] = {4,4,4,4}; +case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: { + int channels[] = {0,1,2,3}; int bits[] = {5,5,5,1}; return createDFDPacked(0, 4, bits, channels, s_UNORM); } +case VK_FORMAT_A8_UNORM_KHR: return createDFDAlpha(0, 1, s_UNORM); diff --git a/thirdparty/libktx/lib/filestream.c b/thirdparty/libktx/lib/filestream.c index b1e0eba7c6..31f964b9fc 100644 --- a/thirdparty/libktx/lib/filestream.c +++ b/thirdparty/libktx/lib/filestream.c @@ -307,15 +307,17 @@ KTX_error_code ktxFileStream_getsize(ktxStream* str, ktx_size_t* size) assert(str->type == eStreamTypeFile); - // Need to flush so that fstat will return the current size. - // Can ignore return value. The only error that can happen is to tell you - // it was a NOP because the file is read only. + // Need to flush so that fstat will return the current size. + // Can ignore return value. The only error that can happen is to tell you + // it was a NOP because the file is read only. #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(__MINGW64__) && !defined(_UCRT) - // Bug in VS2013 msvcrt. fflush on FILE open for READ changes file offset - // to 4096. - if (str->data.file->_flag & _IOWRT) -#endif + // Bug in VS2013 msvcrt. fflush on FILE open for READ changes file offset + // to 4096. + if (str->data.file->_flag & _IOWRT) + (void)fflush(str->data.file); +#else (void)fflush(str->data.file); +#endif statret = fstat(fileno(str->data.file), &statbuf); if (statret < 0) { switch (errno) { diff --git a/thirdparty/libktx/lib/formatsize.h b/thirdparty/libktx/lib/formatsize.h index 7112a3a90d..149ff18d61 100644 --- a/thirdparty/libktx/lib/formatsize.h +++ b/thirdparty/libktx/lib/formatsize.h @@ -27,6 +27,7 @@ typedef enum ktxFormatSizeFlagBits { KTX_FORMAT_SIZE_PALETTIZED_BIT = 0x00000004, KTX_FORMAT_SIZE_DEPTH_BIT = 0x00000008, KTX_FORMAT_SIZE_STENCIL_BIT = 0x00000010, + KTX_FORMAT_SIZE_YUVSDA_BIT = 0x00000020, } ktxFormatSizeFlagBits; typedef ktx_uint32_t ktxFormatSizeFlags; diff --git a/thirdparty/libktx/lib/gl_format.h b/thirdparty/libktx/lib/gl_format.h index 2381505a68..3986bc430c 100644 --- a/thirdparty/libktx/lib/gl_format.h +++ b/thirdparty/libktx/lib/gl_format.h @@ -92,9 +92,9 @@ MODIFICATIONS for use in libktx #include "vkformat_enum.h" #if defined(_WIN32) && !defined(__MINGW32__) -#ifndef NOMINMAX +#if !defined(NOMINMAX) #define NOMINMAX -#endif +#endif // !defined(NOMINMAX) #ifndef __cplusplus #undef inline #define inline __inline diff --git a/thirdparty/libktx/lib/hashlist.c b/thirdparty/libktx/lib/hashlist.c index 0ca89fc561..acfe41e5fc 100644 --- a/thirdparty/libktx/lib/hashlist.c +++ b/thirdparty/libktx/lib/hashlist.c @@ -525,14 +525,38 @@ ktxHashList_Deserialize(ktxHashList* pHead, unsigned int kvdLen, void* pKvd) result = KTX_SUCCESS; while (result == KTX_SUCCESS && src < (char *)pKvd + kvdLen) { + if (src + 6 > (char *)pKvd + kvdLen) { + // Not enough space for another entry + return KTX_FILE_DATA_ERROR; + } + char* key; unsigned int keyLen, valueLen; void* value; ktx_uint32_t keyAndValueByteSize = *((ktx_uint32_t*)src); + if (src + 4 + keyAndValueByteSize > (char *)pKvd + kvdLen) { + // Not enough space for this entry + return KTX_FILE_DATA_ERROR; + } + src += sizeof(keyAndValueByteSize); key = src; - keyLen = (unsigned int)strlen(key) + 1; + keyLen = 0; + + while (keyLen < keyAndValueByteSize && key[keyLen] != '\0') keyLen++; + + if (key[keyLen] != '\0') { + // Missing NULL terminator + return KTX_FILE_DATA_ERROR; + } + + if (keyLen >= 3 && key[0] == '\xEF' && key[1] == '\xBB' && key[2] == '\xBF') { + // Forbidden BOM + return KTX_FILE_DATA_ERROR; + } + + keyLen += 1; value = key + keyLen; valueLen = keyAndValueByteSize - keyLen; diff --git a/thirdparty/libktx/lib/ktxint.h b/thirdparty/libktx/lib/ktxint.h index 03c9945ce7..fdfec56dcb 100644 --- a/thirdparty/libktx/lib/ktxint.h +++ b/thirdparty/libktx/lib/ktxint.h @@ -1,7 +1,7 @@ /* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ -/* $Id: e36ad79b5eac8ea237d6a05602c71aadab575519 $ */ +/* $Id$ */ /* * Copyright 2010-2020 The Khronos Group Inc. @@ -29,6 +29,9 @@ #ifndef MAX #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #endif +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif #define QUOTE(x) #x #define STR(x) QUOTE(x) @@ -212,6 +215,37 @@ KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat, GLint R16Formats, GLboolean supportsSRGB); /* + * @internal + * ktxCompressZLIBBounds + * + * Returns upper bound for compresses data using miniz (ZLIB) + */ +ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength); + +/* + * @internal + * ktxCompressZLIBInt + * + * Compresses data using miniz (ZLIB) + */ +KTX_error_code ktxCompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength, + ktx_uint32_t level); + +/* + * @internal + * ktxUncompressZLIBInt + * + * Uncompresses data using miniz (ZLIB) + */ +KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength); + +/* * Pad nbytes to next multiple of n */ #define _KTX_PADN(n, nbytes) (ktx_uint32_t)(n * ceilf((float)(nbytes) / n)) @@ -257,7 +291,55 @@ KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat, ====================================== */ -void printKTX2Info2(ktxStream* src, KTX_header2* header); +KTX_error_code printKTX2Info2(ktxStream* src, KTX_header2* header); + +/* + * fopen a file identified by a UTF-8 path. + */ +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <assert.h> +#include <windows.h> +#include <shellapi.h> +#include <stdlib.h> + +// For Windows, we convert the UTF-8 path and mode to UTF-16 path and use +// _wfopen which correctly handles unicode characters. +static inline FILE* ktxFOpenUTF8(char const* path, char const* mode) { + int wpLen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + int wmLen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + FILE* fp = NULL; + if (wpLen > 0 && wmLen > 0) + { + wchar_t* wpath = (wchar_t*)malloc(wpLen * sizeof(wchar_t)); + wchar_t* wmode = (wchar_t*)malloc(wmLen * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, wpLen); + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, wmLen); + // Returned errno_t value is also set in the global errno. + // Apps use that for error detail as libktx only returns + // KTX_FILE_OPEN_FAILED. + (void)_wfopen_s(&fp, wpath, wmode); + free(wpath); + free(wmode); + return fp; + } else { + assert(KTX_FALSE + && "ktxFOpenUTF8 called with zero length path or mode."); + return NULL; + } +} +#else +// For other platforms there is no need for any conversion, they +// support UTF-8 natively. +static inline FILE* ktxFOpenUTF8(char const* path, char const* mode) { + return fopen(path, mode); +} +#endif #ifdef __cplusplus } diff --git a/thirdparty/libktx/lib/miniz_wrapper.cpp b/thirdparty/libktx/lib/miniz_wrapper.cpp new file mode 100644 index 0000000000..cbd7da540a --- /dev/null +++ b/thirdparty/libktx/lib/miniz_wrapper.cpp @@ -0,0 +1,149 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright 2023-2023 The Khronos Group Inc. + * Copyright 2023-2023 RasterGrid Kft. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file miniz_wrapper.c + * @~English + * + * @brief Wrapper functions for ZLIB compression/decompression using miniz. + * + * @author Daniel Rakos, RasterGrid + */ + +#include "ktx.h" +#include "ktxint.h" + +#include <assert.h> + +#if !KTX_FEATURE_WRITE +// The reader does not link with the basisu components that already include a +// definition of miniz so we include it here explicitly. +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif +#include "encoder/basisu_miniz.h" +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#else +// Otherwise we only declare the interfaces and link with the basisu version. +// This is needed because while miniz is defined as a header in basisu it's +// not declaring the functions as static or inline, hence causing multiple +// conflicting definitions at link-time. +namespace buminiz { + typedef unsigned long mz_ulong; + enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + mz_ulong mz_compressBound(mz_ulong source_len); + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +} +#endif + +using namespace buminiz; + +extern "C" { + +/** + * @internal + * @~English + * @brief Returns upper bound for compresses data using miniz (ZLIB). + * + * @param srcLength source data length + * + * @author Daniel Rakos, RasterGrid + */ +ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength) { + return mz_compressBound((mz_ulong)srcLength); +} + +/** + * @internal + * @~English + * @brief Compresses data using miniz (ZLIB) + * + * @param pDest destination data buffer + * @param pDestLength destination data buffer size + * (filled with written byte count on success) + * @param pSrc source data buffer + * @param srcLength source data size + * @param level compression level (between 1 and 9) + * + * @author Daniel Rakos, RasterGrid + */ +KTX_error_code ktxCompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength, + ktx_uint32_t level) { + if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE; + mz_ulong mzCompressedSize = (mz_ulong)*pDestLength; + int status = mz_compress2(pDest, &mzCompressedSize, pSrc, (mz_ulong)srcLength, level); + switch (status) { + case MZ_OK: + *pDestLength = mzCompressedSize; + return KTX_SUCCESS; + case MZ_PARAM_ERROR: + return KTX_INVALID_VALUE; + case MZ_BUF_ERROR: +#ifdef DEBUG + assert(false && "Deflate dstSize too small."); +#endif + return KTX_OUT_OF_MEMORY; + case MZ_MEM_ERROR: +#ifdef DEBUG + assert(false && "Deflate workspace too small."); +#endif + return KTX_OUT_OF_MEMORY; + default: + // The remaining errors look like they should only + // occur during decompression but just in case. +#ifdef DEBUG + assert(true); +#endif + return KTX_INVALID_OPERATION; + } +} + +/** + * @internal + * @~English + * @brief Uncompresses data using miniz (ZLIB) + * + * @param pDest destination data buffer + * @param pDestLength destination data buffer size + * (filled with written byte count on success) + * @param pSrc source data buffer + * @param srcLength source data size + * + * @author Daniel Rakos, RasterGrid + */ +KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest, + ktx_size_t* pDestLength, + const unsigned char* pSrc, + ktx_size_t srcLength) { + if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE; + mz_ulong mzUncompressedSize = (mz_ulong)*pDestLength; + int status = mz_uncompress(pDest, &mzUncompressedSize, pSrc, (mz_ulong)srcLength); + switch (status) { + case MZ_OK: + *pDestLength = mzUncompressedSize; + return KTX_SUCCESS; + case MZ_BUF_ERROR: + return KTX_DECOMPRESS_LENGTH_ERROR; // buffer too small + case MZ_MEM_ERROR: + return KTX_OUT_OF_MEMORY; + default: + return KTX_FILE_DATA_ERROR; + } +} + +} diff --git a/thirdparty/libktx/lib/swap.c b/thirdparty/libktx/lib/swap.c index 3fdeb4f3a4..02ea6de2d8 100644 --- a/thirdparty/libktx/lib/swap.c +++ b/thirdparty/libktx/lib/swap.c @@ -1,7 +1,7 @@ /* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ -/* $Id: 02ea6de2d8db512ca3af08f48b98ab5f6c35e7e5 $ */ +/* $Id$ */ /* * Copyright 2010-2020 The Khronos Group Inc. diff --git a/thirdparty/libktx/lib/texture.c b/thirdparty/libktx/lib/texture.c index 35619a3e73..76821e195b 100644 --- a/thirdparty/libktx/lib/texture.c +++ b/thirdparty/libktx/lib/texture.c @@ -8,7 +8,7 @@ /** * @internal - * @file writer.c + * @file texture.c * @~English * * @brief ktxTexture implementation. @@ -305,10 +305,13 @@ ktxDetermineFileType_(ktxStream* pStream, ktxFileType_* pFileType, /** * @memberof ktxTexture * @~English - * @brief Construct (initialize) a ktx1 or ktx2 texture according to the stream + * @brief Create a ktx1 or ktx2 texture according to the stream * data. * - * @copydetails ktxTexture_CreateFromStdioStream + * See @ref ktxTexture1::ktxTexture1_CreateFromStream + * "ktxTexture1_CreateFromStream" or + * @ref ktxTexture2::ktxTexture2_CreateFromStream + * "ktxTexture2_CreateFromStream" for details. */ KTX_error_code ktxTexture_CreateFromStream(ktxStream* pStream, @@ -359,7 +362,10 @@ ktxTexture_CreateFromStream(ktxStream* pStream, * @brief Create a ktxTexture1 or ktxTexture2 from a stdio stream according * to the stream data. * - * @copydetails ktxTexture1_CreateFromStdioStream() + * See @ref ktxTexture1::ktxTexture1_CreateFromStdioStream + * "ktxTexture1_CreateFromStdioStream" or + * @ref ktxTexture2::ktxTexture2_CreateFromStdioStream + * "ktxTexture2_CreateFromStdioStream" for details. */ KTX_error_code ktxTexture_CreateFromStdioStream(FILE* stdioStream, @@ -385,29 +391,10 @@ ktxTexture_CreateFromStdioStream(FILE* stdioStream, * @brief Create a ktxTexture1 or ktxTexture2 from a named KTX file according * to the file contents. * - * The address of a newly created ktxTexture reflecting the contents of the - * file is written to the location pointed at by @p newTex. - * - * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, - * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This - * will minimize memory usage by allowing, for example, loading the images - * directly from the source into a Vulkan staging buffer. - * - * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is - * provided solely to enable implementation of the @e libktx v1 API on top of - * ktxTexture. - * - * @param[in] filename pointer to a char array containing the file name. - * @param[in] createFlags bitmask requesting specific actions during creation. - * @param[in,out] newTex pointer to a location in which store the address of - * the newly created texture. - * - * @return KTX_SUCCESS on success, other KTX_* enum values on error. - - * @exception KTX_FILE_OPEN_FAILED The file could not be opened. - * @exception KTX_INVALID_VALUE @p filename is @c NULL. - * - * For other exceptions, see ktxTexture_CreateFromStdioStream(). + * See @ref ktxTexture1::ktxTexture1_CreateFromNamedFile + * "ktxTexture1_CreateFromNamedFile" or + * @ref ktxTexture2::ktxTexture2_CreateFromNamedFile + * "ktxTexture2_CreateFromNamedFile" for details. */ KTX_error_code ktxTexture_CreateFromNamedFile(const char* const filename, @@ -421,7 +408,7 @@ ktxTexture_CreateFromNamedFile(const char* const filename, if (filename == NULL || newTex == NULL) return KTX_INVALID_VALUE; - file = fopen(filename, "rb"); + file = ktxFOpenUTF8(filename, "rb"); if (!file) return KTX_FILE_OPEN_FAILED; @@ -438,29 +425,10 @@ ktxTexture_CreateFromNamedFile(const char* const filename, * @brief Create a ktxTexture1 or ktxTexture2 from KTX-formatted data in memory * according to the data contents. * - * The address of a newly created ktxTexture reflecting the contents of the - * serialized KTX data is written to the location pointed at by @p newTex. - * - * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, - * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This - * will minimize memory usage by allowing, for example, loading the images - * directly from the source into a Vulkan staging buffer. - * - * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is - * provided solely to enable implementation of the @e libktx v1 API on top of - * ktxTexture. - * - * @param[in] bytes pointer to the memory containing the serialized KTX data. - * @param[in] size length of the KTX data in bytes. - * @param[in] createFlags bitmask requesting specific actions during creation. - * @param[in,out] newTex pointer to a location in which store the address of - * the newly created texture. - * - * @return KTX_SUCCESS on success, other KTX_* enum values on error. - * - * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. - * - * For other exceptions, see ktxTexture_CreateFromStdioStream(). + * See @ref ktxTexture1::ktxTexture1_CreateFromMemory + * "ktxTexture1_CreateFromMemory" or + * @ref ktxTexture2::ktxTexture2_CreateFromMemory + * "ktxTexture2_CreateFromMemory" for details. */ KTX_error_code ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, @@ -567,7 +535,7 @@ ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level, blockCount.y = (ktx_uint32_t)ceilf(levelHeight / prtctd->_formatSize.blockHeight); blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x); - blockCount.y = MAX(prtctd->_formatSize.minBlocksX, blockCount.y); + blockCount.y = MAX(prtctd->_formatSize.minBlocksY, blockCount.y); blockSizeInBytes = prtctd->_formatSize.blockSizeInBits / 8; @@ -726,8 +694,10 @@ ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level, ktx_size_t imageSize, layerSize; assert (This != NULL); + assert (prtctd->_formatSize.blockDepth != 0); - blockCountZ = MAX(1, (This->baseDepth / prtctd->_formatSize.blockDepth) >> level); + blockCountZ = ((This->baseDepth >> level) + prtctd->_formatSize.blockDepth - 1) / prtctd->_formatSize.blockDepth; + blockCountZ = MAX(1, blockCountZ); imageSize = ktxTexture_calcImageSize(This, level, fv); layerSize = imageSize * blockCountZ; if (fv == KTX_FORMAT_VERSION_ONE && KTX_GL_UNPACK_ALIGNMENT != 4) { diff --git a/thirdparty/libktx/lib/texture1.c b/thirdparty/libktx/lib/texture1.c index 8420f402b2..1591f3b6dc 100644 --- a/thirdparty/libktx/lib/texture1.c +++ b/thirdparty/libktx/lib/texture1.c @@ -458,6 +458,9 @@ ktxTexture1_constructFromStdioStream(ktxTexture1* This, FILE* stdioStream, * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from a named KTX file. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * See ktxTextureInt_constructFromStream for details. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to @@ -484,7 +487,7 @@ ktxTexture1_constructFromNamedFile(ktxTexture1* This, if (This == NULL || filename == NULL) return KTX_INVALID_VALUE; - file = fopen(filename, "rb"); + file = ktxFOpenUTF8(filename, "rb"); if (!file) return KTX_FILE_OPEN_FAILED; @@ -614,7 +617,7 @@ ktxTexture1_Create(ktxTextureCreateInfo* createInfo, * @~English * @brief Create a ktxTexture1 from a stdio stream reading from a KTX source. * - * The address of a newly created ktxTexture1 reflecting the contents of the + * The address of a newly created texture reflecting the contents of the * stdio stream is written to the location pointed at by @p newTex. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, @@ -673,14 +676,17 @@ ktxTexture1_CreateFromStdioStream(FILE* stdioStream, return result; } -/* +/** * @memberof ktxTexture1 * @~English * @brief Create a ktxTexture1 from a named KTX file. * - * The address of a newly created ktxTexture1 reflecting the contents of the + * The address of a newly created texture reflecting the contents of the * file is written to the location pointed at by @p newTex. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images @@ -700,7 +706,7 @@ ktxTexture1_CreateFromStdioStream(FILE* stdioStream, * @exception KTX_FILE_OPEN_FAILED The file could not be opened. * @exception KTX_INVALID_VALUE @p filename is @c NULL. * - * For other exceptions, see ktxTexture_CreateFromStdioStream(). + * For other exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromNamedFile(const char* const filename, @@ -731,7 +737,7 @@ ktxTexture1_CreateFromNamedFile(const char* const filename, * @~English * @brief Create a ktxTexture1 from KTX-formatted data in memory. * - * The address of a newly created ktxTexture1 reflecting the contents of the + * The address of a newly created texture reflecting the contents of the * serialized KTX data is written to the location pointed at by @p newTex. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, @@ -753,7 +759,7 @@ ktxTexture1_CreateFromNamedFile(const char* const filename, * * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. * - * For other exceptions, see ktxTexture_CreateFromStdioStream(). + * For other exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, @@ -784,7 +790,7 @@ ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, * @~English * @brief Create a ktxTexture1 from KTX-formatted data from a `ktxStream`. * - * The address of a newly created ktxTexture1 reflecting the contents of the + * The address of a newly created texture reflecting the contents of the * serialized KTX data is written to the location pointed at by @p newTex. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, @@ -796,19 +802,17 @@ ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * - * @param[in] stream pointer to the stream to read KTX data from. + * @param[in] pStream pointer to the stream to read KTX data from. * @param[in] createFlags bitmask requesting specific actions during creation. * @param[in,out] newTex pointer to a location in which store the address of * the newly created texture. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * - * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. - * - * For other exceptions, see ktxTexture_CreateFromStdioStream(). + * For exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code -ktxTexture1_CreateFromStream(ktxStream* stream, +ktxTexture1_CreateFromStream(ktxStream* pStream, ktxTextureCreateFlags createFlags, ktxTexture1** newTex) { @@ -820,7 +824,7 @@ ktxTexture1_CreateFromStream(ktxStream* stream, if (tex == NULL) return KTX_OUT_OF_MEMORY; - result = ktxTexture1_constructFromStream(tex, stream, createFlags); + result = ktxTexture1_constructFromStream(tex, pStream, createFlags); if (result == KTX_SUCCESS) *newTex = (ktxTexture1*)tex; else { @@ -1044,9 +1048,9 @@ ktxTexture1_glTypeSize(ktxTexture1* This) * @~English * @brief Iterate over the mip levels in a ktxTexture1 object. * - * This is almost identical to ktxTexture_IterateLevelFaces(). The difference is - * that the blocks of image data for non-array cube maps include all faces of - * a mip level. + * This is almost identical to @ref ktxTexture::ktxTexture_IterateLevelFaces + * "ktxTexture_IterateLevelFaces". The difference is that the blocks of image + * data for non-array cube maps include all faces of a mip level. * * This function works even if @p This->pData == 0 so it can be used to * obtain offsets and sizes for each level by callers who have loaded the data @@ -1114,11 +1118,12 @@ ktxTexture1_IterateLevels(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata * @brief Iterate over the images in a ktxTexture1 object while loading the * image data. * - * This operates similarly to ktxTexture_IterateLevelFaces() except that it - * loads the images from the ktxTexture1's source to a temporary buffer - * while iterating. The callback function must copy the image data if it - * wishes to preserve it as the temporary buffer is reused for each level and - * is freed when this function exits. + * This operates similarly to @ref ktxTexture::ktxTexture_IterateLevelFaces + * "ktxTexture_IterateLevelFaces" except that it loads the images from the + * ktxTexture1's source to a temporary buffer while iterating. The callback + * function must copy the image data if it wishes to preserve it as the + * temporary buffer is reused for each level and is freed when this function + * exits. * * This function is helpful for reducing memory usage when uploading the data * to a graphics API. diff --git a/thirdparty/libktx/lib/texture2.c b/thirdparty/libktx/lib/texture2.c index afbe7dcbfe..173e5026d9 100644 --- a/thirdparty/libktx/lib/texture2.c +++ b/thirdparty/libktx/lib/texture2.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> +#include <math.h> #include <zstd.h> #include <zstd_errors.h> #include <KHR/khr_df.h> @@ -293,6 +294,10 @@ ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd) return false; if (result & i_PACKED_FORMAT_BIT) This->flags |= KTX_FORMAT_SIZE_PACKED_BIT; + if (result & i_COMPRESSED_FORMAT_BIT) + This->flags |= KTX_FORMAT_SIZE_COMPRESSED_BIT; + if (result & i_YUVSDA_FORMAT_BIT) + This->flags |= KTX_FORMAT_SIZE_YUVSDA_BIT; } } if (This->blockSizeInBits == 0) { @@ -325,20 +330,7 @@ ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd) static uint32_t* ktxVk2dfd(ktx_uint32_t vkFormat) { - switch(vkFormat) { - case VK_FORMAT_D16_UNORM_S8_UINT: - // 2 16-bit words. D16 in the first. S8 in the 8 LSBs of the second. - return createDFDDepthStencil(16, 8, 4); - case VK_FORMAT_D24_UNORM_S8_UINT: - // 1 32-bit word. D24 in the MSBs. S8 in the LSBs. - return createDFDDepthStencil(24, 8, 4); - case VK_FORMAT_D32_SFLOAT_S8_UINT: - // 2 32-bit words. D32 float in the first word. S8 in LSBs of the - // second. - return createDFDDepthStencil(32, 8, 8); - default: - return vk2dfd(vkFormat); - } + return vk2dfd(vkFormat); } /** @@ -419,7 +411,7 @@ ktxTexture2_construct(ktxTexture2* This, ktxTextureCreateInfo* createInfo, if (!This->pDfd) return KTX_OUT_OF_MEMORY; memcpy(This->pDfd, createInfo->pDfd, *createInfo->pDfd); - if (ktxFormatSize_initFromDfd(&formatSize, This->pDfd)) { + if (!ktxFormatSize_initFromDfd(&formatSize, This->pDfd)) { result = KTX_UNSUPPORTED_TEXTURE_TYPE; goto cleanup; } @@ -437,15 +429,26 @@ ktxTexture2_construct(ktxTexture2* This, ktxTextureCreateInfo* createInfo, // Ideally we'd set all these things in ktxFormatSize_initFromDfd // but This->_protected is not allocated until ktxTexture_construct; - if (This->isCompressed) + if (This->isCompressed && (formatSize.flags & KTX_FORMAT_SIZE_YUVSDA_BIT) == 0) { This->_protected->_typeSize = 1; - else if (formatSize.flags & KTX_FORMAT_SIZE_PACKED_BIT) - This->_protected->_typeSize = formatSize.blockSizeInBits / 8; - else if (formatSize.flags & (KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT)) { - if (createInfo->vkFormat == VK_FORMAT_D16_UNORM_S8_UINT) + } else if (formatSize.flags & (KTX_FORMAT_SIZE_DEPTH_BIT | KTX_FORMAT_SIZE_STENCIL_BIT)) { + switch (createInfo->vkFormat) { + case VK_FORMAT_S8_UINT: + This->_protected->_typeSize = 1; + break; + case VK_FORMAT_D16_UNORM: // [[fallthrough]]; + case VK_FORMAT_D16_UNORM_S8_UINT: This->_protected->_typeSize = 2; - else + break; + case VK_FORMAT_X8_D24_UNORM_PACK32: // [[fallthrough]]; + case VK_FORMAT_D24_UNORM_S8_UINT: // [[fallthrough]]; + case VK_FORMAT_D32_SFLOAT: // [[fallthrough]]; + case VK_FORMAT_D32_SFLOAT_S8_UINT: This->_protected->_typeSize = 4; + break; + } + } else if (formatSize.flags & KTX_FORMAT_SIZE_PACKED_BIT) { + This->_protected->_typeSize = formatSize.blockSizeInBits / 8; } else { // Unpacked and uncompressed uint32_t numComponents; @@ -503,7 +506,7 @@ cleanup: * * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data. */ -static KTX_error_code +KTX_error_code ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig) { KTX_error_code result; @@ -648,6 +651,7 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, KTX_error_code result; KTX_supplemental_info suppInfo; ktxStream* stream; + struct BDFD* pBDFD; ktx_size_t levelIndexSize; assert(pHeader != NULL && pStream != NULL); @@ -721,9 +725,21 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, for (ktx_uint32_t level = 0; level < This->numLevels; level++) { private->_levelIndex[level].byteOffset -= private->_firstLevelFileOffset; + if (This->supercompressionScheme == KTX_SS_NONE && + private->_levelIndex[level].byteLength != private->_levelIndex[level].uncompressedByteLength) { + // For non-supercompressed files the levels must have matching byte lengths + result = KTX_FILE_DATA_ERROR; + } } + if (result != KTX_SUCCESS) + goto cleanup; // Read DFD + if (pHeader->dataFormatDescriptor.byteOffset == 0 || pHeader->dataFormatDescriptor.byteLength < 16) { + // Missing or too small DFD + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } This->pDfd = (ktx_uint32_t*)malloc(pHeader->dataFormatDescriptor.byteLength); if (!This->pDfd) { @@ -735,19 +751,87 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, if (result != KTX_SUCCESS) goto cleanup; + if (pHeader->dataFormatDescriptor.byteLength != This->pDfd[0]) { + // DFD byteLength does not match dfdTotalSize + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + pBDFD = (struct BDFD*)(This->pDfd + 1); + if (pBDFD->descriptorBlockSize < 24 || (pBDFD->descriptorBlockSize - 24) % 16 != 0) { + // BDFD has invalid size + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->transfer != KHR_DF_TRANSFER_LINEAR && pBDFD->transfer != KHR_DF_TRANSFER_SRGB) { + // Unsupported transfer function + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (!ktxFormatSize_initFromDfd(&This->_protected->_formatSize, This->pDfd)) { result = KTX_UNSUPPORTED_TEXTURE_TYPE; goto cleanup; } This->isCompressed = (This->_protected->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT); - if (This->supercompressionScheme == KTX_SS_BASIS_LZ - && KHR_DFDVAL(This->pDfd + 1, MODEL) != KHR_DF_MODEL_ETC1S) - { + if (This->supercompressionScheme == KTX_SS_BASIS_LZ && pBDFD->model != KHR_DF_MODEL_ETC1S) { result = KTX_FILE_DATA_ERROR; goto cleanup; } + // Check compatibility with the KHR_texture_basisu glTF extension, if needed. + if (createFlags & KTX_TEXTURE_CREATE_CHECK_GLTF_BASISU_BIT) { + uint32_t max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); + uint32_t full_mip_pyramid_level_count = 1 + (uint32_t)log2(max_dim); + if (pHeader->levelCount != 1 && pHeader->levelCount != full_mip_pyramid_level_count) { + // KHR_texture_basisu requires full mip pyramid or single mip level + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (This->numDimensions != 2 || This->isArray || This->isCubemap) { + // KHR_texture_basisu requires 2D textures. + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if ((This->baseWidth % 4) != 0 || (This->baseHeight % 4) != 0) { + // KHR_texture_basisu requires width and height to be a multiple of 4. + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->model != KHR_DF_MODEL_ETC1S && pBDFD->model != KHR_DF_MODEL_UASTC) { + // KHR_texture_basisu requires BasisLZ or UASTC + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->model == KHR_DF_MODEL_UASTC && + This->supercompressionScheme != KTX_SS_NONE && + This->supercompressionScheme != KTX_SS_ZSTD) { + // KHR_texture_basisu only allows NONE and ZSTD supercompression for UASTC + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + } + + uint32_t sampleCount = KHR_DFDSAMPLECOUNT(This->pDfd + 1); + if (sampleCount == 0) { + // Invalid sample count + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->model == KHR_DF_MODEL_ETC1S || pBDFD->model == KHR_DF_MODEL_UASTC) { + if (sampleCount < 1 || sampleCount > 2 || (sampleCount == 2 && pBDFD->model == KHR_DF_MODEL_UASTC)) { + // Invalid sample count + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + if (pBDFD->texelBlockDimension0 != 3 || pBDFD->texelBlockDimension1 != 3 || + pBDFD->texelBlockDimension2 != 0 || pBDFD->texelBlockDimension3 != 0) { + // Texel block dimension must be 4x4x1x1 (offset by one) + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } + } + This->_private->_requiredLevelAlignment = ktxTexture2_calcRequiredLevelAlignment(This); @@ -755,6 +839,12 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, ktxHashList_Construct(&This->kvDataHead); // Load KVData. if (pHeader->keyValueData.byteLength > 0) { + uint32_t expectedOffset = pHeader->dataFormatDescriptor.byteOffset + pHeader->dataFormatDescriptor.byteLength; + expectedOffset = (expectedOffset + 3) & ~0x3; // 4 byte aligned + if (pHeader->keyValueData.byteOffset != expectedOffset) { + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) { ktx_uint32_t kvdLen = pHeader->keyValueData.byteLength; ktx_uint8_t* pKvd; @@ -850,9 +940,30 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, } else { stream->skip(stream, pHeader->keyValueData.byteLength); } + } else if (pHeader->keyValueData.byteOffset != 0) { + // Non-zero KVD byteOffset with zero byteLength + result = KTX_FILE_DATA_ERROR; + goto cleanup; } if (pHeader->supercompressionGlobalData.byteLength > 0) { + switch (This->supercompressionScheme) { + case KTX_SS_BASIS_LZ: + break; + case KTX_SS_NONE: + case KTX_SS_ZSTD: + case KTX_SS_ZLIB: + // In these cases SGD is not allowed + result = KTX_FILE_DATA_ERROR; + break; + default: + // We don't support other supercompression schemes + result = KTX_UNSUPPORTED_FEATURE; + break; + } + if (result != KTX_SUCCESS) + goto cleanup; + // There could be padding here so seek to the next item. (void)stream->setpos(stream, pHeader->supercompressionGlobalData.byteOffset); @@ -871,6 +982,14 @@ ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, if (result != KTX_SUCCESS) goto cleanup; + } else if (pHeader->supercompressionGlobalData.byteOffset != 0) { + // Non-zero SGD byteOffset with zero byteLength + result = KTX_FILE_DATA_ERROR; + goto cleanup; + } else if (This->supercompressionScheme == KTX_SS_BASIS_LZ) { + // SGD is required for BasisLZ + result = KTX_FILE_DATA_ERROR; + goto cleanup; } // Calculate size of the image data. Level 0 is the last level in the data. @@ -982,6 +1101,9 @@ ktxTexture2_constructFromStdioStream(ktxTexture2* This, FILE* stdioStream, * @~English * @brief Construct a ktxTexture from a named KTX file. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * See ktxTextureInt_constructFromStream for details. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to @@ -1008,7 +1130,7 @@ ktxTexture2_constructFromNamedFile(ktxTexture2* This, if (This == NULL || filename == NULL) return KTX_INVALID_VALUE; - file = fopen(filename, "rb"); + file = ktxFOpenUTF8(filename, "rb"); if (!file) return KTX_FILE_OPEN_FAILED; @@ -1259,6 +1381,9 @@ ktxTexture2_CreateFromStdioStream(FILE* stdioStream, * The address of a newly created ktxTexture2 reflecting the contents of the * file is written to the location pointed at by @p newTex. * + * The file name must be encoded in utf-8. On Windows convert unicode names + * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. + * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images @@ -1581,7 +1706,7 @@ ktxTexture2_calcPostInflationLevelAlignment(ktxTexture2* This) // Should actually work for none supercompressed but don't want to // encourage use of it. - assert(This->supercompressionScheme >= KTX_SS_ZSTD); + assert(This->supercompressionScheme != KTX_SS_NONE && This->supercompressionScheme != KTX_SS_BASIS_LZ); if (This->vkFormat != VK_FORMAT_UNDEFINED) alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8); @@ -1834,15 +1959,17 @@ ktxTexture2_NeedsTranscoding(ktxTexture2* This) /** * @memberof ktxTexture2 * @~English - * @brief Return the total size in bytes of the uncompressed data of a ktxTexture2. - * - * If supercompressionScheme == KTX_SS_NONE or - * KTX_SS_BASIS_LZ, returns the value of @c This->dataSize - * else if supercompressionScheme == KTX_SS_ZSTD, it returns the - * sum of the uncompressed sizes of each mip level plus space for the level padding. With no - * supercompression the data size and uncompressed data size are the same. For Basis - * supercompression the uncompressed size cannot be known until the data is transcoded - * so the compressed size is returned. + * @brief Return the total size in bytes of the uncompressed data of a + * ktxTexture2. + * + * If supercompressionScheme == @c KTX_SS_NONE or + * @c KTX_SS_BASIS_LZ, returns the value of @c This->dataSize + * else if supercompressionScheme == @c KTX_SS_ZSTD or @c KTX_SS_ZLIB, it + * returns the sum of the uncompressed sizes of each mip level plus space for + * the level padding. With no supercompression the data size and uncompressed + * data size are the same. For Basis supercompression the uncompressed size + * cannot be known until the data is transcoded so the compressed size is + * returned. * * @param[in] This pointer to the ktxTexture1 object of interest. */ @@ -1854,6 +1981,7 @@ ktxTexture2_GetDataSizeUncompressed(ktxTexture2* This) case KTX_SS_NONE: return This->dataSize; case KTX_SS_ZSTD: + case KTX_SS_ZLIB: { ktx_size_t uncompressedSize = 0; ktx_uint32_t uncompressedLevelAlignment; @@ -1984,7 +2112,7 @@ ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata * * This operates similarly to ktxTexture_IterateLevelFaces() except that it * loads the images from the ktxTexture2's source to a temporary buffer - * while iterating. If supercompressionScheme == KTX_SS_ZSTD, + * while iterating. If supercompressionScheme == KTX_SS_ZSTD or KTX_SS_ZLIB, * it will inflate the data before passing it to the callback. The callback function * must copy the image data if it wishes to preserve it as the temporary buffer * is reused for each level and is freed when this function exits. @@ -1992,8 +2120,8 @@ ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata * This function is helpful for reducing memory usage when uploading the data * to a graphics API. * - * Intended for use only when supercompressionScheme == SUPERCOMPRESSION_NONE - * or SUPERCOMPRESSION_ZSTD. As there is no access to the ktxTexture's data on + * Intended for use only when supercompressionScheme == KTX_SS_NONE, + * KTX_SS_ZSTD or KTX_SS_ZLIB. As there is no access to the ktxTexture's data on * conclusion of this function, destroying the texture on completion is recommended. * * @param[in] This pointer to the ktxTexture2 object of interest. @@ -2013,8 +2141,9 @@ ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata * this ktxTexture2's images have already * been loaded. * @exception KTX_INVALID_OPERATION - * supercompressionScheme != SUPERCOMPRESSION_NONE. - * and supercompressionScheme != SUPERCOMPRESSION_ZSTD. + * supercompressionScheme != KTX_SS_NONE, + * supercompressionScheme != KTX_SS_ZSTD, and + * supercompressionScheme != KTX_SS_ZLIB. * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. * @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to * hold the base level image. @@ -2040,7 +2169,8 @@ ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, return KTX_INVALID_OPERATION; if (This->supercompressionScheme != KTX_SS_NONE && - This->supercompressionScheme != KTX_SS_ZSTD) + This->supercompressionScheme != KTX_SS_ZSTD && + This->supercompressionScheme != KTX_SS_ZLIB) return KTX_INVALID_OPERATION; if (iterCb == NULL) @@ -2057,14 +2187,16 @@ ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, dataBuf = malloc(dataSize); if (!dataBuf) return KTX_OUT_OF_MEMORY; - if (This->supercompressionScheme == KTX_SS_ZSTD) { + if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) { uncompressedDataSize = levelIndex[0].uncompressedByteLength; uncompressedDataBuf = malloc(uncompressedDataSize); if (!uncompressedDataBuf) { result = KTX_OUT_OF_MEMORY; goto cleanup; } - dctx = ZSTD_createDCtx(); + if (This->supercompressionScheme == KTX_SS_ZSTD) { + dctx = ZSTD_createDCtx(); + } pData = uncompressedDataBuf; } else { pData = dataBuf; @@ -2107,21 +2239,34 @@ ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb, ZSTD_ErrorCode error = ZSTD_getErrorCode(levelSize); switch(error) { case ZSTD_error_dstSize_tooSmall: - return KTX_INVALID_VALUE; // inflatedDataCapacity too small. + return KTX_DECOMPRESS_LENGTH_ERROR; // inflatedDataCapacity too small. + case ZSTD_error_checksum_wrong: + return KTX_DECOMPRESS_CHECKSUM_ERROR; case ZSTD_error_memory_allocation: return KTX_OUT_OF_MEMORY; default: return KTX_FILE_DATA_ERROR; } } + // We don't fix up the texture's dataSize, levelIndex or // _requiredAlignment because after this function completes there // is no way to get at the texture's data. //nindex[level].byteOffset = levelOffset; //nindex[level].uncompressedByteLength = nindex[level].byteLength = //levelByteLength; + } else if (This->supercompressionScheme == KTX_SS_ZLIB) { + result = ktxUncompressZLIBInt(uncompressedDataBuf, + &uncompressedDataSize, + dataBuf, + levelSize); + if (result != KTX_SUCCESS) + return result; } + if (levelIndex[level].uncompressedByteLength != levelSize) + return KTX_DECOMPRESS_LENGTH_ERROR; + #if IS_BIG_ENDIAN switch (prtctd->_typeSize) { case 2: @@ -2188,16 +2333,23 @@ KTX_error_code ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, ktx_uint8_t* pInflatedData, ktx_size_t inflatedDataCapacity); + +KTX_error_code +ktxTexture2_inflateZLIBInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, + ktx_uint8_t* pInflatedData, + ktx_size_t inflatedDataCapacity); + /** * @memberof ktxTexture2 * @~English * @brief Load all the image data from the ktxTexture2's source. * - * The data will be inflated if supercompressionScheme == SUPERCOMPRESSION_ZSTD. + * The data will be inflated if supercompressionScheme == @c KTX_SS_ZSTD or + * @c KTX_SS_ZLIB. * The data is loaded into the provided buffer or to an internally allocated * buffer, if @p pBuffer is @c NULL. Callers providing their own buffer must * ensure the buffer large enough to hold the inflated data for files deflated - * with Zstd. See ktxTexture2_GetDataSizeUncompressed(). + * with Zstd or ZLIB. See ktxTexture2\_GetDataSizeUncompressed(). * * The texture's levelIndex, dataSize, DFD and supercompressionScheme will * all be updated after successful inflation to reflect the inflated data. @@ -2248,7 +2400,7 @@ ktxTexture2_LoadImageData(ktxTexture2* This, pDest = pBuffer; } - if (This->supercompressionScheme == KTX_SS_ZSTD) { + if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) { // Create buffer to hold deflated data. pDeflatedData = malloc(This->dataSize); if (pDeflatedData == NULL) @@ -2271,10 +2423,15 @@ ktxTexture2_LoadImageData(ktxTexture2* This, if (result != KTX_SUCCESS) return result; - if (This->supercompressionScheme == KTX_SS_ZSTD) { + if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) { assert(pDeflatedData != NULL); - result = ktxTexture2_inflateZstdInt(This, pDeflatedData, pDest, - inflatedDataCapacity); + if (This->supercompressionScheme == KTX_SS_ZSTD) { + result = ktxTexture2_inflateZstdInt(This, pDeflatedData, pDest, + inflatedDataCapacity); + } else if (This->supercompressionScheme == KTX_SS_ZLIB) { + result = ktxTexture2_inflateZLIBInt(This, pDeflatedData, pDest, + inflatedDataCapacity); + } free(pDeflatedData); if (result != KTX_SUCCESS) { if (pBuffer == NULL) { @@ -2388,13 +2545,19 @@ ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, ZSTD_ErrorCode error = ZSTD_getErrorCode(levelByteLength); switch(error) { case ZSTD_error_dstSize_tooSmall: - return KTX_INVALID_VALUE; // inflatedDataCapacity too small. + return KTX_DECOMPRESS_LENGTH_ERROR; // inflatedDataCapacity too small. + case ZSTD_error_checksum_wrong: + return KTX_DECOMPRESS_CHECKSUM_ERROR; case ZSTD_error_memory_allocation: return KTX_OUT_OF_MEMORY; default: return KTX_FILE_DATA_ERROR; } } + + if (This->_private->_levelIndex[level].uncompressedByteLength != levelByteLength) + return KTX_DECOMPRESS_LENGTH_ERROR; + nindex[level].byteOffset = levelOffset; nindex[level].uncompressedByteLength = nindex[level].byteLength = levelByteLength; @@ -2421,6 +2584,89 @@ ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, return KTX_SUCCESS; } +/** + * @memberof ktxTexture2 @private + * @~English + * @brief Inflate the data in a ktxTexture2 object using miniz (ZLIB). + * + * The texture's levelIndex, dataSize, DFD and supercompressionScheme will + * all be updated after successful inflation to reflect the inflated data. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] pDeflatedData pointer to a buffer containing the deflated + * data of the entire texture. + * @param[in,out] pInflatedData pointer to a buffer in which to write the + * inflated data. + * @param[in] inflatedDataCapacity capacity of the buffer pointed at by + * @p pInflatedData. + */ +KTX_error_code +ktxTexture2_inflateZLIBInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData, + ktx_uint8_t* pInflatedData, + ktx_size_t inflatedDataCapacity) +{ + DECLARE_PROTECTED(ktxTexture); + ktx_uint32_t levelIndexByteLength = + This->numLevels * sizeof(ktxLevelIndexEntry); + uint64_t levelOffset = 0; + ktxLevelIndexEntry* cindex = This->_private->_levelIndex; + ktxLevelIndexEntry* nindex; + ktx_uint32_t uncompressedLevelAlignment; + + if (pDeflatedData == NULL) + return KTX_INVALID_VALUE; + + if (pInflatedData == NULL) + return KTX_INVALID_VALUE; + + if (This->supercompressionScheme != KTX_SS_ZLIB) + return KTX_INVALID_OPERATION; + + nindex = malloc(levelIndexByteLength); + if (nindex == NULL) + return KTX_OUT_OF_MEMORY; + + uncompressedLevelAlignment = + ktxTexture2_calcPostInflationLevelAlignment(This); + + ktx_size_t inflatedByteLength = 0; + for (int32_t level = This->numLevels - 1; level >= 0; level--) { + size_t levelByteLength = inflatedDataCapacity; + KTX_error_code result = ktxUncompressZLIBInt(pInflatedData + levelOffset, + &levelByteLength, + &pDeflatedData[cindex[level].byteOffset], + cindex[level].byteLength); + if (result != KTX_SUCCESS) + return result; + + if (This->_private->_levelIndex[level].uncompressedByteLength != levelByteLength) + return KTX_DECOMPRESS_LENGTH_ERROR; + + nindex[level].byteOffset = levelOffset; + nindex[level].uncompressedByteLength = nindex[level].byteLength = + levelByteLength; + ktx_size_t paddedLevelByteLength + = _KTX_PADN(uncompressedLevelAlignment, levelByteLength); + inflatedByteLength += paddedLevelByteLength; + levelOffset += paddedLevelByteLength; + inflatedDataCapacity -= paddedLevelByteLength; + } + + // Now modify the texture. + + This->dataSize = inflatedByteLength; + This->supercompressionScheme = KTX_SS_NONE; + memcpy(cindex, nindex, levelIndexByteLength); // Update level index + free(nindex); + This->_private->_requiredLevelAlignment = uncompressedLevelAlignment; + // Set bytesPlane as we're now sized. + uint32_t* bdb = This->pDfd + 1; + // blockSizeInBits was set to the inflated size on file load. + bdb[KHR_DF_WORD_BYTESPLANE0] = prtctd->_formatSize.blockSizeInBits / 8; + + return KTX_SUCCESS; +} + #if !KTX_FEATURE_WRITE /* diff --git a/thirdparty/libktx/lib/texture2.h b/thirdparty/libktx/lib/texture2.h index 14e4115ecf..08507804d9 100644 --- a/thirdparty/libktx/lib/texture2.h +++ b/thirdparty/libktx/lib/texture2.h @@ -51,6 +51,8 @@ ktxTexture2_LoadImageData(ktxTexture2* This, ktx_uint8_t* pBuffer, ktx_size_t bufSize); KTX_error_code +ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig); +KTX_error_code ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream, KTX_header2* pHeader, ktxTextureCreateFlags createFlags); diff --git a/thirdparty/libktx/lib/vkformat_check.c b/thirdparty/libktx/lib/vkformat_check.c new file mode 100644 index 0000000000..e987b3d76a --- /dev/null +++ b/thirdparty/libktx/lib/vkformat_check.c @@ -0,0 +1,165 @@ + +/***************************** Do not edit. ***************************** + Automatically generated from vulkan_core.h version 267 by mkvkformatfiles. + *************************************************************************/ + +/* +** Copyright 2015-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +#include <stdint.h> +#include <stdbool.h> + +#include "vkformat_enum.h" + +bool +isProhibitedFormat(VkFormat format) +{ + switch (format) { + case VK_FORMAT_R8_USCALED: + case VK_FORMAT_R8_SSCALED: + case VK_FORMAT_R8G8_USCALED: + case VK_FORMAT_R8G8_SSCALED: + case VK_FORMAT_R8G8B8_USCALED: + case VK_FORMAT_R8G8B8_SSCALED: + case VK_FORMAT_B8G8R8_USCALED: + case VK_FORMAT_B8G8R8_SSCALED: + case VK_FORMAT_R8G8B8A8_USCALED: + case VK_FORMAT_R8G8B8A8_SSCALED: + case VK_FORMAT_B8G8R8A8_USCALED: + case VK_FORMAT_B8G8R8A8_SSCALED: + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + case VK_FORMAT_A8B8G8R8_SNORM_PACK32: + case VK_FORMAT_A8B8G8R8_USCALED_PACK32: + case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: + case VK_FORMAT_A8B8G8R8_UINT_PACK32: + case VK_FORMAT_A8B8G8R8_SINT_PACK32: + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + case VK_FORMAT_A2R10G10B10_USCALED_PACK32: + case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: + case VK_FORMAT_A2B10G10R10_USCALED_PACK32: + case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: + case VK_FORMAT_R16_USCALED: + case VK_FORMAT_R16_SSCALED: + case VK_FORMAT_R16G16_USCALED: + case VK_FORMAT_R16G16_SSCALED: + case VK_FORMAT_R16G16B16_USCALED: + case VK_FORMAT_R16G16B16_SSCALED: + case VK_FORMAT_R16G16B16A16_USCALED: + case VK_FORMAT_R16G16B16A16_SSCALED: + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM: + return true; + default: + return false; + } +} + +bool +isValidFormat(VkFormat format) +{ + // On MSVC VkFormat can be a signed integer + if ((uint32_t) format <= VK_FORMAT_MAX_STANDARD_ENUM) + return true; + else switch(format) { + case VK_FORMAT_G8B8G8R8_422_UNORM: + case VK_FORMAT_B8G8R8G8_422_UNORM: + case VK_FORMAT_R10X6_UNORM_PACK16: + case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: + case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case VK_FORMAT_R12X4_UNORM_PACK16: + case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: + case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + case VK_FORMAT_G16B16G16R16_422_UNORM: + case VK_FORMAT_B16G16R16G16_422_UNORM: + case VK_FORMAT_A4R4G4B4_UNORM_PACK16: + case VK_FORMAT_A4B4G4R4_UNORM_PACK16: + case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: + case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: + case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: + case VK_FORMAT_R16G16_S10_5_NV: + case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: + case VK_FORMAT_A8_UNORM_KHR: + return true; + default: + return false; + } +} + diff --git a/thirdparty/libktx/lib/vkformat_enum.h b/thirdparty/libktx/lib/vkformat_enum.h index c6d85602bd..62279bb009 100644 --- a/thirdparty/libktx/lib/vkformat_enum.h +++ b/thirdparty/libktx/lib/vkformat_enum.h @@ -2,11 +2,11 @@ #define _VKFORMAT_ENUM_H_ /***************************** Do not edit. ***************************** - Automatically generated from vulkan_core.h version 151 by mkvkformatfiles. + Automatically generated from vulkan_core.h version 267 by mkvkformatfiles. *************************************************************************/ /* -** Copyright (c) 2015-2020 The Khronos Group Inc. +** Copyright 2015-2023 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -238,6 +238,26 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -246,20 +266,6 @@ typedef enum VkFormat { VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT = 1000288000, VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT = 1000288001, VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT = 1000288002, @@ -290,10 +296,18 @@ typedef enum VkFormat { VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT = 1000288027, VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT = 1000288028, VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT = 1000288029, - VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000, - VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001, + VK_FORMAT_R16G16_S10_5_NV = 1000464000, + VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = 1000470000, + VK_FORMAT_A8_UNORM_KHR = 1000470001, VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; +#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015. +typedef unsigned __int32 VkFlags; +#else +#include <stdint.h> +typedef uint64_t VkFlags64; +#endif + #define VK_FORMAT_MAX_STANDARD_ENUM 184 diff --git a/thirdparty/libktx/patches/godot.patch b/thirdparty/libktx/patches/godot.patch new file mode 100644 index 0000000000..28db86cf9b --- /dev/null +++ b/thirdparty/libktx/patches/godot.patch @@ -0,0 +1,50 @@ +diff --git a/thirdparty/libktx/lib/basis_transcode.cpp b/thirdparty/libktx/lib/basis_transcode.cpp +index ca68545e4a..d7ecb7a0fd 100644 +--- a/thirdparty/libktx/lib/basis_transcode.cpp ++++ b/thirdparty/libktx/lib/basis_transcode.cpp +@@ -29,9 +29,9 @@ + #include "vkformat_enum.h" + #include "vk_format.h" + #include "basis_sgd.h" +-#include "basisu/transcoder/basisu_file_headers.h" +-#include "basisu/transcoder/basisu_transcoder.h" +-#include "basisu/transcoder/basisu_transcoder_internal.h" ++#include "transcoder/basisu_file_headers.h" ++#include "transcoder/basisu_transcoder.h" ++#include "transcoder/basisu_transcoder_internal.h" + + #undef DECLARE_PRIVATE + #undef DECLARE_PROTECTED +diff --git a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl +index 85d53202a5..25c7a2c238 100644 +--- a/thirdparty/libktx/lib/dfdutils/vk2dfd.inl ++++ b/thirdparty/libktx/lib/dfdutils/vk2dfd.inl +@@ -370,6 +370,7 @@ case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8 + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_SRGB); + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_SRGB); + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 4, 4, 1, s_SRGB); ++#if 0 + case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_UNORM); + case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SRGB); + case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 3, 3, 3, s_SFLOAT); +@@ -400,6 +401,7 @@ case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6 + case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_UNORM); + case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SRGB); + case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: return createDFDCompressed(c_ASTC, 6, 6, 6, s_SFLOAT); ++#endif + case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: { + int channels[] = {0,1,2,3}; int bits[] = {5,5,5,1}; + return createDFDPacked(0, 4, bits, channels, s_UNORM); +diff --git a/thirdparty/libktx/lib/miniz_wrapper.cpp b/thirdparty/libktx/lib/miniz_wrapper.cpp +index 07920c4809..cbd7da540a 100644 +--- a/thirdparty/libktx/lib/miniz_wrapper.cpp ++++ b/thirdparty/libktx/lib/miniz_wrapper.cpp +@@ -30,7 +30,7 @@ + #pragma GCC diagnostic ignored "-Wextra" + #pragma GCC diagnostic ignored "-Wmisleading-indentation" + #endif +-#include "basisu/encoder/basisu_miniz.h" ++#include "encoder/basisu_miniz.h" + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif |