diff options
20 files changed, 301 insertions, 61 deletions
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 236f3d7b08..ddeb8643b8 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -367,6 +367,10 @@ void ConnectDialog::popup_dialog(const String &p_for_signal) { error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root())); } + if (first_popup) { + first_popup = false; + _advanced_pressed(); + } popup_centered(); } @@ -389,6 +393,7 @@ void ConnectDialog::_advanced_pressed() { } _update_ok_enabled(); + EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "use_advanced_connections", advanced->is_pressed()); popup_centered(); } @@ -480,6 +485,7 @@ ConnectDialog::ConnectDialog() { vbc_left->add_child(advanced); advanced->set_text(TTR("Advanced")); advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND); + advanced->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "use_advanced_connections", false)); advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed)); HBoxContainer *hbox = memnew(HBoxContainer); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index e37246e7a0..db2f855617 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -112,6 +112,7 @@ private: LineEdit *dst_method = nullptr; ConnectDialogBinds *cdbinds = nullptr; bool edit_mode = false; + bool first_popup = true; NodePath dst_path; VBoxContainer *vbc_right = nullptr; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 673fa3404c..28768b7f34 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6901,23 +6901,24 @@ EditorNode::EditorNode() { play_button->set_toggle_mode(true); play_button->set_focus_mode(Control::FOCUS_NONE); play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY)); + play_button->set_tooltip_text(TTR("Run the project's default scene.")); - ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5); - ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::META | Key::B); - play_button->set_shortcut(ED_GET_SHORTCUT("editor/play")); + ED_SHORTCUT_AND_COMMAND("editor/run_project", TTR("Run Project"), Key::F5); + ED_SHORTCUT_OVERRIDE("editor/run_project", "macos", KeyModifierMask::META | Key::B); + play_button->set_shortcut(ED_GET_SHORTCUT("editor/run_project")); pause_button = memnew(Button); pause_button->set_flat(true); pause_button->set_toggle_mode(true); pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"))); pause_button->set_focus_mode(Control::FOCUS_NONE); - pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging.")); + pause_button->set_tooltip_text(TTR("Pause the running project's execution for debugging.")); pause_button->set_disabled(true); launch_pad_hb->add_child(pause_button); - ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7); - ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y); - pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_scene")); + ED_SHORTCUT("editor/pause_running_project", TTR("Pause Running Project"), Key::F7); + ED_SHORTCUT_OVERRIDE("editor/pause_running_project", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y); + pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_running_project")); stop_button = memnew(Button); stop_button->set_flat(true); @@ -6925,12 +6926,12 @@ EditorNode::EditorNode() { stop_button->set_focus_mode(Control::FOCUS_NONE); stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP)); - stop_button->set_tooltip_text(TTR("Stop the scene.")); + stop_button->set_tooltip_text(TTR("Stop the currently running project.")); stop_button->set_disabled(true); - ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8); - ED_SHORTCUT_OVERRIDE("editor/stop", "macos", KeyModifierMask::META | Key::PERIOD); - stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop")); + ED_SHORTCUT("editor/stop_running_project", TTR("Stop Running Project"), Key::F8); + ED_SHORTCUT_OVERRIDE("editor/stop_running_project", "macos", KeyModifierMask::META | Key::PERIOD); + stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop_running_project")); run_native = memnew(EditorRunNative); launch_pad_hb->add_child(run_native); @@ -6942,10 +6943,11 @@ EditorNode::EditorNode() { play_scene_button->set_toggle_mode(true); play_scene_button->set_focus_mode(Control::FOCUS_NONE); play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE)); + play_scene_button->set_tooltip_text(TTR("Run the currently edited scene.")); - ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6); - ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::META | Key::R); - play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_scene")); + ED_SHORTCUT_AND_COMMAND("editor/run_current_scene", TTR("Run Current Scene"), Key::F6); + ED_SHORTCUT_OVERRIDE("editor/run_current_scene", "macos", KeyModifierMask::META | Key::R); + play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_current_scene")); play_custom_scene_button = memnew(Button); play_custom_scene_button->set_flat(true); @@ -6953,12 +6955,11 @@ EditorNode::EditorNode() { play_custom_scene_button->set_toggle_mode(true); play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE); play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE)); + play_custom_scene_button->set_tooltip_text(TTR("Run a specific scene.")); - _reset_play_buttons(); - - ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5); - ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R); - play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene")); + ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::META | KeyModifierMask::SHIFT | Key::F5); + ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R); + play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene")); write_movie_panel = memnew(PanelContainer); write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles"))); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 941fcbac2a..3679657567 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2546,7 +2546,7 @@ void ScriptEditor::apply_scripts() const { } } -void ScriptEditor::reload_scripts() { +void ScriptEditor::reload_scripts(bool p_refresh_only) { for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); if (!se) { @@ -2559,30 +2559,33 @@ void ScriptEditor::reload_scripts() { continue; //internal script, who cares } - uint64_t last_date = edited_res->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); + if (!p_refresh_only) { + uint64_t last_date = edited_res->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); - if (last_date == date) { - continue; - } + if (last_date == date) { + continue; + } - Ref<Script> script = edited_res; - if (script != nullptr) { - Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); - ERR_CONTINUE(!rel_script.is_valid()); - script->set_source_code(rel_script->get_source_code()); - script->set_last_modified_time(rel_script->get_last_modified_time()); - script->reload(true); - } + Ref<Script> script = edited_res; + if (script != nullptr) { + Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); + ERR_CONTINUE(!rel_script.is_valid()); + script->set_source_code(rel_script->get_source_code()); + script->set_last_modified_time(rel_script->get_last_modified_time()); + script->reload(true); + } - Ref<TextFile> text_file = edited_res; - if (text_file != nullptr) { - Error err; - Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); - ERR_CONTINUE(!rel_text_file.is_valid()); - text_file->set_text(rel_text_file->get_text()); - text_file->set_last_modified_time(rel_text_file->get_last_modified_time()); + Ref<TextFile> text_file = edited_res; + if (text_file != nullptr) { + Error err; + Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); + ERR_CONTINUE(!rel_text_file.is_valid()); + text_file->set_text(rel_text_file->get_text()); + text_file->set_last_modified_time(rel_text_file->get_last_modified_time()); + } } + se->reload_text(); } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 59191b8891..1e78dc4ec4 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -477,7 +477,7 @@ public: bool toggle_scripts_panel(); bool is_scripts_panel_toggled(); void apply_scripts() const; - void reload_scripts(); + void reload_scripts(bool p_refresh_only = false); void open_script_create_dialog(const String &p_base_name, const String &p_base_path); void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = ""); Ref<Resource> open_file(const String &p_file); diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 5ad9680ea0..ccde0521f2 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -422,6 +422,7 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin if (error == OK) { if (script->load_source_code(path) == OK) { script->reload(true); + ScriptEditor::get_singleton()->reload_scripts(true); // Refresh scripts opened in the internal editor. } } } diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 00ba32eae1..aed95294e7 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -100,7 +100,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff uint32_t width = p_header.image_width; uint32_t height = p_header.image_height; tga_origin_e origin = static_cast<tga_origin_e>((p_header.image_descriptor & TGA_ORIGIN_MASK) >> TGA_ORIGIN_SHIFT); - + uint8_t alpha_bits = p_header.image_descriptor & TGA_IMAGE_DESCRIPTOR_ALPHA_MASK; uint32_t x_start; int32_t x_step; uint32_t x_end; @@ -184,6 +184,27 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff y += y_step; } } + } else if (p_header.pixel_depth == 16) { + while (y != y_end) { + while (x != x_end) { + if (i + 1 >= p_input_size) { + return ERR_PARSE_ERROR; + } + + // Always stored as RGBA5551 + uint8_t r = (p_buffer[i + 1] & 0x7c) << 1; + uint8_t g = ((p_buffer[i + 1] & 0x03) << 6) | ((p_buffer[i + 0] & 0xe0) >> 2); + uint8_t b = (p_buffer[i + 0] & 0x1f) << 3; + uint8_t a = (p_buffer[i + 1] & 0x80) ? 0xff : 0; + + TGA_PUT_PIXEL(r, g, b, alpha_bits ? a : 0xff); + + x += x_step; + i += 2; + } + x = x_start; + y += y_step; + } } else if (p_header.pixel_depth == 24) { while (y != y_end) { while (x != x_end) { @@ -277,7 +298,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField err = FAILED; } - if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) { + if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 16 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) { err = FAILED; } diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index b257ed110d..de964373ed 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -33,6 +33,8 @@ #include "core/io/image_loader.h" +#define TGA_IMAGE_DESCRIPTOR_ALPHA_MASK 0xf + class ImageLoaderTGA : public ImageFormatLoader { enum tga_type_e { TGA_TYPE_NO_DATA = 0, diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index f6e0e4216d..8069ab465b 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -1216,30 +1216,39 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const { } void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { + bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT); + if (draw_breakpoints && breakpoint_icon.is_valid()) { bool hovering = p_region.has_point(get_local_mouse_pos()); bool breakpointed = is_line_breakpointed(p_line); - if (breakpointed || (hovering && !is_dragging_cursor())) { + if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) { int padding = p_region.size.x / 6; Rect2 icon_region = p_region; icon_region.position += Point2(padding, padding); icon_region.size -= Point2(padding, padding) * 2; - // Darken icon when hovering & not yet breakpointed. - Color use_color = hovering && !breakpointed ? breakpoint_color.darkened(0.4) : breakpoint_color; + // Darken icon when hovering, shift not pressed & not yet breakpointed. + Color use_color = hovering && !breakpointed && !shift_pressed ? breakpoint_color.darkened(0.4) : breakpoint_color; breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color); } } - if (draw_bookmarks && is_line_bookmarked(p_line) && bookmark_icon.is_valid()) { - int horizontal_padding = p_region.size.x / 2; - int vertical_padding = p_region.size.y / 4; + if (draw_bookmarks && bookmark_icon.is_valid()) { + bool hovering = p_region.has_point(get_local_mouse_pos()); + bool bookmarked = is_line_bookmarked(p_line); - Rect2 bookmark_region = p_region; - bookmark_region.position += Point2(horizontal_padding, 0); - bookmark_region.size -= Point2(horizontal_padding * 1.1, vertical_padding); - bookmark_icon->draw_rect(get_canvas_item(), bookmark_region, false, bookmark_color); + if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) { + int horizontal_padding = p_region.size.x / 2; + int vertical_padding = p_region.size.y / 4; + Rect2 icon_region = p_region; + icon_region.position += Point2(horizontal_padding, 0); + icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding); + + // Darken icon when hovering, shift pressed & not yet bookmarked. + Color use_color = hovering && !bookmarked && shift_pressed ? bookmark_color.darkened(0.4) : bookmark_color; + bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color); + } } if (draw_executing_lines && is_line_executing(p_line) && executing_line_icon.is_valid()) { @@ -2378,9 +2387,13 @@ int CodeEdit::_get_auto_brace_pair_close_at_pos(int p_line, int p_col) { /* Gutters */ void CodeEdit::_gutter_clicked(int p_line, int p_gutter) { + bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT); + if (p_gutter == main_gutter) { - if (draw_breakpoints) { + if (draw_breakpoints && !shift_pressed) { set_line_as_breakpoint(p_line, !is_line_breakpointed(p_line)); + } else if (draw_bookmarks && shift_pressed) { + set_line_as_bookmarked(p_line, !is_line_bookmarked(p_line)); } return; } diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 459d798a80..a3734a7218 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -597,7 +597,7 @@ void main() { #ifdef MODE_LIGHT_ONLY color = vec4(0.0); -#else +#elif !defined(MODE_UNSHADED) color *= canvas_data.canvas_modulation; #endif diff --git a/servers/rendering/renderer_rd/shaders/effects/SCsub b/servers/rendering/renderer_rd/shaders/effects/SCsub index 741da8fe69..f06a2d86e2 100644 --- a/servers/rendering/renderer_rd/shaders/effects/SCsub +++ b/servers/rendering/renderer_rd/shaders/effects/SCsub @@ -4,7 +4,7 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: # find all include files - gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] # find all shader code(all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] diff --git a/servers/rendering/renderer_rd/shaders/environment/SCsub b/servers/rendering/renderer_rd/shaders/environment/SCsub index 741da8fe69..f06a2d86e2 100644 --- a/servers/rendering/renderer_rd/shaders/environment/SCsub +++ b/servers/rendering/renderer_rd/shaders/environment/SCsub @@ -4,7 +4,7 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: # find all include files - gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] # find all shader code(all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub index 741da8fe69..f06a2d86e2 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub @@ -4,7 +4,7 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: # find all include files - gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] # find all shader code(all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub index 741da8fe69..f06a2d86e2 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub @@ -4,7 +4,7 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: # find all include files - gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] # find all shader code(all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h index 9b7800164a..0d7f1163e4 100644 --- a/tests/core/math/test_vector2.h +++ b/tests/core/math/test_vector2.h @@ -37,6 +37,14 @@ namespace TestVector2 { +TEST_CASE("[Vector2] Constructor methods") { + const Vector2 vector_empty = Vector2(); + const Vector2 vector_zero = Vector2(0.0, 0.0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector2 Constructor with no inputs should return a zero Vector2."); +} + TEST_CASE("[Vector2] Angle methods") { const Vector2 vector_x = Vector2(1, 0); const Vector2 vector_y = Vector2(0, 1); @@ -102,6 +110,9 @@ TEST_CASE("[Vector2] Interpolation methods") { Vector2(1, 1).slerp(Vector2(), 0.5) == Vector2(0.5, 0.5), "Vector2 slerp with one input as zero should behave like a regular lerp."); CHECK_MESSAGE( + Vector2(4, 6).slerp(Vector2(8, 10), 0.5).is_equal_approx(Vector2(5.9076470794008017626, 8.07918879020090480697)), + "Vector2 slerp should work as expected."); + CHECK_MESSAGE( Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)4.31959610746631919), "Vector2 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( @@ -171,6 +182,15 @@ TEST_CASE("[Vector2] Normalization methods") { CHECK_MESSAGE( Vector2(1, 1).normalized().is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)), "Vector2 normalized should work as expected."); + + Vector2 vector = Vector2(3.2, -5.4); + vector.normalize(); + CHECK_MESSAGE( + vector == Vector2(3.2, -5.4).normalized(), + "Vector2 normalize should convert same way as Vector2 normalized."); + CHECK_MESSAGE( + vector.is_equal_approx(Vector2(0.509802390301732898898, -0.860291533634174266891)), + "Vector2 normalize should work as expected."); } TEST_CASE("[Vector2] Operators") { @@ -276,12 +296,14 @@ TEST_CASE("[Vector2] Other methods") { CHECK_MESSAGE( Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4), "Vector2 aspect should work as expected."); + CHECK_MESSAGE( vector.direction_to(Vector2()).is_equal_approx(-vector.normalized()), "Vector2 direction_to should work as expected."); CHECK_MESSAGE( Vector2(1, 1).direction_to(Vector2(2, 2)).is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)), "Vector2 direction_to should work as expected."); + CHECK_MESSAGE( vector.posmod(2).is_equal_approx(Vector2(1.2, 1.4)), "Vector2 posmod should work as expected."); @@ -294,10 +316,21 @@ TEST_CASE("[Vector2] Other methods") { CHECK_MESSAGE( (-vector).posmodv(Vector2(2, 3)).is_equal_approx(Vector2(0.8, 2.6)), "Vector2 posmodv should work as expected."); + + CHECK_MESSAGE( + vector.rotated(Math_TAU).is_equal_approx(Vector2(1.2, 3.4)), + "Vector2 rotated should work as expected."); CHECK_MESSAGE( vector.rotated(Math_TAU / 4).is_equal_approx(Vector2(-3.4, 1.2)), "Vector2 rotated should work as expected."); CHECK_MESSAGE( + vector.rotated(Math_TAU / 3).is_equal_approx(Vector2(-3.544486372867091398996, -0.660769515458673623883)), + "Vector2 rotated should work as expected."); + CHECK_MESSAGE( + vector.rotated(Math_TAU / 2).is_equal_approx(vector.rotated(Math_TAU / -2)), + "Vector2 rotated should work as expected."); + + CHECK_MESSAGE( vector.snapped(Vector2(1, 1)) == Vector2(1, 3), "Vector2 snapped to integers should be the same as rounding."); CHECK_MESSAGE( @@ -306,23 +339,57 @@ TEST_CASE("[Vector2] Other methods") { CHECK_MESSAGE( vector.snapped(Vector2(0.25, 0.25)) == Vector2(1.25, 3.5), "Vector2 snapped to 0.25 should give exact results."); + + CHECK_MESSAGE( + Vector2(1.2, 2.5).is_equal_approx(vector.min(Vector2(3.0, 2.5))), + "Vector2 min should return expected value."); + + CHECK_MESSAGE( + Vector2(5.3, 3.4).is_equal_approx(vector.max(Vector2(5.3, 2.0))), + "Vector2 max should return expected value."); } TEST_CASE("[Vector2] Plane methods") { const Vector2 vector = Vector2(1.2, 3.4); const Vector2 vector_y = Vector2(0, 1); + const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919); + const Vector2 vector_non_normal = Vector2(5.4, 1.6); CHECK_MESSAGE( vector.bounce(vector_y) == Vector2(1.2, -3.4), "Vector2 bounce on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.bounce(vector_normal).is_equal_approx(Vector2(-2.85851197982345523329, 2.197477931904161412358)), + "Vector2 bounce with normal should return expected value."); + CHECK_MESSAGE( vector.reflect(vector_y) == Vector2(-1.2, 3.4), "Vector2 reflect on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.reflect(vector_normal).is_equal_approx(Vector2(2.85851197982345523329, -2.197477931904161412358)), + "Vector2 reflect with normal should return expected value."); + CHECK_MESSAGE( vector.project(vector_y) == Vector2(0, 3.4), - "Vector2 projected on the X axis should only give the Y component."); + "Vector2 projected on the Y axis should only give the Y component."); + CHECK_MESSAGE( + vector.project(vector_normal).is_equal_approx(Vector2(2.0292559899117276166, 0.60126103404791929382)), + "Vector2 projected on a normal should return expected value."); CHECK_MESSAGE( vector.slide(vector_y) == Vector2(1.2, 0), "Vector2 slide on a plane with normal of the Y axis should set the Y to zero."); + CHECK_MESSAGE( + vector.slide(vector_normal).is_equal_approx(Vector2(-0.8292559899117276166456, 2.798738965952080706179)), + "Vector2 slide with normal should return expected value."); + // There's probably a better way to test these ones? + ERR_PRINT_OFF; + CHECK_MESSAGE( + vector.bounce(vector_non_normal).is_equal_approx(Vector2()), + "Vector2 bounce should return empty Vector2 with non-normalised input."); + CHECK_MESSAGE( + vector.reflect(vector_non_normal).is_equal_approx(Vector2()), + "Vector2 reflect should return empty Vector2 with non-normalised input."); + CHECK_MESSAGE( + vector.slide(vector_non_normal).is_equal_approx(Vector2()), + "Vector2 slide should return empty Vector2 with non-normalised input."); + ERR_PRINT_ON; } TEST_CASE("[Vector2] Rounding methods") { @@ -367,12 +434,20 @@ TEST_CASE("[Vector2] Rounding methods") { TEST_CASE("[Vector2] Linear algebra methods") { const Vector2 vector_x = Vector2(1, 0); const Vector2 vector_y = Vector2(0, 1); + const Vector2 a = Vector2(3.5, 8.5); + const Vector2 b = Vector2(5.2, 4.6); CHECK_MESSAGE( vector_x.cross(vector_y) == 1, "Vector2 cross product of X and Y should give 1."); CHECK_MESSAGE( vector_y.cross(vector_x) == -1, "Vector2 cross product of Y and X should give negative 1."); + CHECK_MESSAGE( + Math::is_equal_approx(a.cross(b), (real_t)-28.1), + "Vector2 cross should return expected value."); + CHECK_MESSAGE( + Math::is_equal_approx(Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)), (real_t)-28.1), + "Vector2 cross should return expected value."); CHECK_MESSAGE( vector_x.dot(vector_y) == 0.0, @@ -383,6 +458,12 @@ TEST_CASE("[Vector2] Linear algebra methods") { CHECK_MESSAGE( (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector2 dot product of same direction vectors should behave as expected."); + CHECK_MESSAGE( + Math::is_equal_approx(a.dot(b), (real_t)57.3), + "Vector2 dot should return expected value."); + CHECK_MESSAGE( + Math::is_equal_approx(Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)), (real_t)-57.3), + "Vector2 dot should return expected value."); } } // namespace TestVector2 diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h index 841bb793a4..49b0632e3c 100644 --- a/tests/core/math/test_vector2i.h +++ b/tests/core/math/test_vector2i.h @@ -37,6 +37,14 @@ namespace TestVector2i { +TEST_CASE("[Vector2i] Constructor methods") { + const Vector2i vector_empty = Vector2i(); + const Vector2i vector_zero = Vector2i(0, 0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector2i Constructor with no inputs should return a zero Vector2i."); +} + TEST_CASE("[Vector2i] Axis methods") { Vector2i vector = Vector2i(2, 3); CHECK_MESSAGE( @@ -121,6 +129,14 @@ TEST_CASE("[Vector2i] Other methods") { CHECK_MESSAGE( Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0), "Vector2i aspect should work as expected."); + + CHECK_MESSAGE( + Vector2i(1, 2) == vector.min(Vector2i(3, 2)), + "Vector2i min should return expected value."); + + CHECK_MESSAGE( + Vector2i(5, 3) == vector.max(Vector2i(5, 2)), + "Vector2i max should return expected value."); } TEST_CASE("[Vector2i] Abs and sign methods") { diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h index 6f99fada2b..52118fa943 100644 --- a/tests/core/math/test_vector3.h +++ b/tests/core/math/test_vector3.h @@ -39,6 +39,14 @@ namespace TestVector3 { +TEST_CASE("[Vector3] Constructor methods") { + const Vector3 vector_empty = Vector3(); + const Vector3 vector_zero = Vector3(0.0, 0.0, 0.0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector3 Constructor with no inputs should return a zero Vector3."); +} + TEST_CASE("[Vector3] Angle methods") { const Vector3 vector_x = Vector3(1, 0, 0); const Vector3 vector_y = Vector3(0, 1, 0); @@ -123,6 +131,9 @@ TEST_CASE("[Vector3] Interpolation methods") { Vector3(1, 1, 1).slerp(Vector3(), 0.5) == Vector3(0.5, 0.5, 0.5), "Vector3 slerp with one input as zero should behave like a regular lerp."); CHECK_MESSAGE( + Vector3(4, 6, 2).slerp(Vector3(8, 10, 3), 0.5).is_equal_approx(Vector3(5.90194219811429941053, 8.06758688849378394534, 2.558307894718317120038)), + "Vector3 slerp should work as expected."); + CHECK_MESSAGE( Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)6.25831088708303172), "Vector3 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( @@ -195,6 +206,15 @@ TEST_CASE("[Vector3] Normalization methods") { CHECK_MESSAGE( Vector3(1, 1, 1).normalized().is_equal_approx(Vector3(Math_SQRT13, Math_SQRT13, Math_SQRT13)), "Vector3 normalized should work as expected."); + + Vector3 vector = Vector3(3.2, -5.4, 6); + vector.normalize(); + CHECK_MESSAGE( + vector == Vector3(3.2, -5.4, 6).normalized(), + "Vector3 normalize should convert same way as Vector3 normalized."); + CHECK_MESSAGE( + vector.is_equal_approx(Vector3(0.368522751763902980457, -0.621882143601586279522, 0.6909801595573180883585)), + "Vector3 normalize should work as expected."); } TEST_CASE("[Vector3] Operators") { @@ -318,10 +338,21 @@ TEST_CASE("[Vector3] Other methods") { CHECK_MESSAGE( (-vector).posmodv(Vector3(2, 3, 4)).is_equal_approx(Vector3(0.8, 2.6, 2.4)), "Vector3 posmodv should work as expected."); + + CHECK_MESSAGE( + vector.rotated(Vector3(0, 1, 0), Math_TAU).is_equal_approx(vector), + "Vector3 rotated should work as expected."); CHECK_MESSAGE( vector.rotated(Vector3(0, 1, 0), Math_TAU / 4).is_equal_approx(Vector3(5.6, 3.4, -1.2)), "Vector3 rotated should work as expected."); CHECK_MESSAGE( + vector.rotated(Vector3(1, 0, 0), Math_TAU / 3).is_equal_approx(Vector3(1.2, -6.54974226119285642, 0.1444863728670914)), + "Vector3 rotated should work as expected."); + CHECK_MESSAGE( + vector.rotated(Vector3(0, 0, 1), Math_TAU / 2).is_equal_approx(vector.rotated(Vector3(0, 0, 1), Math_TAU / -2)), + "Vector3 rotated should work as expected."); + + CHECK_MESSAGE( vector.snapped(Vector3(1, 1, 1)) == Vector3(1, 3, 6), "Vector3 snapped to integers should be the same as rounding."); CHECK_MESSAGE( @@ -332,18 +363,44 @@ TEST_CASE("[Vector3] Other methods") { TEST_CASE("[Vector3] Plane methods") { const Vector3 vector = Vector3(1.2, 3.4, 5.6); const Vector3 vector_y = Vector3(0, 1, 0); + const Vector3 vector_normal = Vector3(0.88763458893247992491, 0.26300284116517923701, 0.37806658417494515320); + const Vector3 vector_non_normal = Vector3(5.4, 1.6, 2.3); CHECK_MESSAGE( vector.bounce(vector_y) == Vector3(1.2, -3.4, 5.6), "Vector3 bounce on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.bounce(vector_normal).is_equal_approx(Vector3(-6.0369629829775736287, 1.25571467171034855444, 2.517589840583626047)), + "Vector3 bounce with normal should return expected value."); + CHECK_MESSAGE( vector.reflect(vector_y) == Vector3(-1.2, 3.4, -5.6), "Vector3 reflect on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.reflect(vector_normal).is_equal_approx(Vector3(6.0369629829775736287, -1.25571467171034855444, -2.517589840583626047)), + "Vector3 reflect with normal should return expected value."); + CHECK_MESSAGE( vector.project(vector_y) == Vector3(0, 3.4, 0), - "Vector3 projected on the X axis should only give the Y component."); + "Vector3 projected on the Y axis should only give the Y component."); + CHECK_MESSAGE( + vector.project(vector_normal).is_equal_approx(Vector3(3.61848149148878681437, 1.0721426641448257227776, 1.54120507970818697649)), + "Vector3 projected on a normal should return expected value."); CHECK_MESSAGE( vector.slide(vector_y) == Vector3(1.2, 0, 5.6), "Vector3 slide on a plane with normal of the Y axis should set the Y to zero."); + CHECK_MESSAGE( + vector.slide(vector_normal).is_equal_approx(Vector3(-2.41848149148878681437, 2.32785733585517427722237, 4.0587949202918130235)), + "Vector3 slide with normal should return expected value."); + // There's probably a better way to test these ones? + ERR_PRINT_OFF; + CHECK_MESSAGE( + vector.bounce(vector_non_normal).is_equal_approx(Vector3()), + "Vector3 bounce should return empty Vector3 with non-normalised input."); + CHECK_MESSAGE( + vector.reflect(vector_non_normal).is_equal_approx(Vector3()), + "Vector3 reflect should return empty Vector3 with non-normalised input."); + CHECK_MESSAGE( + vector.slide(vector_non_normal).is_equal_approx(Vector3()), + "Vector3 slide should return empty Vector3 with non-normalised input."); + ERR_PRINT_ON; } TEST_CASE("[Vector3] Rounding methods") { @@ -389,6 +446,8 @@ TEST_CASE("[Vector3] Linear algebra methods") { const Vector3 vector_x = Vector3(1, 0, 0); const Vector3 vector_y = Vector3(0, 1, 0); const Vector3 vector_z = Vector3(0, 0, 1); + const Vector3 a = Vector3(3.5, 8.5, 2.3); + const Vector3 b = Vector3(5.2, 4.6, 7.8); CHECK_MESSAGE( vector_x.cross(vector_y) == vector_z, "Vector3 cross product of X and Y should give Z."); @@ -401,6 +460,12 @@ TEST_CASE("[Vector3] Linear algebra methods") { CHECK_MESSAGE( vector_z.cross(vector_x) == vector_y, "Vector3 cross product of Z and X should give Y."); + CHECK_MESSAGE( + a.cross(b).is_equal_approx(Vector3(55.72, -15.34, -28.1)), + "Vector3 cross should return expected value."); + CHECK_MESSAGE( + Vector3(-a.x, a.y, -a.z).cross(Vector3(b.x, -b.y, b.z)).is_equal_approx(Vector3(55.72, 15.34, -28.1)), + "Vector2 cross should return expected value."); CHECK_MESSAGE( vector_x.dot(vector_y) == 0.0, @@ -411,6 +476,12 @@ TEST_CASE("[Vector3] Linear algebra methods") { CHECK_MESSAGE( (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector3 dot product of same direction vectors should behave as expected."); + CHECK_MESSAGE( + Math::is_equal_approx(a.dot(b), (real_t)75.24), + "Vector3 dot should return expected value."); + CHECK_MESSAGE( + Math::is_equal_approx(Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)), (real_t)-75.24), + "Vector3 dot should return expected value."); } } // namespace TestVector3 diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h index b1c6944eba..6c52781556 100644 --- a/tests/core/math/test_vector3i.h +++ b/tests/core/math/test_vector3i.h @@ -36,6 +36,14 @@ namespace TestVector3i { +TEST_CASE("[Vector3i] Constructor methods") { + const Vector3i vector_empty = Vector3i(); + const Vector3i vector_zero = Vector3i(0, 0, 0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector3i Constructor with no inputs should return a zero Vector3i."); +} + TEST_CASE("[Vector3i] Axis methods") { Vector3i vector = Vector3i(1, 2, 3); CHECK_MESSAGE( diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h index ccf991401b..25ec8929b8 100644 --- a/tests/core/math/test_vector4.h +++ b/tests/core/math/test_vector4.h @@ -38,6 +38,14 @@ namespace TestVector4 { +TEST_CASE("[Vector4] Constructor methods") { + const Vector4 vector_empty = Vector4(); + const Vector4 vector_zero = Vector4(0.0, 0.0, 0.0, 0.0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector4 Constructor with no inputs should return a zero Vector4."); +} + TEST_CASE("[Vector4] Axis methods") { Vector4 vector = Vector4(1.2, 3.4, 5.6, -0.9); CHECK_MESSAGE( diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h index ac63001b24..e106099914 100644 --- a/tests/core/math/test_vector4i.h +++ b/tests/core/math/test_vector4i.h @@ -36,6 +36,14 @@ namespace TestVector4i { +TEST_CASE("[Vector4i] Constructor methods") { + const Vector4i vector_empty = Vector4i(); + const Vector4i vector_zero = Vector4i(0, 0, 0, 0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector4i Constructor with no inputs should return a zero Vector4i."); +} + TEST_CASE("[Vector4i] Axis methods") { Vector4i vector = Vector4i(1, 2, 3, 4); CHECK_MESSAGE( |