From 3c63ca3965f911e269b4e336de311c6664958f8d Mon Sep 17 00:00:00 2001 From: Nomango Date: Mon, 29 Jul 2019 12:58:17 +0800 Subject: [PATCH] some optimizations on AffineTransform --- Kiwano/2d/Node.cpp | 21 ++++- Kiwano/2d/Node.h | 9 ++- Kiwano/2d/Transform.hpp | 13 +--- Kiwano/math/Matrix.hpp | 167 ++++++++++++++++++++++------------------ 4 files changed, 120 insertions(+), 90 deletions(-) diff --git a/Kiwano/2d/Node.cpp b/Kiwano/2d/Node.cpp index 9ae4377e..619f0242 100644 --- a/Kiwano/2d/Node.cpp +++ b/Kiwano/2d/Node.cpp @@ -188,7 +188,7 @@ namespace kiwano UpdateTransform(); if (dirty_transform_inverse_) { - transform_matrix_inverse_ = Matrix::Invert(transform_matrix_); + transform_matrix_inverse_ = transform_matrix_.Invert(); dirty_transform_inverse_ = false; } return transform_matrix_inverse_; @@ -202,13 +202,26 @@ namespace kiwano dirty_transform_ = false; 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 }; transform_matrix_.Translate(offset); if (parent_) + { transform_matrix_ = transform_matrix_ * parent_->transform_matrix_; + } // update children's transform for (Node* child = children_.First().Get(); child; child = child->NextItem().Get()) @@ -343,6 +356,7 @@ namespace kiwano { transform_ = transform; dirty_transform_ = true; + is_fast_transform_ = false; } void Node::SetVisible(bool val) @@ -417,6 +431,7 @@ namespace kiwano transform_.scale.x = scale_x; transform_.scale.y = scale_y; dirty_transform_ = true; + is_fast_transform_ = false; } void Node::SetScale(Point const& scale) @@ -442,6 +457,7 @@ namespace kiwano transform_.skew.x = skew_x; transform_.skew.y = skew_y; dirty_transform_ = true; + is_fast_transform_ = false; } void Node::SetSkew(Point const& skew) @@ -456,6 +472,7 @@ namespace kiwano transform_.rotation = angle; dirty_transform_ = true; + is_fast_transform_ = false; } void Node::AddChild(NodePtr child) diff --git a/Kiwano/2d/Node.h b/Kiwano/2d/Node.h index 60ea6394..72347f93 100644 --- a/Kiwano/2d/Node.h +++ b/Kiwano/2d/Node.h @@ -416,15 +416,16 @@ namespace kiwano int z_order_; float opacity_; float display_opacity_; - size_t hash_name_; - Transform transform_; - Point anchor_; - Size size_; Node* parent_; Scene* scene_; + size_t hash_name_; + Point anchor_; + Size size_; Children children_; UpdateCallback cb_update_; + Transform transform_; + bool is_fast_transform_; mutable bool dirty_transform_; mutable bool dirty_transform_inverse_; mutable Matrix transform_matrix_; diff --git a/Kiwano/2d/Transform.hpp b/Kiwano/2d/Transform.hpp index 69e1605c..db928c97 100644 --- a/Kiwano/2d/Transform.hpp +++ b/Kiwano/2d/Transform.hpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../math/Matrix.hpp" +#include "../math/Vec2.hpp" namespace kiwano { @@ -34,7 +34,7 @@ namespace kiwano public: Transform() : position() - , rotation(0) + , rotation(0.f) , scale(1.f, 1.f) , skew(0.f, 0.f) {} @@ -46,14 +46,5 @@ namespace kiwano skew == other.skew && 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); - } }; } diff --git a/Kiwano/math/Matrix.hpp b/Kiwano/math/Matrix.hpp index 6fd0358f..dd251212 100644 --- a/Kiwano/math/Matrix.hpp +++ b/Kiwano/math/Matrix.hpp @@ -34,6 +34,8 @@ namespace kiwano struct MatrixT { using value_type = _Ty; + using vec2_type = Vec2T; + using rect_type = RectT; union { @@ -83,47 +85,16 @@ namespace kiwano 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 Transform(const Rect & rect) const - { - Vec2T top_left = Transform(rect.GetLeftTop()); - Vec2T top_right = Transform(rect.GetRightTop()); - Vec2T bottom_left = Transform(rect.GetLeftBottom()); - Vec2T 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 { return m[index]; } + inline value_type& operator [](unsigned int index) + { + return m[index]; + } + template inline MatrixT& operator= (MatrixMultiply const& other) { @@ -132,16 +103,31 @@ namespace kiwano 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 { return _11 == 1.f && _12 == 0.f && - _21 == 0.f && _22 == 1.f && - _31 == 0.f && _32 == 0.f; + _21 == 0.f && _22 == 1.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 @@ -149,7 +135,41 @@ namespace kiwano 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( 1.f, 0.f, @@ -158,16 +178,18 @@ namespace kiwano ); } - static inline MatrixT Translation( - value_type x, - value_type y) + static inline MatrixT Scaling(const vec2_type& v) { - return Translation(Vec2(x, y)); + return MatrixT( + v.x, 0.f, + 0.f, v.y, + 0.f, 0.f + ); } static inline MatrixT Scaling( - const Vec2& v, - const Vec2& center = Vec2()) + const vec2_type& v, + const vec2_type& center) { return MatrixT( v.x, 0.f, @@ -177,17 +199,20 @@ namespace kiwano ); } - static inline MatrixT Scaling( - value_type x, - value_type y, - const Vec2& center = Vec2()) + static inline MatrixT Rotation(value_type angle) { - 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( value_type angle, - const Vec2& center = Vec2()) + const vec2_type& center) { value_type s = math::Sin(angle); value_type c = math::Cos(angle); @@ -199,33 +224,29 @@ namespace kiwano ); } - static inline MatrixT Skewing( - value_type angle_x, - value_type angle_y, - const Vec2& center = Vec2()) + static inline MatrixT Skewing(const vec2_type& angle) { - value_type tx = math::Tan(angle_x); - value_type ty = math::Tan(angle_y); + value_type tx = math::Tan(angle.x); + 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( 1.f, -ty, -tx, 1.f, 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) - ); - } };