summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/classes/EditorSettings.xml12
-rw-r--r--doc/classes/Joint2D.xml10
-rw-r--r--doc/classes/Joint3D.xml12
-rw-r--r--editor/action_map_editor.cpp3
-rw-r--r--editor/debugger/editor_debugger_node.cpp6
-rw-r--r--editor/debugger/script_editor_debugger.cpp1
-rw-r--r--editor/editor_node.cpp12
-rw-r--r--editor/editor_node.h11
-rw-r--r--editor/editor_settings.cpp6
-rw-r--r--editor/filesystem_dock.cpp12
-rw-r--r--scene/resources/material.cpp23
-rw-r--r--tests/core/math/test_transform_2d.h110
12 files changed, 161 insertions, 57 deletions
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 3e3d2205f2..7ee239415f 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -925,14 +925,14 @@
<member name="run/auto_save/save_before_running" type="bool" setter="" getter="">
If [code]true[/code], saves all scenes and scripts automatically before running the project. Setting this to [code]false[/code] prevents the editor from saving if there are no changes which can speed up the project startup slightly, but it makes it possible to run a project that has unsaved changes. (Unsaved changes will not be visible in the running project.)
</member>
- <member name="run/output/always_clear_output_on_play" type="bool" setter="" getter="">
- If [code]true[/code], the editor will clear the Output panel when running the project.
+ <member name="run/bottom_panel/action_on_play" type="int" setter="" getter="">
+ The action to execute on the bottom panel when running the project.
</member>
- <member name="run/output/always_close_output_on_stop" type="bool" setter="" getter="">
- If [code]true[/code], the editor will collapse the Output panel when stopping the project.
+ <member name="run/bottom_panel/action_on_stop" type="int" setter="" getter="">
+ The action to execute on the bottom panel when stopping the project.
</member>
- <member name="run/output/always_open_output_on_play" type="bool" setter="" getter="">
- If [code]true[/code], the editor will expand the Output panel when running the project.
+ <member name="run/output/always_clear_output_on_play" type="bool" setter="" getter="">
+ If [code]true[/code], the editor will clear the Output panel when running the project.
</member>
<member name="run/output/font_size" type="int" setter="" getter="">
The size of the font in the [b]Output[/b] panel at the bottom of the editor. This setting does not impact the font size of the script editor (see [member interface/editor/code_font_size]).
diff --git a/doc/classes/Joint2D.xml b/doc/classes/Joint2D.xml
index af0a54815f..0099c76d08 100644
--- a/doc/classes/Joint2D.xml
+++ b/doc/classes/Joint2D.xml
@@ -4,7 +4,7 @@
Abstract base class for all 2D physics joints.
</brief_description>
<description>
- Abstract base class for all joints in 2D physics. 2D joints bind together two physics bodies and apply a constraint.
+ Abstract base class for all joints in 2D physics. 2D joints bind together two physics bodies ([member node_a] and [member node_b]) and apply a constraint.
</description>
<tutorials>
</tutorials>
@@ -12,7 +12,7 @@
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
- Returns the joint's [RID].
+ Returns the joint's internal [RID] from the [PhysicsServer2D].
</description>
</method>
</methods>
@@ -22,13 +22,13 @@
When set to [code]0[/code], the default value from [member ProjectSettings.physics/2d/solver/default_constraint_bias] is used.
</member>
<member name="disable_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
- If [code]true[/code], [member node_a] and [member node_b] can not collide.
+ If [code]true[/code], the two bodies bound together do not collide with each other.
</member>
<member name="node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath(&quot;&quot;)">
- The first body attached to the joint. Must derive from [PhysicsBody2D].
+ Path to the first body (A) attached to the joint. The node must inherit [PhysicsBody2D].
</member>
<member name="node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath(&quot;&quot;)">
- The second body attached to the joint. Must derive from [PhysicsBody2D].
+ Path to the second body (B) attached to the joint. The node must inherit [PhysicsBody2D].
</member>
</members>
</class>
diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml
index ea0dda881a..950129806a 100644
--- a/doc/classes/Joint3D.xml
+++ b/doc/classes/Joint3D.xml
@@ -4,7 +4,7 @@
Abstract base class for all 3D physics joints.
</brief_description>
<description>
- Abstract base class for all joints in 3D physics. 3D joints bind together two physics bodies and apply a constraint.
+ Abstract base class for all joints in 3D physics. 3D joints bind together two physics bodies ([member node_a] and [member node_b]) and apply a constraint. If only one body is defined, it is attached to a fixed [StaticBody3D] without collision shapes.
</description>
<tutorials>
<link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/2752</link>
@@ -13,19 +13,21 @@
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
- Returns the joint's [RID].
+ Returns the joint's internal [RID] from the [PhysicsServer3D].
</description>
</method>
</methods>
<members>
<member name="exclude_nodes_from_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
- If [code]true[/code], the two bodies of the nodes are not able to collide with each other.
+ If [code]true[/code], the two bodies bound together do not collide with each other.
</member>
<member name="node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath(&quot;&quot;)">
- The node attached to the first side (A) of the joint.
+ Path to the first node (A) attached to the joint. The node must inherit [PhysicsBody3D].
+ If left empty and [member node_b] is set, the body is attached to a fixed [StaticBody3D] without collision shapes.
</member>
<member name="node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath(&quot;&quot;)">
- The node attached to the second side (B) of the joint.
+ Path to the second node (B) attached to the joint. The node must inherit [PhysicsBody3D].
+ If left empty and [member node_a] is set, the body is attached to a fixed [StaticBody3D] without collision shapes.
</member>
<member name="solver_priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1">
The priority used to define which solver is executed first for multiple joints. The lower the value, the higher the priority.
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 3023c5907a..f70730d540 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -428,6 +428,7 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
// Update Tree...
TreeItem *action_item = action_tree->create_item(root);
+ ERR_FAIL_NULL(action_item);
action_item->set_meta("__action", action_info.action);
action_item->set_meta("__name", action_info.name);
@@ -604,7 +605,7 @@ ActionMapEditor::ActionMapEditor() {
action_tree->set_column_custom_minimum_width(1, 80 * EDSCALE);
action_tree->set_column_expand(2, false);
action_tree->set_column_custom_minimum_width(2, 50 * EDSCALE);
- action_tree->connect("item_edited", callable_mp(this, &ActionMapEditor::_action_edited));
+ action_tree->connect("item_edited", callable_mp(this, &ActionMapEditor::_action_edited), CONNECT_DEFERRED);
action_tree->connect("item_activated", callable_mp(this, &ActionMapEditor::_tree_item_activated));
action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed));
main_vbox->add_child(action_tree);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 2f7183b883..2a98f50a3a 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -268,11 +268,7 @@ Error EditorDebuggerNode::start(const String &p_uri) {
}
stop(true);
current_uri = p_uri;
- if (EDITOR_GET("run/output/always_open_output_on_play")) {
- EditorNode::get_bottom_panel()->make_item_visible(EditorNode::get_log());
- } else {
- EditorNode::get_bottom_panel()->make_item_visible(this);
- }
+
server = Ref<EditorDebuggerServer>(EditorDebuggerServer::create(p_uri.substr(0, p_uri.find("://") + 3)));
const Error err = server->start(p_uri);
if (err != OK) {
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 156e740509..37bb048b19 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -1009,7 +1009,6 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
set_process(true);
camera_override = CameraOverride::OVERRIDE_NONE;
- tabs->set_current_tab(0);
_set_reason_text(TTR("Debug session started."), MESSAGE_SUCCESS);
_update_buttons_state();
emit_signal(SNAME("started"));
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 964061505f..0df4df36bc 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4543,17 +4543,19 @@ void EditorNode::_project_run_started() {
log->clear();
}
- if (bool(EDITOR_GET("run/output/always_open_output_on_play"))) {
+ int action_on_play = EDITOR_GET("run/bottom_panel/action_on_play");
+ if (action_on_play == ACTION_ON_PLAY_OPEN_OUTPUT) {
bottom_panel->make_item_visible(log);
+ } else if (action_on_play == ACTION_ON_PLAY_OPEN_DEBUGGER) {
+ bottom_panel->make_item_visible(EditorDebuggerNode::get_singleton());
}
}
void EditorNode::_project_run_stopped() {
- if (!bool(EDITOR_GET("run/output/always_close_output_on_stop"))) {
- return;
+ int action_on_stop = EDITOR_GET("run/bottom_panel/action_on_stop");
+ if (action_on_stop == ACTION_ON_STOP_CLOSE_BUTTOM_PANEL) {
+ bottom_panel->hide_bottom_panel();
}
-
- bottom_panel->make_item_visible(log, false);
}
void EditorNode::notify_all_debug_sessions_exited() {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 9643bc2229..5d7bd5b4f8 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -140,6 +140,17 @@ public:
SCENE_NAME_CASING_KEBAB_CASE,
};
+ enum ActionOnPlay {
+ ACTION_ON_PLAY_DO_NOTHING,
+ ACTION_ON_PLAY_OPEN_OUTPUT,
+ ACTION_ON_PLAY_OPEN_DEBUGGER,
+ };
+
+ enum ActionOnStop {
+ ACTION_ON_STOP_DO_NOTHING,
+ ACTION_ON_STOP_CLOSE_BUTTOM_PANEL,
+ };
+
struct ExecuteThreadArgs {
String path;
List<String> args;
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index d7bc3502ce..737bec352d 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -818,11 +818,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Auto save
_initial_set("run/auto_save/save_before_running", true);
+ // Bottom panel
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/bottom_panel/action_on_play", EditorNode::ACTION_ON_PLAY_OPEN_OUTPUT, "Do Nothing,Open Output,Open Debugger")
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/bottom_panel/action_on_stop", EditorNode::ACTION_ON_STOP_DO_NOTHING, "Do Nothing,Close Bottom Panel")
+
// Output
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "run/output/font_size", 13, "8,48,1")
_initial_set("run/output/always_clear_output_on_play", true);
- _initial_set("run/output/always_open_output_on_play", true);
- _initial_set("run/output/always_close_output_on_stop", false);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "run/output/max_lines", 10000, "100,100000,1")
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 2e88540fc4..c07667ac12 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -3310,15 +3310,15 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
// Opening the system file manager is not supported on the Android and web editors.
const bool is_directory = fpath.ends_with("/");
- p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
- p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager"));
+ p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
+ p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal"));
if (!is_directory) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ExternalLink")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL);
}
- p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
- p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal"));
+ p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
+ p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager"));
#endif
current_path = fpath;
@@ -3362,8 +3362,8 @@ void FileSystemDock::_tree_empty_click(const Vector2 &p_pos, MouseButton p_butto
#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
// Opening the system file manager is not supported on the Android and web editors.
tree_popup->add_separator();
- tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
+ tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
#endif
tree_popup->set_position(tree->get_screen_position() + p_pos);
@@ -3425,8 +3425,8 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton
file_list_popup->add_icon_item(get_editor_theme_icon(SNAME("Object")), TTR("New Resource..."), FILE_NEW_RESOURCE);
file_list_popup->add_icon_item(get_editor_theme_icon(SNAME("TextFile")), TTR("New TextFile..."), FILE_NEW_TEXTFILE);
file_list_popup->add_separator();
- file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
+ file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
file_list_popup->set_position(files->get_screen_position() + p_pos);
file_list_popup->reset_size();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 27da825bfe..8e49a8b56f 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -822,7 +822,18 @@ uniform float distance_fade_max : hint_range(0.0, 4096.0, 0.01);
)";
}
- if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && flags[FLAG_UV1_USE_TRIPLANAR]) {
+ String msg = "MSDF is not supported on triplanar materials. Ignoring MSDF in favor of triplanar mapping.";
+ if (textures[TEXTURE_ALBEDO].is_valid()) {
+ WARN_PRINT(vformat("%s (albedo %s): " + msg, get_path(), textures[TEXTURE_ALBEDO]->get_path()));
+ } else if (!get_path().is_empty()) {
+ WARN_PRINT(vformat("%s: " + msg, get_path()));
+ } else {
+ WARN_PRINT(msg);
+ }
+ }
+
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
code += R"(
uniform float msdf_pixel_range : hint_range(1.0, 100.0, 1.0);
uniform float msdf_outline_size : hint_range(0.0, 250.0, 1.0);
@@ -1271,7 +1282,7 @@ void vertex() {)";
code += "}\n";
- if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
code += R"(
float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
@@ -1414,7 +1425,7 @@ void fragment() {)";
}
}
- if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
code += R"(
{
// Albedo Texture MSDF: Enabled
@@ -1427,11 +1438,7 @@ void fragment() {)";
if (flags[FLAG_USE_POINT_SIZE]) {
code += " vec2 dest_size = vec2(1.0) / fwidth(POINT_COORD);\n";
} else {
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec2 dest_size = vec2(1.0) / fwidth(uv1_triplanar_pos);\n";
- } else {
- code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n";
- }
+ code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n";
}
code += R"(
float px_size = max(0.5 * dot(msdf_size, dest_size), 1.0);
diff --git a/tests/core/math/test_transform_2d.h b/tests/core/math/test_transform_2d.h
index 36d27ce7a9..6d3c80e5ca 100644
--- a/tests/core/math/test_transform_2d.h
+++ b/tests/core/math/test_transform_2d.h
@@ -45,48 +45,132 @@ Transform2D identity() {
return Transform2D();
}
+TEST_CASE("[Transform2D] Default constructor") {
+ Transform2D default_constructor = Transform2D();
+ CHECK(default_constructor == Transform2D(Vector2(1, 0), Vector2(0, 1), Vector2(0, 0)));
+}
+
+TEST_CASE("[Transform2D] Copy constructor") {
+ Transform2D T = create_dummy_transform();
+ Transform2D copy_constructor = Transform2D(T);
+ CHECK(T == copy_constructor);
+}
+
+TEST_CASE("[Transform2D] Constructor from angle and position") {
+ constexpr float ROTATION = Math_PI / 4;
+ const Vector2 TRANSLATION = Vector2(20, -20);
+
+ const Transform2D test = Transform2D(ROTATION, TRANSLATION);
+ const Transform2D expected = Transform2D().rotated(ROTATION).translated(TRANSLATION);
+ CHECK(test == expected);
+}
+
+TEST_CASE("[Transform2D] Constructor from angle, scale, skew and position") {
+ constexpr float ROTATION = Math_PI / 2;
+ const Vector2 SCALE = Vector2(2, 0.5);
+ constexpr float SKEW = Math_PI / 4;
+ const Vector2 TRANSLATION = Vector2(30, 0);
+
+ const Transform2D test = Transform2D(ROTATION, SCALE, SKEW, TRANSLATION);
+ Transform2D expected = Transform2D().scaled(SCALE).rotated(ROTATION).translated(TRANSLATION);
+ expected.set_skew(SKEW);
+
+ CHECK(test.is_equal_approx(expected));
+}
+
+TEST_CASE("[Transform2D] Constructor from raw values") {
+ const Transform2D test = Transform2D(1, 2, 3, 4, 5, 6);
+ const Transform2D expected = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6));
+ CHECK(test == expected);
+}
+
+TEST_CASE("[Transform2D] xform") {
+ const Vector2 v = Vector2(2, 3);
+ const Transform2D T = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6));
+ const Vector2 expected = Vector2(1 * 2 + 3 * 3 + 5 * 1, 2 * 2 + 4 * 3 + 6 * 1);
+ CHECK(T.xform(v) == expected);
+}
+
+TEST_CASE("[Transform2D] Basis xform") {
+ const Vector2 v = Vector2(2, 2);
+ const Transform2D T1 = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(0, 0));
+
+ // Both versions should be the same when the origin is (0,0).
+ CHECK(T1.basis_xform(v) == T1.xform(v));
+
+ const Transform2D T2 = Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6));
+
+ // Each version should be different when the origin is not (0,0).
+ CHECK_FALSE(T2.basis_xform(v) == T2.xform(v));
+}
+
+TEST_CASE("[Transform2D] Affine inverse") {
+ const Transform2D orig = create_dummy_transform();
+ const Transform2D affine_inverted = orig.affine_inverse();
+ const Transform2D affine_inverted_again = affine_inverted.affine_inverse();
+ CHECK(affine_inverted_again == orig);
+}
+
+TEST_CASE("[Transform2D] Orthonormalized") {
+ const Transform2D T = create_dummy_transform();
+ const Transform2D orthonormalized_T = T.orthonormalized();
+
+ // Check each basis has length 1.
+ CHECK(Math::is_equal_approx(orthonormalized_T[0].length_squared(), 1));
+ CHECK(Math::is_equal_approx(orthonormalized_T[1].length_squared(), 1));
+
+ const Vector2 vx = Vector2(orthonormalized_T[0].x, orthonormalized_T[1].x);
+ const Vector2 vy = Vector2(orthonormalized_T[0].y, orthonormalized_T[1].y);
+
+ // Check the basis are orthogonal.
+ CHECK(Math::is_equal_approx(orthonormalized_T.tdotx(vx), 1));
+ CHECK(Math::is_equal_approx(orthonormalized_T.tdotx(vy), 0));
+ CHECK(Math::is_equal_approx(orthonormalized_T.tdoty(vx), 0));
+ CHECK(Math::is_equal_approx(orthonormalized_T.tdoty(vy), 1));
+}
+
TEST_CASE("[Transform2D] translation") {
- Vector2 offset = Vector2(1, 2);
+ const Vector2 offset = Vector2(1, 2);
// Both versions should give the same result applied to identity.
CHECK(identity().translated(offset) == identity().translated_local(offset));
// Check both versions against left and right multiplications.
- Transform2D orig = create_dummy_transform();
- Transform2D T = identity().translated(offset);
+ const Transform2D orig = create_dummy_transform();
+ const Transform2D T = identity().translated(offset);
CHECK(orig.translated(offset) == T * orig);
CHECK(orig.translated_local(offset) == orig * T);
}
TEST_CASE("[Transform2D] scaling") {
- Vector2 scaling = Vector2(1, 2);
+ const Vector2 scaling = Vector2(1, 2);
// Both versions should give the same result applied to identity.
CHECK(identity().scaled(scaling) == identity().scaled_local(scaling));
// Check both versions against left and right multiplications.
- Transform2D orig = create_dummy_transform();
- Transform2D S = identity().scaled(scaling);
+ const Transform2D orig = create_dummy_transform();
+ const Transform2D S = identity().scaled(scaling);
CHECK(orig.scaled(scaling) == S * orig);
CHECK(orig.scaled_local(scaling) == orig * S);
}
TEST_CASE("[Transform2D] rotation") {
- real_t phi = 1.0;
+ constexpr real_t phi = 1.0;
// Both versions should give the same result applied to identity.
CHECK(identity().rotated(phi) == identity().rotated_local(phi));
// Check both versions against left and right multiplications.
- Transform2D orig = create_dummy_transform();
- Transform2D R = identity().rotated(phi);
+ const Transform2D orig = create_dummy_transform();
+ const Transform2D R = identity().rotated(phi);
CHECK(orig.rotated(phi) == R * orig);
CHECK(orig.rotated_local(phi) == orig * R);
}
TEST_CASE("[Transform2D] Interpolation") {
- Transform2D rotate_scale_skew_pos = Transform2D(Math::deg_to_rad(170.0), Vector2(3.6, 8.0), Math::deg_to_rad(20.0), Vector2(2.4, 6.8));
- Transform2D rotate_scale_skew_pos_halfway = Transform2D(Math::deg_to_rad(85.0), Vector2(2.3, 4.5), Math::deg_to_rad(10.0), Vector2(1.2, 3.4));
+ const Transform2D rotate_scale_skew_pos = Transform2D(Math::deg_to_rad(170.0), Vector2(3.6, 8.0), Math::deg_to_rad(20.0), Vector2(2.4, 6.8));
+ const Transform2D rotate_scale_skew_pos_halfway = Transform2D(Math::deg_to_rad(85.0), Vector2(2.3, 4.5), Math::deg_to_rad(10.0), Vector2(1.2, 3.4));
Transform2D interpolated = Transform2D().interpolate_with(rotate_scale_skew_pos, 0.5);
CHECK(interpolated.get_origin().is_equal_approx(rotate_scale_skew_pos_halfway.get_origin()));
CHECK(interpolated.get_rotation() == doctest::Approx(rotate_scale_skew_pos_halfway.get_rotation()));
@@ -98,8 +182,8 @@ TEST_CASE("[Transform2D] Interpolation") {
}
TEST_CASE("[Transform2D] Finite number checks") {
- const Vector2 x(0, 1);
- const Vector2 infinite(NAN, NAN);
+ const Vector2 x = Vector2(0, 1);
+ const Vector2 infinite = Vector2(NAN, NAN);
CHECK_MESSAGE(
Transform2D(x, x, x).is_finite(),