diff options
Diffstat (limited to 'main/tests')
-rw-r--r-- | main/tests/SCsub | 2 | ||||
-rw-r--r-- | main/tests/test_astar.cpp | 91 | ||||
-rw-r--r-- | main/tests/test_basis.cpp | 325 | ||||
-rw-r--r-- | main/tests/test_basis.h | 40 | ||||
-rw-r--r-- | main/tests/test_class_db.cpp | 882 | ||||
-rw-r--r-- | main/tests/test_class_db.h | 42 | ||||
-rw-r--r-- | main/tests/test_gdscript.cpp | 221 | ||||
-rw-r--r-- | main/tests/test_gui.cpp | 13 | ||||
-rw-r--r-- | main/tests/test_main.cpp | 49 | ||||
-rw-r--r-- | main/tests/test_main.h | 3 | ||||
-rw-r--r-- | main/tests/test_math.cpp | 124 | ||||
-rw-r--r-- | main/tests/test_oa_hash_map.cpp | 155 | ||||
-rw-r--r-- | main/tests/test_oa_hash_map.h | 1 | ||||
-rw-r--r-- | main/tests/test_ordered_hash_map.cpp | 20 | ||||
-rw-r--r-- | main/tests/test_ordered_hash_map.h | 4 | ||||
-rw-r--r-- | main/tests/test_physics_2d.cpp | 124 | ||||
-rw-r--r-- | main/tests/test_physics_3d.cpp (renamed from main/tests/test_physics.cpp) | 197 | ||||
-rw-r--r-- | main/tests/test_physics_3d.h (renamed from main/tests/test_physics.h) | 4 | ||||
-rw-r--r-- | main/tests/test_render.cpp | 45 | ||||
-rw-r--r-- | main/tests/test_shader_lang.cpp | 112 | ||||
-rw-r--r-- | main/tests/test_string.cpp | 138 |
21 files changed, 1988 insertions, 604 deletions
diff --git a/main/tests/SCsub b/main/tests/SCsub index 437d9ed777..cb1d35b12f 100644 --- a/main/tests/SCsub +++ b/main/tests/SCsub @@ -1,6 +1,6 @@ #!/usr/bin/python -Import('env') +Import("env") env.tests_sources = [] env.add_source_files(env.tests_sources, "*.cpp") diff --git a/main/tests/test_astar.cpp b/main/tests/test_astar.cpp index e82d885af2..fe335589b0 100644 --- a/main/tests/test_astar.cpp +++ b/main/tests/test_astar.cpp @@ -173,7 +173,9 @@ bool test_add_remove() { for (int i = 0; i < 20000; i++) { int u = Math::rand() % 5; int v = Math::rand() % 4; - if (u == v) v = 4; + if (u == v) { + v = 4; + } if (Math::rand() % 2 == 1) { // Add a (possibly existing) directed edge and confirm connectivity a.connect_points(u, v, false); @@ -188,18 +190,22 @@ bool test_add_remove() { // Random tests for point removal for (int i = 0; i < 20000; i++) { a.clear(); - for (int j = 0; j < 5; j++) + for (int j = 0; j < 5; j++) { a.add_point(j, Vector3(0, 0, 0)); + } // Add or remove random edges for (int j = 0; j < 10; j++) { int u = Math::rand() % 5; int v = Math::rand() % 4; - if (u == v) v = 4; - if (Math::rand() % 2 == 1) + if (u == v) { + v = 4; + } + if (Math::rand() % 2 == 1) { a.connect_points(u, v, false); - else + } else { a.disconnect_points(u, v, false); + } } // Remove point 0 @@ -239,7 +245,9 @@ bool test_solutions() { int u, v; u = Math::rand() % N; v = Math::rand() % (N - 1); - if (u == v) v = N - 1; + if (u == v) { + v = N - 1; + } // Pick a random operation int op = Math::rand(); @@ -253,14 +261,18 @@ bool test_solutions() { // Add edge (u, v); possibly bidirectional a.connect_points(u, v, op % 2); adj[u][v] = true; - if (op % 2) adj[v][u] = true; + if (op % 2) { + adj[v][u] = true; + } break; case 6: case 7: // Remove edge (u, v); possibly bidirectional a.disconnect_points(u, v, op % 2); adj[u][v] = false; - if (op % 2) adj[v][u] = false; + if (op % 2) { + adj[v][u] = false; + } break; case 8: // Remove point u and add it back; clears adjacent edges and changes coordinates @@ -269,40 +281,55 @@ bool test_solutions() { p[u].y = Math::rand() % 100; p[u].z = Math::rand() % 100; a.add_point(u, p[u]); - for (v = 0; v < N; v++) + for (v = 0; v < N; v++) { adj[u][v] = adj[v][u] = false; + } break; } } // Floyd-Warshall float d[N][N]; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { d[u][v] = (u == v || adj[u][v]) ? p[u].distance_to(p[v]) : INFINITY; + } + } - for (int w = 0; w < N; w++) - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) - if (d[u][v] > d[u][w] + d[w][v]) + for (int w = 0; w < N; w++) { + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { + if (d[u][v] > d[u][w] + d[w][v]) { d[u][v] = d[u][w] + d[w][v]; + } + } + } + } // Display statistics int count = 0; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) - if (adj[u][v]) count++; + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { + if (adj[u][v]) { + count++; + } + } + } printf("Test #%4d: %3d edges, ", test + 1, count); count = 0; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) - if (!Math::is_inf(d[u][v])) count++; + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { + if (!Math::is_inf(d[u][v])) { + count++; + } + } + } printf("%3d/%d pairs of reachable points\n", count - N, N * (N - 1)); // Check A*'s output bool match = true; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { if (u != v) { Vector<int> route = a.get_id_path(u, v); if (!Math::is_inf(d[u][v])) { @@ -337,21 +364,25 @@ bool test_solutions() { } } } + } + } exit: - if (!match) return false; + if (!match) { + return false; + } } return true; } -typedef bool (*TestFunc)(void); +typedef bool (*TestFunc)(); TestFunc test_funcs[] = { test_abc, test_abcx, test_add_remove, test_solutions, - NULL + nullptr }; MainLoop *test() { @@ -359,18 +390,20 @@ MainLoop *test() { int passed = 0; while (true) { - if (!test_funcs[count]) + if (!test_funcs[count]) { break; + } bool pass = test_funcs[count](); - if (pass) + if (pass) { passed++; + } OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); count++; } OS::get_singleton()->print("\n"); OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return NULL; + return nullptr; } } // namespace TestAStar diff --git a/main/tests/test_basis.cpp b/main/tests/test_basis.cpp new file mode 100644 index 0000000000..5904fc386a --- /dev/null +++ b/main/tests/test_basis.cpp @@ -0,0 +1,325 @@ +/*************************************************************************/ +/* test_basis.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_basis.h" + +#include "core/math/random_number_generator.h" +#include "core/os/os.h" +#include "core/ustring.h" + +namespace TestBasis { + +enum RotOrder { + EulerXYZ, + EulerXZY, + EulerYZX, + EulerYXZ, + EulerZXY, + EulerZYX +}; + +Vector3 deg2rad(const Vector3 &p_rotation) { + return p_rotation / 180.0 * Math_PI; +} + +Vector3 rad2deg(const Vector3 &p_rotation) { + return p_rotation / Math_PI * 180.0; +} + +Basis EulerToBasis(RotOrder mode, const Vector3 &p_rotation) { + Basis ret; + switch (mode) { + case EulerXYZ: + ret.set_euler_xyz(p_rotation); + break; + + case EulerXZY: + ret.set_euler_xzy(p_rotation); + break; + + case EulerYZX: + ret.set_euler_yzx(p_rotation); + break; + + case EulerYXZ: + ret.set_euler_yxz(p_rotation); + break; + + case EulerZXY: + ret.set_euler_zxy(p_rotation); + break; + + case EulerZYX: + ret.set_euler_zyx(p_rotation); + break; + + default: + // If you land here, Please integrate all rotation orders. + CRASH_NOW_MSG("This is not unreachable."); + } + + return ret; +} + +Vector3 BasisToEuler(RotOrder mode, const Basis &p_rotation) { + switch (mode) { + case EulerXYZ: + return p_rotation.get_euler_xyz(); + + case EulerXZY: + return p_rotation.get_euler_xzy(); + + case EulerYZX: + return p_rotation.get_euler_yzx(); + + case EulerYXZ: + return p_rotation.get_euler_yxz(); + + case EulerZXY: + return p_rotation.get_euler_zxy(); + + case EulerZYX: + return p_rotation.get_euler_zyx(); + + default: + // If you land here, Please integrate all rotation orders. + CRASH_NOW_MSG("This is not unreachable."); + return Vector3(); + } +} + +String get_rot_order_name(RotOrder ro) { + switch (ro) { + case EulerXYZ: + return "XYZ"; + case EulerXZY: + return "XZY"; + case EulerYZX: + return "YZX"; + case EulerYXZ: + return "YXZ"; + case EulerZXY: + return "ZXY"; + case EulerZYX: + return "ZYX"; + default: + return "[Not supported]"; + } +} + +bool test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { + // This test: + // 1. Converts the rotation vector from deg to rad. + // 2. Converts euler to basis. + // 3. Converts the above basis back into euler. + // 4. Converts the above euler into basis again. + // 5. Compares the basis obtained in step 2 with the basis of step 4 + // + // The conversion "basis to euler", done in the step 3, may be different from + // the original euler, even if the final rotation are the same. + // This happens because there are more ways to represents the same rotation, + // both valid, using eulers. + // For this reason is necessary to convert that euler back to basis and finally + // compares it. + // + // In this way we can assert that both functions: basis to euler / euler to basis + // are correct. + + bool pass = true; + + // Euler to rotation + const Vector3 original_euler = deg2rad(deg_original_euler); + const Basis to_rotation = EulerToBasis(rot_order, original_euler); + + // Euler from rotation + const Vector3 euler_from_rotation = BasisToEuler(rot_order, to_rotation); + const Basis rotation_from_computed_euler = EulerToBasis(rot_order, euler_from_rotation); + + Basis res = to_rotation.inverse() * rotation_from_computed_euler; + + if ((res.get_axis(0) - Vector3(1.0, 0.0, 0.0)).length() > 0.1) { + OS::get_singleton()->print("Fail due to X %ls\n", String(res.get_axis(0)).c_str()); + pass = false; + } + if ((res.get_axis(1) - Vector3(0.0, 1.0, 0.0)).length() > 0.1) { + OS::get_singleton()->print("Fail due to Y %ls\n", String(res.get_axis(1)).c_str()); + pass = false; + } + if ((res.get_axis(2) - Vector3(0.0, 0.0, 1.0)).length() > 0.1) { + OS::get_singleton()->print("Fail due to Z %ls\n", String(res.get_axis(2)).c_str()); + pass = false; + } + + if (pass) { + // Double check `to_rotation` decomposing with XYZ rotation order. + const Vector3 euler_xyz_from_rotation = to_rotation.get_euler_xyz(); + Basis rotation_from_xyz_computed_euler; + rotation_from_xyz_computed_euler.set_euler_xyz(euler_xyz_from_rotation); + + res = to_rotation.inverse() * rotation_from_xyz_computed_euler; + + if ((res.get_axis(0) - Vector3(1.0, 0.0, 0.0)).length() > 0.1) { + OS::get_singleton()->print("Double check with XYZ rot order failed, due to X %ls\n", String(res.get_axis(0)).c_str()); + pass = false; + } + if ((res.get_axis(1) - Vector3(0.0, 1.0, 0.0)).length() > 0.1) { + OS::get_singleton()->print("Double check with XYZ rot order failed, due to Y %ls\n", String(res.get_axis(1)).c_str()); + pass = false; + } + if ((res.get_axis(2) - Vector3(0.0, 0.0, 1.0)).length() > 0.1) { + OS::get_singleton()->print("Double check with XYZ rot order failed, due to Z %ls\n", String(res.get_axis(2)).c_str()); + pass = false; + } + } + + if (pass == false) { + // Print phase only if not pass. + OS *os = OS::get_singleton(); + os->print("Rotation order: %ls\n.", get_rot_order_name(rot_order).c_str()); + os->print("Original Rotation: %ls\n", String(deg_original_euler).c_str()); + os->print("Quaternion to rotation order: %ls\n", String(rad2deg(euler_from_rotation)).c_str()); + } + + return pass; +} + +void test_euler_conversion() { + Vector<RotOrder> rotorder_to_test; + rotorder_to_test.push_back(EulerXYZ); + rotorder_to_test.push_back(EulerXZY); + rotorder_to_test.push_back(EulerYZX); + rotorder_to_test.push_back(EulerYXZ); + rotorder_to_test.push_back(EulerZXY); + rotorder_to_test.push_back(EulerZYX); + + Vector<Vector3> vectors_to_test; + + // Test the special cases. + vectors_to_test.push_back(Vector3(0.0, 0.0, 0.0)); + vectors_to_test.push_back(Vector3(0.5, 0.5, 0.5)); + vectors_to_test.push_back(Vector3(-0.5, -0.5, -0.5)); + vectors_to_test.push_back(Vector3(40.0, 40.0, 40.0)); + vectors_to_test.push_back(Vector3(-40.0, -40.0, -40.0)); + vectors_to_test.push_back(Vector3(0.0, 0.0, -90.0)); + vectors_to_test.push_back(Vector3(0.0, -90.0, 0.0)); + vectors_to_test.push_back(Vector3(-90.0, 0.0, 0.0)); + vectors_to_test.push_back(Vector3(0.0, 0.0, 90.0)); + vectors_to_test.push_back(Vector3(0.0, 90.0, 0.0)); + vectors_to_test.push_back(Vector3(90.0, 0.0, 0.0)); + vectors_to_test.push_back(Vector3(0.0, 0.0, -30.0)); + vectors_to_test.push_back(Vector3(0.0, -30.0, 0.0)); + vectors_to_test.push_back(Vector3(-30.0, 0.0, 0.0)); + vectors_to_test.push_back(Vector3(0.0, 0.0, 30.0)); + vectors_to_test.push_back(Vector3(0.0, 30.0, 0.0)); + vectors_to_test.push_back(Vector3(30.0, 0.0, 0.0)); + vectors_to_test.push_back(Vector3(0.5, 50.0, 20.0)); + vectors_to_test.push_back(Vector3(-0.5, -50.0, -20.0)); + vectors_to_test.push_back(Vector3(0.5, 0.0, 90.0)); + vectors_to_test.push_back(Vector3(0.5, 0.0, -90.0)); + vectors_to_test.push_back(Vector3(360.0, 360.0, 360.0)); + vectors_to_test.push_back(Vector3(-360.0, -360.0, -360.0)); + vectors_to_test.push_back(Vector3(-90.0, 60.0, -90.0)); + vectors_to_test.push_back(Vector3(90.0, 60.0, -90.0)); + vectors_to_test.push_back(Vector3(90.0, -60.0, -90.0)); + vectors_to_test.push_back(Vector3(-90.0, -60.0, -90.0)); + vectors_to_test.push_back(Vector3(-90.0, 60.0, 90.0)); + vectors_to_test.push_back(Vector3(90.0, 60.0, 90.0)); + vectors_to_test.push_back(Vector3(90.0, -60.0, 90.0)); + vectors_to_test.push_back(Vector3(-90.0, -60.0, 90.0)); + vectors_to_test.push_back(Vector3(60.0, 90.0, -40.0)); + vectors_to_test.push_back(Vector3(60.0, -90.0, -40.0)); + vectors_to_test.push_back(Vector3(-60.0, -90.0, -40.0)); + vectors_to_test.push_back(Vector3(-60.0, 90.0, 40.0)); + vectors_to_test.push_back(Vector3(60.0, 90.0, 40.0)); + vectors_to_test.push_back(Vector3(60.0, -90.0, 40.0)); + vectors_to_test.push_back(Vector3(-60.0, -90.0, 40.0)); + vectors_to_test.push_back(Vector3(-90.0, 90.0, -90.0)); + vectors_to_test.push_back(Vector3(90.0, 90.0, -90.0)); + vectors_to_test.push_back(Vector3(90.0, -90.0, -90.0)); + vectors_to_test.push_back(Vector3(-90.0, -90.0, -90.0)); + vectors_to_test.push_back(Vector3(-90.0, 90.0, 90.0)); + vectors_to_test.push_back(Vector3(90.0, 90.0, 90.0)); + vectors_to_test.push_back(Vector3(90.0, -90.0, 90.0)); + vectors_to_test.push_back(Vector3(20.0, 150.0, 30.0)); + vectors_to_test.push_back(Vector3(20.0, -150.0, 30.0)); + vectors_to_test.push_back(Vector3(-120.0, -150.0, 30.0)); + vectors_to_test.push_back(Vector3(-120.0, -150.0, -130.0)); + vectors_to_test.push_back(Vector3(120.0, -150.0, -130.0)); + vectors_to_test.push_back(Vector3(120.0, 150.0, -130.0)); + vectors_to_test.push_back(Vector3(120.0, 150.0, 130.0)); + + // Add 1000 random vectors with weirds numbers. + RandomNumberGenerator rng; + for (int _ = 0; _ < 1000; _ += 1) { + vectors_to_test.push_back(Vector3( + rng.randf_range(-1800, 1800), + rng.randf_range(-1800, 1800), + rng.randf_range(-1800, 1800))); + } + + bool success = true; + for (int h = 0; h < rotorder_to_test.size(); h += 1) { + int passed = 0; + int failed = 0; + for (int i = 0; i < vectors_to_test.size(); i += 1) { + if (test_rotation(vectors_to_test[i], rotorder_to_test[h])) { + //OS::get_singleton()->print("Success. \n\n"); + passed += 1; + } else { + OS::get_singleton()->print("FAILED FAILED FAILED. \n\n"); + OS::get_singleton()->print("------------>\n"); + OS::get_singleton()->print("------------>\n"); + failed += 1; + success = false; + } + } + + if (failed == 0) { + OS::get_singleton()->print("%i passed tests for rotation order: %ls.\n", passed, get_rot_order_name(rotorder_to_test[h]).c_str()); + } else { + OS::get_singleton()->print("%i FAILED tests for rotation order: %ls.\n", failed, get_rot_order_name(rotorder_to_test[h]).c_str()); + } + } + + if (success) { + OS::get_singleton()->print("Euler conversion checks passed.\n"); + } else { + OS::get_singleton()->print("Euler conversion checks FAILED.\n"); + } +} + +MainLoop *test() { + OS::get_singleton()->print("Start euler conversion checks.\n"); + test_euler_conversion(); + + return NULL; +} + +} // namespace TestBasis diff --git a/main/tests/test_basis.h b/main/tests/test_basis.h new file mode 100644 index 0000000000..63297bd3b8 --- /dev/null +++ b/main/tests/test_basis.h @@ -0,0 +1,40 @@ +/*************************************************************************/ +/* test_basis.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_BASIS_H +#define TEST_BASIS_H + +#include "core/os/main_loop.h" + +namespace TestBasis { +MainLoop *test(); +} + +#endif diff --git a/main/tests/test_class_db.cpp b/main/tests/test_class_db.cpp new file mode 100644 index 0000000000..3171091402 --- /dev/null +++ b/main/tests/test_class_db.cpp @@ -0,0 +1,882 @@ +/*************************************************************************/ +/* test_class_db.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_class_db.h" + +#include "core/global_constants.h" +#include "core/ordered_hash_map.h" +#include "core/os/os.h" +#include "core/string_name.h" +#include "core/ustring.h" +#include "core/variant.h" + +namespace TestClassDB { + +enum class [[nodiscard]] TestResult{ + FAILED, + PASS +}; + +#define TEST_FAIL_COND(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + ERR_PRINT(m_msg); \ + return TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_COND(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + ERR_PRINT(m_msg); \ + __test_result__ = TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_FAIL_CHECK(m_test_expr) \ + if (unlikely((m_test_expr) == TestResult::FAILED)) { \ + return TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_CHECK(m_test_expr) \ + if (unlikely((m_test_expr) == TestResult::FAILED)) { \ + __test_result__ = TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_START() \ + TestResult __test_result__ = TestResult::PASS; \ + ((void)0) + +#define TEST_END() return __test_result__; + +struct TypeReference { + StringName name; + bool is_enum = false; +}; + +struct ConstantData { + String name; + int value = 0; +}; + +struct EnumData { + StringName name; + List<ConstantData> constants; + + _FORCE_INLINE_ bool operator==(const EnumData &p_enum) const { + return p_enum.name == name; + } +}; + +struct PropertyData { + StringName name; + int index = 0; + + StringName getter; + StringName setter; +}; + +struct ArgumentData { + TypeReference type; + String name; + bool has_defval = false; + Variant defval; +}; + +struct MethodData { + StringName name; + TypeReference return_type; + List<ArgumentData> arguments; + bool is_virtual = false; + bool is_vararg = false; +}; + +struct SignalData { + StringName name; + List<ArgumentData> arguments; +}; + +struct ExposedClass { + StringName name; + StringName base; + + bool is_singleton = false; + bool is_instantiable = false; + bool is_reference = false; + + ClassDB::APIType api_type; + + List<ConstantData> constants; + List<EnumData> enums; + List<PropertyData> properties; + List<MethodData> methods; + List<SignalData> signals_; + + const PropertyData *find_property_by_name(const StringName &p_name) const { + for (const List<PropertyData>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_name) { + return &E->get(); + } + } + + return nullptr; + } + + const MethodData *find_method_by_name(const StringName &p_name) const { + for (const List<MethodData>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name == p_name) { + return &E->get(); + } + } + + return nullptr; + } +}; + +struct NamesCache { + StringName variant_type = StaticCString::create("Variant"); + StringName object_class = StaticCString::create("Object"); + StringName reference_class = StaticCString::create("Reference"); + StringName string_type = StaticCString::create("String"); + StringName string_name_type = StaticCString::create("StringName"); + StringName node_path_type = StaticCString::create("NodePath"); + StringName bool_type = StaticCString::create("bool"); + StringName int_type = StaticCString::create("int"); + StringName float_type = StaticCString::create("float"); + StringName void_type = StaticCString::create("void"); + StringName vararg_stub_type = StaticCString::create("@VarArg@"); + StringName vector2_type = StaticCString::create("Vector2"); + StringName rect2_type = StaticCString::create("Rect2"); + StringName vector3_type = StaticCString::create("Vector3"); + + // Object not included as it must be checked for all derived classes + static constexpr int nullable_types_count = 17; + StringName nullable_types[nullable_types_count] = { + string_type, + string_name_type, + node_path_type, + + StaticCString::create(_STR(Array)), + StaticCString::create(_STR(Dictionary)), + StaticCString::create(_STR(Callable)), + StaticCString::create(_STR(Signal)), + + StaticCString::create(_STR(PackedByteArray)), + StaticCString::create(_STR(PackedInt32Array)), + StaticCString::create(_STR(PackedInt64rray)), + StaticCString::create(_STR(PackedFloat32Array)), + StaticCString::create(_STR(PackedFloat64Array)), + StaticCString::create(_STR(PackedStringArray)), + StaticCString::create(_STR(PackedVector2Array)), + StaticCString::create(_STR(PackedVector3Array)), + StaticCString::create(_STR(PackedColorArray)), + }; + + bool is_nullable_type(const StringName &p_type) const { + for (int i = 0; i < nullable_types_count; i++) { + if (p_type == nullable_types[i]) { + return true; + } + } + + return false; + } +}; + +typedef OrderedHashMap<StringName, ExposedClass> ExposedClasses; + +struct Context { + Vector<StringName> enum_types; + Vector<StringName> builtin_types; + ExposedClasses exposed_classes; + List<EnumData> global_enums; + NamesCache names_cache; + + const ExposedClass *find_exposed_class(const StringName &p_name) const { + ExposedClasses::ConstElement elem = exposed_classes.find(p_name); + return elem ? &elem.value() : nullptr; + } + + const ExposedClass *find_exposed_class(const TypeReference &p_type_ref) const { + ExposedClasses::ConstElement elem = exposed_classes.find(p_type_ref.name); + return elem ? &elem.value() : nullptr; + } + + bool has_type(const TypeReference &p_type_ref) const { + if (builtin_types.find(p_type_ref.name) >= 0) { + return true; + } + + if (p_type_ref.is_enum) { + if (enum_types.find(p_type_ref.name) >= 0) { + return true; + } + + // Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead. + return builtin_types.find(names_cache.int_type); + } + + return false; + } +}; + +bool arg_default_value_is_assignable_to_type(const Context &p_context, const Variant &p_val, const TypeReference &p_arg_type) { + if (p_arg_type.name == p_context.names_cache.variant_type) { + // Variant can take anything + return true; + } + + switch (p_val.get_type()) { + case Variant::NIL: + return p_context.find_exposed_class(p_arg_type) || + p_context.names_cache.is_nullable_type(p_arg_type.name); + case Variant::BOOL: + return p_arg_type.name == p_context.names_cache.bool_type; + case Variant::INT: + return p_arg_type.name == p_context.names_cache.int_type || + p_arg_type.name == p_context.names_cache.float_type || + p_arg_type.is_enum; + case Variant::FLOAT: + return p_arg_type.name == p_context.names_cache.float_type; + case Variant::STRING: + case Variant::STRING_NAME: + return p_arg_type.name == p_context.names_cache.string_type || + p_arg_type.name == p_context.names_cache.string_name_type || + p_arg_type.name == p_context.names_cache.node_path_type; + case Variant::NODE_PATH: + return p_arg_type.name == p_context.names_cache.node_path_type; + case Variant::TRANSFORM: + case Variant::TRANSFORM2D: + case Variant::BASIS: + case Variant::QUAT: + case Variant::PLANE: + case Variant::AABB: + case Variant::COLOR: + case Variant::VECTOR2: + case Variant::RECT2: + case Variant::VECTOR3: + case Variant::_RID: + case Variant::ARRAY: + case Variant::DICTIONARY: + case Variant::PACKED_BYTE_ARRAY: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_STRING_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + case Variant::CALLABLE: + case Variant::SIGNAL: + return p_arg_type.name == Variant::get_type_name(p_val.get_type()); + case Variant::OBJECT: + return p_context.find_exposed_class(p_arg_type); + case Variant::VECTOR2I: + return p_arg_type.name == p_context.names_cache.vector2_type || + p_arg_type.name == Variant::get_type_name(p_val.get_type()); + case Variant::RECT2I: + return p_arg_type.name == p_context.names_cache.rect2_type || + p_arg_type.name == Variant::get_type_name(p_val.get_type()); + case Variant::VECTOR3I: + return p_arg_type.name == p_context.names_cache.vector3_type || + p_arg_type.name == Variant::get_type_name(p_val.get_type()); + default: + ERR_PRINT("Unexpected Variant type: " + itos(p_val.get_type())); + break; + } + + return false; +} + +TestResult validate_property(const Context &p_context, const ExposedClass &p_class, const PropertyData &p_prop) { + TEST_START(); + + const MethodData *setter = p_class.find_method_by_name(p_prop.setter); + + // Search it in base classes too + const ExposedClass *top = &p_class; + while (!setter && top->base != StringName()) { + top = p_context.find_exposed_class(top->base); + TEST_FAIL_COND(!top, "Class not found '" + top->base + "'. Inherited by '" + top->name + "'."); + setter = top->find_method_by_name(p_prop.setter); + } + + const MethodData *getter = p_class.find_method_by_name(p_prop.getter); + + // Search it in base classes too + top = &p_class; + while (!getter && top->base != StringName()) { + top = p_context.find_exposed_class(top->base); + TEST_FAIL_COND(!top, "Class not found '" + top->base + "'. Inherited by '" + top->name + "'."); + getter = top->find_method_by_name(p_prop.getter); + } + + TEST_FAIL_COND(!setter && !getter, + "Couldn't find neither the setter nor the getter for property: '" + p_class.name + "." + String(p_prop.name) + "'."); + + if (setter) { + int setter_argc = p_prop.index != -1 ? 2 : 1; + TEST_FAIL_COND(setter->arguments.size() != setter_argc, + "Invalid property setter argument count: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + + if (getter) { + int getter_argc = p_prop.index != -1 ? 1 : 0; + TEST_FAIL_COND(getter->arguments.size() != getter_argc, + "Invalid property setter argument count: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + + if (getter && setter) { + const ArgumentData &setter_first_arg = setter->arguments.back()->get(); + if (getter->return_type.name != setter_first_arg.type.name) { + // Special case for Node::set_name + bool whitelisted = getter->return_type.name == p_context.names_cache.string_name_type && + setter_first_arg.type.name == p_context.names_cache.string_type; + + TEST_FAIL_COND(!whitelisted, + "Return type from getter doesn't match first argument of setter, for property: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + } + + const TypeReference &prop_type_ref = getter ? getter->return_type : setter->arguments.back()->get().type; + + const ExposedClass *prop_class = p_context.find_exposed_class(prop_type_ref); + if (prop_class) { + TEST_COND(prop_class->is_singleton, + "Property type is a singleton: '" + p_class.name + "." + String(p_prop.name) + "'."); + } else { + TEST_FAIL_COND(!p_context.has_type(prop_type_ref), + "Property type '" + prop_type_ref.name + "' not found: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + + if (getter) { + if (p_prop.index != -1) { + const ArgumentData &idx_arg = getter->arguments.front()->get(); + if (idx_arg.type.name != p_context.names_cache.int_type) { + // If not an int, it can be an enum + TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0, + "Invalid type '" + idx_arg.type.name + "' for index argument of property getter: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + } + } + + if (setter) { + if (p_prop.index != -1) { + const ArgumentData &idx_arg = setter->arguments.front()->get(); + if (idx_arg.type.name != p_context.names_cache.int_type) { + // Assume the index parameter is an enum + // If not an int, it can be an enum + TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0, + "Invalid type '" + idx_arg.type.name + "' for index argument of property setter: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + } + } + + TEST_END(); +} + +TestResult validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) { + TEST_START(); + + const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type); + if (return_class) { + TEST_COND(return_class->is_singleton, + "Method return type is a singleton: '" + p_class.name + "." + p_method.name + "'."); + } + + for (const List<ArgumentData>::Element *F = p_method.arguments.front(); F; F = F->next()) { + const ArgumentData &arg = F->get(); + + const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); + if (arg_class) { + TEST_COND(arg_class->is_singleton, + "Argument type is a singleton: '" + arg.name + "' of method '" + p_class.name + "." + p_method.name + "'."); + } else { + TEST_FAIL_COND(!p_context.has_type(arg.type), + "Argument type '" + arg.type.name + "' not found: '" + arg.name + "' of method" + p_class.name + "." + p_method.name + "'."); + } + + if (arg.has_defval) { + TEST_COND(!arg_default_value_is_assignable_to_type(p_context, arg.defval, arg.type), + "Invalid default value for parameter '" + arg.name + "' of method '" + p_class.name + "." + p_method.name + "'."); + } + } + + TEST_END(); +} + +TestResult validate_signal(const Context &p_context, const ExposedClass &p_class, const SignalData &p_signal) { + TEST_START(); + + for (const List<ArgumentData>::Element *F = p_signal.arguments.front(); F; F = F->next()) { + const ArgumentData &arg = F->get(); + + const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); + if (arg_class) { + TEST_COND(arg_class->is_singleton, + "Argument class is a singleton: '" + arg.name + "' of signal" + p_class.name + "." + p_signal.name + "'."); + } else { + TEST_FAIL_COND(!p_context.has_type(arg.type), + "Argument type '" + arg.type.name + "' not found: '" + arg.name + "' of signal" + p_class.name + "." + p_signal.name + "'."); + } + } + + TEST_END(); +} + +TestResult validate_class(const Context &p_context, const ExposedClass &p_exposed_class) { + TEST_START(); + + bool is_derived_type = p_exposed_class.base != StringName(); + + if (!is_derived_type) { + // Asserts about the base Object class + TEST_FAIL_COND(p_exposed_class.name != p_context.names_cache.object_class, + "Class '" + p_exposed_class.name + "' has no base class."); + TEST_FAIL_COND(!p_exposed_class.is_instantiable, + "Object class is not instantiable."); + TEST_FAIL_COND(p_exposed_class.api_type != ClassDB::API_CORE, + "Object class is API is not API_CORE."); + TEST_FAIL_COND(p_exposed_class.is_singleton, + "Object class is registered as a singleton."); + } + + TEST_FAIL_COND(p_exposed_class.is_singleton && p_exposed_class.base != p_context.names_cache.object_class, + "Singleton base class '" + String(p_exposed_class.base) + "' is not Object, for class '" + p_exposed_class.name + "'."); + + TEST_FAIL_COND(is_derived_type && !p_context.exposed_classes.has(p_exposed_class.base), + "Base type '" + p_exposed_class.base.operator String() + "' does not exist, for class '" + p_exposed_class.name + "'."); + + for (const List<PropertyData>::Element *F = p_exposed_class.properties.front(); F; F = F->next()) { + TEST_CHECK(validate_property(p_context, p_exposed_class, F->get())); + } + + for (const List<MethodData>::Element *F = p_exposed_class.methods.front(); F; F = F->next()) { + TEST_CHECK(validate_method(p_context, p_exposed_class, F->get())); + } + + for (const List<SignalData>::Element *F = p_exposed_class.signals_.front(); F; F = F->next()) { + TEST_CHECK(validate_signal(p_context, p_exposed_class, F->get())); + } + + TEST_END(); +} + +TestResult add_exposed_classes(Context &r_context) { + TEST_START(); + + List<StringName> class_list; + ClassDB::get_class_list(&class_list); + class_list.sort_custom<StringName::AlphCompare>(); + + while (class_list.size()) { + StringName class_name = class_list.front()->get(); + + ClassDB::APIType api_type = ClassDB::get_api_type(class_name); + + if (api_type == ClassDB::API_NONE) { + class_list.pop_front(); + continue; + } + + if (!ClassDB::is_class_exposed(class_name)) { + OS::get_singleton()->print("Ignoring class '%s' because it's not exposed\n", String(class_name).utf8().get_data()); + class_list.pop_front(); + continue; + } + + if (!ClassDB::is_class_enabled(class_name)) { + OS::get_singleton()->print("Ignoring class '%s' because it's not enabled\n", String(class_name).utf8().get_data()); + class_list.pop_front(); + continue; + } + + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name); + + ExposedClass exposed_class; + exposed_class.name = class_name; + exposed_class.api_type = api_type; + exposed_class.is_singleton = Engine::get_singleton()->has_singleton(class_name); + exposed_class.is_instantiable = class_info->creation_func && !exposed_class.is_singleton; + exposed_class.is_reference = ClassDB::is_parent_class(class_name, "Reference"); + exposed_class.base = ClassDB::get_parent_class(class_name); + + // Add properties + + List<PropertyInfo> property_list; + ClassDB::get_property_list(class_name, &property_list, true); + + Map<StringName, StringName> accessor_methods; + + for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { + const PropertyInfo &property = E->get(); + + if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY) { + continue; + } + + PropertyData prop; + prop.name = property.name; + prop.setter = ClassDB::get_property_setter(class_name, prop.name); + prop.getter = ClassDB::get_property_getter(class_name, prop.name); + + if (prop.setter != StringName()) { + accessor_methods[prop.setter] = prop.name; + } + if (prop.getter != StringName()) { + accessor_methods[prop.getter] = prop.name; + } + + bool valid = false; + prop.index = ClassDB::get_property_index(class_name, prop.name, &valid); + TEST_FAIL_COND(!valid, "Invalid property: '" + exposed_class.name + "." + String(prop.name) + "'."); + + exposed_class.properties.push_back(prop); + } + + // Add methods + + List<MethodInfo> virtual_method_list; + ClassDB::get_virtual_methods(class_name, &virtual_method_list, true); + + List<MethodInfo> method_list; + ClassDB::get_method_list(class_name, &method_list, true); + method_list.sort(); + + for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) { + const MethodInfo &method_info = E->get(); + + int argc = method_info.arguments.size(); + + if (method_info.name.empty()) { + continue; + } + + MethodData method; + method.name = method_info.name; + + if (method_info.flags & METHOD_FLAG_VIRTUAL) { + method.is_virtual = true; + } + + PropertyInfo return_info = method_info.return_val; + + MethodBind *m = method.is_virtual ? nullptr : ClassDB::get_method(class_name, method_info.name); + + method.is_vararg = m && m->is_vararg(); + + if (!m && !method.is_virtual) { + TEST_FAIL_COND(!virtual_method_list.find(method_info), + "Missing MethodBind for non-virtual method: '" + exposed_class.name + "." + method.name + "'."); + + // A virtual method without the virtual flag. This is a special case. + + // The method Object.free is registered as a virtual method, but without the virtual flag. + // This is because this method is not supposed to be overridden, but called. + // We assume the return type is void. + method.return_type.name = r_context.names_cache.void_type; + + // Actually, more methods like this may be added in the future, which could return + // something different. Let's put this check to notify us if that ever happens. + if (exposed_class.name != r_context.names_cache.object_class || String(method.name) != "free") { + WARN_PRINT("Notification: New unexpected virtual non-overridable method found." + " We only expected Object.free, but found '" + + exposed_class.name + "." + method.name + "'."); + } + } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + method.return_type.name = return_info.class_name; + method.return_type.is_enum = true; + } else if (return_info.class_name != StringName()) { + method.return_type.name = return_info.class_name; + + bool bad_reference_hint = !method.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE && + ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.reference_class); + TEST_COND(bad_reference_hint, String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." + + " Are you returning a reference type by pointer? Method: '" + + exposed_class.name + "." + method.name + "'."); + } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + method.return_type.name = return_info.hint_string; + } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { + method.return_type.name = r_context.names_cache.variant_type; + } else if (return_info.type == Variant::NIL) { + method.return_type.name = r_context.names_cache.void_type; + } else { + // NOTE: We don't care about the size and sign of int and float in these tests + method.return_type.name = Variant::get_type_name(return_info.type); + } + + for (int i = 0; i < argc; i++) { + PropertyInfo arg_info = method_info.arguments[i]; + + String orig_arg_name = arg_info.name; + + ArgumentData arg; + arg.name = orig_arg_name; + + if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + arg.type.name = arg_info.class_name; + arg.type.is_enum = true; + } else if (arg_info.class_name != StringName()) { + arg.type.name = arg_info.class_name; + } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + arg.type.name = arg_info.hint_string; + } else if (arg_info.type == Variant::NIL) { + arg.type.name = r_context.names_cache.variant_type; + } else { + // NOTE: We don't care about the size and sign of int and float in these tests + arg.type.name = Variant::get_type_name(arg_info.type); + } + + if (m && m->has_default_argument(i)) { + arg.has_defval = true; + arg.defval = m->get_default_argument(i); + } + + method.arguments.push_back(arg); + } + + if (method.is_vararg) { + ArgumentData vararg; + vararg.type.name = r_context.names_cache.vararg_stub_type; + vararg.name = "@varargs@"; + method.arguments.push_back(vararg); + } + + TEST_COND(exposed_class.find_property_by_name(method.name), + "Method name conflicts with property: '" + String(class_name) + "." + String(method.name) + "'."); + + // Classes starting with an underscore are ignored unless they're used as a property setter or getter + if (!method.is_virtual && String(method.name)[0] == '_') { + for (const List<PropertyData>::Element *F = exposed_class.properties.front(); F; F = F->next()) { + const PropertyData &prop = F->get(); + + if (prop.setter == method.name || prop.getter == method.name) { + exposed_class.methods.push_back(method); + break; + } + } + } else { + exposed_class.methods.push_back(method); + } + } + + // Add signals + + const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map; + const StringName *k = nullptr; + + while ((k = signal_map.next(k))) { + SignalData signal; + + const MethodInfo &method_info = signal_map.get(*k); + + signal.name = method_info.name; + + int argc = method_info.arguments.size(); + + for (int i = 0; i < argc; i++) { + PropertyInfo arg_info = method_info.arguments[i]; + + String orig_arg_name = arg_info.name; + + ArgumentData arg; + arg.name = orig_arg_name; + + if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + arg.type.name = arg_info.class_name; + arg.type.is_enum = true; + } else if (arg_info.class_name != StringName()) { + arg.type.name = arg_info.class_name; + } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + arg.type.name = arg_info.hint_string; + } else if (arg_info.type == Variant::NIL) { + arg.type.name = r_context.names_cache.variant_type; + } else { + // NOTE: We don't care about the size and sign of int and float in these tests + arg.type.name = Variant::get_type_name(arg_info.type); + } + + signal.arguments.push_back(arg); + } + + bool method_conflict = exposed_class.find_property_by_name(signal.name); + + if (method_conflict || exposed_class.find_method_by_name(signal.name)) { + // TODO: + // ClassDB allows signal names that conflict with method or property names. + // However registering a signal with a conflicting name is still considered wrong. + // Unfortunately there are some existing cases that are yet to be fixed. + // Until those are fixed we will print a warning instead of failing the test. + WARN_PRINT("Signal name conflicts with " + String(method_conflict ? "method" : "property") + + ": '" + String(class_name) + "." + String(signal.name) + "'."); + } + + exposed_class.signals_.push_back(signal); + } + + // Add enums and constants + + List<String> constants; + ClassDB::get_integer_constant_list(class_name, &constants, true); + + const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map; + k = nullptr; + + while ((k = enum_map.next(k))) { + EnumData enum_; + enum_.name = *k; + + const List<StringName> &enum_constants = enum_map.get(*k); + for (const List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { + const StringName &constant_name = E->get(); + int *value = class_info->constant_map.getptr(constant_name); + TEST_FAIL_COND(!value, "Missing enum constant value: '" + + String(class_name) + "." + String(enum_.name) + "." + String(constant_name) + "'."); + constants.erase(constant_name); + + ConstantData constant; + constant.name = constant_name; + constant.value = *value; + + enum_.constants.push_back(constant); + } + + exposed_class.enums.push_back(enum_); + + r_context.enum_types.push_back(String(class_name) + "." + String(*k)); + } + + for (const List<String>::Element *E = constants.front(); E; E = E->next()) { + const String &constant_name = E->get(); + int *value = class_info->constant_map.getptr(StringName(E->get())); + TEST_FAIL_COND(!value, "Missing enum constant value: '" + String(class_name) + "." + String(constant_name) + "'."); + + ConstantData constant; + constant.name = constant_name; + constant.value = *value; + + exposed_class.constants.push_back(constant); + } + + r_context.exposed_classes.insert(class_name, exposed_class); + class_list.pop_front(); + } + + TEST_END(); +} + +void add_builtin_types(Context &r_context) { + // NOTE: We don't care about the size and sign of int and float in these tests + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + r_context.builtin_types.push_back(Variant::get_type_name(Variant::Type(i))); + } + + r_context.builtin_types.push_back(_STR(Variant)); + r_context.builtin_types.push_back(r_context.names_cache.vararg_stub_type); + r_context.builtin_types.push_back("void"); +} + +void add_global_enums(Context &r_context) { + int global_constants_count = GlobalConstants::get_global_constant_count(); + + if (global_constants_count > 0) { + for (int i = 0; i < global_constants_count; i++) { + StringName enum_name = GlobalConstants::get_global_constant_enum(i); + + if (enum_name != StringName()) { + ConstantData constant; + constant.name = GlobalConstants::get_global_constant_name(i); + constant.value = GlobalConstants::get_global_constant_value(i); + + EnumData enum_; + enum_.name = enum_name; + List<EnumData>::Element *enum_match = r_context.global_enums.find(enum_); + if (enum_match) { + enum_match->get().constants.push_back(constant); + } else { + enum_.constants.push_back(constant); + r_context.global_enums.push_back(enum_); + } + } + } + + for (List<EnumData>::Element *E = r_context.global_enums.front(); E; E = E->next()) { + r_context.enum_types.push_back(E->get().name); + } + } + + // HARDCODED + List<StringName> hardcoded_enums; + hardcoded_enums.push_back("Vector2.Axis"); + hardcoded_enums.push_back("Vector2i.Axis"); + hardcoded_enums.push_back("Vector3.Axis"); + hardcoded_enums.push_back("Vector3i.Axis"); + for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) { + // These enums are not generated and must be written manually (e.g.: Vector3.Axis) + // Here, we assume core types do not begin with underscore + r_context.enum_types.push_back(E->get()); + } +} + +TestResult run_class_db_tests() { + TEST_START(); + + Context context; + + TEST_FAIL_CHECK(add_exposed_classes(context)); + add_builtin_types(context); + add_global_enums(context); + + const ExposedClass *object_class = context.find_exposed_class(context.names_cache.object_class); + TEST_FAIL_COND(!object_class, "Object class not found."); + TEST_FAIL_COND(object_class->base != StringName(), + "Object class derives from another class: '" + object_class->base + "'."); + + for (ExposedClasses::Element E = context.exposed_classes.front(); E; E = E.next()) { + TEST_CHECK(validate_class(context, E.value())); + } + + TEST_END(); +} + +MainLoop *test() { + TestResult pass = run_class_db_tests(); + + OS::get_singleton()->print("ClassDB tests: %s\n", pass == TestResult::PASS ? "PASS" : "FAILED"); + + if (pass == TestResult::FAILED) { + OS::get_singleton()->set_exit_code(pass == TestResult::PASS ? 0 : 1); + } + + return nullptr; +} + +} // namespace TestClassDB diff --git a/main/tests/test_class_db.h b/main/tests/test_class_db.h new file mode 100644 index 0000000000..1a31cfb01b --- /dev/null +++ b/main/tests/test_class_db.h @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* test_class_db.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_TEST_CLASS_DB_H +#define GODOT_TEST_CLASS_DB_H + +#include "core/os/main_loop.h" + +namespace TestClassDB { + +MainLoop *test(); + +} + +#endif //GODOT_TEST_CLASS_DB_H diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp index 0e7c45f603..10586c6495 100644 --- a/main/tests/test_gdscript.cpp +++ b/main/tests/test_gdscript.cpp @@ -45,7 +45,6 @@ namespace TestGDScript { static void _print_indent(int p_ident, const String &p_text) { - String txt; for (int i = 0; i < p_ident; i++) { txt += '\t'; @@ -55,18 +54,18 @@ static void _print_indent(int p_ident, const String &p_text) { } static String _parser_extends(const GDScriptParser::ClassNode *p_class) { - String txt = "extends "; if (String(p_class->extends_file) != "") { txt += "\"" + p_class->extends_file + "\""; - if (p_class->extends_class.size()) + if (p_class->extends_class.size()) { txt += "."; + } } for (int i = 0; i < p_class->extends_class.size(); i++) { - - if (i != 0) + if (i != 0) { txt += "."; + } txt += p_class->extends_class[i]; } @@ -75,21 +74,19 @@ static String _parser_extends(const GDScriptParser::ClassNode *p_class) { } static String _parser_expr(const GDScriptParser::Node *p_expr) { - String txt; switch (p_expr->type) { - case GDScriptParser::Node::TYPE_IDENTIFIER: { - const GDScriptParser::IdentifierNode *id_node = static_cast<const GDScriptParser::IdentifierNode *>(p_expr); txt = id_node->name; } break; case GDScriptParser::Node::TYPE_CONSTANT: { const GDScriptParser::ConstantNode *c_node = static_cast<const GDScriptParser::ConstantNode *>(p_expr); - if (c_node->value.get_type() == Variant::STRING) + if (c_node->value.get_type() == Variant::STRING) { txt = "\"" + String(c_node->value) + "\""; - else + } else { txt = c_node->value; + } } break; case GDScriptParser::Node::TYPE_SELF: { @@ -99,9 +96,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { const GDScriptParser::ArrayNode *arr_node = static_cast<const GDScriptParser::ArrayNode *>(p_expr); txt += "["; for (int i = 0; i < arr_node->elements.size(); i++) { - - if (i > 0) + if (i > 0) { txt += ", "; + } txt += _parser_expr(arr_node->elements[i]); } txt += "]"; @@ -110,9 +107,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { const GDScriptParser::DictionaryNode *dict_node = static_cast<const GDScriptParser::DictionaryNode *>(p_expr); txt += "{"; for (int i = 0; i < dict_node->elements.size(); i++) { - - if (i > 0) + if (i > 0) { txt += ", "; + } const GDScriptParser::DictionaryNode::Pair &p = dict_node->elements[i]; txt += _parser_expr(p.key); @@ -122,37 +119,32 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { txt += "}"; } break; case GDScriptParser::Node::TYPE_OPERATOR: { - const GDScriptParser::OperatorNode *c_node = static_cast<const GDScriptParser::OperatorNode *>(p_expr); switch (c_node->op) { - case GDScriptParser::OperatorNode::OP_PARENT_CALL: txt += "."; [[fallthrough]]; case GDScriptParser::OperatorNode::OP_CALL: { - ERR_FAIL_COND_V(c_node->arguments.size() < 1, ""); String func_name; const GDScriptParser::Node *nfunc = c_node->arguments[0]; int arg_ofs = 0; if (nfunc->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { - const GDScriptParser::BuiltInFunctionNode *bif_node = static_cast<const GDScriptParser::BuiltInFunctionNode *>(nfunc); func_name = GDScriptFunctions::get_func_name(bif_node->function); arg_ofs = 1; } else if (nfunc->type == GDScriptParser::Node::TYPE_TYPE) { - const GDScriptParser::TypeNode *t_node = static_cast<const GDScriptParser::TypeNode *>(nfunc); func_name = Variant::get_type_name(t_node->vtype); arg_ofs = 1; } else { - ERR_FAIL_COND_V(c_node->arguments.size() < 2, ""); nfunc = c_node->arguments[1]; ERR_FAIL_COND_V(nfunc->type != GDScriptParser::Node::TYPE_IDENTIFIER, ""); - if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF) + if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF) { func_name = _parser_expr(c_node->arguments[0]) + "."; + } func_name += _parser_expr(nfunc); arg_ofs = 2; @@ -161,10 +153,10 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { txt += func_name + "("; for (int i = arg_ofs; i < c_node->arguments.size(); i++) { - const GDScriptParser::Node *arg = c_node->arguments[i]; - if (i > arg_ofs) + if (i > arg_ofs) { txt += ", "; + } txt += _parser_expr(arg); } @@ -172,7 +164,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } break; case GDScriptParser::OperatorNode::OP_INDEX: { - ERR_FAIL_COND_V(c_node->arguments.size() != 2, ""); //index with [] @@ -180,7 +171,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } break; case GDScriptParser::OperatorNode::OP_INDEX_NAMED: { - ERR_FAIL_COND_V(c_node->arguments.size() != 2, ""); txt = _parser_expr(c_node->arguments[0]) + "." + _parser_expr(c_node->arguments[1]); @@ -296,11 +286,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } break; case GDScriptParser::Node::TYPE_NEWLINE: { - //skippie } break; default: { - ERR_FAIL_V_MSG("", "Parser bug at " + itos(p_expr->line) + ", invalid expression type: " + itos(p_expr->type)); } } @@ -309,20 +297,14 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_indent) { - for (int i = 0; i < p_block->statements.size(); i++) { - const GDScriptParser::Node *statement = p_block->statements[i]; switch (statement->type) { - case GDScriptParser::Node::TYPE_CONTROL_FLOW: { - const GDScriptParser::ControlFlowNode *cf_node = static_cast<const GDScriptParser::ControlFlowNode *>(statement); switch (cf_node->cf_type) { - case GDScriptParser::ControlFlowNode::CF_IF: { - ERR_FAIL_COND(cf_node->arguments.size() != 1); String txt; txt += "if "; @@ -351,7 +333,6 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i } break; case GDScriptParser::ControlFlowNode::CF_WHILE: { - ERR_FAIL_COND(cf_node->arguments.size() != 1); String txt; txt += "while "; @@ -366,25 +347,22 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i // FIXME: Implement } break; case GDScriptParser::ControlFlowNode::CF_CONTINUE: { - _print_indent(p_indent, "continue"); } break; case GDScriptParser::ControlFlowNode::CF_BREAK: { - _print_indent(p_indent, "break"); } break; case GDScriptParser::ControlFlowNode::CF_RETURN: { - - if (cf_node->arguments.size()) + if (cf_node->arguments.size()) { _print_indent(p_indent, "return " + _parser_expr(cf_node->arguments[0])); - else + } else { _print_indent(p_indent, "return "); + } } break; } } break; case GDScriptParser::Node::TYPE_LOCAL_VAR: { - const GDScriptParser::LocalVarNode *lv_node = static_cast<const GDScriptParser::LocalVarNode *>(statement); _print_indent(p_indent, "var " + String(lv_node->name)); } break; @@ -396,22 +374,23 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i } } -static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = NULL) { - +static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = nullptr) { String txt; - if (p_func->_static) + if (p_func->_static) { txt = "static "; + } txt += "func "; - if (p_func->name == "") // initializer + if (p_func->name == "") { // initializer txt += "[built-in-initializer]"; - else + } else { txt += String(p_func->name); + } txt += "("; for (int i = 0; i < p_func->arguments.size(); i++) { - - if (i != 0) + if (i != 0) { txt += ", "; + } txt += "var " + String(p_func->arguments[i]); if (i >= (p_func->arguments.size() - p_func->default_values.size())) { int defarg = i - (p_func->arguments.size() - p_func->default_values.size()); @@ -427,25 +406,24 @@ static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, in txt += ":"; _print_indent(p_indent, txt); - if (p_initializer) + if (p_initializer) { _parser_show_block(p_initializer, p_indent + 1); + } _parser_show_block(p_func->body, p_indent + 1); } static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_indent, const Vector<String> &p_code) { - if (p_indent == 0 && (String(p_class->extends_file) != "" || p_class->extends_class.size())) { - _print_indent(p_indent, _parser_extends(p_class)); print_line("\n"); } for (int i = 0; i < p_class->subclasses.size(); i++) { - const GDScriptParser::ClassNode *subclass = p_class->subclasses[i]; String line = "class " + subclass->name; - if (String(subclass->extends_file) != "" || subclass->extends_class.size()) + if (String(subclass->extends_file) != "" || subclass->extends_class.size()) { line += " " + _parser_extends(subclass); + } line += ":"; _print_indent(p_indent, line); _parser_show_class(subclass, p_indent + 1, p_code); @@ -458,7 +436,6 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i } for (int i = 0; i < p_class->variables.size(); i++) { - const GDScriptParser::ClassNode::Member &m = p_class->variables[i]; _print_indent(p_indent, "var " + String(m.identifier)); @@ -467,17 +444,16 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i print_line("\n"); for (int i = 0; i < p_class->static_functions.size(); i++) { - _parser_show_function(p_class->static_functions[i], p_indent); print_line("\n"); } for (int i = 0; i < p_class->functions.size(); i++) { - if (String(p_class->functions[i]->name) == "_init") { _parser_show_function(p_class->functions[i], p_indent, p_class->initializer); - } else + } else { _parser_show_function(p_class->functions[i], p_indent); + } print_line("\n"); } //_parser_show_function(p_class->initializer,p_indent); @@ -485,11 +461,9 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i } static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFunction &func, int p_addr) { - int addr = p_addr & GDScriptFunction::ADDR_MASK; switch (p_addr >> GDScriptFunction::ADDR_BITS) { - case GDScriptFunction::ADDR_TYPE_SELF: { return "self"; } break; @@ -497,33 +471,28 @@ static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFun return "class"; } break; case GDScriptFunction::ADDR_TYPE_MEMBER: { - return "member(" + p_script->debug_get_member_by_index(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: { - return "class_const(" + func.get_global_name(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: { - Variant v = func.get_constant(addr); String txt; - if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH) + if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH) { txt = "\"" + String(v) + "\""; - else + } else { txt = v; + } return "const(" + txt + ")"; } break; case GDScriptFunction::ADDR_TYPE_STACK: { - return "stack(" + itos(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: { - return "var_stack(" + itos(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_GLOBAL: { - return "global(" + func.get_global_name(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_NIL: { @@ -535,11 +504,9 @@ static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFun } static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String> &p_code) { - const Map<StringName, GDScriptFunction *> &mf = p_class->debug_get_member_functions(); for (const Map<StringName, GDScriptFunction *>::Element *E = mf.front(); E; E = E->next()) { - const GDScriptFunction &func = *E->get(); const int *code = func.get_code(); int codelen = func.get_code_size(); @@ -547,9 +514,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String if (func.get_default_argument_count()) { defargs = "defarg at: "; for (int i = 0; i < func.get_default_argument_count(); i++) { - - if (i > 0) + if (i > 0) { defargs += ","; + } defargs += itos(func.get_default_argument_addr(i)); } defargs += " "; @@ -559,14 +526,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String #define DADDR(m_ip) (_disassemble_addr(p_class, func, code[ip + m_ip])) for (int ip = 0; ip < codelen;) { - int incr = 0; String txt = itos(ip) + " "; switch (code[ip]) { - case GDScriptFunction::OPCODE_OPERATOR: { - int op = code[ip + 1]; txt += " op "; @@ -581,7 +545,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_SET: { - txt += "set "; txt += DADDR(1); txt += "["; @@ -592,7 +555,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_GET: { - txt += " get "; txt += DADDR(3); txt += "="; @@ -604,7 +566,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_SET_NAMED: { - txt += " set_named "; txt += DADDR(1); txt += "[\""; @@ -615,7 +576,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_GET_NAMED: { - txt += " get_named "; txt += DADDR(3); txt += "="; @@ -627,7 +587,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_SET_MEMBER: { - txt += " set_member "; txt += "[\""; txt += func.get_global_name(code[ip + 1]); @@ -637,7 +596,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_GET_MEMBER: { - txt += " get_member "; txt += DADDR(2); txt += "="; @@ -648,7 +606,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN: { - txt += " assign "; txt += DADDR(1); txt += "="; @@ -657,7 +614,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN_TRUE: { - txt += " assign "; txt += DADDR(1); txt += "= true"; @@ -665,7 +621,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN_FALSE: { - txt += " assign "; txt += DADDR(1); txt += "= false"; @@ -673,7 +628,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN: { - txt += " assign typed builtin ("; txt += Variant::get_type_name((Variant::Type)code[ip + 1]); txt += ") "; @@ -697,7 +651,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CAST_TO_SCRIPT: { - txt += " cast "; txt += DADDR(3); txt += "="; @@ -708,7 +661,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CONSTRUCT: { - Variant::Type t = Variant::Type(code[ip + 1]); int argc = code[ip + 2]; @@ -718,9 +670,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += Variant::get_type_name(t) + "("; for (int i = 0; i < argc; i++) { - - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(i + 3); } txt += ")"; @@ -729,15 +681,15 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CONSTRUCT_ARRAY: { - int argc = code[ip + 1]; txt += " make_array "; txt += DADDR(2 + argc); txt += " = [ "; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(2 + i); } @@ -747,15 +699,15 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY: { - int argc = code[ip + 1]; txt += " make_dict "; txt += DADDR(2 + argc * 2); txt += " = { "; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(2 + i * 2 + 0); txt += ":"; txt += DADDR(2 + i * 2 + 1); @@ -769,13 +721,13 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String case GDScriptFunction::OPCODE_CALL: case GDScriptFunction::OPCODE_CALL_RETURN: { - bool ret = code[ip] == GDScriptFunction::OPCODE_CALL_RETURN; - if (ret) + if (ret) { txt += " call-ret "; - else + } else { txt += " call "; + } int argc = code[ip + 1]; if (ret) { @@ -787,8 +739,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(4 + i); } txt += ")"; @@ -797,7 +750,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CALL_BUILT_IN: { - txt += " call-built-in "; int argc = code[ip + 2]; @@ -807,8 +759,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(3 + i); } txt += ")"; @@ -817,7 +770,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CALL_SELF_BASE: { - txt += " call-self-base "; int argc = code[ip + 2]; @@ -827,8 +779,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(3 + i); } txt += ")"; @@ -837,13 +790,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_YIELD: { - txt += " yield "; incr = 1; } break; case GDScriptFunction::OPCODE_YIELD_SIGNAL: { - txt += " yield_signal "; txt += DADDR(1); txt += ","; @@ -851,13 +802,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String incr = 3; } break; case GDScriptFunction::OPCODE_YIELD_RESUME: { - txt += " yield resume: "; txt += DADDR(1); incr = 2; } break; case GDScriptFunction::OPCODE_JUMP: { - txt += " jump "; txt += itos(code[ip + 1]); @@ -865,7 +814,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_JUMP_IF: { - txt += " jump-if "; txt += DADDR(1); txt += " to "; @@ -874,7 +822,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String incr = 3; } break; case GDScriptFunction::OPCODE_JUMP_IF_NOT: { - txt += " jump-if-not "; txt += DADDR(1); txt += " to "; @@ -883,12 +830,10 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String incr = 3; } break; case GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT: { - txt += " jump-to-default-argument "; incr = 1; } break; case GDScriptFunction::OPCODE_RETURN: { - txt += " return "; txt += DADDR(1); @@ -896,33 +841,29 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ITERATE_BEGIN: { - txt += " for-init " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]); incr += 5; } break; case GDScriptFunction::OPCODE_ITERATE: { - txt += " for-loop " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]); incr += 5; } break; case GDScriptFunction::OPCODE_LINE: { - int line = code[ip + 1] - 1; - if (line >= 0 && line < p_code.size()) + if (line >= 0 && line < p_code.size()) { txt = "\n" + itos(line + 1) + ": " + p_code[line] + "\n"; - else + } else { txt = ""; + } incr += 2; } break; case GDScriptFunction::OPCODE_END: { - txt += " end"; incr += 1; } break; case GDScriptFunction::OPCODE_ASSERT: { - txt += " assert "; txt += DADDR(1); incr += 2; @@ -931,33 +872,32 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } if (incr == 0) { - ERR_BREAK_MSG(true, "Unhandled opcode: " + itos(code[ip])); } ip += incr; - if (txt != "") + if (txt != "") { print_line(txt); + } } } } MainLoop *test(TestType p_type) { - List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); if (cmdlargs.empty()) { - return NULL; + return nullptr; } String test = cmdlargs.back()->get(); if (!test.ends_with(".gd") && !test.ends_with(".gdc")) { print_line("This test expects a path to a GDScript file as its last parameter. Got: " + test); - return NULL; + return nullptr; } FileAccess *fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test); + ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test); Vector<uint8_t> buf; int flen = fa->get_len(); @@ -972,40 +912,38 @@ MainLoop *test(TestType p_type) { int last = 0; for (int i = 0; i <= code.length(); i++) { - if (code[i] == '\n' || code[i] == 0) { - lines.push_back(code.substr(last, i - last)); last = i + 1; } } if (p_type == TEST_TOKENIZER) { - GDScriptTokenizerText tk; tk.set_code(code); int line = -1; while (tk.get_token() != GDScriptTokenizer::TK_EOF) { - String text; - if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER) + if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER) { text = "'" + tk.get_token_identifier() + "' (identifier)"; - else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) { + } else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) { const Variant &c = tk.get_token_constant(); - if (c.get_type() == Variant::STRING) + if (c.get_type() == Variant::STRING) { text = "\"" + String(c) + "\""; - else + } else { text = c; + } text = text + " (" + Variant::get_type_name(c.get_type()) + " constant)"; - } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR) + } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR) { text = "ERROR: " + tk.get_token_error(); - else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE) + } else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE) { text = "newline (" + itos(tk.get_token_line()) + ") + indent: " + itos(tk.get_token_line_indent()); - else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) + } else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) { text = "'" + String(GDScriptFunctions::get_func_name(tk.get_token_built_in_func())) + "' (built-in function)"; - else + } else { text = tk.get_token_name(tk.get_token()); + } if (tk.get_token_line() != line) { int from = line + 1; @@ -1024,31 +962,29 @@ MainLoop *test(TestType p_type) { } if (p_type == TEST_PARSER) { - GDScriptParser parser; Error err = parser.parse(code); if (err) { print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error()); memdelete(fa); - return NULL; + return nullptr; } const GDScriptParser::Node *root = parser.get_parse_tree(); - ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, NULL); + ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, nullptr); const GDScriptParser::ClassNode *cnode = static_cast<const GDScriptParser::ClassNode *>(root); _parser_show_class(cnode, 0, lines); } if (p_type == TEST_COMPILER) { - GDScriptParser parser; Error err = parser.parse(code); if (err) { print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error()); memdelete(fa); - return NULL; + return nullptr; } Ref<GDScript> gds; @@ -1057,15 +993,13 @@ MainLoop *test(TestType p_type) { GDScriptCompiler gdc; err = gdc.compile(&parser, gds.ptr()); if (err) { - print_line("Compile Error:\n" + itos(gdc.get_error_line()) + ":" + itos(gdc.get_error_column()) + ":" + gdc.get_error()); - return NULL; + return nullptr; } Ref<GDScript> current = gds; while (current.is_valid()) { - print_line("** CLASS **"); _disassemble_class(current, lines); @@ -1073,7 +1007,6 @@ MainLoop *test(TestType p_type) { } } else if (p_type == TEST_BYTECODE) { - Vector<uint8_t> buf2 = GDScriptTokenizerBuffer::parse_code_string(code); String dst = test.get_basename() + ".gdc"; FileAccess *fw = FileAccess::open(dst, FileAccess::WRITE); @@ -1083,8 +1016,9 @@ MainLoop *test(TestType p_type) { memdelete(fa); - return NULL; + return nullptr; } + } // namespace TestGDScript #else @@ -1093,8 +1027,9 @@ namespace TestGDScript { MainLoop *test(TestType p_type) { ERR_PRINT("The GDScript module is disabled, therefore GDScript tests cannot be used."); - return NULL; + return nullptr; } + } // namespace TestGDScript #endif diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp index f0b00aeeae..d46a13d2c0 100644 --- a/main/tests/test_gui.cpp +++ b/main/tests/test_gui.cpp @@ -35,7 +35,7 @@ #include "core/io/image_loader.h" #include "core/os/os.h" #include "core/print_string.h" -#include "scene/2d/sprite.h" +#include "scene/2d/sprite_2d.h" #include "scene/gui/button.h" #include "scene/gui/control.h" #include "scene/gui/label.h" @@ -53,20 +53,17 @@ #include "scene/gui/tree.h" #include "scene/main/scene_tree.h" -#include "scene/3d/camera.h" -#include "scene/main/viewport.h" +#include "scene/3d/camera_3d.h" +#include "scene/main/window.h" namespace TestGUI { class TestMainLoop : public SceneTree { - public: virtual void request_quit() { - quit(); } virtual void init() { - SceneTree::init(); Panel *frame = memnew(Panel); @@ -220,7 +217,7 @@ public: richtext->add_text("faeries.\n"); richtext->pop(); richtext->add_text("In this new episode, we will attempt to "); - richtext->push_font(richtext->get_font("mono_font", "Fonts")); + richtext->push_font(richtext->get_theme_font("mono_font", "Fonts")); richtext->push_color(Color(0.7, 0.5, 1.0)); richtext->add_text("deliver something nice"); richtext->pop(); @@ -266,9 +263,9 @@ public: }; MainLoop *test() { - return memnew(TestMainLoop); } + } // namespace TestGUI #endif diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp index 2c2e6e8b45..5ebdaf1741 100644 --- a/main/tests/test_main.cpp +++ b/main/tests/test_main.cpp @@ -28,32 +28,36 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "test_main.h" + #include "core/list.h" -#include "core/os/main_loop.h" #ifdef DEBUG_ENABLED #include "test_astar.h" +#include "test_basis.h" +#include "test_class_db.h" #include "test_gdscript.h" #include "test_gui.h" #include "test_math.h" #include "test_oa_hash_map.h" #include "test_ordered_hash_map.h" -#include "test_physics.h" #include "test_physics_2d.h" +#include "test_physics_3d.h" #include "test_render.h" #include "test_shader_lang.h" #include "test_string.h" const char **tests_get_names() { - static const char *test_names[] = { "string", "math", - "physics", + "basis", "physics_2d", + "physics_3d", "render", "oa_hash_map", + "class_db", "gui", "shaderlang", "gd_tokenizer", @@ -62,104 +66,95 @@ const char **tests_get_names() { "gd_bytecode", "ordered_hash_map", "astar", - NULL + nullptr }; return test_names; } MainLoop *test_main(String p_test, const List<String> &p_args) { - if (p_test == "string") { - return TestString::test(); } if (p_test == "math") { - return TestMath::test(); } - if (p_test == "physics") { - - return TestPhysics::test(); + if (p_test == "basis") { + return TestBasis::test(); } if (p_test == "physics_2d") { - return TestPhysics2D::test(); } - if (p_test == "render") { + if (p_test == "physics_3d") { + return TestPhysics3D::test(); + } + if (p_test == "render") { return TestRender::test(); } if (p_test == "oa_hash_map") { - return TestOAHashMap::test(); } + if (p_test == "class_db") { + return TestClassDB::test(); + } + #ifndef _3D_DISABLED if (p_test == "gui") { - return TestGUI::test(); } #endif if (p_test == "shaderlang") { - return TestShaderLang::test(); } if (p_test == "gd_tokenizer") { - return TestGDScript::test(TestGDScript::TEST_TOKENIZER); } if (p_test == "gd_parser") { - return TestGDScript::test(TestGDScript::TEST_PARSER); } if (p_test == "gd_compiler") { - return TestGDScript::test(TestGDScript::TEST_COMPILER); } if (p_test == "gd_bytecode") { - return TestGDScript::test(TestGDScript::TEST_BYTECODE); } if (p_test == "ordered_hash_map") { - return TestOrderedHashMap::test(); } if (p_test == "astar") { - return TestAStar::test(); } print_line("Unknown test: " + p_test); - return NULL; + return nullptr; } #else const char **tests_get_names() { - static const char *test_names[] = { - NULL + nullptr }; return test_names; } MainLoop *test_main(String p_test, const List<String> &p_args) { - - return NULL; + return nullptr; } #endif diff --git a/main/tests/test_main.h b/main/tests/test_main.h index 56db3ea2a5..bdb1668d21 100644 --- a/main/tests/test_main.h +++ b/main/tests/test_main.h @@ -32,9 +32,10 @@ #define TEST_MAIN_H #include "core/list.h" +#include "core/os/main_loop.h" #include "core/ustring.h" const char **tests_get_names(); MainLoop *test_main(String p_test, const List<String> &p_args); -#endif +#endif // TEST_MAIN_H diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp index d91503501d..5f84bad4e9 100644 --- a/main/tests/test_math.cpp +++ b/main/tests/test_math.cpp @@ -32,8 +32,11 @@ #include "core/math/basis.h" #include "core/math/camera_matrix.h" +#include "core/math/delaunay_3d.h" +#include "core/math/geometry_2d.h" #include "core/math/math_funcs.h" #include "core/math/transform.h" +#include "core/method_ptrcall.h" #include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -43,14 +46,11 @@ #include "core/vmap.h" #include "scene/main/node.h" #include "scene/resources/texture.h" -#include "servers/visual/shader_language.h" - -#include "core/method_ptrcall.h" +#include "servers/rendering/shader_language.h" namespace TestMath { class GetClassAndNamespace { - String code; int idx; int line; @@ -77,12 +77,9 @@ class GetClassAndNamespace { }; Token get_token() { - while (true) { switch (code[idx]) { - case '\n': { - line++; idx++; break; @@ -92,37 +89,30 @@ class GetClassAndNamespace { } break; case '{': { - idx++; return TK_CURLY_BRACKET_OPEN; }; case '}': { - idx++; return TK_CURLY_BRACKET_CLOSE; }; case '[': { - idx++; return TK_BRACKET_OPEN; }; case ']': { - idx++; return TK_BRACKET_CLOSE; }; case ':': { - idx++; return TK_COLON; }; case ',': { - idx++; return TK_COMMA; }; case '.': { - idx++; return TK_PERIOD; }; @@ -134,7 +124,6 @@ class GetClassAndNamespace { continue; } break; case '/': { - switch (code[idx + 1]) { case '*': { // block comment @@ -145,7 +134,6 @@ class GetClassAndNamespace { error = true; return TK_ERROR; } else if (code[idx] == '*' && code[idx + 1] == '/') { - idx += 2; break; } else if (code[idx] == '\n') { @@ -174,7 +162,6 @@ class GetClassAndNamespace { } break; case '\'': case '"': { - CharType begin_str = code[idx]; idx++; String tk_string = String(); @@ -198,15 +185,24 @@ class GetClassAndNamespace { CharType res = 0; switch (next) { - - case 'b': res = 8; break; - case 't': res = 9; break; - case 'n': res = 10; break; - case 'f': res = 12; break; + case 'b': + res = 8; + break; + case 't': + res = 9; + break; + case 'n': + res = 10; + break; + case 'f': + res = 12; + break; case 'r': res = 13; break; - case '\"': res = '\"'; break; + case '\"': + res = '\"'; + break; case '\\': res = '\\'; break; @@ -218,8 +214,9 @@ class GetClassAndNamespace { tk_string += res; } else { - if (code[idx] == '\n') + if (code[idx] == '\n') { line++; + } tk_string += code[idx]; } idx++; @@ -231,7 +228,6 @@ class GetClassAndNamespace { } break; default: { - if (code[idx] <= 32) { idx++; break; @@ -252,11 +248,9 @@ class GetClassAndNamespace { return TK_NUMBER; } else if ((code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) { - String id; while ((code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) { - id += code[idx]; idx++; } @@ -275,7 +269,6 @@ class GetClassAndNamespace { public: Error parse(const String &p_code, const String &p_known_class_name = String()) { - code = p_code; idx = 0; line = 0; @@ -291,7 +284,6 @@ public: int curly_stack = 0; while (!error || tk != TK_EOF) { - if (tk == TK_BRACKET_OPEN) { tk = get_token(); if (tk == TK_IDENTIFIER && String(value) == "ScriptClass") { @@ -348,8 +340,9 @@ public: tk = get_token(); } - if (error) + if (error) { return ERR_PARSE_ERROR; + } return OK; } @@ -364,7 +357,6 @@ public: }; void test_vec(Plane p_vec) { - CameraMatrix cm; cm.set_perspective(45, 1, 0, 100); Plane v0 = cm.xform4(p_vec); @@ -403,6 +395,54 @@ uint32_t ihash3(uint32_t a) { } MainLoop *test() { + { + Vector<Vector3> points; + points.push_back(Vector3(0, 0, 0)); + points.push_back(Vector3(0, 0, 1)); + points.push_back(Vector3(0, 1, 0)); + points.push_back(Vector3(0, 1, 1)); + points.push_back(Vector3(1, 1, 0)); + points.push_back(Vector3(1, 0, 0)); + points.push_back(Vector3(1, 0, 1)); + points.push_back(Vector3(1, 1, 1)); + + for (int i = 0; i < 800; i++) { + points.push_back(Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * Vector3(25, 30, 33)); + } + + Vector<Delaunay3D::OutputSimplex> os = Delaunay3D::tetrahedralize(points); + print_line("simplices in the end: " + itos(os.size())); + for (int i = 0; i < os.size(); i++) { + print_line("Simplex " + itos(i) + ": "); + print_line(points[os[i].points[0]]); + print_line(points[os[i].points[1]]); + print_line(points[os[i].points[2]]); + print_line(points[os[i].points[3]]); + } + + { + FileAccessRef f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); + for (int i = 0; i < os.size(); i++) { + f->store_line("o Simplex" + itos(i)); + for (int j = 0; j < 4; j++) { + f->store_line(vformat("v %f %f %f", points[os[i].points[j]].x, points[os[i].points[j]].y, points[os[i].points[j]].z)); + } + static const int face_order[4][3] = { + { 1, 2, 3 }, + { 1, 3, 4 }, + { 1, 2, 4 }, + { 2, 3, 4 } + }; + + for (int j = 0; j < 4; j++) { + f->store_line(vformat("f %d %d %d", 4 * i + face_order[j][0], 4 * i + face_order[j][1], 4 * i + face_order[j][2])); + } + } + f->close(); + } + + return nullptr; + } { float r = 1; @@ -443,7 +483,7 @@ MainLoop *test() { float gb = (rgbe >> 9) & 0x1ff; float bb = (rgbe >> 18) & 0x1ff; float eb = (rgbe >> 27); - float mb = Math::pow(2, eb - 15.0 - 9.0); + float mb = Math::pow(2.0, eb - 15.0 - 9.0); float rd = rb * mb; float gd = gb * mb; float bd = bb * mb; @@ -475,18 +515,18 @@ MainLoop *test() { if (cmdlargs.empty()) { //try editor! - return NULL; + return nullptr; } String test = cmdlargs.back()->get(); if (test == "math") { // Not a file name but the test name, abort. // FIXME: This test is ugly as heck, needs fixing :) - return NULL; + return nullptr; } FileAccess *fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test); + ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test); Vector<uint8_t> buf; int flen = fa->get_len(); @@ -505,26 +545,22 @@ MainLoop *test() { } { - Vector<int> hashes; List<StringName> tl; ClassDB::get_class_list(&tl); for (List<StringName>::Element *E = tl.front(); E; E = E->next()) { - Vector<uint8_t> m5b = E->get().operator String().md5_buffer(); hashes.push_back(hashes.size()); } for (int i = nearest_shift(hashes.size()); i < 20; i++) { - bool success = true; for (int s = 0; s < 10000; s++) { Set<uint32_t> existing; success = true; for (int j = 0; j < hashes.size(); j++) { - uint32_t eh = ihash2(ihash3(hashes[j] + ihash(s) + s)) & ((1 << i) - 1); if (existing.has(eh)) { success = false; @@ -538,8 +574,9 @@ MainLoop *test() { break; } } - if (success) + if (success) { break; + } } print_line("DONE"); @@ -580,7 +617,7 @@ MainLoop *test() { List<String> args; args.push_back("-l"); - Error err = OS::get_singleton()->execute("/bin/ls", args, true, NULL, &ret); + Error err = OS::get_singleton()->execute("/bin/ls", args, true, nullptr, &ret); print_line("error: " + itos(err)); print_line(ret); @@ -599,7 +636,7 @@ MainLoop *test() { b["44"] = 4; } - print_line("inters: " + rtos(Geometry::segment_intersects_circle(Vector2(-5, 0), Vector2(-2, 0), Vector2(), 1.0))); + print_line("inters: " + rtos(Geometry2D::segment_intersects_circle(Vector2(-5, 0), Vector2(-2, 0), Vector2(), 1.0))); print_line("cross: " + Vector3(1, 2, 3).cross(Vector3(4, 5, 7))); print_line("dot: " + rtos(Vector3(1, 2, 3).dot(Vector3(4, 5, 7)))); @@ -660,6 +697,7 @@ MainLoop *test() { print_line("scalar /=: " + v); } - return NULL; + return nullptr; } + } // namespace TestMath diff --git a/main/tests/test_oa_hash_map.cpp b/main/tests/test_oa_hash_map.cpp index edb57f2a9f..9182f66b61 100644 --- a/main/tests/test_oa_hash_map.cpp +++ b/main/tests/test_oa_hash_map.cpp @@ -30,14 +30,43 @@ #include "test_oa_hash_map.h" -#include "core/os/os.h" - #include "core/oa_hash_map.h" +#include "core/os/os.h" namespace TestOAHashMap { -MainLoop *test() { +struct CountedItem { + static int count; + + int id = -1; + bool destroyed = false; + + CountedItem() { + count++; + } + CountedItem(int p_id) : + id(p_id) { + count++; + } + + CountedItem(const CountedItem &p_other) : + id(p_other.id) { + count++; + } + + CountedItem &operator=(const CountedItem &p_other) = default; + + ~CountedItem() { + CRASH_COND(destroyed); + count--; + destroyed = true; + } +}; + +int CountedItem::count; + +MainLoop *test() { OS::get_singleton()->print("\n\n\nHello from test\n"); // test element tracking. @@ -72,8 +101,9 @@ MainLoop *test() { uint32_t num_elems = 0; for (int i = 0; i < 500; i++) { int tmp; - if (map.lookup(i, tmp) && tmp == i * 2) + if (map.lookup(i, tmp) && tmp == i * 2) { num_elems++; + } } OS::get_singleton()->print("elements %d == %d.\n", map.get_num_elements(), num_elems); @@ -106,8 +136,9 @@ MainLoop *test() { keys[i] = Math::rand(); map.set(keys[i], dummy); - if (!map.lookup(keys[i], dummy)) + if (!map.lookup(keys[i], dummy)) { OS::get_singleton()->print("could not find 0x%X despite it was just inserted!\n", unsigned(keys[i])); + } } // check whether the keys are still present @@ -123,7 +154,6 @@ MainLoop *test() { // regression test / test for issue related to #31402 { - OS::get_singleton()->print("test for issue #31402 started...\n"); const int num_test_values = 12; @@ -153,6 +183,117 @@ MainLoop *test() { map.set(5, 1); } - return NULL; + // test memory management of items, should not crash or leak items + { + // Exercise different patterns of removal + for (int i = 0; i < 4; ++i) { + { + OAHashMap<String, CountedItem> map; + int id = 0; + for (int j = 0; j < 100; ++j) { + map.insert(itos(j), CountedItem(id)); + } + if (i <= 1) { + for (int j = 0; j < 100; ++j) { + map.remove(itos(j)); + } + } + if (i % 2 == 0) { + map.clear(); + } + } + + if (CountedItem::count != 0) { + OS::get_singleton()->print("%d != 0 (not performing the other test sub-cases, breaking...)\n", CountedItem::count); + break; + } + } + } + + // Test map with 0 capacity. + { + OAHashMap<int, String> original_map(0); + original_map.set(1, "1"); + OS::get_singleton()->print("OAHashMap 0 capacity initialization passed.\n"); + } + + // Test copy constructor. + { + OAHashMap<int, String> original_map; + original_map.set(1, "1"); + original_map.set(2, "2"); + original_map.set(3, "3"); + original_map.set(4, "4"); + original_map.set(5, "5"); + + OAHashMap<int, String> map_copy(original_map); + + bool pass = true; + for ( + OAHashMap<int, String>::Iterator it = original_map.iter(); + it.valid; + it = original_map.next_iter(it)) { + if (map_copy.lookup_ptr(*it.key) == nullptr) { + pass = false; + } + if (*it.value != *map_copy.lookup_ptr(*it.key)) { + pass = false; + } + } + if (pass) { + OS::get_singleton()->print("OAHashMap copy constructor test passed.\n"); + } else { + OS::get_singleton()->print("OAHashMap copy constructor test FAILED.\n"); + } + + map_copy.set(1, "Random String"); + if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) { + OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test FAILED.\n"); + } else { + OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test passed.\n"); + } + } + + // Test assign operator. + { + OAHashMap<int, String> original_map; + original_map.set(1, "1"); + original_map.set(2, "2"); + original_map.set(3, "3"); + original_map.set(4, "4"); + original_map.set(5, "5"); + + OAHashMap<int, String> map_copy(100000); + map_copy.set(1, "Just a string."); + map_copy = original_map; + + bool pass = true; + for ( + OAHashMap<int, String>::Iterator it = map_copy.iter(); + it.valid; + it = map_copy.next_iter(it)) { + if (original_map.lookup_ptr(*it.key) == nullptr) { + pass = false; + } + if (*it.value != *original_map.lookup_ptr(*it.key)) { + pass = false; + } + } + if (pass) { + OS::get_singleton()->print("OAHashMap assign operation test passed.\n"); + } else { + OS::get_singleton()->print("OAHashMap assign operation test FAILED.\n"); + } + + map_copy.set(1, "Random String"); + if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) { + OS::get_singleton()->print("OAHashMap assign operation atomic copy test FAILED.\n"); + } else { + OS::get_singleton()->print("OAHashMap assign operation atomic copy test passed.\n"); + } + } + + return nullptr; } + } // namespace TestOAHashMap diff --git a/main/tests/test_oa_hash_map.h b/main/tests/test_oa_hash_map.h index 60cde961c5..eb2b3d1e99 100644 --- a/main/tests/test_oa_hash_map.h +++ b/main/tests/test_oa_hash_map.h @@ -37,4 +37,5 @@ namespace TestOAHashMap { MainLoop *test(); } + #endif // TEST_OA_HASH_MAP_H diff --git a/main/tests/test_ordered_hash_map.cpp b/main/tests/test_ordered_hash_map.cpp index 4a74ad5898..d18a3784be 100644 --- a/main/tests/test_ordered_hash_map.cpp +++ b/main/tests/test_ordered_hash_map.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "test_ordered_hash_map.h" + #include "core/ordered_hash_map.h" #include "core/os/os.h" #include "core/pair.h" @@ -84,7 +86,7 @@ bool test_iteration() { map.insert(123485, 1238888); map.insert(123, 111111); - Vector<Pair<int, int> > expected; + Vector<Pair<int, int>> expected; expected.push_back(Pair<int, int>(42, 84)); expected.push_back(Pair<int, int>(123, 111111)); expected.push_back(Pair<int, int>(0, 12934)); @@ -101,7 +103,7 @@ bool test_iteration() { } bool test_const_iteration(const OrderedHashMap<int, int> &map) { - Vector<Pair<int, int> > expected; + Vector<Pair<int, int>> expected; expected.push_back(Pair<int, int>(42, 84)); expected.push_back(Pair<int, int>(123, 111111)); expected.push_back(Pair<int, int>(0, 12934)); @@ -128,7 +130,7 @@ bool test_const_iteration() { return test_const_iteration(map); } -typedef bool (*TestFunc)(void); +typedef bool (*TestFunc)(); TestFunc test_funcs[] = { @@ -139,21 +141,22 @@ TestFunc test_funcs[] = { test_size, test_iteration, test_const_iteration, - 0 + nullptr }; MainLoop *test() { - int count = 0; int passed = 0; while (true) { - if (!test_funcs[count]) + if (!test_funcs[count]) { break; + } bool pass = test_funcs[count](); - if (pass) + if (pass) { passed++; + } OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); count++; @@ -166,6 +169,7 @@ MainLoop *test() { OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return NULL; + return nullptr; } + } // namespace TestOrderedHashMap diff --git a/main/tests/test_ordered_hash_map.h b/main/tests/test_ordered_hash_map.h index 03e559107e..f251da0ba2 100644 --- a/main/tests/test_ordered_hash_map.h +++ b/main/tests/test_ordered_hash_map.h @@ -31,9 +31,11 @@ #ifndef TEST_ORDERED_HASH_MAP_H #define TEST_ORDERED_HASH_MAP_H +#include "core/os/main_loop.h" + namespace TestOrderedHashMap { MainLoop *test(); } -#endif +#endif // TEST_ORDERED_HASH_MAP_H diff --git a/main/tests/test_physics_2d.cpp b/main/tests/test_physics_2d.cpp index 160c25f43a..6cb9bf7b60 100644 --- a/main/tests/test_physics_2d.cpp +++ b/main/tests/test_physics_2d.cpp @@ -35,15 +35,15 @@ #include "core/os/os.h" #include "core/print_string.h" #include "scene/resources/texture.h" -#include "servers/physics_2d_server.h" -#include "servers/visual_server.h" +#include "servers/display_server.h" +#include "servers/physics_server_2d.h" +#include "servers/rendering_server.h" static const unsigned char convex_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0xaa, 0x69, 0x71, 0xde, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x43, 0xbb, 0x7f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0x6, 0xa, 0x3, 0x13, 0x31, 0x66, 0xa7, 0xac, 0x79, 0x0, 0x0, 0x4, 0xef, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x9b, 0xdd, 0x4e, 0x2a, 0x57, 0x14, 0xc7, 0xf7, 0x1e, 0xc0, 0x19, 0x38, 0x32, 0x80, 0xa, 0x6a, 0xda, 0x18, 0xa3, 0xc6, 0x47, 0x50, 0x7b, 0xa1, 0xd9, 0x36, 0x27, 0x7e, 0x44, 0xed, 0x45, 0x4d, 0x93, 0x3e, 0x40, 0x1f, 0x64, 0x90, 0xf4, 0x1, 0xbc, 0xf0, 0xc2, 0x9c, 0x57, 0x30, 0x4d, 0xbc, 0xa8, 0x6d, 0xc, 0x69, 0x26, 0xb5, 0x68, 0x8b, 0x35, 0x7e, 0x20, 0xb4, 0xf5, 0x14, 0xbf, 0x51, 0x3c, 0x52, 0xe, 0xc, 0xe, 0xc8, 0xf0, 0xb1, 0x7a, 0x51, 0x3d, 0xb1, 0x9e, 0x19, 0x1c, 0x54, 0x70, 0x1c, 0xdc, 0x9, 0x17, 0x64, 0x8, 0xc9, 0xff, 0xb7, 0xd6, 0x7f, 0xcd, 0x3f, 0x2b, 0xd9, 0x8, 0xbd, 0x9c, 0xda, 0x3e, 0xf8, 0x31, 0xff, 0xc, 0x0, 0x8, 0x42, 0x88, 0x9c, 0x9f, 0x9f, 0xbf, 0xa, 0x87, 0xc3, 0xad, 0x7d, 0x7d, 0x7d, 0x7f, 0x23, 0x84, 0x78, 0x8c, 0x31, 0xaf, 0x55, 0x0, 0xc6, 0xc7, 0x14, 0x1e, 0x8f, 0xc7, 0xbf, 0x38, 0x3c, 0x3c, 0x6c, 0x9b, 0x9f, 0x9f, 0x6f, 0xb8, 0x82, 0x9b, 0xee, 0xe8, 0xe8, 0xf8, 0x12, 0x0, 0xbe, 0xd3, 0x2a, 0x8, 0xfc, 0x50, 0xd1, 0xf9, 0x7c, 0x9e, 0x8a, 0x46, 0xa3, 0x5f, 0x9d, 0x9e, 0x9e, 0x7e, 0xb2, 0xb0, 0xb0, 0x60, 0xe5, 0x79, 0x1e, 0xf1, 0xfc, 0x7f, 0x3a, 0x9, 0x21, 0x88, 0x10, 0x82, 0x26, 0x26, 0x26, 0xde, 0x77, 0x75, 0x75, 0x85, 0x59, 0x96, 0xfd, 0x5e, 0x6b, 0x20, 0xf0, 0x7d, 0x85, 0x4b, 0x92, 0xf4, 0xfa, 0xe0, 0xe0, 0xe0, 0xd3, 0xb9, 0xb9, 0xb9, 0x46, 0x49, 0x92, 0xea, 0x6f, 0xa, 0xbf, 0x7d, 0x8, 0x21, 0x68, 0x70, 0x70, 0xb0, 0x38, 0x39, 0x39, 0x79, 0xd6, 0xd9, 0xd9, 0xb9, 0xcf, 0x30, 0xcc, 0xa2, 0xd6, 0xad, 0x21, 0x2b, 0x1c, 0x0, 0x38, 0x41, 0x10, 0xfc, 0xdb, 0xdb, 0xdb, 0x27, 0x1e, 0x8f, 0x27, 0x4b, 0x8, 0x1, 0x84, 0x90, 0xea, 0xf, 0x21, 0x4, 0x3c, 0x1e, 0x4f, 0x76, 0x67, 0x67, 0x67, 0x3f, 0x9f, 0xcf, 0xff, 0x7c, 0x5, 0xf3, 0xd9, 0x0, 0xe0, 0x2, 0x81, 0xc0, 0xa9, 0xdb, 0xed, 0x2e, 0x94, 0x2b, 0x5c, 0xe, 0xc4, 0xca, 0xca, 0x8a, 0x18, 0x8d, 0x46, 0x3, 0x0, 0xc0, 0x69, 0x1e, 0x4, 0x0, 0x90, 0x48, 0x24, 0x12, 0xe4, 0x38, 0xee, 0x41, 0xc2, 0x6f, 0x43, 0xe0, 0x38, 0xe, 0xfc, 0x7e, 0xbf, 0x10, 0x8b, 0xc5, 0xd6, 0x35, 0xd, 0x22, 0x9b, 0xcd, 0x7a, 0x96, 0x97, 0x97, 0x33, 0xf, 0xad, 0x7c, 0x29, 0x10, 0x9b, 0x9b, 0x9b, 0xef, 0x2e, 0x2e, 0x2e, 0x7e, 0xd5, 0x1c, 0x8, 0x0, 0x20, 0xe1, 0x70, 0x38, 0xfc, 0x98, 0xd5, 0x57, 0x2, 0xe1, 0x76, 0xbb, 0xf3, 0xa1, 0x50, 0xe8, 0x38, 0x9b, 0xcd, 0xfe, 0xa2, 0x9, 0x8, 0x0, 0x40, 0x2e, 0x2f, 0x2f, 0x7d, 0x4b, 0x4b, 0x4b, 0xb9, 0x4a, 0x54, 0x5f, 0x9, 0xc4, 0xd2, 0xd2, 0x92, 0xb4, 0xb7, 0xb7, 0xf7, 0x36, 0x97, 0xcb, 0x4d, 0x3d, 0x29, 0x8, 0x0, 0xe0, 0x42, 0xa1, 0xd0, 0x71, 0xb5, 0xc4, 0xdf, 0xb6, 0xc5, 0x93, 0xe, 0x4a, 0x0, 0x20, 0xa9, 0x54, 0xea, 0x37, 0xb7, 0xdb, 0x5d, 0xa8, 0xa6, 0x78, 0x39, 0x10, 0x6b, 0x6b, 0x6b, 0xf1, 0x64, 0x32, 0xb9, 0x5a, 0x55, 0x10, 0x0, 0xc0, 0x6d, 0x6c, 0x6c, 0x9c, 0x57, 0xbb, 0xfa, 0x25, 0x40, 0x14, 0x3, 0x81, 0x40, 0x34, 0x93, 0xc9, 0x2c, 0x57, 0x1c, 0x4, 0x0, 0x90, 0x58, 0x2c, 0xb6, 0x5e, 0xe9, 0xc1, 0x77, 0x1f, 0x10, 0x53, 0x53, 0x53, 0x52, 0xc5, 0x83, 0x14, 0x0, 0x70, 0x7e, 0xbf, 0x5f, 0xd0, 0x42, 0xf5, 0x95, 0x40, 0xf8, 0x7c, 0xbe, 0xcb, 0xa3, 0xa3, 0xa3, 0x3f, 0x1e, 0xbd, 0x1b, 0x0, 0x80, 0x1c, 0x1f, 0x1f, 0x87, 0xb4, 0x56, 0xfd, 0xaa, 0x5, 0x29, 0x51, 0x14, 0xbf, 0xf5, 0xf9, 0x7c, 0x97, 0x5a, 0xad, 0xbe, 0x12, 0x88, 0xf5, 0xf5, 0xf5, 0xd8, 0x83, 0x83, 0x54, 0xb5, 0x42, 0x8f, 0x66, 0x83, 0x94, 0xd6, 0xbd, 0x5f, 0xce, 0x7c, 0x38, 0x3c, 0x3c, 0xfc, 0xb3, 0x50, 0x28, 0xb8, 0xcb, 0x2, 0x1, 0x0, 0xdc, 0xf4, 0xf4, 0xf4, 0xfe, 0x73, 0x15, 0x2f, 0x17, 0xa4, 0x22, 0x91, 0x48, 0x50, 0xb5, 0x2d, 0x0, 0x80, 0x9b, 0x99, 0x99, 0x79, 0xfb, 0xdc, 0x1, 0xc8, 0x5, 0xa9, 0x44, 0x22, 0xf1, 0xfb, 0x9d, 0x10, 0x0, 0x80, 0x9b, 0x9d, 0x9d, 0xd, 0xea, 0x5, 0xc0, 0xad, 0xfd, 0x43, 0x1a, 0x0, 0xb8, 0xdb, 0x9a, 0xa9, 0x8f, 0xb6, 0xa4, 0x46, 0xa3, 0xa4, 0xb7, 0xd5, 0x37, 0xcf, 0xf3, 0x68, 0x75, 0x75, 0xf5, 0x4c, 0xee, 0x99, 0x1c, 0x80, 0x9c, 0x1e, 0xf7, 0xff, 0x16, 0x8b, 0x45, 0x50, 0x5, 0xa0, 0xb7, 0xb7, 0xb7, 0x85, 0x10, 0xa2, 0x2b, 0xf1, 0x84, 0x10, 0xd4, 0xdf, 0xdf, 0x6f, 0x57, 0x3, 0x80, 0x37, 0x18, 0xc, 0x5, 0x3d, 0x2, 0xa0, 0x69, 0x3a, 0x8b, 0x10, 0xe2, 0x4b, 0x2, 0xc0, 0x18, 0xf3, 0xc1, 0x60, 0x70, 0x47, 0x8f, 0x16, 0x38, 0x3a, 0x3a, 0x5a, 0x93, 0x5b, 0xc3, 0x7f, 0x64, 0x81, 0xba, 0xba, 0x3a, 0x49, 0x8f, 0x0, 0x1a, 0x1a, 0x1a, 0xd4, 0xcd, 0x0, 0x93, 0xc9, 0xa4, 0xcb, 0x21, 0xe8, 0x74, 0x3a, 0xd5, 0x1, 0xa0, 0x69, 0x5a, 0x77, 0x1d, 0x80, 0x31, 0x2e, 0x38, 0x9d, 0x4e, 0xb1, 0x66, 0x1, 0x30, 0xc, 0x23, 0x28, 0x3d, 0x93, 0x9b, 0x1, 0xb9, 0x9a, 0x6, 0x60, 0x36, 0x9b, 0x75, 0xd7, 0x1, 0x4a, 0x21, 0xa8, 0x26, 0x0, 0x94, 0xa, 0x41, 0xb2, 0x0, 0x18, 0x86, 0xc9, 0xe9, 0xd, 0x80, 0x52, 0x8, 0x92, 0x5, 0x60, 0xb1, 0x58, 0x74, 0x67, 0x1, 0xa5, 0x10, 0xa4, 0x4, 0x40, 0x77, 0x43, 0xd0, 0xe1, 0x70, 0xa8, 0x9f, 0x1, 0x14, 0x45, 0x1, 0x45, 0x51, 0x79, 0x3d, 0x1, 0x68, 0x6e, 0x6e, 0x4e, 0xaa, 0x6, 0x80, 0x10, 0x42, 0x6, 0x83, 0x41, 0x37, 0x36, 0x28, 0x15, 0x82, 0x6a, 0x2, 0x0, 0x4d, 0xd3, 0xa9, 0x52, 0xcf, 0x95, 0x0, 0xe8, 0x66, 0xe, 0x98, 0xcd, 0x66, 0xa1, 0x6c, 0x0, 0x7a, 0x5a, 0x8b, 0x59, 0x2c, 0x96, 0x64, 0xcd, 0x2, 0xb8, 0x2b, 0x4, 0xe9, 0xde, 0x2, 0x77, 0x85, 0xa0, 0x9a, 0xb0, 0x40, 0xa9, 0x10, 0xa4, 0x8, 0xc0, 0x64, 0x32, 0xe9, 0x6, 0x40, 0xa9, 0x10, 0x54, 0xaa, 0x3, 0x74, 0xf3, 0x16, 0x70, 0xb9, 0x5c, 0xe5, 0x3, 0xe8, 0xe9, 0xe9, 0x69, 0xd5, 0xc3, 0x66, 0x18, 0x63, 0x5c, 0x68, 0x6a, 0x6a, 0x12, 0xcb, 0x5, 0xa0, 0x9b, 0xd5, 0x38, 0x4d, 0xd3, 0x29, 0x8a, 0xa2, 0xa0, 0x2c, 0x0, 0x18, 0x63, 0x3e, 0x14, 0xa, 0xfd, 0x55, 0xb, 0x21, 0x48, 0xd1, 0x2, 0x7a, 0x59, 0x8d, 0xdf, 0x1b, 0x80, 0x1e, 0x56, 0xe3, 0x84, 0x10, 0x34, 0x30, 0x30, 0x60, 0xbb, 0xeb, 0x77, 0x46, 0x5, 0xef, 0x48, 0xcf, 0x4d, 0xec, 0x8d, 0x99, 0x5, 0xf5, 0xf5, 0xf5, 0xef, 0x46, 0x47, 0x47, 0xb, 0x2e, 0x97, 0xeb, 0xbc, 0x54, 0x8, 0x52, 0x4, 0xc0, 0x30, 0x8c, 0xf4, 0x5c, 0x4, 0x9b, 0x4c, 0xa6, 0xf4, 0xf8, 0xf8, 0xb8, 0xc8, 0xb2, 0x6c, 0x32, 0x9d, 0x4e, 0xff, 0xd4, 0xdd, 0xdd, 0x7d, 0x66, 0x34, 0x1a, 0x8b, 0xd7, 0x3, 0xfd, 0xae, 0x5b, 0x29, 0xb2, 0x57, 0x66, 0xb6, 0xb6, 0xb6, 0xde, 0xc4, 0xe3, 0xf1, 0x6f, 0xae, 0xaf, 0xc1, 0x28, 0x5d, 0x85, 0x79, 0x2, 0xc1, 0x60, 0xb5, 0x5a, 0xa3, 0xa3, 0xa3, 0xa3, 0x45, 0xab, 0xd5, 0x9a, 0x2a, 0x16, 0x8b, 0x8b, 0x6d, 0x6d, 0x6d, 0xef, 0xd5, 0x8a, 0x55, 0xd, 0x20, 0x91, 0x48, 0xbc, 0x3e, 0x38, 0x38, 0xf8, 0xda, 0x6e, 0xb7, 0xf7, 0x5f, 0x5c, 0x5c, 0xd4, 0x7b, 0xbd, 0xde, 0xbc, 0x20, 0x8, 0xcd, 0x85, 0x42, 0x81, 0xfe, 0xf0, 0xae, 0xac, 0x10, 0x98, 0x9b, 0xd5, 0xc5, 0x18, 0x17, 0x59, 0x96, 0x3d, 0x1d, 0x19, 0x19, 0x1, 0x96, 0x65, 0x5, 0x8a, 0xa2, 0x7e, 0x6c, 0x69, 0x69, 0x49, 0x3d, 0x44, 0xb0, 0x2a, 0x0, 0x1f, 0xcc, 0x74, 0x75, 0x41, 0xea, 0xfa, 0x7b, 0x32, 0x99, 0x64, 0x76, 0x77, 0x77, 0x5d, 0xe, 0x87, 0xa3, 0x5f, 0x14, 0xc5, 0x57, 0x57, 0x60, 0x5a, 0x8b, 0xc5, 0xa2, 0xf1, 0xbe, 0x50, 0x6e, 0xa, 0x66, 0x18, 0x26, 0x31, 0x36, 0x36, 0x96, 0x65, 0x59, 0x36, 0x29, 0x49, 0x92, 0xb7, 0xbd, 0xbd, 0xfd, 0x9f, 0x72, 0xda, 0xf9, 0xd1, 0x1, 0xa8, 0x1, 0x93, 0xcf, 0xe7, 0xa9, 0x93, 0x93, 0x13, 0x1b, 0x4d, 0xd3, 0x9f, 0xb, 0x82, 0x60, 0xf5, 0x7a, 0xbd, 0xd9, 0x54, 0x2a, 0xe5, 0xcc, 0x64, 0x32, 0xe, 0xb9, 0x6e, 0xb9, 0x16, 0x8c, 0x31, 0x2e, 0xda, 0x6c, 0xb6, 0xc8, 0xd0, 0xd0, 0x10, 0x65, 0xb3, 0xd9, 0x92, 0x95, 0xa8, 0x6e, 0xc5, 0x0, 0xa8, 0xe9, 0x96, 0x68, 0x34, 0x6a, 0xdd, 0xdf, 0xdf, 0x6f, 0x76, 0xb9, 0x5c, 0x9f, 0x89, 0xa2, 0x58, 0xbf, 0xb8, 0xb8, 0x8, 0x26, 0x93, 0x29, 0x3b, 0x3c, 0x3c, 0x8c, 0xed, 0x76, 0x7b, 0xd2, 0x68, 0x34, 0xfe, 0xd0, 0xd8, 0xd8, 0x98, 0xae, 0xb6, 0xe0, 0x8a, 0x1, 0x50, 0xb, 0xe6, 0xa9, 0x5, 0xbf, 0x9c, 0x97, 0xf3, 0xff, 0xf3, 0x2f, 0x6a, 0x82, 0x7f, 0xf6, 0x4e, 0xca, 0x1b, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; class TestPhysics2DMainLoop : public MainLoop { - GDCLASS(TestPhysics2DMainLoop, MainLoop); RID circle_img; @@ -57,7 +57,6 @@ class TestPhysics2DMainLoop : public MainLoop { Vector2 ray_from, ray_to; struct BodyShapeData { - RID image; RID shape; }; @@ -65,19 +64,16 @@ class TestPhysics2DMainLoop : public MainLoop { BodyShapeData body_shape_data[8]; void _create_body_shape_data() { - VisualServer *vs = VisualServer::get_singleton(); - Physics2DServer *ps = Physics2DServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); // SEGMENT { - Vector<uint8_t> pixels; pixels.resize(32 * 2 * 2); for (int i = 0; i < 2; i++) { - for (int j = 0; j < 32; j++) { - pixels.set(i * 32 * 2 + j * 2 + 0, (j == 0) ? 255 : 0); pixels.set(i * 32 * 2 + j * 2 + 1, 255); } @@ -85,24 +81,21 @@ class TestPhysics2DMainLoop : public MainLoop { Ref<Image> image = memnew(Image(32, 2, 0, Image::FORMAT_LA8, pixels)); - body_shape_data[Physics2DServer::SHAPE_SEGMENT].image = vs->texture_2d_create(image); + body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].image = vs->texture_2d_create(image); RID segment_shape = ps->segment_shape_create(); Rect2 sg(Point2(-16, 0), Point2(16, 0)); ps->shape_set_data(segment_shape, sg); - body_shape_data[Physics2DServer::SHAPE_SEGMENT].shape = segment_shape; + body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].shape = segment_shape; } // CIRCLE { - Vector<uint8_t> pixels; pixels.resize(32 * 32 * 2); for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - bool black = Vector2(i - 16, j - 16).length_squared() < 16 * 16; pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16) ? 255 : 0); @@ -112,24 +105,21 @@ class TestPhysics2DMainLoop : public MainLoop { Ref<Image> image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels)); - body_shape_data[Physics2DServer::SHAPE_CIRCLE].image = vs->texture_2d_create(image); + body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].image = vs->texture_2d_create(image); RID circle_shape = ps->circle_shape_create(); ps->shape_set_data(circle_shape, 16); - body_shape_data[Physics2DServer::SHAPE_CIRCLE].shape = circle_shape; + body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].shape = circle_shape; } // BOX { - Vector<uint8_t> pixels; pixels.resize(32 * 32 * 2); for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - bool black = i > 0 && i < 31 && j > 0 && j < 31; pixels.set(i * 32 * 2 + j * 2 + 0, black ? 0 : 255); @@ -139,24 +129,21 @@ class TestPhysics2DMainLoop : public MainLoop { Ref<Image> image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels)); - body_shape_data[Physics2DServer::SHAPE_RECTANGLE].image = vs->texture_2d_create(image); + body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].image = vs->texture_2d_create(image); RID rectangle_shape = ps->rectangle_shape_create(); ps->shape_set_data(rectangle_shape, Vector2(16, 16)); - body_shape_data[Physics2DServer::SHAPE_RECTANGLE].shape = rectangle_shape; + body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].shape = rectangle_shape; } // CAPSULE { - Vector<uint8_t> pixels; pixels.resize(32 * 64 * 2); for (int i = 0; i < 64; i++) { - for (int j = 0; j < 32; j++) { - int si = i > 48 ? i - 32 : (i < 16 ? i : 16); bool black = Vector2(si - 16, j - 16).length_squared() < 16 * 16; @@ -167,21 +154,20 @@ class TestPhysics2DMainLoop : public MainLoop { Ref<Image> image = memnew(Image(32, 64, 0, Image::FORMAT_LA8, pixels)); - body_shape_data[Physics2DServer::SHAPE_CAPSULE].image = vs->texture_2d_create(image); + body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].image = vs->texture_2d_create(image); RID capsule_shape = ps->capsule_shape_create(); ps->shape_set_data(capsule_shape, Vector2(16, 32)); - body_shape_data[Physics2DServer::SHAPE_CAPSULE].shape = capsule_shape; + body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].shape = capsule_shape; } // CONVEX { - Ref<Image> image = memnew(Image(convex_png)); - body_shape_data[Physics2DServer::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image); + body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image); RID convex_polygon_shape = ps->convex_polygon_shape_create(); @@ -196,27 +182,23 @@ class TestPhysics2DMainLoop : public MainLoop { arr.push_back(Point2(11, 7) - sb); ps->shape_set_data(convex_polygon_shape, arr); - body_shape_data[Physics2DServer::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape; + body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape; } } void _do_ray_query() { - /* - Physics2DServer *ps = Physics2DServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); ps->query_intersection_segment(ray_query,ray_from,ray_to); */ } protected: void input_event(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->is_pressed()) { - Point2 p(mb->get_position().x, mb->get_position().y); if (mb->get_button_index() == 1) { @@ -232,7 +214,6 @@ protected: Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - Point2 p = mm->get_position(); if (mm->get_button_mask() & BUTTON_MASK_LEFT) { @@ -245,16 +226,15 @@ protected: } } - RID _add_body(Physics2DServer::ShapeType p_shape, const Transform2D &p_xform) { - - VisualServer *vs = VisualServer::get_singleton(); - Physics2DServer *ps = Physics2DServer::get_singleton(); + RID _add_body(PhysicsServer2D::ShapeType p_shape, const Transform2D &p_xform) { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); RID body = ps->body_create(); ps->body_add_shape(body, body_shape_data[p_shape].shape); ps->body_set_space(body, space); - ps->body_set_continuous_collision_detection_mode(body, Physics2DServer::CCD_MODE_CAST_SHAPE); - ps->body_set_state(body, Physics2DServer::BODY_STATE_TRANSFORM, p_xform); + ps->body_set_continuous_collision_detection_mode(body, PhysicsServer2D::CCD_MODE_CAST_SHAPE); + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform); //print_line("add body with xform: "+p_xform); RID sprite = vs->canvas_item_create(); @@ -271,8 +251,7 @@ protected: } void _add_plane(const Vector2 &p_normal, real_t p_d) { - - Physics2DServer *ps = Physics2DServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); Array arr; arr.push_back(p_normal); @@ -282,23 +261,22 @@ protected: ps->shape_set_data(plane, arr); RID plane_body = ps->body_create(); - ps->body_set_mode(plane_body, Physics2DServer::BODY_MODE_STATIC); + ps->body_set_mode(plane_body, PhysicsServer2D::BODY_MODE_STATIC); ps->body_set_space(plane_body, space); ps->body_add_shape(plane_body, plane); } void _add_concave(const Vector<Vector2> &p_points, const Transform2D &p_xform = Transform2D()) { - - Physics2DServer *ps = Physics2DServer::get_singleton(); - VisualServer *vs = VisualServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); RID concave = ps->concave_polygon_shape_create(); ps->shape_set_data(concave, p_points); RID body = ps->body_create(); - ps->body_set_mode(body, Physics2DServer::BODY_MODE_STATIC); + ps->body_set_mode(body, PhysicsServer2D::BODY_MODE_STATIC); ps->body_set_space(body, space); ps->body_add_shape(body, concave); - ps->body_set_state(body, Physics2DServer::BODY_STATE_TRANSFORM, p_xform); + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform); RID sprite = vs->canvas_item_create(); vs->canvas_item_set_parent(sprite, canvas); @@ -309,12 +287,11 @@ protected: } void _body_moved(Object *p_state, RID p_sprite) { - Physics2DDirectBodyState *state = (Physics2DDirectBodyState *)p_state; - VisualServer::get_singleton()->canvas_item_set_transform(p_sprite, state->get_transform()); + PhysicsDirectBodyState2D *state = (PhysicsDirectBodyState2D *)p_state; + RenderingServer::get_singleton()->canvas_item_set_transform(p_sprite, state->get_transform()); } void _ray_query_callback(const RID &p_rid, ObjectID p_id, int p_shape, const Vector2 &p_point, const Vector2 &p_normal) { - Vector2 ray_end; if (p_rid.is_valid()) { @@ -323,38 +300,36 @@ protected: ray_end = ray_to; } - VisualServer *vs = VisualServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); vs->canvas_item_clear(ray); vs->canvas_item_add_line(ray, ray_from, ray_end, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); - if (p_rid.is_valid()) + if (p_rid.is_valid()) { vs->canvas_item_add_line(ray, ray_end, ray_end + p_normal * 20, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); + } } static void _bind_methods() { - ClassDB::bind_method(D_METHOD("_body_moved"), &TestPhysics2DMainLoop::_body_moved); ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback); } public: virtual void init() { - - VisualServer *vs = VisualServer::get_singleton(); - Physics2DServer *ps = Physics2DServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); space = ps->space_create(); ps->space_set_active(space, true); ps->set_active(true); - ps->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1)); - ps->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY, 98); + ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1)); + ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 98); { - RID vp = vs->viewport_create(); canvas = vs->canvas_create(); - Size2i screen_size = OS::get_singleton()->get_window_size(); + Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); vs->viewport_attach_canvas(vp, canvas); vs->viewport_set_size(vp, screen_size.x, screen_size.y); vs->viewport_attach_to_screen(vp, Rect2(Vector2(), screen_size)); @@ -376,32 +351,30 @@ public: _create_body_shape_data(); for (int i = 0; i < 32; i++) { - - Physics2DServer::ShapeType types[4] = { - Physics2DServer::SHAPE_CIRCLE, - Physics2DServer::SHAPE_CAPSULE, - Physics2DServer::SHAPE_RECTANGLE, - Physics2DServer::SHAPE_CONVEX_POLYGON, + PhysicsServer2D::ShapeType types[4] = { + PhysicsServer2D::SHAPE_CIRCLE, + PhysicsServer2D::SHAPE_CAPSULE, + PhysicsServer2D::SHAPE_RECTANGLE, + PhysicsServer2D::SHAPE_CONVEX_POLYGON, }; - Physics2DServer::ShapeType type = types[i % 4]; - //type=Physics2DServer::SHAPE_SEGMENT; + PhysicsServer2D::ShapeType type = types[i % 4]; + //type=PhysicsServer2D::SHAPE_SEGMENT; _add_body(type, Transform2D(i * 0.8, Point2(152 + i * 40, 100 - 40 * i))); /* if (i==0) - ps->body_set_mode(b,Physics2DServer::BODY_MODE_STATIC); + ps->body_set_mode(b,PhysicsServer2D::BODY_MODE_STATIC); */ } - //RID b= _add_body(Physics2DServer::SHAPE_CIRCLE,Transform2D(0,Point2(101,140))); - //ps->body_set_mode(b,Physics2DServer::BODY_MODE_STATIC); + //RID b= _add_body(PhysicsServer2D::SHAPE_CIRCLE,Transform2D(0,Point2(101,140))); + //ps->body_set_mode(b,PhysicsServer2D::BODY_MODE_STATIC); Point2 prev; Vector<Point2> parr; for (int i = 0; i < 30; i++) { - Point2 p(i * 60, Math::randf() * 70 + 340); if (i > 0) { parr.push_back(prev); @@ -417,7 +390,6 @@ public: } virtual bool idle(float p_time) { - return false; } virtual void finish() { @@ -429,7 +401,7 @@ public: namespace TestPhysics2D { MainLoop *test() { - return memnew(TestPhysics2DMainLoop); } + } // namespace TestPhysics2D diff --git a/main/tests/test_physics.cpp b/main/tests/test_physics_3d.cpp index 0304e8f6dd..dfe2e946cf 100644 --- a/main/tests/test_physics.cpp +++ b/main/tests/test_physics_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* test_physics.cpp */ +/* test_physics_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "test_physics.h" +#include "test_physics_3d.h" #include "core/map.h" #include "core/math/math_funcs.h" @@ -36,12 +36,12 @@ #include "core/os/main_loop.h" #include "core/os/os.h" #include "core/print_string.h" -#include "servers/physics_server.h" -#include "servers/visual_server.h" +#include "servers/display_server.h" +#include "servers/physics_server_3d.h" +#include "servers/rendering_server.h" -class TestPhysicsMainLoop : public MainLoop { - - GDCLASS(TestPhysicsMainLoop, MainLoop); +class TestPhysics3DMainLoop : public MainLoop { + GDCLASS(TestPhysics3DMainLoop, MainLoop); enum { LINK_COUNT = 20, @@ -64,13 +64,12 @@ class TestPhysicsMainLoop : public MainLoop { Point2 joy_direction; List<RID> bodies; - Map<PhysicsServer::ShapeType, RID> type_shape_map; - Map<PhysicsServer::ShapeType, RID> type_mesh_map; + Map<PhysicsServer3D::ShapeType, RID> type_shape_map; + Map<PhysicsServer3D::ShapeType, RID> type_mesh_map; void body_changed_transform(Object *p_state, RID p_visual_instance) { - - PhysicsDirectBodyState *state = (PhysicsDirectBodyState *)p_state; - VisualServer *vs = VisualServer::get_singleton(); + PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; + RenderingServer *vs = RenderingServer::get_singleton(); Transform t = state->get_transform(); vs->instance_set_transform(p_visual_instance, t); } @@ -79,41 +78,37 @@ class TestPhysicsMainLoop : public MainLoop { protected: static void _bind_methods() { - - ClassDB::bind_method("body_changed_transform", &TestPhysicsMainLoop::body_changed_transform); + ClassDB::bind_method("body_changed_transform", &TestPhysics3DMainLoop::body_changed_transform); } - RID create_body(PhysicsServer::ShapeType p_shape, PhysicsServer::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) { - - VisualServer *vs = VisualServer::get_singleton(); - PhysicsServer *ps = PhysicsServer::get_singleton(); + RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape], scenario); RID body = ps->body_create(p_body, !p_active_default); ps->body_set_space(body, space); - ps->body_set_param(body, PhysicsServer::BODY_PARAM_BOUNCE, 0.0); + ps->body_set_param(body, PhysicsServer3D::BODY_PARAM_BOUNCE, 0.0); //todo set space ps->body_add_shape(body, type_shape_map[p_shape]); ps->body_set_force_integration_callback(body, this, "body_changed_transform", mesh_instance); - ps->body_set_state(body, PhysicsServer::BODY_STATE_TRANSFORM, p_location); + ps->body_set_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location); bodies.push_back(body); - if (p_body == PhysicsServer::BODY_MODE_STATIC) { - + if (p_body == PhysicsServer3D::BODY_MODE_STATIC) { vs->instance_set_transform(mesh_instance, p_location); } return body; } RID create_static_plane(const Plane &p_plane) { + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - PhysicsServer *ps = PhysicsServer::get_singleton(); - - RID world_margin_shape = ps->shape_create(PhysicsServer::SHAPE_PLANE); + RID world_margin_shape = ps->shape_create(PhysicsServer3D::SHAPE_PLANE); ps->shape_set_data(world_margin_shape, p_plane); - RID b = ps->body_create(PhysicsServer::BODY_MODE_STATIC); + RID b = ps->body_create(PhysicsServer3D::BODY_MODE_STATIC); ps->body_set_space(b, space); //todo set space ps->body_add_shape(b, world_margin_shape); @@ -121,81 +116,77 @@ protected: } void configure_body(RID p_body, float p_mass, float p_friction, float p_bounce) { - - PhysicsServer *ps = PhysicsServer::get_singleton(); - ps->body_set_param(p_body, PhysicsServer::BODY_PARAM_MASS, p_mass); - ps->body_set_param(p_body, PhysicsServer::BODY_PARAM_FRICTION, p_friction); - ps->body_set_param(p_body, PhysicsServer::BODY_PARAM_BOUNCE, p_bounce); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_MASS, p_mass); + ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_FRICTION, p_friction); + ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_BOUNCE, p_bounce); } void init_shapes() { - - VisualServer *vs = VisualServer::get_singleton(); - PhysicsServer *ps = PhysicsServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); /* SPHERE SHAPE */ RID sphere_mesh = vs->make_sphere_mesh(10, 20, 0.5); - type_mesh_map[PhysicsServer::SHAPE_SPHERE] = sphere_mesh; + type_mesh_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_mesh; - RID sphere_shape = ps->shape_create(PhysicsServer::SHAPE_SPHERE); + RID sphere_shape = ps->shape_create(PhysicsServer3D::SHAPE_SPHERE); ps->shape_set_data(sphere_shape, 0.5); - type_shape_map[PhysicsServer::SHAPE_SPHERE] = sphere_shape; + type_shape_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_shape; /* BOX SHAPE */ - Vector<Plane> box_planes = Geometry::build_box_planes(Vector3(0.5, 0.5, 0.5)); + Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(0.5, 0.5, 0.5)); RID box_mesh = vs->mesh_create(); - Geometry::MeshData box_data = Geometry::build_convex_mesh(box_planes); + Geometry3D::MeshData box_data = Geometry3D::build_convex_mesh(box_planes); vs->mesh_add_surface_from_mesh_data(box_mesh, box_data); - type_mesh_map[PhysicsServer::SHAPE_BOX] = box_mesh; + type_mesh_map[PhysicsServer3D::SHAPE_BOX] = box_mesh; - RID box_shape = ps->shape_create(PhysicsServer::SHAPE_BOX); + RID box_shape = ps->shape_create(PhysicsServer3D::SHAPE_BOX); ps->shape_set_data(box_shape, Vector3(0.5, 0.5, 0.5)); - type_shape_map[PhysicsServer::SHAPE_BOX] = box_shape; + type_shape_map[PhysicsServer3D::SHAPE_BOX] = box_shape; /* CAPSULE SHAPE */ - Vector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5, 0.7, 12, Vector3::AXIS_Z); + Vector<Plane> capsule_planes = Geometry3D::build_capsule_planes(0.5, 0.7, 12, Vector3::AXIS_Z); RID capsule_mesh = vs->mesh_create(); - Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes); + Geometry3D::MeshData capsule_data = Geometry3D::build_convex_mesh(capsule_planes); vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data); - type_mesh_map[PhysicsServer::SHAPE_CAPSULE] = capsule_mesh; + type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh; - RID capsule_shape = ps->shape_create(PhysicsServer::SHAPE_CAPSULE); + RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE); Dictionary capsule_params; capsule_params["radius"] = 0.5; capsule_params["height"] = 1.4; ps->shape_set_data(capsule_shape, capsule_params); - type_shape_map[PhysicsServer::SHAPE_CAPSULE] = capsule_shape; + type_shape_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_shape; /* CONVEX SHAPE */ - Vector<Plane> convex_planes = Geometry::build_cylinder_planes(0.5, 0.7, 5, Vector3::AXIS_Z); + Vector<Plane> convex_planes = Geometry3D::build_cylinder_planes(0.5, 0.7, 5, Vector3::AXIS_Z); RID convex_mesh = vs->mesh_create(); - Geometry::MeshData convex_data = Geometry::build_convex_mesh(convex_planes); + Geometry3D::MeshData convex_data = Geometry3D::build_convex_mesh(convex_planes); QuickHull::build(convex_data.vertices, convex_data); vs->mesh_add_surface_from_mesh_data(convex_mesh, convex_data); - type_mesh_map[PhysicsServer::SHAPE_CONVEX_POLYGON] = convex_mesh; + type_mesh_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_mesh; - RID convex_shape = ps->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON); + RID convex_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON); ps->shape_set_data(convex_shape, convex_data.vertices); - type_shape_map[PhysicsServer::SHAPE_CONVEX_POLYGON] = convex_shape; + type_shape_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_shape; } void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) { - - VisualServer *vs = VisualServer::get_singleton(); - PhysicsServer *ps = PhysicsServer::get_singleton(); - RID trimesh_shape = ps->shape_create(PhysicsServer::SHAPE_CONCAVE_POLYGON); + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON); ps->shape_set_data(trimesh_shape, p_faces); p_faces = ps->shape_get_data(trimesh_shape); // optimized one Vector<Vector3> normals; // for drawing for (int i = 0; i < p_faces.size() / 3; i++) { - Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]); normals.push_back(p.normal); normals.push_back(p.normal); @@ -204,34 +195,31 @@ protected: RID trimesh_mesh = vs->mesh_create(); Array d; - d.resize(VS::ARRAY_MAX); - d[VS::ARRAY_VERTEX] = p_faces; - d[VS::ARRAY_NORMAL] = normals; - vs->mesh_add_surface_from_arrays(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, d); + d.resize(RS::ARRAY_MAX); + d[RS::ARRAY_VERTEX] = p_faces; + d[RS::ARRAY_NORMAL] = normals; + vs->mesh_add_surface_from_arrays(trimesh_mesh, RS::PRIMITIVE_TRIANGLES, d); RID triins = vs->instance_create2(trimesh_mesh, scenario); - RID tribody = ps->body_create(PhysicsServer::BODY_MODE_STATIC); + RID tribody = ps->body_create(PhysicsServer3D::BODY_MODE_STATIC); ps->body_set_space(tribody, space); //todo set space ps->body_add_shape(tribody, trimesh_shape); Transform tritrans = p_xform; - ps->body_set_state(tribody, PhysicsServer::BODY_STATE_TRANSFORM, tritrans); + ps->body_set_state(tribody, PhysicsServer3D::BODY_STATE_TRANSFORM, tritrans); vs->instance_set_transform(triins, tritrans); } void make_grid(int p_width, int p_height, float p_cellsize, float p_cellheight, const Transform &p_xform = Transform()) { - - Vector<Vector<float> > grid; + Vector<Vector<float>> grid; grid.resize(p_width); for (int i = 0; i < p_width; i++) { - grid.write[i].resize(p_height); for (int j = 0; j < p_height; j++) { - grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight); } } @@ -239,9 +227,7 @@ protected: Vector<Vector3> faces; for (int i = 1; i < p_width; i++) { - for (int j = 1; j < p_height; j++) { - #define MAKE_VERTEX(m_x, m_z) \ faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize)) @@ -260,44 +246,38 @@ protected: public: virtual void input_event(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && mm->get_button_mask() & 4) { - ofs_y -= mm->get_relative().y / 200.0; ofs_x += mm->get_relative().x / 200.0; } if (mm.is_valid() && mm->get_button_mask() & 1) { - float y = -mm->get_relative().y / 20.0; float x = mm->get_relative().x / 20.0; if (mover.is_valid()) { - - PhysicsServer *ps = PhysicsServer::get_singleton(); - Transform t = ps->body_get_state(mover, PhysicsServer::BODY_STATE_TRANSFORM); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); t.origin += Vector3(x, y, 0); - ps->body_set_state(mover, PhysicsServer::BODY_STATE_TRANSFORM, t); + ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); } } } virtual void request_quit() { - quit = true; } virtual void init() { - ofs_x = ofs_y = 0; init_shapes(); - PhysicsServer *ps = PhysicsServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); space = ps->space_create(); ps->space_set_active(space, true); - VisualServer *vs = VisualServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); /* LIGHT */ RID lightaux = vs->directional_light_create(); @@ -313,7 +293,7 @@ public: camera = vs->camera_create(); RID viewport = vs->viewport_create(); - Size2i screen_size = OS::get_singleton()->get_window_size(); + Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); vs->viewport_set_size(viewport, screen_size.x, screen_size.y); vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size)); vs->viewport_set_active(viewport, true); @@ -331,20 +311,19 @@ public: quit = false; } virtual bool iteration(float p_time) { - if (mover.is_valid()) { static float joy_speed = 10; - PhysicsServer *ps = PhysicsServer::get_singleton(); - Transform t = ps->body_get_state(mover, PhysicsServer::BODY_STATE_TRANSFORM); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); + Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); t.origin += Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time, 0); - ps->body_set_state(mover, PhysicsServer::BODY_STATE_TRANSFORM, t); + ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); }; Transform cameratr; cameratr.rotate(Vector3(0, 1, 0), ofs_x); cameratr.rotate(Vector3(1, 0, 0), -ofs_y); cameratr.translate(Vector3(0, 2, 8)); - VisualServer *vs = VisualServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); vs->camera_set_transform(camera, cameratr); return quit; @@ -359,18 +338,17 @@ public: } void test_character() { + RenderingServer *vs = RenderingServer::get_singleton(); + PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - VisualServer *vs = VisualServer::get_singleton(); - PhysicsServer *ps = PhysicsServer::get_singleton(); - - Vector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5, 1, 12, 5, Vector3::AXIS_Y); + Vector<Plane> capsule_planes = Geometry3D::build_capsule_planes(0.5, 1, 12, 5, Vector3::AXIS_Y); RID capsule_mesh = vs->mesh_create(); - Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes); + Geometry3D::MeshData capsule_data = Geometry3D::build_convex_mesh(capsule_planes); vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data); - type_mesh_map[PhysicsServer::SHAPE_CAPSULE] = capsule_mesh; + type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh; - RID capsule_shape = ps->shape_create(PhysicsServer::SHAPE_CAPSULE); + RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE); Dictionary capsule_params; capsule_params["radius"] = 0.5; capsule_params["height"] = 1; @@ -380,44 +358,41 @@ public: ps->shape_set_data(capsule_shape, capsule_params); RID mesh_instance = vs->instance_create2(capsule_mesh, scenario); - character = ps->body_create(PhysicsServer::BODY_MODE_CHARACTER); + character = ps->body_create(PhysicsServer3D::BODY_MODE_CHARACTER); ps->body_set_space(character, space); //todo add space ps->body_add_shape(character, capsule_shape); ps->body_set_force_integration_callback(character, this, "body_changed_transform", mesh_instance); - ps->body_set_state(character, PhysicsServer::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2))); + ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2))); bodies.push_back(character); } void test_fall() { - for (int i = 0; i < 35; i++) { - - static const PhysicsServer::ShapeType shape_idx[] = { - PhysicsServer::SHAPE_CAPSULE, - PhysicsServer::SHAPE_BOX, - PhysicsServer::SHAPE_SPHERE, - PhysicsServer::SHAPE_CONVEX_POLYGON + static const PhysicsServer3D::ShapeType shape_idx[] = { + PhysicsServer3D::SHAPE_CAPSULE, + PhysicsServer3D::SHAPE_BOX, + PhysicsServer3D::SHAPE_SPHERE, + PhysicsServer3D::SHAPE_CONVEX_POLYGON }; - PhysicsServer::ShapeType type = shape_idx[i % 4]; + PhysicsServer3D::ShapeType type = shape_idx[i % 4]; Transform t; t.origin = Vector3(0.0 * i, 3.5 + 1.1 * i, 0.7 + 0.0 * i); t.basis.rotate(Vector3(0.2, -1, 0), Math_PI / 2 * 0.6); - create_body(type, PhysicsServer::BODY_MODE_RIGID, t); + create_body(type, PhysicsServer3D::BODY_MODE_RIGID, t); } create_static_plane(Plane(Vector3(0, 1, 0), -1)); } void test_activate() { - - create_body(PhysicsServer::SHAPE_BOX, PhysicsServer::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true); + create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true); create_static_plane(Plane(Vector3(0, 1, 0), -1)); } @@ -425,14 +400,14 @@ public: return false; } - TestPhysicsMainLoop() { + TestPhysics3DMainLoop() { } }; -namespace TestPhysics { +namespace TestPhysics3D { MainLoop *test() { - - return memnew(TestPhysicsMainLoop); + return memnew(TestPhysics3DMainLoop); } -} // namespace TestPhysics + +} // namespace TestPhysics3D diff --git a/main/tests/test_physics.h b/main/tests/test_physics_3d.h index fbbc59bba9..d03f2c6573 100644 --- a/main/tests/test_physics.h +++ b/main/tests/test_physics_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* test_physics.h */ +/* test_physics_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,7 +33,7 @@ #include "core/os/main_loop.h" -namespace TestPhysics { +namespace TestPhysics3D { MainLoop *test(); } diff --git a/main/tests/test_render.cpp b/main/tests/test_render.cpp index 62239a5cb5..d936dd72e7 100644 --- a/main/tests/test_render.cpp +++ b/main/tests/test_render.cpp @@ -36,14 +36,14 @@ #include "core/os/main_loop.h" #include "core/os/os.h" #include "core/print_string.h" -#include "servers/visual_server.h" +#include "servers/display_server.h" +#include "servers/rendering_server.h" #define OBJECT_COUNT 50 namespace TestRender { class TestMainLoop : public MainLoop { - RID test_cube; RID instance; RID camera; @@ -52,7 +52,6 @@ class TestMainLoop : public MainLoop { RID scenario; struct InstanceInfo { - RID instance; Transform base; Vector3 rot_axis; @@ -66,23 +65,22 @@ class TestMainLoop : public MainLoop { protected: public: virtual void input_event(const Ref<InputEvent> &p_event) { - - if (p_event->is_pressed()) + if (p_event->is_pressed()) { quit = true; + } } virtual void init() { - print_line("INITIALIZING TEST RENDER"); - VisualServer *vs = VisualServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); test_cube = vs->get_test_cube(); scenario = vs->scenario_create(); Vector<Vector3> vts; /* - Vector<Plane> sp = Geometry::build_sphere_planes(2,5,5); - Geometry::MeshData md2 = Geometry::build_convex_mesh(sp); + Vector<Plane> sp = Geometry3D::build_sphere_planes(2,5,5); + Geometry3D::MeshData md2 = Geometry3D::build_convex_mesh(sp); vts=md2.vertices; */ /* @@ -120,12 +118,12 @@ public: vts.push_back(Vector3(-1, 1, -1)); vts.push_back(Vector3(-1, -1, -1)); - Geometry::MeshData md; + Geometry3D::MeshData md; Error err = QuickHull::build(vts, md); print_line("ERR: " + itos(err)); test_cube = vs->mesh_create(); vs->mesh_add_surface_from_mesh_data(test_cube, md); - //vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME); + //vs->scenario_set_debug(scenario,RS::SCENARIO_DEBUG_WIREFRAME); /* RID sm = vs->shader_create(); @@ -143,7 +141,6 @@ public: }; for (int i = 0; i < object_count; i++) { - InstanceInfo ii; ii.instance = vs->instance_create2(test_cube, scenario); @@ -163,7 +160,7 @@ public: // vs->camera_set_perspective( camera, 60.0,0.1, 100.0 ); viewport = vs->viewport_create(); - Size2i screen_size = OS::get_singleton()->get_window_size(); + Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); vs->viewport_set_size(viewport, screen_size.x, screen_size.y); vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size)); vs->viewport_set_active(viewport, true); @@ -173,16 +170,16 @@ public: vs->camera_set_perspective(camera, 60, 0.1, 1000); /* - RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI ); - vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 ); - vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 ); - vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 ); + RID lightaux = vs->light_create( RenderingServer::LIGHT_OMNI ); + vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_RADIUS, 80 ); + vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ATTENUATION, 1 ); + vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ENERGY, 1.5 ); light = vs->instance_create( lightaux ); */ RID lightaux; lightaux = vs->directional_light_create(); - //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) ); + //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) ); vs->light_set_color(lightaux, Color(1.0, 1.0, 1.0)); //vs->light_set_shadow( lightaux, true ); light = vs->instance_create2(lightaux, scenario); @@ -193,10 +190,10 @@ public: vs->instance_set_transform(light, lla); lightaux = vs->omni_light_create(); - //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) ); + //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) ); vs->light_set_color(lightaux, Color(1.0, 1.0, 0.0)); - vs->light_set_param(lightaux, VisualServer::LIGHT_PARAM_RANGE, 4); - vs->light_set_param(lightaux, VisualServer::LIGHT_PARAM_ENERGY, 8); + vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_RANGE, 4); + vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_ENERGY, 8); //vs->light_set_shadow( lightaux, true ); //light = vs->instance_create( lightaux ); @@ -204,8 +201,7 @@ public: quit = false; } virtual bool iteration(float p_time) { - - VisualServer *vs = VisualServer::get_singleton(); + RenderingServer *vs = RenderingServer::get_singleton(); //Transform t; //t.rotate(Vector3(0, 1, 0), ofs); //t.translate(Vector3(0,0,20 )); @@ -216,7 +212,6 @@ public: //return quit; for (List<InstanceInfo>::Element *E = instances.front(); E; E = E->next()) { - Transform pre(Basis(E->get().rot_axis, ofs), Vector3()); vs->instance_set_transform(E->get().instance, pre * E->get().base); /* @@ -239,7 +234,7 @@ public: }; MainLoop *test() { - return memnew(TestMainLoop); } + } // namespace TestRender diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp index 941a6771bf..34ee3e3210 100644 --- a/main/tests/test_shader_lang.cpp +++ b/main/tests/test_shader_lang.cpp @@ -37,14 +37,13 @@ #include "core/print_string.h" #include "scene/gui/control.h" #include "scene/gui/text_edit.h" -#include "servers/visual/shader_language.h" +#include "servers/rendering/shader_language.h" typedef ShaderLanguage SL; namespace TestShaderLang { static String _mktab(int p_level) { - String tb; for (int i = 0; i < p_level; i++) { tb += "\t"; @@ -54,61 +53,74 @@ static String _mktab(int p_level) { } static String _typestr(SL::DataType p_type) { - return ShaderLanguage::get_datatype_name(p_type); } static String _prestr(SL::DataPrecision p_pres) { - switch (p_pres) { - case SL::PRECISION_LOWP: return "lowp "; - case SL::PRECISION_MEDIUMP: return "mediump "; - case SL::PRECISION_HIGHP: return "highp "; - case SL::PRECISION_DEFAULT: return ""; + case SL::PRECISION_LOWP: + return "lowp "; + case SL::PRECISION_MEDIUMP: + return "mediump "; + case SL::PRECISION_HIGHP: + return "highp "; + case SL::PRECISION_DEFAULT: + return ""; } return ""; } static String _opstr(SL::Operator p_op) { - return ShaderLanguage::get_operator_text(p_op); } static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { - switch (p_type) { - case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false"; - case SL::TYPE_BVEC2: return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")"; - case SL::TYPE_BVEC3: return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")"; - case SL::TYPE_BVEC4: return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")"; - case SL::TYPE_INT: return rtos(p_values[0].sint); - case SL::TYPE_IVEC2: return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")"; - case SL::TYPE_IVEC3: return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")"; - case SL::TYPE_IVEC4: return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")"; - case SL::TYPE_UINT: return rtos(p_values[0].real); - case SL::TYPE_UVEC2: return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; - case SL::TYPE_UVEC3: return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; - case SL::TYPE_UVEC4: return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; - case SL::TYPE_FLOAT: return rtos(p_values[0].real); - case SL::TYPE_VEC2: return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; - case SL::TYPE_VEC3: return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; - case SL::TYPE_VEC4: return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; - default: ERR_FAIL_V(String()); + case SL::TYPE_BOOL: + return p_values[0].boolean ? "true" : "false"; + case SL::TYPE_BVEC2: + return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")"; + case SL::TYPE_BVEC3: + return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")"; + case SL::TYPE_BVEC4: + return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")"; + case SL::TYPE_INT: + return rtos(p_values[0].sint); + case SL::TYPE_IVEC2: + return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")"; + case SL::TYPE_IVEC3: + return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")"; + case SL::TYPE_IVEC4: + return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")"; + case SL::TYPE_UINT: + return rtos(p_values[0].real); + case SL::TYPE_UVEC2: + return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; + case SL::TYPE_UVEC3: + return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; + case SL::TYPE_UVEC4: + return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; + case SL::TYPE_FLOAT: + return rtos(p_values[0].real); + case SL::TYPE_VEC2: + return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; + case SL::TYPE_VEC3: + return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; + case SL::TYPE_VEC4: + return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; + default: + ERR_FAIL_V(String()); } } static String dump_node_code(SL::Node *p_node, int p_level) { - String code; switch (p_node->type) { - case SL::Node::TYPE_SHADER: { - SL::ShaderNode *pnode = (SL::ShaderNode *)p_node; for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - String ucode = "uniform "; ucode += _prestr(E->get().precision); ucode += _typestr(E->get().type); @@ -128,14 +140,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { "white" }; - if (E->get().hint) + if (E->get().hint) { ucode += " : " + String(hint_name[E->get().hint]); + } code += ucode + "\n"; } for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { - String vcode = "varying "; vcode += _prestr(E->get().precision); vcode += _typestr(E->get().type); @@ -144,15 +156,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { code += vcode + "\n"; } for (int i = 0; i < pnode->functions.size(); i++) { - SL::FunctionNode *fnode = pnode->functions[i].function; String header; header = _typestr(fnode->return_type) + " " + fnode->name + "("; for (int j = 0; j < fnode->arguments.size(); j++) { - - if (j > 0) + if (j > 0) { header += ", "; + } header += _prestr(fnode->arguments[j].precision) + _typestr(fnode->arguments[j].type) + " " + fnode->arguments[j].name; } @@ -164,10 +175,8 @@ static String dump_node_code(SL::Node *p_node, int p_level) { //code+=dump_node_code(pnode->body,p_level); } break; case SL::Node::TYPE_STRUCT: { - } break; case SL::Node::TYPE_FUNCTION: { - } break; case SL::Node::TYPE_BLOCK: { SL::BlockNode *bnode = (SL::BlockNode *)p_node; @@ -175,12 +184,10 @@ static String dump_node_code(SL::Node *p_node, int p_level) { //variables code += _mktab(p_level - 1) + "{\n"; for (Map<StringName, SL::BlockNode::Variable>::Element *E = bnode->variables.front(); E; E = E->next()) { - code += _mktab(p_level) + _prestr(E->get().precision) + _typestr(E->get().type) + " " + E->key() + ";\n"; } for (int i = 0; i < bnode->statements.size(); i++) { - String scode = dump_node_code(bnode->statements[i], p_level); if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) { @@ -219,7 +226,6 @@ static String dump_node_code(SL::Node *p_node, int p_level) { SL::OperatorNode *onode = (SL::OperatorNode *)p_node; switch (onode->op) { - case SL::OP_ASSIGN: case SL::OP_ASSIGN_ADD: case SL::OP_ASSIGN_SUB: @@ -248,14 +254,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { case SL::OP_CONSTRUCT: code = dump_node_code(onode->arguments[0], p_level) + "("; for (int i = 1; i < onode->arguments.size(); i++) { - if (i > 1) + if (i > 1) { code += ", "; + } code += dump_node_code(onode->arguments[i], p_level); } code += ")"; break; default: { - code = "(" + dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level) + ")"; break; } @@ -265,17 +271,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { case SL::Node::TYPE_CONTROL_FLOW: { SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node; if (cfnode->flow_op == SL::FLOW_OP_IF) { - code += _mktab(p_level) + "if (" + dump_node_code(cfnode->expressions[0], p_level) + ")\n"; code += dump_node_code(cfnode->blocks[0], p_level + 1); if (cfnode->blocks.size() == 2) { - code += _mktab(p_level) + "else\n"; code += dump_node_code(cfnode->blocks[1], p_level + 1); } } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { - if (cfnode->blocks.size()) { code = "return " + dump_node_code(cfnode->blocks[0], p_level); } else { @@ -295,7 +298,6 @@ static String dump_node_code(SL::Node *p_node, int p_level) { } static Error recreate_code(void *p_str, SL::ShaderNode *p_program) { - String *str = (String *)p_str; *str = dump_node_code(p_program, 0); @@ -304,13 +306,12 @@ static Error recreate_code(void *p_str, SL::ShaderNode *p_program) { } MainLoop *test() { - List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); if (cmdlargs.empty()) { //try editor! print_line("usage: godot -test shader_lang <shader>"); - return NULL; + return nullptr; } String test = cmdlargs.back()->get(); @@ -318,15 +319,16 @@ MainLoop *test() { FileAccess *fa = FileAccess::open(test, FileAccess::READ); if (!fa) { - ERR_FAIL_V(NULL); + ERR_FAIL_V(nullptr); } String code; while (true) { CharType c = fa->get_8(); - if (fa->eof_reached()) + if (fa->eof_reached()) { break; + } code += c; } @@ -342,18 +344,18 @@ MainLoop *test() { Set<String> types; types.insert("spatial"); - Error err = sl.compile(code, dt, rm, types); + Error err = sl.compile(code, dt, rm, types, nullptr); if (err) { - print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text()); - return NULL; + return nullptr; } else { String code2; recreate_code(&code2, sl.get_shader()); print_line("code:\n\n" + code2); } - return NULL; + return nullptr; } + } // namespace TestShaderLang diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp index 84731746fa..775c039282 100644 --- a/main/tests/test_string.cpp +++ b/main/tests/test_string.cpp @@ -45,7 +45,6 @@ namespace TestString { bool test_1() { - OS::get_singleton()->print("\n\nTest 1: Assign from cstr\n"); String s = "Hello"; @@ -57,7 +56,6 @@ bool test_1() { } bool test_2() { - OS::get_singleton()->print("\n\nTest 2: Assign from string (operator=)\n"); String s = "Dolly"; @@ -70,7 +68,6 @@ bool test_2() { } bool test_3() { - OS::get_singleton()->print("\n\nTest 3: Assign from c-string (copycon)\n"); String s("Sheep"); @@ -83,7 +80,6 @@ bool test_3() { } bool test_4() { - OS::get_singleton()->print("\n\nTest 4: Assign from c-widechar (operator=)\n"); String s(L"Give me"); @@ -95,7 +91,6 @@ bool test_4() { } bool test_5() { - OS::get_singleton()->print("\n\nTest 5: Assign from c-widechar (copycon)\n"); String s(L"Wool"); @@ -107,67 +102,72 @@ bool test_5() { } bool test_6() { - OS::get_singleton()->print("\n\nTest 6: comparisons (equal)\n"); String s = "Test Compare"; OS::get_singleton()->print("\tComparing to \"Test Compare\"\n"); - if (!(s == "Test Compare")) + if (!(s == "Test Compare")) { return false; + } - if (!(s == L"Test Compare")) + if (!(s == L"Test Compare")) { return false; + } - if (!(s == String("Test Compare"))) + if (!(s == String("Test Compare"))) { return false; + } return true; } bool test_7() { - OS::get_singleton()->print("\n\nTest 7: comparisons (unequal)\n"); String s = "Test Compare"; OS::get_singleton()->print("\tComparing to \"Test Compare\"\n"); - if (!(s != "Peanut")) + if (!(s != "Peanut")) { return false; + } - if (!(s != L"Coconut")) + if (!(s != L"Coconut")) { return false; + } - if (!(s != String("Butter"))) + if (!(s != String("Butter"))) { return false; + } return true; } bool test_8() { - OS::get_singleton()->print("\n\nTest 8: comparisons (operator<)\n"); String s = "Bees"; OS::get_singleton()->print("\tComparing to \"Bees\"\n"); - if (!(s < "Elephant")) + if (!(s < "Elephant")) { return false; + } - if (s < L"Amber") + if (s < L"Amber") { return false; + } - if (s < String("Beatrix")) + if (s < String("Beatrix")) { return false; + } return true; } bool test_9() { - OS::get_singleton()->print("\n\nTest 9: Concatenation\n"); String s; @@ -186,23 +186,24 @@ bool test_9() { } bool test_10() { - OS::get_singleton()->print("\n\nTest 10: Misc funcs (size/length/empty/etc)\n"); - if (!String("").empty()) + if (!String("").empty()) { return false; + } - if (String("Mellon").size() != 7) + if (String("Mellon").size() != 7) { return false; + } - if (String("Oranges").length() != 7) + if (String("Oranges").length() != 7) { return false; + } return true; } bool test_11() { - OS::get_singleton()->print("\n\nTest 11: Operator[]\n"); String a = "Kugar Sane"; @@ -210,32 +211,34 @@ bool test_11() { a[0] = 'S'; a[6] = 'C'; - if (a != "Sugar Cane") + if (a != "Sugar Cane") { return false; + } - if (a[1] != 'u') + if (a[1] != 'u') { return false; + } return true; } bool test_12() { - OS::get_singleton()->print("\n\nTest 12: case functions\n"); String a = "MoMoNgA"; - if (a.to_upper() != "MOMONGA") + if (a.to_upper() != "MOMONGA") { return false; + } - if (a.nocasecmp_to("momonga") != 0) + if (a.nocasecmp_to("momonga") != 0) { return false; + } return true; } bool test_13() { - OS::get_singleton()->print("\n\nTest 13: UTF8\n"); /* how can i embed UTF in here? */ @@ -252,7 +255,6 @@ bool test_13() { } bool test_14() { - OS::get_singleton()->print("\n\nTest 14: ASCII\n"); String s = L"Primero Leche"; @@ -263,7 +265,6 @@ bool test_14() { } bool test_15() { - OS::get_singleton()->print("\n\nTest 15: substr\n"); String s = "Killer Baby"; @@ -273,7 +274,6 @@ bool test_15() { } bool test_16() { - OS::get_singleton()->print("\n\nTest 16: find\n"); String s = "Pretty Woman"; @@ -281,17 +281,18 @@ bool test_16() { OS::get_singleton()->print("\t\"tty\" is at %i pos.\n", s.find("tty")); OS::get_singleton()->print("\t\"Revenge of the Monster Truck\" is at %i pos.\n", s.find("Revenge of the Monster Truck")); - if (s.find("tty") != 3) + if (s.find("tty") != 3) { return false; + } - if (s.find("Revenge of the Monster Truck") != -1) + if (s.find("Revenge of the Monster Truck") != -1) { return false; + } return true; } bool test_17() { - OS::get_singleton()->print("\n\nTest 17: find no case\n"); String s = "Pretty Whale"; @@ -299,17 +300,18 @@ bool test_17() { OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n", s.findn("WHA")); OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n", s.findn("Revenge of the Monster Truck")); - if (s.findn("WHA") != 7) + if (s.findn("WHA") != 7) { return false; + } - if (s.findn("Revenge of the Monster SawFish") != -1) + if (s.findn("Revenge of the Monster SawFish") != -1) { return false; + } return true; } bool test_18() { - OS::get_singleton()->print("\n\nTest 18: find no case\n"); String s = "Pretty Whale"; @@ -317,17 +319,18 @@ bool test_18() { OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n", s.findn("WHA")); OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n", s.findn("Revenge of the Monster Truck")); - if (s.findn("WHA") != 7) + if (s.findn("WHA") != 7) { return false; + } - if (s.findn("Revenge of the Monster SawFish") != -1) + if (s.findn("Revenge of the Monster SawFish") != -1) { return false; + } return true; } bool test_19() { - OS::get_singleton()->print("\n\nTest 19: Search & replace\n"); String s = "Happy Birthday, Anna!"; @@ -340,7 +343,6 @@ bool test_19() { } bool test_20() { - OS::get_singleton()->print("\n\nTest 20: Insertion\n"); String s = "Who is Frederic?"; @@ -353,7 +355,6 @@ bool test_20() { } bool test_21() { - OS::get_singleton()->print("\n\nTest 21: Number -> String\n"); OS::get_singleton()->print("\tPi is %f\n", 33.141593); @@ -363,7 +364,6 @@ bool test_21() { } bool test_22() { - OS::get_singleton()->print("\n\nTest 22: String -> Int\n"); static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" }; @@ -372,15 +372,15 @@ bool test_22() { for (int i = 0; i < 4; i++) { OS::get_singleton()->print("\tString: \"%s\" as Int is %i\n", nums[i], String(nums[i]).to_int()); - if (String(nums[i]).to_int() != num[i]) + if (String(nums[i]).to_int() != num[i]) { return false; + } } return true; } bool test_23() { - OS::get_singleton()->print("\n\nTest 23: String -> Float\n"); static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" }; @@ -389,15 +389,15 @@ bool test_23() { for (int i = 0; i < 4; i++) { OS::get_singleton()->print("\tString: \"%s\" as Float is %f\n", nums[i], String(nums[i]).to_double()); - if (ABS(String(nums[i]).to_double() - num[i]) > 0.00001) + if (ABS(String(nums[i]).to_double() - num[i]) > 0.00001) { return false; + } } return true; } bool test_24() { - OS::get_singleton()->print("\n\nTest 24: Slicing\n"); String s = "Mars,Jupiter,Saturn,Uranus"; @@ -407,18 +407,17 @@ bool test_24() { OS::get_singleton()->print("\tSlicing \"%ls\" by \"%s\"..\n", s.c_str(), ","); for (int i = 0; i < s.get_slice_count(","); i++) { - OS::get_singleton()->print("\t\t%i- %ls\n", i + 1, s.get_slice(",", i).c_str()); - if (s.get_slice(",", i) != slices[i]) + if (s.get_slice(",", i) != slices[i]) { return false; + } } return true; } bool test_25() { - OS::get_singleton()->print("\n\nTest 25: Erasing\n"); String s = "Josephine is such a cute girl!"; @@ -433,7 +432,6 @@ bool test_25() { } bool test_26() { - OS::get_singleton()->print("\n\nTest 26: RegEx substitution\n"); #ifndef MODULE_REGEX_ENABLED @@ -461,7 +459,6 @@ struct test_27_data { }; bool test_27() { - OS::get_singleton()->print("\n\nTest 27: begins_with\n"); test_27_data tc[] = { { "res://foobar", "res://", true }, @@ -486,7 +483,6 @@ bool test_27() { }; bool test_28() { - OS::get_singleton()->print("\n\nTest 28: sprintf\n"); bool success, state = true; @@ -822,7 +818,6 @@ bool test_28() { } bool test_29() { - bool state = true; IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); @@ -972,28 +967,35 @@ bool test_31() { String a = ""; success = a[0] == 0; OS::get_singleton()->print("Is 0 String[0]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } String b = "Godot"; success = b[b.size()] == 0; OS::get_singleton()->print("Is 0 String[size()]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } const String c = ""; success = c[0] == 0; OS::get_singleton()->print("Is 0 const String[0]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } const String d = "Godot"; success = d[d.size()] == 0; OS::get_singleton()->print("Is 0 const String[size()]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } return state; }; bool test_32() { - #define STRIP_TEST(x) \ { \ bool success = x; \ @@ -1071,7 +1073,7 @@ bool test_33() { OS::get_singleton()->print("\n\nTest 33: parse_utf8(null, -1)\n"); String empty; - return empty.parse_utf8(NULL, -1); + return empty.parse_utf8(nullptr, -1); } bool test_34() { @@ -1125,7 +1127,7 @@ bool test_35() { return state; } -typedef bool (*TestFunc)(void); +typedef bool (*TestFunc)(); TestFunc test_funcs[] = { @@ -1164,12 +1166,11 @@ TestFunc test_funcs[] = { test_33, test_34, test_35, - 0 + nullptr }; MainLoop *test() { - /** A character length != wchar_t may be forced, so the tests won't work */ static_assert(sizeof(CharType) == sizeof(wchar_t)); @@ -1178,11 +1179,13 @@ MainLoop *test() { int passed = 0; while (true) { - if (!test_funcs[count]) + if (!test_funcs[count]) { break; + } bool pass = test_funcs[count](); - if (pass) + if (pass) { passed++; + } OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); count++; @@ -1195,6 +1198,7 @@ MainLoop *test() { OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return NULL; + return nullptr; } + } // namespace TestString |