diff options
-rw-r--r-- | editor/editor_node.cpp | 1 | ||||
-rw-r--r-- | editor/editor_settings.cpp | 1 | ||||
-rw-r--r-- | main/main.cpp | 7 | ||||
-rw-r--r-- | platform/windows/detect.py | 9 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 26 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 1 | ||||
-rw-r--r-- | tests/test_basis.cpp | 325 | ||||
-rw-r--r-- | tests/test_basis.h | 252 | ||||
-rw-r--r-- | tests/test_macros.h | 57 | ||||
-rw-r--r-- | tests/test_validate_testing.h | 135 |
10 files changed, 469 insertions, 345 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ce131e6a05..dabee67033 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2620,7 +2620,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case SETTINGS_TOGGLE_CONSOLE: { bool was_visible = DisplayServer::get_singleton()->is_console_visible(); DisplayServer::get_singleton()->console_set_visible(!was_visible); - EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", was_visible); } break; case EDITOR_SCREENSHOT: { screenshot_timer->start(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index a3438b3601..f86b485dd1 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -334,7 +334,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/automatically_open_screenshots", true); _initial_set("interface/editor/single_window_mode", false); hints["interface/editor/single_window_mode"] = PropertyInfo(Variant::BOOL, "interface/editor/single_window_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - _initial_set("interface/editor/hide_console_window", false); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression _initial_set("interface/editor/quit_confirmation", true); diff --git a/main/main.cpp b/main/main.cpp index c5500a1f66..75f204aa7e 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2203,13 +2203,6 @@ bool Main::start() { } if (project_manager || editor) { - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CONSOLE_WINDOW)) { - // Hide console window if requested (Windows-only). - bool hide_console = EditorSettings::get_singleton()->get_setting( - "interface/editor/hide_console_window"); - DisplayServer::get_singleton()->console_set_visible(!hide_console); - } - // Load SSL Certificates from Editor Settings (or builtin) Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting( "network/ssl/editor_ssl_certificates") diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 271ffc8871..a9f25fa078 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -183,7 +183,6 @@ def configure_msvc(env, manual_msvc_config): env.Append(CCFLAGS=["/O2"]) else: # optimize for size env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) env.Append(LINKFLAGS=["/OPT:REF"]) @@ -193,15 +192,15 @@ def configure_msvc(env, manual_msvc_config): else: # optimize for size env.Append(CCFLAGS=["/O1"]) env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"]) - env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) env.Append(LINKFLAGS=["/OPT:REF"]) elif env["target"] == "debug": env.AppendUnique(CCFLAGS=["/Z7", "/Od", "/EHsc"]) env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"]) - env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) env.Append(LINKFLAGS=["/DEBUG"]) + env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"]) + if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes": env.AppendUnique(CCFLAGS=["/Z7"]) env.AppendUnique(LINKFLAGS=["/DEBUG"]) @@ -314,8 +313,6 @@ def configure_mingw(env): else: # optimize for size env.Prepend(CCFLAGS=["-Os"]) - env.Append(LINKFLAGS=["-Wl,--subsystem,windows"]) - if env["debug_symbols"] == "yes": env.Prepend(CCFLAGS=["-g1"]) if env["debug_symbols"] == "full": @@ -337,6 +334,8 @@ def configure_mingw(env): env.Append(CCFLAGS=["-g3"]) env.Append(CPPDEFINES=["DEBUG_ENABLED"]) + env.Append(LINKFLAGS=["-Wl,--subsystem,windows"]) + ## Compiler configuration if os.name != "nt": diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index da2fc1c2c1..e4a7814cc1 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1135,10 +1135,17 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI void DisplayServerWindows::console_set_visible(bool p_enabled) { _THREAD_SAFE_METHOD_ - if (console_visible == p_enabled) + if (console_visible == p_enabled) { return; - ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE); - console_visible = p_enabled; + } + if (p_enabled && GetConsoleWindow() == nullptr) { // Open new console if not attached. + own_console = true; + AllocConsole(); + } + if (own_console) { // Note: Do not hide parent console. + ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE); + console_visible = p_enabled; + } } bool DisplayServerWindows::is_console_visible() const { @@ -3019,7 +3026,18 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win shift_mem = false; control_mem = false; meta_mem = false; - console_visible = IsWindowVisible(GetConsoleWindow()); + + if (AttachConsole(ATTACH_PARENT_PROCESS)) { + FILE *_file = nullptr; + freopen_s(&_file, "CONOUT$", "w", stdout); + freopen_s(&_file, "CONOUT$", "w", stderr); + freopen_s(&_file, "CONIN$", "r", stdin); + + printf("\n"); + console_visible = true; + } else { + console_visible = false; + } hInstance = ((OS_Windows *)OS::get_singleton())->get_hinstance(); pressrc = 0; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 7bd93a7086..52f5b0f4a9 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -405,6 +405,7 @@ private: bool drop_events = false; bool in_dispatch_input_event = false; bool console_visible = false; + bool own_console = false; WNDCLASSEXW wc; diff --git a/tests/test_basis.cpp b/tests/test_basis.cpp deleted file mode 100644 index 5904fc386a..0000000000 --- a/tests/test_basis.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/*************************************************************************/ -/* 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/tests/test_basis.h b/tests/test_basis.h index 63297bd3b8..05efe33788 100644 --- a/tests/test_basis.h +++ b/tests/test_basis.h @@ -31,10 +31,258 @@ #ifndef TEST_BASIS_H #define TEST_BASIS_H -#include "core/os/main_loop.h" +#include "core/math/random_number_generator.h" +#include "core/os/os.h" +#include "core/ustring.h" + +#include "tests/test_macros.h" namespace TestBasis { -MainLoop *test(); + +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. + FAIL("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. + FAIL("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]"; + } +} + +void 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. + + // 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; + + CHECK_MESSAGE((res.get_axis(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Fail due to X %s\n", String(res.get_axis(0))).utf8().ptr()); + CHECK_MESSAGE((res.get_axis(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Fail due to Y %s\n", String(res.get_axis(1))).utf8().ptr()); + CHECK_MESSAGE((res.get_axis(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Fail due to Z %s\n", String(res.get_axis(2))).utf8().ptr()); + + // 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; + + CHECK_MESSAGE((res.get_axis(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to X %s\n", String(res.get_axis(0))).utf8().ptr()); + CHECK_MESSAGE((res.get_axis(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Y %s\n", String(res.get_axis(1))).utf8().ptr()); + CHECK_MESSAGE((res.get_axis(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Z %s\n", String(res.get_axis(2))).utf8().ptr()); + + INFO(vformat("Rotation order: %s\n.", get_rot_order_name(rot_order)).utf8().ptr()); + INFO(vformat("Original Rotation: %s\n", String(deg_original_euler)).utf8().ptr()); + INFO(vformat("Quaternion to rotation order: %s\n", String(rad2deg(euler_from_rotation))).utf8().ptr()); +} + +TEST_CASE("[Basis] Euler conversions") { + 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)); + + for (int h = 0; h < rotorder_to_test.size(); h += 1) { + for (int i = 0; i < vectors_to_test.size(); i += 1) { + test_rotation(vectors_to_test[i], rotorder_to_test[h]); + } + } +} + +TEST_CASE("[Stress][Basis] Euler conversions") { + 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; + // 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))); + } + + for (int h = 0; h < rotorder_to_test.size(); h += 1) { + for (int i = 0; i < vectors_to_test.size(); i += 1) { + test_rotation(vectors_to_test[i], rotorder_to_test[h]); + } + } +} + +} // namespace TestBasis + #endif diff --git a/tests/test_macros.h b/tests/test_macros.h index e4494ce11a..45ba8581dd 100644 --- a/tests/test_macros.h +++ b/tests/test_macros.h @@ -47,4 +47,61 @@ #define ERR_PRINT_OFF _print_error_enabled = false; #define ERR_PRINT_ON _print_error_enabled = true; +// Stringify all `Variant` compatible types for doctest output by default. +// https://github.com/onqtam/doctest/blob/master/doc/markdown/stringification.md + +#define DOCTEST_STRINGIFY_VARIANT(m_type) \ + template <> \ + struct doctest::StringMaker<m_type> { \ + static doctest::String convert(const m_type &p_val) { \ + const Variant val = p_val; \ + return val.get_construct_string().utf8().get_data(); \ + } \ + }; + +#define DOCTEST_STRINGIFY_VARIANT_POINTER(m_type) \ + template <> \ + struct doctest::StringMaker<m_type> { \ + static doctest::String convert(const m_type *p_val) { \ + const Variant val = p_val; \ + return val.get_construct_string().utf8().get_data(); \ + } \ + }; + +DOCTEST_STRINGIFY_VARIANT(Variant); +DOCTEST_STRINGIFY_VARIANT(::String); // Disambiguate from `doctest::String`. + +DOCTEST_STRINGIFY_VARIANT(Vector2); +DOCTEST_STRINGIFY_VARIANT(Vector2i); +DOCTEST_STRINGIFY_VARIANT(Rect2); +DOCTEST_STRINGIFY_VARIANT(Rect2i); +DOCTEST_STRINGIFY_VARIANT(Vector3); +DOCTEST_STRINGIFY_VARIANT(Vector3i); +DOCTEST_STRINGIFY_VARIANT(Transform2D); +DOCTEST_STRINGIFY_VARIANT(Plane); +DOCTEST_STRINGIFY_VARIANT(Quat); +DOCTEST_STRINGIFY_VARIANT(AABB); +DOCTEST_STRINGIFY_VARIANT(Basis); +DOCTEST_STRINGIFY_VARIANT(Transform); + +DOCTEST_STRINGIFY_VARIANT(::Color); // Disambiguate from `doctest::Color`. +DOCTEST_STRINGIFY_VARIANT(StringName); +DOCTEST_STRINGIFY_VARIANT(NodePath); +DOCTEST_STRINGIFY_VARIANT(RID); +DOCTEST_STRINGIFY_VARIANT_POINTER(Object); +DOCTEST_STRINGIFY_VARIANT(Callable); +DOCTEST_STRINGIFY_VARIANT(Signal); +DOCTEST_STRINGIFY_VARIANT(Dictionary); +DOCTEST_STRINGIFY_VARIANT(Array); + +DOCTEST_STRINGIFY_VARIANT(PackedByteArray); +DOCTEST_STRINGIFY_VARIANT(PackedInt32Array); +DOCTEST_STRINGIFY_VARIANT(PackedInt64Array); +DOCTEST_STRINGIFY_VARIANT(PackedFloat32Array); +DOCTEST_STRINGIFY_VARIANT(PackedFloat64Array); +DOCTEST_STRINGIFY_VARIANT(PackedStringArray); +DOCTEST_STRINGIFY_VARIANT(PackedVector2Array); +DOCTEST_STRINGIFY_VARIANT(PackedVector3Array); +DOCTEST_STRINGIFY_VARIANT(PackedColorArray); + #endif // TEST_MACROS_H diff --git a/tests/test_validate_testing.h b/tests/test_validate_testing.h index 24acdec96c..4bcc57d9c5 100644 --- a/tests/test_validate_testing.h +++ b/tests/test_validate_testing.h @@ -53,6 +53,141 @@ TEST_SUITE("Validate tests") { ERR_PRINT_ON; CHECK_MESSAGE(_print_error_enabled, "Error printing should be re-enabled."); } + TEST_CASE("Stringify Variant types") { + ClassDB::init(); // For objects. + + Variant var; + INFO(var); + + String string("Godot is finally here!"); + INFO(string); + + Vector2 vec2(0.5, 1.0); + INFO(vec2); + + Vector2i vec2i(1, 2); + INFO(vec2i); + + Rect2 rect2(0.5, 0.5, 100.5, 100.5); + INFO(rect2); + + Rect2i rect2i(0, 0, 100, 100); + INFO(rect2i); + + Vector3 vec3(0.5, 1.0, 2.0); + INFO(vec3); + + Vector3i vec3i(1, 2, 3); + INFO(vec3i); + + Transform2D trans2d(0.5, Vector2(100, 100)); + INFO(trans2d); + + Plane plane(Vector3(1, 1, 1), 1.0); + INFO(plane); + + Quat quat(Vector3(0.5, 1.0, 2.0)); + INFO(quat); + + AABB aabb(Vector3(), Vector3(100, 100, 100)); + INFO(aabb); + + Basis basis(quat); + INFO(basis); + + Transform trans(basis); + INFO(trans); + + Color color(1, 0.5, 0.2, 0.3); + INFO(color); + + StringName string_name("has_method"); + INFO(string_name); + + NodePath node_path("godot/sprite"); + INFO(node_path); + + INFO(RID()); + + Object *obj = memnew(Object); + INFO(obj); + + Callable callable(obj, "has_method"); + INFO(callable); + + Signal signal(obj, "script_changed"); + INFO(signal); + + memdelete(obj); + + Dictionary dict; + dict["string"] = string; + dict["color"] = color; + INFO(dict); + + Array arr; + arr.push_back(string); + arr.push_back(color); + INFO(arr); + + PackedByteArray byte_arr; + byte_arr.push_back(0); + byte_arr.push_back(1); + byte_arr.push_back(2); + INFO(byte_arr); + + PackedInt32Array int32_arr; + int32_arr.push_back(0); + int32_arr.push_back(1); + int32_arr.push_back(2); + INFO(int32_arr); + + PackedInt64Array int64_arr; + int64_arr.push_back(0); + int64_arr.push_back(1); + int64_arr.push_back(2); + INFO(int64_arr); + + PackedFloat32Array float32_arr; + float32_arr.push_back(0.5); + float32_arr.push_back(1.5); + float32_arr.push_back(2.5); + INFO(float32_arr); + + PackedFloat64Array float64_arr; + float64_arr.push_back(0.5); + float64_arr.push_back(1.5); + float64_arr.push_back(2.5); + INFO(float64_arr); + + PackedStringArray str_arr = string.split(" "); + INFO(str_arr); + + PackedVector2Array vec2_arr; + vec2_arr.push_back(Vector2(0, 0)); + vec2_arr.push_back(Vector2(1, 1)); + vec2_arr.push_back(Vector2(2, 2)); + INFO(vec2_arr); + + PackedVector3Array vec3_arr; + vec3_arr.push_back(Vector3(0, 0, 0)); + vec3_arr.push_back(Vector3(1, 1, 1)); + vec3_arr.push_back(Vector3(2, 2, 2)); + INFO(vec3_arr); + + PackedColorArray color_arr; + color_arr.push_back(Color(0, 0, 0)); + color_arr.push_back(Color(1, 1, 1)); + color_arr.push_back(Color(2, 2, 2)); + INFO(color_arr); + + INFO("doctest insertion operator << " + << var << " " << vec2 << " " << rect2 << " " << color); + + CHECK(true); // So all above prints. + + ClassDB::cleanup(); + } } #endif // TEST_VALIDATE_TESTING_H |