feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -35,6 +35,8 @@
#include "scene/resources/3d/primitive_meshes.h"
#include "servers/navigation_server_3d.h"
#include "modules/navigation/nav_utils.h"
namespace TestNavigationServer3D {
// TODO: Find a more generic way to create `Callable` mocks.
@ -48,7 +50,7 @@ public:
}
unsigned function1_calls{ 0 };
Variant function1_latest_arg0{};
Variant function1_latest_arg0;
};
static inline Array build_array() {
@ -61,6 +63,32 @@ static inline Array build_array(Variant item, Targs... Fargs) {
return a;
}
struct GreaterThan {
bool operator()(int p_a, int p_b) const { return p_a > p_b; }
};
struct CompareArrayValues {
const int *array;
CompareArrayValues(const int *p_array) :
array(p_array) {}
bool operator()(uint32_t p_index_a, uint32_t p_index_b) const {
return array[p_index_a] < array[p_index_b];
}
};
struct RegisterHeapIndexes {
uint32_t *indexes;
RegisterHeapIndexes(uint32_t *p_indexes) :
indexes(p_indexes) {}
void operator()(uint32_t p_vector_index, uint32_t p_heap_index) {
indexes[p_vector_index] = p_heap_index;
}
};
TEST_SUITE("[Navigation]") {
TEST_CASE("[NavigationServer3D] Server should be empty when initialized") {
NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
@ -545,6 +573,7 @@ TEST_SUITE("[Navigation]") {
RID map = navigation_server->map_create();
RID region = navigation_server->region_create();
Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
navigation_server->map_set_use_async_iterations(map, false);
navigation_server->map_set_active(map, true);
navigation_server->region_set_map(region, map);
navigation_server->region_set_navigation_mesh(region, navigation_mesh);
@ -605,7 +634,7 @@ TEST_SUITE("[Navigation]") {
CHECK_EQ(source_geometry->get_indices().size(), 6);
}
SUBCASE("Parsed geometry should be extendible with other geometry") {
SUBCASE("Parsed geometry should be extendable with other geometry") {
source_geometry->merge(source_geometry); // Merging with itself.
const Vector<float> vertices = source_geometry->get_vertices();
const Vector<int> indices = source_geometry->get_indices();
@ -640,6 +669,7 @@ TEST_SUITE("[Navigation]") {
RID map = navigation_server->map_create();
RID region = navigation_server->region_create();
Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
navigation_server->map_set_use_async_iterations(map, false);
navigation_server->map_set_active(map, true);
navigation_server->region_set_map(region, map);
navigation_server->region_set_navigation_mesh(region, navigation_mesh);
@ -689,6 +719,7 @@ TEST_SUITE("[Navigation]") {
RID map = navigation_server->map_create();
RID region = navigation_server->region_create();
navigation_server->map_set_active(map, true);
navigation_server->map_set_use_async_iterations(map, false);
navigation_server->region_set_map(region, map);
navigation_server->region_set_navigation_mesh(region, navigation_mesh);
navigation_server->process(0.0); // Give server some cycles to commit.
@ -788,6 +819,154 @@ TEST_SUITE("[Navigation]") {
CHECK_EQ(navigation_mesh->get_vertices().size(), 0);
}
*/
TEST_CASE("[NavigationServer3D] Server should simplify path properly") {
real_t simplify_epsilon = 0.2;
Vector<Vector3> source_path;
source_path.resize(7);
source_path.write[0] = Vector3(0.0, 0.0, 0.0);
source_path.write[1] = Vector3(0.0, 0.0, 1.0); // This point needs to go.
source_path.write[2] = Vector3(0.0, 0.0, 2.0); // This point needs to go.
source_path.write[3] = Vector3(0.0, 0.0, 2.0);
source_path.write[4] = Vector3(2.0, 1.0, 3.0);
source_path.write[5] = Vector3(2.0, 1.5, 4.0); // This point needs to go.
source_path.write[6] = Vector3(2.0, 2.0, 5.0);
Vector<Vector3> simplified_path = NavigationServer3D::get_singleton()->simplify_path(source_path, simplify_epsilon);
CHECK_EQ(simplified_path.size(), 4);
}
TEST_CASE("[Heap] size") {
gd::Heap<int> heap;
CHECK(heap.size() == 0);
heap.push(0);
CHECK(heap.size() == 1);
heap.push(1);
CHECK(heap.size() == 2);
heap.pop();
CHECK(heap.size() == 1);
heap.pop();
CHECK(heap.size() == 0);
}
TEST_CASE("[Heap] is_empty") {
gd::Heap<int> heap;
CHECK(heap.is_empty() == true);
heap.push(0);
CHECK(heap.is_empty() == false);
heap.pop();
CHECK(heap.is_empty() == true);
}
TEST_CASE("[Heap] push/pop") {
SUBCASE("Default comparator") {
gd::Heap<int> heap;
heap.push(2);
heap.push(7);
heap.push(5);
heap.push(3);
heap.push(4);
CHECK(heap.pop() == 7);
CHECK(heap.pop() == 5);
CHECK(heap.pop() == 4);
CHECK(heap.pop() == 3);
CHECK(heap.pop() == 2);
}
SUBCASE("Custom comparator") {
GreaterThan greaterThan;
gd::Heap<int, GreaterThan> heap(greaterThan);
heap.push(2);
heap.push(7);
heap.push(5);
heap.push(3);
heap.push(4);
CHECK(heap.pop() == 2);
CHECK(heap.pop() == 3);
CHECK(heap.pop() == 4);
CHECK(heap.pop() == 5);
CHECK(heap.pop() == 7);
}
SUBCASE("Intermediate pops") {
gd::Heap<int> heap;
heap.push(0);
heap.push(3);
heap.pop();
heap.push(1);
heap.push(2);
CHECK(heap.pop() == 2);
CHECK(heap.pop() == 1);
CHECK(heap.pop() == 0);
}
}
TEST_CASE("[Heap] shift") {
int values[] = { 5, 3, 6, 7, 1 };
uint32_t heap_indexes[] = { 0, 0, 0, 0, 0 };
CompareArrayValues comparator(values);
RegisterHeapIndexes indexer(heap_indexes);
gd::Heap<uint32_t, CompareArrayValues, RegisterHeapIndexes> heap(comparator, indexer);
heap.push(0);
heap.push(1);
heap.push(2);
heap.push(3);
heap.push(4);
// Shift down: 6 -> 2
values[2] = 2;
heap.shift(heap_indexes[2]);
// Shift up: 5 -> 8
values[0] = 8;
heap.shift(heap_indexes[0]);
CHECK(heap.pop() == 0);
CHECK(heap.pop() == 3);
CHECK(heap.pop() == 1);
CHECK(heap.pop() == 2);
CHECK(heap.pop() == 4);
CHECK(heap_indexes[0] == UINT32_MAX);
CHECK(heap_indexes[1] == UINT32_MAX);
CHECK(heap_indexes[2] == UINT32_MAX);
CHECK(heap_indexes[3] == UINT32_MAX);
CHECK(heap_indexes[4] == UINT32_MAX);
}
TEST_CASE("[Heap] clear") {
uint32_t heap_indexes[] = { 0, 0, 0, 0 };
RegisterHeapIndexes indexer(heap_indexes);
gd::Heap<uint32_t, Comparator<uint32_t>, RegisterHeapIndexes> heap(indexer);
heap.push(0);
heap.push(2);
heap.push(1);
heap.push(3);
heap.clear();
CHECK(heap.size() == 0);
CHECK(heap_indexes[0] == UINT32_MAX);
CHECK(heap_indexes[1] == UINT32_MAX);
CHECK(heap_indexes[2] == UINT32_MAX);
CHECK(heap_indexes[3] == UINT32_MAX);
}
}
} //namespace TestNavigationServer3D

View file

@ -124,7 +124,7 @@ TEST_SUITE("[TextServer]") {
RID font1 = ts->create_font();
ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
RID font2 = ts->create_font();
ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size);
ts->font_set_data_ptr(font2, _font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size);
Array font;
font.push_back(font1);
@ -180,7 +180,7 @@ TEST_SUITE("[TextServer]") {
ts->font_set_data_ptr(font2, _font_NotoSansThai_Regular, _font_NotoSansThai_Regular_size);
ts->font_set_allow_system_fallback(font2, false);
RID font3 = ts->create_font();
ts->font_set_data_ptr(font3, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size);
ts->font_set_data_ptr(font3, _font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size);
ts->font_set_allow_system_fallback(font3, false);
Array font;
@ -461,7 +461,7 @@ TEST_SUITE("[TextServer]") {
ts->free_rid(ctx);
}
if (ts->has_feature(TextServer::FEATURE_BREAK_ITERATORS)) {
if (ts->has_feature(TextServer::FEATURE_BREAK_ITERATORS)) { // Line breaking opportunities.
String test = U"เป็นภาษาราชการและภาษา";
RID ctx = ts->create_shaped_text();
CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
@ -489,6 +489,67 @@ TEST_SUITE("[TextServer]") {
ts->free_rid(ctx);
}
if (ts->has_feature(TextServer::FEATURE_BREAK_ITERATORS)) { // Break line.
struct TestCase {
String text;
PackedInt32Array breaks;
};
TestCase cases[] = {
{ U" เมาส์ตัวนี้", { 0, 17, 17, 23 } },
{ U" กู้ไฟล์", { 0, 17, 17, 21 } },
{ U" ไม่มีคำ", { 0, 18, 18, 20 } },
{ U" ไม่มีคำพูด", { 0, 18, 18, 23 } },
{ U" ไม่มีคำ", { 0, 17, 17, 19 } },
{ U" มีอุปกรณ์\nนี้", { 0, 11, 11, 19, 19, 22 } },
{ U"الحمدا لحمدا لحمـــد", { 0, 13, 13, 20 } },
{ U" الحمد test", { 0, 15, 15, 19 } },
{ U"الحمـد الرياضي العربي", { 0, 7, 7, 15, 15, 21 } },
{ U"test \rtest", { 0, 6, 6, 10 } },
{ U"test\r test", { 0, 5, 5, 10 } },
{ U"test\r test \r test", { 0, 5, 5, 12, 12, 17 } },
};
for (size_t j = 0; j < sizeof(cases) / sizeof(TestCase); j++) {
RID ctx = ts->create_shaped_text();
CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, cases[j].text, font, 16);
CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
PackedInt32Array breaks = ts->shaped_text_get_line_breaks(ctx, 90.0);
CHECK_FALSE_MESSAGE(breaks != cases[j].breaks, "Invalid break points.");
breaks = ts->shaped_text_get_line_breaks_adv(ctx, { 90.0 }, 0, false);
CHECK_FALSE_MESSAGE(breaks != cases[j].breaks, "Invalid break points.");
ts->free_rid(ctx);
}
}
if (ts->has_feature(TextServer::FEATURE_BREAK_ITERATORS)) { // Break line and trim spaces.
struct TestCase {
String text;
PackedInt32Array breaks;
};
TestCase cases[] = {
{ U"test \rtest", { 0, 4, 6, 10 } },
{ U"test\r test", { 0, 4, 6, 10 } },
{ U"test\r test \r test", { 0, 4, 6, 10, 13, 17 } },
};
for (size_t j = 0; j < sizeof(cases) / sizeof(TestCase); j++) {
RID ctx = ts->create_shaped_text();
CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, cases[j].text, font, 16);
CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
PackedInt32Array breaks = ts->shaped_text_get_line_breaks(ctx, 90.0, 0, TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES);
CHECK_FALSE_MESSAGE(breaks != cases[j].breaks, "Invalid break points.");
breaks = ts->shaped_text_get_line_breaks_adv(ctx, { 90.0 }, 0, false, TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES);
CHECK_FALSE_MESSAGE(breaks != cases[j].breaks, "Invalid break points.");
ts->free_rid(ctx);
}
}
for (int j = 0; j < font.size(); j++) {
ts->free_rid(font[j]);
}
@ -535,6 +596,19 @@ TEST_SUITE("[TextServer]") {
CHECK_FALSE_MESSAGE(brks[5] != 14, "Invalid line break position.");
}
brks = ts->shaped_text_get_line_breaks(ctx, 35.0, 0, TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY | TextServer::BREAK_TRIM_EDGE_SPACES);
CHECK_FALSE_MESSAGE(brks.size() != 6, "Invalid line breaks number.");
if (brks.size() == 6) {
CHECK_FALSE_MESSAGE(brks[0] != 0, "Invalid line break position.");
CHECK_FALSE_MESSAGE(brks[1] != 4, "Invalid line break position.");
CHECK_FALSE_MESSAGE(brks[2] != 5, "Invalid line break position.");
CHECK_FALSE_MESSAGE(brks[3] != 9, "Invalid line break position.");
CHECK_FALSE_MESSAGE(brks[4] != 10, "Invalid line break position.");
CHECK_FALSE_MESSAGE(brks[5] != 14, "Invalid line break position.");
}
ts->free_rid(ctx);
for (int j = 0; j < font.size(); j++) {
@ -556,7 +630,7 @@ TEST_SUITE("[TextServer]") {
RID font1 = ts->create_font();
ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
RID font2 = ts->create_font();
ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size);
ts->font_set_data_ptr(font2, _font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size);
Array font;
font.push_back(font1);
@ -754,12 +828,12 @@ TEST_SUITE("[TextServer]") {
SUBCASE("[TextServer] Word break") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) {
continue;
}
CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
{
String text1 = U"linguistically similar and effectively form";
// 14^ 22^ 26^ 38^
@ -857,6 +931,47 @@ TEST_SUITE("[TextServer]") {
}
}
}
SUBCASE("[TextServer] Buffer invalidation") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) {
continue;
}
RID font1 = ts->create_font();
ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
Array font;
font.push_back(font1);
RID ctx = ts->create_shaped_text();
CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, "T", font, 16);
CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
int gl_size = ts->shaped_text_get_glyph_count(ctx);
CHECK_MESSAGE(gl_size == 1, "Shaping failed, invalid glyph count");
ok = ts->shaped_text_add_object(ctx, "key", Size2(20, 20), INLINE_ALIGNMENT_CENTER, 1, 0.0);
CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
gl_size = ts->shaped_text_get_glyph_count(ctx);
CHECK_MESSAGE(gl_size == 2, "Shaping failed, invalid glyph count");
ok = ts->shaped_text_add_string(ctx, "B", font, 16);
CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
gl_size = ts->shaped_text_get_glyph_count(ctx);
CHECK_MESSAGE(gl_size == 3, "Shaping failed, invalid glyph count");
ts->free_rid(ctx);
for (int j = 0; j < font.size(); j++) {
ts->free_rid(font[j]);
}
font.clear();
}
}
}
}
}; // namespace TestTextServer