Skip to content

Commit 7f61710

Browse files
reduzakien-mga
authored andcommitted
Implement Skew in Node2D
Skew is x-axis only, because it must be bidirectionally convertible to a 2x3 matrix, but you can subtract it to the rotation to get the effect on y-axis (cherry picked from commit efb1f7d)
1 parent 97ffd1f commit 7f61710

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

core/math/transform_2d.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ void Transform2D::rotate(real_t p_phi) {
7070
*this = Transform2D(p_phi, Vector2()) * (*this);
7171
}
7272

73+
real_t Transform2D::get_skew() const {
74+
75+
real_t det = basis_determinant();
76+
return Math::acos(elements[0].normalized().dot(SGN(det) * elements[1].normalized())) - Math_PI * 0.5;
77+
}
78+
79+
void Transform2D::set_skew(float p_angle) {
80+
81+
real_t det = basis_determinant();
82+
elements[1] = SGN(det) * elements[0].rotated((Math_PI * 0.5 + p_angle)).normalized() * elements[1].length();
83+
}
84+
7385
real_t Transform2D::get_rotation() const {
7486
real_t det = basis_determinant();
7587
Transform2D m = orthonormalized();

core/math/transform_2d.h

+11
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ struct Transform2D {
7171

7272
void set_rotation(real_t p_rot);
7373
real_t get_rotation() const;
74+
real_t get_skew() const;
75+
void set_skew(float p_angle);
7476
_FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale);
77+
_FORCE_INLINE_ void set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, float p_skew);
7578
void rotate(real_t p_phi);
7679

7780
void scale(const Size2 &p_scale);
@@ -185,6 +188,14 @@ void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) {
185188
elements[0][1] = Math::sin(p_rot) * p_scale.x;
186189
}
187190

