some optimizations on AffineTransform

This commit is contained in:
Nomango 2019-07-29 12:58:17 +08:00
parent 5bc2a39f7c
commit 3c63ca3965
4 changed files with 120 additions and 90 deletions

View File

@ -188,7 +188,7 @@ namespace kiwano
UpdateTransform(); UpdateTransform();
if (dirty_transform_inverse_) if (dirty_transform_inverse_)
{ {
transform_matrix_inverse_ = Matrix::Invert(transform_matrix_); transform_matrix_inverse_ = transform_matrix_.Invert();
dirty_transform_inverse_ = false; dirty_transform_inverse_ = false;
} }
return transform_matrix_inverse_; return transform_matrix_inverse_;
@ -202,13 +202,26 @@ namespace kiwano
dirty_transform_ = false; dirty_transform_ = false;
dirty_transform_inverse_ = true; dirty_transform_inverse_ = true;
transform_matrix_ = transform_.ToMatrix(); if (is_fast_transform_)
{
transform_matrix_ = Matrix::Translation(transform_.position);
}
else
{
// matrix multiplication is optimized by expression template
transform_matrix_ = Matrix::Scaling(transform_.scale)
* Matrix::Skewing(transform_.skew)
* Matrix::Rotation(transform_.rotation)
* Matrix::Translation(transform_.position);
}
Point offset{ -size_.x * anchor_.x, -size_.y * anchor_.y }; Point offset{ -size_.x * anchor_.x, -size_.y * anchor_.y };
transform_matrix_.Translate(offset); transform_matrix_.Translate(offset);
if (parent_) if (parent_)
{
transform_matrix_ = transform_matrix_ * parent_->transform_matrix_; transform_matrix_ = transform_matrix_ * parent_->transform_matrix_;
}
// update children's transform // update children's transform
for (Node* child = children_.First().Get(); child; child = child->NextItem().Get()) for (Node* child = children_.First().Get(); child; child = child->NextItem().Get())
@ -343,6 +356,7 @@ namespace kiwano
{ {
transform_ = transform; transform_ = transform;
dirty_transform_ = true; dirty_transform_ = true;
is_fast_transform_ = false;
} }
void Node::SetVisible(bool val) void Node::SetVisible(bool val)
@ -417,6 +431,7 @@ namespace kiwano
transform_.scale.x = scale_x; transform_.scale.x = scale_x;
transform_.scale.y = scale_y; transform_.scale.y = scale_y;
dirty_transform_ = true; dirty_transform_ = true;
is_fast_transform_ = false;
} }
void Node::SetScale(Point const& scale) void Node::SetScale(Point const& scale)
@ -442,6 +457,7 @@ namespace kiwano
transform_.skew.x = skew_x; transform_.skew.x = skew_x;
transform_.skew.y = skew_y; transform_.skew.y = skew_y;
dirty_transform_ = true; dirty_transform_ = true;
is_fast_transform_ = false;
} }
void Node::SetSkew(Point const& skew) void Node::SetSkew(Point const& skew)
@ -456,6 +472,7 @@ namespace kiwano
transform_.rotation = angle; transform_.rotation = angle;
dirty_transform_ = true; dirty_transform_ = true;
is_fast_transform_ = false;
} }
void Node::AddChild(NodePtr child) void Node::AddChild(NodePtr child)

View File

@ -416,15 +416,16 @@ namespace kiwano
int z_order_; int z_order_;
float opacity_; float opacity_;
float display_opacity_; float display_opacity_;
size_t hash_name_;
Transform transform_;
Point anchor_;
Size size_;
Node* parent_; Node* parent_;
Scene* scene_; Scene* scene_;
size_t hash_name_;
Point anchor_;
Size size_;
Children children_; Children children_;
UpdateCallback cb_update_; UpdateCallback cb_update_;
Transform transform_;
bool is_fast_transform_;
mutable bool dirty_transform_; mutable bool dirty_transform_;
mutable bool dirty_transform_inverse_; mutable bool dirty_transform_inverse_;
mutable Matrix transform_matrix_; mutable Matrix transform_matrix_;

View File