191+
void Transform2D::set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, float p_skew) {
192+
193+
elements[0][0] = Math::cos(p_rot) * p_scale.x;
194+
elements[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
195+
elements[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
196+
elements[0][1] = Math::sin(p_rot) * p_scale.x;
197+
}
198+
188199
Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const {
189200

190201
Vector2 ends[4] = {

scene/2d/node_2d.cpp

+40-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Dictionary Node2D::_edit_get_state() const {
4242
state["position"] = get_position();
4343
state["rotation"] = get_rotation();
4444
state["scale"] = get_scale();
45+
state["skew"] = get_skew();
4546

4647
return state;
4748
}
@@ -51,11 +52,14 @@ void Node2D::_edit_set_state(const Dictionary &p_state) {
5152
pos = p_state["position"];
5253
angle = p_state["rotation"];
5354
_scale = p_state["scale"];
55+
skew = p_state["skew"];
5456

5557
_update_transform();
5658
_change_notify("rotation");
5759
_change_notify("rotation_degrees");
5860
_change_notify("scale");
61+
_change_notify("skew");
62+
_change_notify("skew_degrees");
5963
_change_notify("position");
6064
}
6165

@@ -111,7 +115,7 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
111115
Point2 new_pos = p_edit_rect.position + p_edit_rect.size * zero_offset;
112116

113117
Transform2D postxf;
114-
postxf.set_rotation_and_scale(angle, _scale);
118+
postxf.set_rotation_scale_and_skew(angle, _scale, skew);
115119
new_pos = postxf.xform(new_pos);
116120

117121
pos += new_pos;
@@ -128,12 +132,13 @@ void Node2D::_update_xform_values() {
128132
pos = _mat.elements[2];
129133
angle = _mat.get_rotation();
130134
_scale = _mat.get_scale();
135+
skew = _mat.get_skew();
131136
_xform_dirty = false;
132137
}
133138

134139
void Node2D::_update_transform() {
135140

136-
_mat.set_rotation_and_scale(angle, _scale);
141+
_mat.set_rotation_scale_and_skew(angle, _scale, skew);
137142
_mat.elements[2] = pos;
138143

139144
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
@@ -163,11 +168,26 @@ void Node2D::set_rotation(float p_radians) {
163168
_change_notify("rotation_degrees");
164169
}
165170

171+
void Node2D::set_skew(float p_radians) {
172+
173+
if (_xform_dirty)
174+
((Node2D *)this)->_update_xform_values();
175+
skew = p_radians;
176+
_update_transform();
177+
_change_notify("skew");
178+
_change_notify("skew_degrees");
179+
}
180+
166181
void Node2D::set_rotation_degrees(float p_degrees) {
167182

168183
set_rotation(Math::deg2rad(p_degrees));
169184
}
170185

186+
void Node2D::set_skew_degrees(float p_degrees) {
187+
188+
set_skew(Math::deg2rad(p_degrees));
189+
}
190+
171191
void Node2D::set_scale(const Size2 &p_scale) {
172192

173193
if (_xform_dirty)
@@ -196,11 +216,22 @@ float Node2D::get_rotation() const {
196216
return angle;
197217
}
198218

219+
float Node2D::get_skew() const {
220+
if (_xform_dirty)
221+
((Node2D *)this)->_update_xform_values();
222+
223+
return skew;
224+
}
225+
199226
float Node2D::get_rotation_degrees() const {
200227

201228
return Math::rad2deg(get_rotation());
202229
}
203230

231+
float Node2D::get_skew_degrees() const {
232+
233+
return Math::rad2deg(get_skew());
234+
}
204235
Size2 Node2D::get_scale() const {
205236
if (_xform_dirty)
206237
((Node2D *)this)->_update_xform_values();
@@ -398,11 +429,15 @@ void Node2D::_bind_methods() {
398429
ClassDB::bind_method(D_METHOD("set_position", "position"), &Node2D::set_position);
399430
ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Node2D::set_rotation);
400431
ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Node2D::set_rotation_degrees);
432+
ClassDB::bind_method(D_METHOD("set_skew", "radians"), &Node2D::set_skew);
433+
ClassDB::bind_method(D_METHOD("set_skew_degrees", "degrees"), &Node2D::set_skew_degrees);
401434
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node2D::set_scale);
402435

403436
ClassDB::bind_method(D_METHOD("get_position"), &Node2D::get_position);
404437
ClassDB::bind_method(D_METHOD("get_rotation"), &Node2D::get_rotation);
405438
ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node2D::get_rotation_degrees);
439+
ClassDB::bind_method(D_METHOD("get_skew"), &Node2D::get_skew);
440+
ClassDB::bind_method(D_METHOD("get_skew_degrees"), &Node2D::get_skew_degrees);
406441
ClassDB::bind_method(D_METHOD("get_scale"), &Node2D::get_scale);
407442

408443
ClassDB::bind_method(D_METHOD("rotate", "radians"), &Node2D::rotate);
@@ -443,6 +478,8 @@ void Node2D::_bind_methods() {
443478
ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
444479
ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
445480
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
481+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "skew", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_skew", "get_skew");
482+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "skew_degrees", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1", PROPERTY_USAGE_EDITOR), "set_skew_degrees", "get_skew_degrees");
446483
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
447484

448485
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
@@ -460,6 +497,7 @@ Node2D::Node2D() {
460497

461498
angle = 0;
462499
_scale = Vector2(1, 1);
500+
skew = 0;
463501
_xform_dirty = false;
464502
z_index = 0;
465503
z_relative = true;

scene/2d/node_2d.h

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class Node2D : public CanvasItem {
4040
Point2 pos;
4141
float angle;
4242
Size2 _scale;
43+
float skew;
4344
int z_index;
4445
bool z_relative;
4546

@@ -75,6 +76,8 @@ class Node2D : public CanvasItem {
7576
void set_position(const Point2 &p_pos);
7677
void set_rotation(float p_radians);
7778
void set_rotation_degrees(float p_degrees);
79+
void set_skew(float p_radians);
80+
void set_skew_degrees(float p_radians);
7881
void set_scale(const Size2 &p_scale);
7982

8083
void rotate(float p_radians);
@@ -86,7 +89,9 @@ class Node2D : public CanvasItem {
8689

8790
Point2 get_position() const;
8891
float get_rotation() const;
92+
float get_skew() const;
8993
float get_rotation_degrees() const;
94+
float get_skew_degrees() const;
9095
Size2 get_scale() const;
9196

9297
Point2 get_global_position() const;

0 commit comments

Comments
 (0)