@ -19,7 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "../math/Matrix.hpp" #include "../math/Vec2.hpp"
namespace kiwano namespace kiwano
{ {
@ -34,7 +34,7 @@ namespace kiwano
public: public:
Transform() Transform()
: position() : position()
, rotation(0) , rotation(0.f)
, scale(1.f, 1.f) , scale(1.f, 1.f)
, skew(0.f, 0.f) , skew(0.f, 0.f)
{} {}
@ -46,14 +46,5 @@ namespace kiwano
skew == other.skew && skew == other.skew &&
rotation == other.rotation; rotation == other.rotation;
} }
inline Matrix ToMatrix() const
{
// matrix multiplication is optimized by expression template
return Matrix::Scaling(scale)
* Matrix::Skewing(skew.x, skew.y)
* Matrix::Rotation(rotation)
* Matrix::Translation(position);
}
}; };
} }

View File

@ -34,6 +34,8 @@ namespace kiwano
struct MatrixT struct MatrixT
{ {
using value_type = _Ty; using value_type = _Ty;
using vec2_type = Vec2T<value_type>;
using rect_type = RectT<value_type>;
union union
{ {
@ -83,47 +85,16 @@ namespace kiwano
m[i] = other[i]; m[i] = other[i];
} }
inline void Identity()
{
_11 = 1.f; _12 = 0.f;
_21 = 0.f; _12 = 1.f;
_31 = 0.f; _32 = 0.f;
}
inline Vec2 Transform(const Vec2& v) const
{
return Vec2(
v.x * _11 + v.y * _21 + _31,
v.x * _12 + v.y * _22 + _32
);
}
RectT<value_type> Transform(const Rect & rect) const
{
Vec2T<value_type> top_left = Transform(rect.GetLeftTop());
Vec2T<value_type> top_right = Transform(rect.GetRightTop());
Vec2T<value_type> bottom_left = Transform(rect.GetLeftBottom());
Vec2T<value_type> bottom_right = Transform(rect.GetRightBottom());
value_type left = std::min(std::min(top_left.x, top_right.x), std::min(bottom_left.x, bottom_right.x));
value_type right = std::max(std::max(top_left.x, top_right.x), std::max(bottom_left.x, bottom_right.x));
value_type top = std::min(std::min(top_left.y, top_right.y), std::min(bottom_left.y, bottom_right.y));
value_type bottom = std::max(std::max(top_left.y, top_right.y), std::max(bottom_left.y, bottom_right.y));
return Rect{ left, top, (right - left), (bottom - top) };
}
inline void Translate(const Vec2& v)
{
_31 += _11 * v.x + _21 * v.y;
_32 += _12 * v.x + _22 * v.y;
}
inline value_type operator [](unsigned int index) const inline value_type operator [](unsigned int index) const
{ {
return m[index]; return m[index];
} }
inline value_type& operator [](unsigned int index)
{
return m[index];
}
template <typename _Lty, typename _Rty> template <typename _Lty, typename _Rty>
inline MatrixT& operator= (MatrixMultiply<value_type, _Lty, _Rty> const& other) inline MatrixT& operator= (MatrixMultiply<value_type, _Lty, _Rty> const& other)
{ {
@ -132,9 +103,11 @@ namespace kiwano
return *this; return *this;
} }
inline value_type Determinant() const inline void Identity()
{ {
return (_11 * _22) - (_12 * _21); _11 = 1.f; _12 = 0.f;
_21 = 0.f; _22 = 1.f;
_31 = 0.f; _32 = 0.f;
} }
inline bool IsIdentity() const inline bool IsIdentity() const
@ -144,12 +117,59 @@ namespace kiwano
_31 == 0.f && _32 == 0.f; _31 == 0.f && _32 == 0.f;
} }
inline MatrixT Invert() const
{
value_type det = 1.f / Determinant();
return MatrixT(
det * _22,
-det * _12,
-det * _21,
det * _11,
det * (_21 * _32 - _22 * _31),
det * (_12 * _31 - _11 * _32)
);
}
inline bool IsInvertible() const inline bool IsInvertible() const
{ {
return 0 != Determinant(); return 0 != Determinant();
} }
static inline MatrixT Translation(const Vec2& v) inline value_type Determinant() const
{
return (_11 * _22) - (_12 * _21);
}
inline vec2_type Transform(const vec2_type& v) const
{
return vec2_type(
v.x * _11 + v.y * _21 + _31,
v.x * _12 + v.y * _22 + _32
);
}
rect_type Transform(const rect_type & rect) const
{
vec2_type top_left = Transform(rect.GetLeftTop());
vec2_type top_right = Transform(rect.GetRightTop());
vec2_type bottom_left = Transform(rect.GetLeftBottom());
vec2_type bottom_right = Transform(rect.GetRightBottom());
value_type left = std::min(std::min(top_left.x, top_right.x), std::min(bottom_left.x, bottom_right.x));
value_type right = std::max(std::max(top_left.x, top_right.x), std::max(bottom_left.x, bottom_right.x));
value_type top = std::min(std::min(top_left.y, top_right.y), std::min(bottom_left.y, bottom_right.y));
value_type bottom = std::max(std::max(top_left.y, top_right.y), std::max(bottom_left.y, bottom_right.y));
return rect_type{ left, top, (right - left), (bottom - top) };
}
inline void Translate(const vec2_type& v)
{
_31 += _11 * v.x + _21 * v.y;
_32 += _12 * v.x + _22 * v.y;
}
static inline MatrixT Translation(const vec2_type& v)
{ {
return MatrixT( return MatrixT(
1.f, 0.f, 1.f, 0.f,
@ -158,16 +178,18 @@ namespace kiwano
); );
} }
static inline MatrixT Translation( static inline MatrixT Scaling(const vec2_type& v)
value_type x,
value_type y)
{ {
return Translation(Vec2(x, y)); return MatrixT(
v.x, 0.f,
0.f, v.y,
0.f, 0.f
);
} }
static inline MatrixT Scaling( static inline MatrixT Scaling(
const Vec2& v, const vec2_type& v,
const Vec2& center = Vec2()) const vec2_type& center)
{ {
return MatrixT( return MatrixT(
v.x, 0.f, v.x, 0.f,
@ -177,17 +199,20 @@ namespace kiwano
); );
} }
static inline MatrixT Scaling( static inline MatrixT Rotation(value_type angle)
value_type x,
value_type y,
const Vec2& center = Vec2())
{ {
return Scaling(Vec2(x, y), center); value_type s = math::Sin(angle);
value_type c = math::Cos(angle);
return MatrixT(
c, s,
-s, c,
0.f, 0.f
);
} }
static inline MatrixT Rotation( static inline MatrixT Rotation(
value_type angle, value_type angle,
const Vec2& center = Vec2()) const vec2_type& center)
{ {
value_type s = math::Sin(angle); value_type s = math::Sin(angle);
value_type c = math::Cos(angle); value_type c = math::Cos(angle);
@ -199,33 +224,29 @@ namespace kiwano
); );
} }
static inline MatrixT Skewing( static inline MatrixT Skewing(const vec2_type& angle)
value_type angle_x,
value_type angle_y,
const Vec2& center = Vec2())
{ {
value_type tx = math::Tan(angle_x); value_type tx = math::Tan(angle.x);
value_type ty = math::Tan(angle_y); value_type ty = math::Tan(angle.y);
return MatrixT(
1.f, -ty,
-tx, 1.f,
0.f, 0.f
);
}
static inline MatrixT Skewing(
const vec2_type& angle,
const vec2_type& center)
{
value_type tx = math::Tan(angle.x);
value_type ty = math::Tan(angle.y);
return MatrixT( return MatrixT(
1.f, -ty, 1.f, -ty,
-tx, 1.f, -tx, 1.f,
center.y * tx, center.x * ty center.y * tx, center.x * ty
); );
} }
static inline MatrixT Invert(MatrixT const& matrix)
{
value_type det = 1.f / matrix.Determinant();
return MatrixT(
det * matrix._22,
-det * matrix._12,
-det * matrix._21,
det * matrix._11,
det * (matrix._21 * matrix._32 - matrix._22 * matrix._31),
det * (matrix._12 * matrix._31 - matrix._11 * matrix._32)
);
}
}; };