diff --git a/projects/kiwano.vcxproj b/projects/kiwano.vcxproj index 545fbfad..6ae1c33b 100644 --- a/projects/kiwano.vcxproj +++ b/projects/kiwano.vcxproj @@ -2,9 +2,11 @@ + + @@ -69,6 +71,7 @@ + @@ -86,8 +89,10 @@ + + @@ -120,6 +125,7 @@ + diff --git a/projects/kiwano.vcxproj.filters b/projects/kiwano.vcxproj.filters index 47f84249..f70612b5 100644 --- a/projects/kiwano.vcxproj.filters +++ b/projects/kiwano.vcxproj.filters @@ -279,6 +279,15 @@ 2d + + renderer + + + 2d\action + + + 2d\action + @@ -425,5 +434,14 @@ 2d + + renderer + + + 2d\action + + + 2d\action + \ No newline at end of file diff --git a/src/kiwano/2d/ShapeActor.cpp b/src/kiwano/2d/ShapeActor.cpp index 8939ebda..1e4689b5 100644 --- a/src/kiwano/2d/ShapeActor.cpp +++ b/src/kiwano/2d/ShapeActor.cpp @@ -20,6 +20,7 @@ #include "ShapeActor.h" #include "../base/logs.h" +#include "../renderer/render.h" namespace kiwano { @@ -31,7 +32,7 @@ namespace kiwano { } - ShapeActor::ShapeActor(ComPtr geometry) + ShapeActor::ShapeActor(Geometry geometry) : ShapeActor() { SetGeometry(geometry); @@ -46,10 +47,7 @@ namespace kiwano if (!geo_) return Rect{}; - D2D1_RECT_F rect; - // no matter it failed or not - geo_->GetBounds(D2D1::Matrix3x2F::Identity(), &rect); - return Rect{ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top }; + return geo_.GetBoundingBox(Matrix()); } Rect ShapeActor::GetBoundingBox() const @@ -57,63 +55,7 @@ namespace kiwano if (!geo_) return Rect{}; - D2D1_RECT_F rect; - // no matter it failed or not - geo_->GetBounds(DX::ConvertToMatrix3x2F(transform_matrix_), &rect); - return Rect{ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top }; - } - - float ShapeActor::GetLength() - { - float length = 0.f; - if (geo_) - { - // no matter it failed or not - geo_->ComputeLength(D2D1::Matrix3x2F::Identity(), &length); - } - return length; - } - - bool ShapeActor::ComputePointAtLength(float length, Point& point, Vec2& tangent) - { - if (geo_) - { - if (SUCCEEDED(geo_->ComputePointAtLength( - length, - D2D1::Matrix3x2F::Identity(), - DX::ConvertToPoint2F(&point), - DX::ConvertToPoint2F(&tangent)))) - { - return true; - } - } - return false; - } - - float ShapeActor::ComputeArea() - { - if (!geo_) - return 0.f; - - float area = 0.f; - // no matter it failed or not - geo_->ComputeArea(D2D1::Matrix3x2F::Identity(), &area); - return area; - } - - bool ShapeActor::ContainsPoint(Point const& point) - { - if (!geo_) - return false; - - BOOL ret = 0; - // no matter it failed or not - geo_->FillContainsPoint( - DX::ConvertToPoint2F(point), - D2D1::Matrix3x2F::Identity(), - &ret - ); - return !!ret; + return geo_.GetBoundingBox(GetTransformMatrix()); } void ShapeActor::SetFillColor(const Color & color) @@ -164,49 +106,23 @@ namespace kiwano { } - LineActor::LineActor(Point const& begin, Point const& end) + LineActor::LineActor(Point const& end) { - SetLine(begin, end); + SetEndPoint(end); } LineActor::~LineActor() { } - void LineActor::SetLine(Point const& begin, Point const& end) + void LineActor::SetEndPoint(Point const& end) { - ComPtr path_geo; - ComPtr path_sink; + Renderer::GetInstance()->CreateLineGeometry(geo_, Point{}, end); - HRESULT hr = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory()->CreatePathGeometry(&path_geo); - - if (SUCCEEDED(hr)) + if (geo_) { - hr = path_geo->Open(&path_sink); + SetSize(end); } - - if (SUCCEEDED(hr)) - { - path_sink->BeginFigure(DX::ConvertToPoint2F(begin), D2D1_FIGURE_BEGIN_FILLED); - path_sink->AddLine(DX::ConvertToPoint2F(end)); - path_sink->EndFigure(D2D1_FIGURE_END_OPEN); - hr = path_sink->Close(); - } - - if (SUCCEEDED(hr)) - { - geo_ = path_geo; - } - } - - void LineActor::SetBegin(Point const& begin) - { - SetLine(begin, end_); - } - - void LineActor::SetEnd(Point const& end) - { - SetLine(begin_, end); } @@ -218,29 +134,22 @@ namespace kiwano { } - RectActor::RectActor(Rect const& rect) + RectActor::RectActor(Size const& size) { - SetRect(rect); - } - - RectActor::RectActor(Point const& left_top, Size const& size) - { - SetRect(Rect{ left_top, size }); + SetRectSize(size); } RectActor::~RectActor() { } - void RectActor::SetRect(Rect const& rect) + void RectActor::SetRectSize(Size const& size) { - ComPtr geo; - auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory(); + Renderer::GetInstance()->CreateRectGeometry(geo_, Rect{ Point{}, size }); - if (SUCCEEDED(factory->CreateRectangleGeometry(DX::ConvertToRectF(rect), &geo))) + if (geo_) { - geo_ = geo; - rect_ = rect; + SetSize(size); } } @@ -250,47 +159,35 @@ namespace kiwano //------------------------------------------------------- RoundRectActor::RoundRectActor() - : radius_x_(0.f) - , radius_y_(0.f) { } - RoundRectActor::RoundRectActor(Rect const& rect, float radius_x, float radius_y) + RoundRectActor::RoundRectActor(Size const& size, Vec2 const& radius) { - SetRoundedRect(rect, radius_x, radius_y); + SetRoundedRect(size, radius); } RoundRectActor::~RoundRectActor() { } - void RoundRectActor::SetRadius(float radius_x, float radius_y) + void RoundRectActor::SetRadius(Vec2 const& radius) { - SetRoundedRect(rect_, radius_x, radius_y); + SetRoundedRect(size_, radius); } - void RoundRectActor::SetRect(Rect const& rect) + void RoundRectActor::SetRectSize(Size const& size) { - SetRoundedRect(rect, radius_x_, radius_y_); + SetRoundedRect(size, radius_); } - void RoundRectActor::SetRoundedRect(Rect const& rect, float radius_x, float radius_y) + void RoundRectActor::SetRoundedRect(Size const& size, Vec2 const& radius) { - ComPtr geo; - auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory(); + Renderer::GetInstance()->CreateRoundedRectGeometry(geo_, Rect{ Point{}, size }, radius); - if (SUCCEEDED(factory->CreateRoundedRectangleGeometry( - D2D1::RoundedRect( - DX::ConvertToRectF(rect), - radius_x, - radius_y - ), - &geo))) + if (geo_) { - geo_ = geo; - rect_ = rect; - radius_x_ = radius_x; - radius_y_ = radius_y; + SetSize(size); } } @@ -304,9 +201,9 @@ namespace kiwano { } - CircleActor::CircleActor(Point const& center, float radius) + CircleActor::CircleActor(float radius) { - SetCircle(center, radius); + SetRadius(radius); } CircleActor::~CircleActor() @@ -315,29 +212,11 @@ namespace kiwano void CircleActor::SetRadius(float radius) { - SetCircle(center_, radius); - } + Renderer::GetInstance()->CreateEllipseGeometry(geo_, Point{}, Vec2{ radius, radius }); - void CircleActor::SetCenter(Point const& center) - { - SetCircle(center, radius_); - } - - void CircleActor::SetCircle(Point const& center, float radius) - { - ComPtr geo; - auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory(); - - if (SUCCEEDED(factory->CreateEllipseGeometry( - D2D1::Ellipse( - DX::ConvertToPoint2F(center), - radius, - radius), - &geo))) + if (geo_) { - geo_ = geo; - center_ = center; - radius_ = radius; + SetSize(radius * 2, radius * 2); } } @@ -347,45 +226,25 @@ namespace kiwano //------------------------------------------------------- EllipseActor::EllipseActor() - : radius_x_(0.f) - , radius_y_(0.f) { } - EllipseActor::EllipseActor(Point const& center, float radius_x, float radius_y) + EllipseActor::EllipseActor(Vec2 const& radius) { - SetEllipse(center, radius_x, radius_y); + SetRadius(radius); } EllipseActor::~EllipseActor() { } - void EllipseActor::SetRadius(float radius_x, float radius_y) + void EllipseActor::SetRadius(Vec2 const& radius) { - SetEllipse(center_, radius_x, radius_y); - } + Renderer::GetInstance()->CreateEllipseGeometry(geo_, Point{}, radius); - void EllipseActor::SetCenter(Point const& center) - { - SetEllipse(center, radius_x_, radius_y_); - } - - void EllipseActor::SetEllipse(Point const& center, float radius_x, float radius_y) - { - ComPtr geo; - auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory(); - - if (SUCCEEDED(factory->CreateEllipseGeometry( - D2D1::Ellipse( - DX::ConvertToPoint2F(center), - radius_x, - radius_y), - &geo))) + if (geo_) { - geo_ = geo; - radius_x_ = radius_x; - radius_y_ = radius_y; + SetSize(radius * 2); } } @@ -404,89 +263,38 @@ namespace kiwano void PathActor::BeginPath(Point const& begin_pos) { - current_geometry_ = nullptr; - - auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory(); - - ThrowIfFailed( - factory->CreatePathGeometry(¤t_geometry_) - ); - - ThrowIfFailed( - current_geometry_->Open(¤t_sink_) - ); - - current_sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); + sink_.BeginPath(begin_pos); } void PathActor::EndPath(bool closed) { - if (current_sink_) - { - current_sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); - ThrowIfFailed( - current_sink_->Close() - ); - - geo_ = current_geometry_; - - current_sink_ = nullptr; - current_geometry_ = nullptr; - } + sink_.EndPath(closed); + geo_ = sink_.GetGeometry(); } void PathActor::AddLine(Point const& point) { - if (current_sink_) - current_sink_->AddLine(DX::ConvertToPoint2F(point)); + sink_.AddLine(point); } void PathActor::AddLines(Vector const& points) { - if (current_sink_ && !points.empty()) - { - current_sink_->AddLines( - reinterpret_cast(&points[0]), - static_cast(points.size()) - ); - } + sink_.AddLines(points); } void PathActor::AddBezier(Point const& point1, Point const& point2, Point const& point3) { - if (current_sink_) - { - current_sink_->AddBezier( - D2D1::BezierSegment( - DX::ConvertToPoint2F(point1), - DX::ConvertToPoint2F(point2), - DX::ConvertToPoint2F(point3) - ) - ); - } + sink_.AddBezier(point1, point2, point3); } void PathActor::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small) { - if (current_sink_) - { - current_sink_->AddArc( - D2D1::ArcSegment( - DX::ConvertToPoint2F(point), - DX::ConvertToSizeF(radius), - rotation, - clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, - is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE - ) - ); - } + sink_.AddArc(point, radius, rotation, clockwise, is_small); } void PathActor::ClearPath() { - geo_ = nullptr; - current_sink_ = nullptr; - current_geometry_ = nullptr; + geo_.SetGeometry(nullptr); } } diff --git a/src/kiwano/2d/ShapeActor.h b/src/kiwano/2d/ShapeActor.h index 25498b2e..940a34df 100644 --- a/src/kiwano/2d/ShapeActor.h +++ b/src/kiwano/2d/ShapeActor.h @@ -20,7 +20,7 @@ #pragma once #include "Actor.h" -#include "../renderer/render.h" // ID2D1Geometry +#include "../renderer/Geometry.h" namespace kiwano { @@ -32,7 +32,7 @@ namespace kiwano ShapeActor(); ShapeActor( - ComPtr geometry + Geometry geometry ); virtual ~ShapeActor(); @@ -55,24 +55,6 @@ namespace kiwano // 获取外切包围盒 Rect GetBoundingBox() const override; - // 判断图形是否包含点 - bool ContainsPoint( - Point const& point - ); - - // 获取图形展开成一条直线的长度 - float GetLength(); - - // 计算面积 - float ComputeArea(); - - // 计算图形路径上点的位置和切线向量 - bool ComputePointAtLength( - float length, - Point& point, - Vec2& tangent - ); - // 设置填充颜色 void SetFillColor( const Color& color @@ -94,19 +76,19 @@ namespace kiwano ); // 设置形状 - inline void SetGeometry(ComPtr geometry) { geo_ = geometry; } + inline void SetGeometry(Geometry geometry) { geo_ = geometry; } // 获取形状 - inline ComPtr GetGeometry() const { return geo_; } + inline Geometry GetGeometry() const { return geo_; } void OnRender(Renderer* renderer) override; protected: - Color fill_color_; - Color stroke_color_; - float stroke_width_; - StrokeStyle outline_join_; - ComPtr geo_; + Color fill_color_; + Color stroke_color_; + float stroke_width_; + StrokeStyle outline_join_; + Geometry geo_; }; @@ -118,31 +100,18 @@ namespace kiwano LineActor(); LineActor( - Point const& begin, - Point const& end + Point const& end_pos ); virtual ~LineActor(); - Point const& GetBegin() const { return begin_; } + Point const& GetEndPoint() const { return end_; } - Point const& GetEnd() const { return end_; } - - void SetLine( - Point const& begin, - Point const& end - ); - - void SetBegin( - Point const& begin - ); - - void SetEnd( + void SetEndPoint( Point const& end ); protected: - Point begin_; Point end_; }; @@ -155,22 +124,17 @@ namespace kiwano RectActor(); RectActor( - Rect const& rect - ); - - RectActor( - Point const& left_top, Size const& size ); virtual ~RectActor(); - Rect const& GetRect() const { return rect_; } + void SetRectSize(Size const& size); - void SetRect(Rect const& rect); + inline Size const& GetRectSize() const { return size_; } protected: - Rect rect_; + Size size_; }; @@ -182,38 +146,32 @@ namespace kiwano RoundRectActor(); RoundRectActor( - Rect const& rect, - float radius_x, - float radius_y + Size const& size, + Vec2 const& radius ); virtual ~RoundRectActor(); - float GetRadiusX() const { return radius_x_; } - - float GetRadiusY() const { return radius_y_; } - void SetRadius( - float radius_x, - float radius_y + Vec2 const& radius ); - Rect const& GetRect() const { return rect_; } - - void SetRect( - Rect const& rect + void SetRectSize( + Size const& size ); void SetRoundedRect( - Rect const& rect, - float radius_x, - float radius_y + Size const& size, + Vec2 const& radius ); + inline Vec2 GetRadius() const { return radius_; } + + inline Size GetRectSize() const { return size_; } + protected: - Rect rect_; - float radius_x_; - float radius_y_; + Size size_; + Vec2 radius_; }; @@ -225,31 +183,16 @@ namespace kiwano CircleActor(); CircleActor( - Point const& center, float radius ); virtual ~CircleActor(); - float GetRadius() const { return radius_; } + inline float GetRadius() const { return radius_; } - void SetRadius( - float radius - ); - - Point const& GetCenter() const { return center_; } - - void SetCenter( - Point const& center - ); - - void SetCircle( - Point const& center, - float radius - ); + void SetRadius(float radius); protected: - Point center_; float radius_; }; @@ -262,38 +205,19 @@ namespace kiwano EllipseActor(); EllipseActor( - Point const& center, - float radius_x, - float radius_y + Vec2 const& radius ); virtual ~EllipseActor(); - float GetRadiusX() const { return radius_x_; } - - float GetRadiusY() const { return radius_y_; } + Vec2 GetRadius() const { return radius_; } void SetRadius( - float radius_x, - float radius_y - ); - - Point const& GetCenter() const { return center_; } - - void SetCenter( - Point const& center - ); - - void SetEllipse( - Point const& center, - float radius_x, - float radius_y + Vec2 const& radius ); protected: - Point center_; - float radius_x_; - float radius_y_; + Vec2 radius_; }; @@ -346,8 +270,7 @@ namespace kiwano void ClearPath(); protected: - ComPtr current_geometry_; - ComPtr current_sink_; + GeometrySink sink_; }; } diff --git a/src/kiwano/2d/Sprite.cpp b/src/kiwano/2d/Sprite.cpp index 301747aa..0223fe08 100644 --- a/src/kiwano/2d/Sprite.cpp +++ b/src/kiwano/2d/Sprite.cpp @@ -88,6 +88,7 @@ namespace kiwano if (frame_ && renderer->CheckVisibility(size_, transform_matrix_)) { PrepareRender(renderer); + renderer->DrawBitmap(frame_->GetImage()->GetBitmap(), frame_->GetCropRect(), GetBounds()); } } diff --git a/src/kiwano/2d/action/ActionDelay.cpp b/src/kiwano/2d/action/ActionDelay.cpp new file mode 100644 index 00000000..7f784431 --- /dev/null +++ b/src/kiwano/2d/action/ActionDelay.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "ActionDelay.h" + +namespace kiwano +{ + ActionDelay::ActionDelay(Duration delay) + { + SetDelay(delay); + } + + ActionPtr ActionDelay::Clone() const + { + return new ActionDelay(delay_); + } + + ActionPtr ActionDelay::Reverse() const + { + return new ActionDelay(delay_); + } + +} diff --git a/src/kiwano/2d/action/ActionDelay.h b/src/kiwano/2d/action/ActionDelay.h new file mode 100644 index 00000000..3c3dfd10 --- /dev/null +++ b/src/kiwano/2d/action/ActionDelay.h @@ -0,0 +1,41 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "Action.h" + +namespace kiwano +{ + // 延时动作 + class KGE_API ActionDelay + : public Action + { + public: + ActionDelay( + Duration delay /* 持续时长 */ + ); + + // 获取该动作的拷贝对象 + ActionPtr Clone() const override; + + // 获取该动作的倒转 + ActionPtr Reverse() const override; + }; +} diff --git a/src/kiwano/2d/action/ActionHelper.h b/src/kiwano/2d/action/ActionHelper.h index 4735b1e6..c8d396f3 100644 --- a/src/kiwano/2d/action/ActionHelper.h +++ b/src/kiwano/2d/action/ActionHelper.h @@ -19,8 +19,10 @@ // THE SOFTWARE. #pragma once -#include "ActionGroup.h" #include "ActionTween.h" +#include "ActionWalk.h" +#include "ActionDelay.h" +#include "ActionGroup.h" #include "Animation.h" namespace kiwano @@ -185,6 +187,32 @@ namespace kiwano return TweenHelper(new kiwano::ActionRotateTo(dur, rotation)); } + static inline TweenHelper + Walk( + Duration duration, /* 持续时长 */ + Geometry const& geo, /* 路线 */ + bool rotating = false, /* 沿路线切线方向旋转 */ + float start = 0.f, /* 起点 */ + float end = 1.f, /* 终点 */ + EaseFunc func = nullptr /* 速度变化 */ + ) + { + return TweenHelper(new kiwano::ActionWalk(duration, geo, rotating, start, end, func)); + } + + static inline TweenHelper + Walk( + Duration duration, /* 持续时长 */ + GeometrySink& sink, /* 路线生成器 */ + bool rotating = false, /* 沿路线切线方向旋转 */ + float start = 0.f, /* 起点 */ + float end = 1.f, /* 终点 */ + EaseFunc func = nullptr /* 速度变化 */ + ) + { + return TweenHelper(new kiwano::ActionWalk(duration, sink.GetGeometry(), rotating, start, end, func)); + } + static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames) { @@ -220,7 +248,7 @@ namespace kiwano KGE_DEPRECATED("Tween::OpacityBy has been removed, use Tween::FadeTo instead") static inline TweenHelper - OpacityBy(float opacity) + OpacityBy(float opacity) { KGE_ASSERT("Tween::OpacityBy has been removed, use Tween::FadeTo instead"); return TweenHelper(nullptr); @@ -242,7 +270,7 @@ namespace kiwano KGE_DEPRECATED("Tween::Spawn is deprecated, use Tween::Multiple instead") static inline ActionHelper - Spawn(Vector const& actions) + Spawn(Vector const& actions) { return ActionHelper(new kiwano::ActionGroup(actions, false)); } diff --git a/src/kiwano/2d/action/ActionTween.cpp b/src/kiwano/2d/action/ActionTween.cpp index 0bb1e597..b78c8720 100644 --- a/src/kiwano/2d/action/ActionTween.cpp +++ b/src/kiwano/2d/action/ActionTween.cpp @@ -419,218 +419,6 @@ namespace kiwano } - //------------------------------------------------------- - // ActionPath - //------------------------------------------------------- - - ActionPath::ActionPath(Duration duration, bool rotating, float start, float end, EaseFunc func) - : ActionTween(duration, func) - , start_(start) - , end_(end) - , rotating_(rotating) - , path_beginning_(false) - , geo_(nullptr) - , geo_sink_(nullptr) - { - } - - ActionPtr ActionPath::Clone() const - { - ActionPathPtr clone = new ActionPath(dur_, rotating_, start_, end_, ease_func_); - if (clone) - { - clone->SetGeometry(geo_); - } - return clone; - } - - ActionPtr ActionPath::Reverse() const - { - ActionPathPtr reverse = new ActionPath(dur_, rotating_, end_, start_, ease_func_); - if (reverse) - { - reverse->SetGeometry(geo_); - } - return reverse; - } - - float ActionPath::GetPathLength() const - { - float length = 0.f; - if (geo_) - { - // no matter it failed or not - geo_->ComputeLength(D2D1::Matrix3x2F::Identity(), &length); - } - return length; - } - - bool ActionPath::ComputePointAtLength(float length, Point* point, Vec2* tangent) const - { - if (geo_) - { - HRESULT hr = geo_->ComputePointAtLength( - length, - D2D1::Matrix3x2F::Identity(), - DX::ConvertToPoint2F(point), - DX::ConvertToPoint2F(tangent) - ); - return SUCCEEDED(hr); - } - return false; - } - - void ActionPath::Init(ActorPtr target) - { - start_pos_ = target->GetPosition(); - - if (path_beginning_) - { - EndPath(); - } - - if (!geo_) - { - Complete(target); - } - } - - void ActionPath::UpdateTween(ActorPtr target, float percent) - { - float length = GetPathLength() * std::min(std::max((end_ - start_) * percent + start_, 0.f), 1.f); - - Point point, tangent; - if (ComputePointAtLength(length, &point, &tangent)) - { - target->SetPosition(start_pos_ + point); - - if (rotating_) - { - float ac = math::Acos(tangent.x); - float rotation = (tangent.y < 0.f) ? 360.f - ac : ac; - target->SetRotation(rotation); - } - } - } - - void ActionPath::BeginPath() - { - if (path_beginning_) return; - path_beginning_ = true; - - geo_ = nullptr; - geo_sink_ = nullptr; - - auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory(); - - ThrowIfFailed( - factory->CreatePathGeometry(&geo_) - ); - - ThrowIfFailed( - geo_->Open(&geo_sink_) - ); - - geo_sink_->BeginFigure(DX::ConvertToPoint2F(Point{ 0, 0 }), D2D1_FIGURE_BEGIN_FILLED); - } - - void ActionPath::EndPath(bool closed) - { - if (!path_beginning_) return; - path_beginning_ = false; - - if (geo_sink_) - { - geo_sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); - ThrowIfFailed( - geo_sink_->Close() - ); - - // Clear geometry sink - geo_sink_ = nullptr; - } - } - - void ActionPath::AddLine(Point const& point) - { - if (!path_beginning_) - { - BeginPath(); - } - - if (geo_sink_) - { - geo_sink_->AddLine(DX::ConvertToPoint2F(point)); - } - } - - void ActionPath::AddLines(Vector const& points) - { - if (!path_beginning_) - { - BeginPath(); - } - - if (geo_sink_ && !points.empty()) - { - geo_sink_->AddLines( - reinterpret_cast(&points[0]), - static_cast(points.size()) - ); - } - } - - void ActionPath::AddBezier(Point const& point1, Point const& point2, Point const& point3) - { - if (!path_beginning_) - { - BeginPath(); - } - - if (geo_sink_) - { - geo_sink_->AddBezier( - D2D1::BezierSegment( - DX::ConvertToPoint2F(point1), - DX::ConvertToPoint2F(point2), - DX::ConvertToPoint2F(point3) - ) - ); - } - } - - void ActionPath::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small) - { - if (!path_beginning_) - { - BeginPath(); - } - - if (geo_sink_) - { - geo_sink_->AddArc( - D2D1::ArcSegment( - DX::ConvertToPoint2F(point), - DX::ConvertToSizeF(radius), - rotation, - clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, - is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE - ) - ); - } - } - - void ActionPath::ClearPath() - { - if (path_beginning_) - { - EndPath(); - } - - geo_sink_ = nullptr; - geo_ = nullptr; - } - //------------------------------------------------------- // ActionCustom //------------------------------------------------------- @@ -658,24 +446,4 @@ namespace kiwano tween_func_(target, percent); } - - //------------------------------------------------------- - // ActionDelay - //------------------------------------------------------- - - ActionDelay::ActionDelay(Duration delay) - { - SetDelay(delay); - } - - ActionPtr ActionDelay::Clone() const - { - return new ActionDelay(delay_); - } - - ActionPtr ActionDelay::Reverse() const - { - return new ActionDelay(delay_); - } - } diff --git a/src/kiwano/2d/action/ActionTween.h b/src/kiwano/2d/action/ActionTween.h index 43e7d240..46854a7c 100644 --- a/src/kiwano/2d/action/ActionTween.h +++ b/src/kiwano/2d/action/ActionTween.h @@ -21,7 +21,6 @@ #pragma once #include "Action.h" #include "../../base/logs.h" -#include "../../renderer/render.h" // ID2D1PathGeometry, ID2D1GeometrySink namespace kiwano { @@ -412,91 +411,6 @@ namespace kiwano }; - // 路径动作 - class KGE_API ActionPath - : public ActionTween - { - public: - ActionPath( - Duration duration, /* 持续时长 */ - bool rotating = false, /* 沿路径切线方向旋转 */ - float start = 0.f, /* 起点 */ - float end = 1.f, /* 终点 */ - EaseFunc func = nullptr /* 速度变化 */ - ); - - // 获取该动作的拷贝对象 - ActionPtr Clone() const override; - - // 获取该动作的倒转 - ActionPtr Reverse() const override; - - // 开始添加路径 - void BeginPath(); - - // 结束路径 - void EndPath( - bool closed = false /* 路径是否闭合 */ - ); - - // 添加一条线段 - void AddLine( - Point const& point /* 端点 */ - ); - - // 添加多条线段 - void AddLines( - Vector const& points - ); - - // 添加一条三次方贝塞尔曲线 - void AddBezier( - Point const& point1, /* 贝塞尔曲线的第一个控制点 */ - Point const& point2, /* 贝塞尔曲线的第二个控制点 */ - Point const& point3 /* 贝塞尔曲线的终点 */ - ); - - // 添加弧线 - void AddArc( - Point const& point, /* 终点 */ - Size const& radius, /* 椭圆半径 */ - float rotation, /* 椭圆旋转角度 */ - bool clockwise = true, /* 顺时针 or 逆时针 */ - bool is_small = true /* 是否取小于 180° 的弧 */ - ); - - // 清除路径 - void ClearPath(); - - // 获取路径长度 - float GetPathLength() const; - - // 计算当前路径上指定点坐标和切线 - bool ComputePointAtLength(float length, Point* point, Vec2* tangent) const; - - // 获取几何路径 - inline ComPtr GetGeometry() const { return geo_; } - - // 设置几何路径 - inline void SetGeometry(ComPtr geo) { geo_ = geo; } - - protected: - void Init(ActorPtr target) override; - - void UpdateTween(ActorPtr target, float percent) override; - - protected: - bool path_beginning_; - bool rotating_; - float start_; - float end_; - Point start_pos_; - - ComPtr geo_; - ComPtr geo_sink_; - }; - - // 自定义动作 class KGE_API ActionCustom : public ActionTween @@ -529,20 +443,4 @@ namespace kiwano TweenFunc tween_func_; }; - - // 延时动作 - class KGE_API ActionDelay - : public Action - { - public: - ActionDelay( - Duration delay /* 持续时长 */ - ); - - // 获取该动作的拷贝对象 - ActionPtr Clone() const override; - - // 获取该动作的倒转 - ActionPtr Reverse() const override; - }; } diff --git a/src/kiwano/2d/action/ActionWalk.cpp b/src/kiwano/2d/action/ActionWalk.cpp new file mode 100644 index 00000000..addf325e --- /dev/null +++ b/src/kiwano/2d/action/ActionWalk.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "ActionWalk.h" +#include "../Actor.h" + +namespace kiwano +{ + ActionWalk::ActionWalk(Duration duration, bool rotating, float start, float end, EaseFunc func) + : ActionTween(duration, func) + , start_(start) + , end_(end) + , rotating_(rotating) + , length_(0.f) + { + } + + ActionWalk::ActionWalk(Duration duration, Geometry const& path, bool rotating, float start, float end, EaseFunc func) + : ActionWalk(duration, rotating, start, end, func) + { + path_ = path; + } + + ActionPtr ActionWalk::Clone() const + { + ActionWalkPtr clone = new ActionWalk(dur_, rotating_, start_, end_, ease_func_); + if (clone) + { + clone->SetPath(path_); + } + return clone; + } + + ActionPtr ActionWalk::Reverse() const + { + ActionWalkPtr reverse = new ActionWalk(dur_, rotating_, end_, start_, ease_func_); + if (reverse) + { + reverse->SetPath(path_); + } + return reverse; + } + + void ActionWalk::Init(ActorPtr target) + { + if (!path_) + { + Complete(target); + return; + } + + start_pos_ = target->GetPosition(); + length_ = path_.GetLength(); + } + + void ActionWalk::UpdateTween(ActorPtr target, float percent) + { + float distance = length_ * std::min(std::max((end_ - start_) * percent + start_, 0.f), 1.f); + + Point point, tangent; + if (path_.ComputePointAtLength(distance, point, tangent)) + { + target->SetPosition(start_pos_ + point); + + if (rotating_) + { + float ac = math::Acos(tangent.x); + float rotation = (tangent.y < 0.f) ? 360.f - ac : ac; + target->SetRotation(rotation); + } + } + KGE_LOG(L"%.2f, %.2f", target->GetPositionX(), target->GetPositionY()); + } + + void ActionWalk::BeginPath() + { + sink_.BeginPath(); + } + + void ActionWalk::EndPath(bool closed) + { + sink_.EndPath(closed); + path_ = sink_.GetGeometry(); + } + + void ActionWalk::AddLine(Point const& point) + { + sink_.AddLine(point); + } + + void ActionWalk::AddLines(Vector const& points) + { + sink_.AddLines(points); + } + + void ActionWalk::AddBezier(Point const& point1, Point const& point2, Point const& point3) + { + sink_.AddBezier(point1, point2, point3); + } + + void ActionWalk::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small) + { + sink_.AddArc(point, radius, rotation, clockwise, is_small); + } + + void ActionWalk::ClearPath() + { + path_.SetGeometry(nullptr); + } + +} diff --git a/src/kiwano/2d/action/ActionWalk.h b/src/kiwano/2d/action/ActionWalk.h new file mode 100644 index 00000000..f9747556 --- /dev/null +++ b/src/kiwano/2d/action/ActionWalk.h @@ -0,0 +1,112 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "ActionTween.h" +#include "../../renderer/Geometry.h" // Geometry, GeometrySink + +namespace kiwano +{ + // 路线行走动作 + class KGE_API ActionWalk + : public ActionTween + { + public: + ActionWalk( + Duration duration, /* 持续时长 */ + bool rotating = false, /* 沿路线切线方向旋转 */ + float start = 0.f, /* 起点 */ + float end = 1.f, /* 终点 */ + EaseFunc func = nullptr /* 速度变化 */ + ); + + ActionWalk( + Duration duration, /* 持续时长 */ + Geometry const& path, /* 路线 */ + bool rotating = false, /* 沿路线切线方向旋转 */ + float start = 0.f, /* 起点 */ + float end = 1.f, /* 终点 */ + EaseFunc func = nullptr /* 速度变化 */ + ); + + // 获取该动作的拷贝对象 + ActionPtr Clone() const override; + + // 获取该动作的倒转 + ActionPtr Reverse() const override; + + // 开始添加路线 + void BeginPath(); + + // 结束路线 + void EndPath( + bool closed = false /* 路线是否闭合 */ + ); + + // 添加一条线段 + void AddLine( + Point const& point /* 端点 */ + ); + + // 添加多条线段 + void AddLines( + Vector const& points + ); + + // 添加一条三次方贝塞尔曲线 + void AddBezier( + Point const& point1, /* 贝塞尔曲线的第一个控制点 */ + Point const& point2, /* 贝塞尔曲线的第二个控制点 */ + Point const& point3 /* 贝塞尔曲线的终点 */ + ); + + // 添加弧线 + void AddArc( + Point const& point, /* 终点 */ + Size const& radius, /* 椭圆半径 */ + float rotation, /* 椭圆旋转角度 */ + bool clockwise = true, /* 顺时针 or 逆时针 */ + bool is_small = true /* 是否取小于 180° 的弧 */ + ); + + // 清除路径 + void ClearPath(); + + // 获取路线 + inline Geometry GetPath() const { return path_; } + + // 设置路径 + inline void SetPath(Geometry path) { path_ = path; } + + protected: + void Init(ActorPtr target) override; + + void UpdateTween(ActorPtr target, float percent) override; + + protected: + bool rotating_; + float start_; + float end_; + float length_; + Point start_pos_; + Geometry path_; + GeometrySink sink_; + }; +} diff --git a/src/kiwano/2d/include-forwards.h b/src/kiwano/2d/include-forwards.h index 35f39f36..98f832e4 100644 --- a/src/kiwano/2d/include-forwards.h +++ b/src/kiwano/2d/include-forwards.h @@ -62,7 +62,7 @@ namespace kiwano KGE_DECLARE_SMART_PTR(ActionFadeOut); KGE_DECLARE_SMART_PTR(ActionRotateBy); KGE_DECLARE_SMART_PTR(ActionRotateTo); - KGE_DECLARE_SMART_PTR(ActionPath); + KGE_DECLARE_SMART_PTR(ActionWalk); KGE_DECLARE_SMART_PTR(Animation); KGE_DECLARE_SMART_PTR(ActionGroup); KGE_DECLARE_SMART_PTR(ActionSpawn); diff --git a/src/kiwano/kiwano.h b/src/kiwano/kiwano.h index 6a2d0c7a..76c05fd6 100644 --- a/src/kiwano/kiwano.h +++ b/src/kiwano/kiwano.h @@ -92,6 +92,8 @@ #include "2d/action/Action.h" #include "2d/action/ActionGroup.h" #include "2d/action/ActionTween.h" +#include "2d/action/ActionWalk.h" +#include "2d/action/ActionDelay.h" #include "2d/action/Animation.h" #include "2d/action/ActionHelper.h" #include "2d/action/ActionManager.h" diff --git a/src/kiwano/renderer/Geometry.cpp b/src/kiwano/renderer/Geometry.cpp new file mode 100644 index 00000000..2814ac8a --- /dev/null +++ b/src/kiwano/renderer/Geometry.cpp @@ -0,0 +1,203 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "Geometry.h" +#include "render.h" +#include "../base/logs.h" + +namespace kiwano +{ + + // + // Geometry + // + + Geometry::Geometry() + { + } + + Geometry::Geometry(ComPtr geo) + : geo_(geo) + { + } + + Rect Geometry::GetBoundingBox(Matrix const& transform) const + { + if (!geo_) + return Rect{}; + + D2D1_RECT_F rect; + // no matter it failed or not + geo_->GetBounds(DX::ConvertToMatrix3x2F(transform), &rect); + return Rect{ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top }; + } + + float Geometry::GetLength() + { + float length = 0.f; + if (geo_) + { + // no matter it failed or not + geo_->ComputeLength(D2D1::Matrix3x2F::Identity(), &length); + } + return length; + } + + bool Geometry::ComputePointAtLength(float length, Point& point, Vec2& tangent) + { + if (geo_) + { + HRESULT hr = geo_->ComputePointAtLength( + length, + D2D1::Matrix3x2F::Identity(), + DX::ConvertToPoint2F(&point), + DX::ConvertToPoint2F(&tangent) + ); + + return SUCCEEDED(hr); + } + return false; + } + + float Geometry::ComputeArea() + { + if (!geo_) + return 0.f; + + float area = 0.f; + // no matter it failed or not + geo_->ComputeArea(D2D1::Matrix3x2F::Identity(), &area); + return area; + } + + bool Geometry::ContainsPoint(Point const& point) + { + if (!geo_) + return false; + + BOOL ret = 0; + // no matter it failed or not + geo_->FillContainsPoint( + DX::ConvertToPoint2F(point), + D2D1::Matrix3x2F::Identity(), + &ret + ); + return !!ret; + } + + // + // GeometrySink + // + + GeometrySink::GeometrySink() + { + } + + GeometrySink& GeometrySink::BeginPath(Point const& begin_pos) + { + if (!path_geo_) + { + Renderer::GetInstance()->CreatePathGeometrySink(*this); + } + + if (!sink_) + { + ThrowIfFailed(path_geo_->Open(&sink_)); + } + + if (sink_) + { + sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); + } + return (*this); + } + + GeometrySink& GeometrySink::EndPath(bool closed) + { + if (sink_) + { + sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); + + ThrowIfFailed(sink_->Close()); + + sink_ = nullptr; + } + return (*this); + } + + GeometrySink& GeometrySink::AddLine(Point const& point) + { + if (!sink_) BeginPath(); + + sink_->AddLine(DX::ConvertToPoint2F(point)); + return (*this); + } + + GeometrySink& GeometrySink::AddLines(Vector const& points) + { + if (!sink_) BeginPath(); + + sink_->AddLines( + reinterpret_cast(&points[0]), + static_cast(points.size()) + ); + return (*this); + } + + GeometrySink& GeometrySink::AddBezier(Point const& point1, Point const& point2, Point const& point3) + { + if (!sink_) BeginPath(); + + sink_->AddBezier( + D2D1::BezierSegment( + DX::ConvertToPoint2F(point1), + DX::ConvertToPoint2F(point2), + DX::ConvertToPoint2F(point3) + ) + ); + return (*this); + } + + GeometrySink& GeometrySink::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small) + { + if (!sink_) BeginPath(); + + sink_->AddArc( + D2D1::ArcSegment( + DX::ConvertToPoint2F(point), + DX::ConvertToSizeF(radius), + rotation, + clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, + is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE + ) + ); + return (*this); + } + + Geometry GeometrySink::GetGeometry() + { + if (sink_) + { + EndPath(); + } + return Geometry(path_geo_); + } + +} diff --git a/src/kiwano/renderer/Geometry.h b/src/kiwano/renderer/Geometry.h new file mode 100644 index 00000000..0217dde9 --- /dev/null +++ b/src/kiwano/renderer/Geometry.h @@ -0,0 +1,126 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "../base/SmartPtr.hpp" +#include "D2DDeviceResources.h" + +namespace kiwano +{ + // 几何体 + class KGE_API Geometry + { + public: + // 获取外切包围盒 + Rect GetBoundingBox( + Matrix const& transform = Matrix() + ) const; + + // 判断图形是否包含点 + bool ContainsPoint( + Point const& point + ); + + // 获取图形展开成一条直线的长度 + float GetLength(); + + // 计算面积 + float ComputeArea(); + + // 计算图形路径上点的位置和切线向量 + bool ComputePointAtLength( + float length, + Point& point, + Vec2& tangent + ); + + public: + Geometry(); + + Geometry(ComPtr geo); + + public: + inline ComPtr GetGeometry() const { return geo_; } + + inline void SetGeometry(ComPtr geometry) { geo_ = geometry; } + + inline operator bool() const { return static_cast(geo_); } + + protected: + ComPtr geo_; + }; + + + // 几何体生成器 + class KGE_API GeometrySink + : protected noncopyable + { + public: + GeometrySink(); + + // 开始添加路径 + GeometrySink& BeginPath( + Point const& begin_pos = Point{} /* 起始点 */ + ); + + // 结束路径 + GeometrySink& EndPath( + bool closed = false /* 路径是否闭合 */ + ); + + // 添加一条线段 + GeometrySink& AddLine( + Point const& point /* 端点 */ + ); + + // 添加多条线段 + GeometrySink& AddLines( + Vector const& points + ); + + // 添加一条三次方贝塞尔曲线 + GeometrySink& AddBezier( + Point const& point1, /* 贝塞尔曲线的第一个控制点 */ + Point const& point2, /* 贝塞尔曲线的第二个控制点 */ + Point const& point3 /* 贝塞尔曲线的终点 */ + ); + + // 添加弧线 + GeometrySink& AddArc( + Point const& point, /* 终点 */ + Size const& radius, /* 椭圆半径 */ + float rotation, /* 椭圆旋转角度 */ + bool clockwise = true, /* 顺时针 or 逆时针 */ + bool is_small = true /* 是否取小于 180° 的弧 */ + ); + + // 获取生成路径几何体 + Geometry GetGeometry(); + + public: + inline ComPtr GetPathGeometry() const { return path_geo_; } + + inline void SetPathGeometry(ComPtr path) { path_geo_ = path; } + + protected: + ComPtr path_geo_; + ComPtr sink_; + }; +} diff --git a/src/kiwano/renderer/Image.h b/src/kiwano/renderer/Image.h index c3d6ee89..295d1e72 100644 --- a/src/kiwano/renderer/Image.h +++ b/src/kiwano/renderer/Image.h @@ -20,7 +20,7 @@ #pragma once #include "../base/Resource.h" -#include "render.h" // ID2D1Bitmap +#include "D2DDeviceResources.h" // ID2D1Bitmap namespace kiwano { diff --git a/src/kiwano/renderer/render.cpp b/src/kiwano/renderer/render.cpp index 984855d3..3829fb2c 100644 --- a/src/kiwano/renderer/render.cpp +++ b/src/kiwano/renderer/render.cpp @@ -132,13 +132,16 @@ namespace kiwano { HRESULT hr = S_OK; + solid_color_brush_.reset(); hr = device_context_->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White), + D2D1::BrushProperties(), &solid_color_brush_ ); if (SUCCEEDED(hr)) { + text_renderer_.reset(); hr = ITextRenderer::Create( &text_renderer_, device_context_.get() @@ -242,8 +245,144 @@ namespace kiwano ThrowIfFailed(hr); } + void Renderer::CreateLineGeometry(Geometry& geo, Point const& begin_pos, Point const& end_pos) + { + HRESULT hr = S_OK; + if (!device_context_ || !d2d_res_) + { + hr = E_UNEXPECTED; + } + + ComPtr path_geo; + ComPtr path_sink; + if (SUCCEEDED(hr)) + { + hr = d2d_res_->GetFactory()->CreatePathGeometry(&path_geo); + } + + if (SUCCEEDED(hr)) + { + hr = path_geo->Open(&path_sink); + } + + if (SUCCEEDED(hr)) + { + path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); + path_sink->AddLine(DX::ConvertToPoint2F(end_pos)); + path_sink->EndFigure(D2D1_FIGURE_END_OPEN); + hr = path_sink->Close(); + } + + if (SUCCEEDED(hr)) + { + geo.SetGeometry(path_geo); + } + + ThrowIfFailed(hr); + } + + void Renderer::CreateRectGeometry(Geometry& geo, Rect const& rect) + { + HRESULT hr = S_OK; + if (!device_context_ || !d2d_res_) + { + hr = E_UNEXPECTED; + } + + ComPtr output; + if (SUCCEEDED(hr)) + { + hr = d2d_res_->GetFactory()->CreateRectangleGeometry(DX::ConvertToRectF(rect), &output); + } + + if (SUCCEEDED(hr)) + { + geo.SetGeometry(output); + } + + ThrowIfFailed(hr); + } + + void Renderer::CreateRoundedRectGeometry(Geometry& geo, Rect const& rect, Vec2 const& radius) + { + HRESULT hr = S_OK; + if (!device_context_ || !d2d_res_) + { + hr = E_UNEXPECTED; + } + + ComPtr output; + if (SUCCEEDED(hr)) + { + hr = d2d_res_->GetFactory()->CreateRoundedRectangleGeometry( + D2D1::RoundedRect( + DX::ConvertToRectF(rect), + radius.x, + radius.y + ), + &output); + } + + if (SUCCEEDED(hr)) + { + geo.SetGeometry(output); + } + + ThrowIfFailed(hr); + } + + void Renderer::CreateEllipseGeometry(Geometry& geo, Point const& center, Vec2 const& radius) + { + HRESULT hr = S_OK; + if (!device_context_ || !d2d_res_) + { + hr = E_UNEXPECTED; + } + + ComPtr output; + if (SUCCEEDED(hr)) + { + hr = d2d_res_->GetFactory()->CreateEllipseGeometry( + D2D1::Ellipse( + DX::ConvertToPoint2F(center), + radius.x, + radius.y + ), + &output); + } + + if (SUCCEEDED(hr)) + { + geo.SetGeometry(output); + } + + ThrowIfFailed(hr); + } + + void Renderer::CreatePathGeometrySink(GeometrySink& sink) + { + HRESULT hr = S_OK; + if (!device_context_ || !d2d_res_) + { + hr = E_UNEXPECTED; + } + + ComPtr output; + if (SUCCEEDED(hr)) + { + hr = d2d_res_->GetFactory()->CreatePathGeometry(&output); + } + + if (SUCCEEDED(hr)) + { + sink.SetPathGeometry(output); + } + + ThrowIfFailed(hr); + } + void Renderer::DrawGeometry( - ComPtr const& geometry, + Geometry const& geometry, Color const& stroke_color, float stroke_width, StrokeStyle stroke @@ -255,12 +394,12 @@ namespace kiwano hr = E_UNEXPECTED; } - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && geometry.GetGeometry()) { solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color)); device_context_->DrawGeometry( - geometry.get(), + geometry.GetGeometry().get(), solid_color_brush_.get(), stroke_width, d2d_res_->GetStrokeStyle(stroke) @@ -272,7 +411,7 @@ namespace kiwano ThrowIfFailed(hr); } - void Renderer::FillGeometry(ComPtr const & geometry, Color const& fill_color) + void Renderer::FillGeometry(Geometry const & geometry, Color const& fill_color) { HRESULT hr = S_OK; if (!solid_color_brush_ || !device_context_) @@ -280,11 +419,11 @@ namespace kiwano hr = E_UNEXPECTED; } - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && geometry.GetGeometry()) { solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color)); device_context_->FillGeometry( - geometry.get(), + geometry.GetGeometry().get(), solid_color_brush_.get() ); } @@ -292,7 +431,7 @@ namespace kiwano ThrowIfFailed(hr); } - void Renderer::DrawRectangle(Rect const& rect, const Color& stroke_color, float stroke_width, StrokeStyle stroke) + void Renderer::DrawRectangle(Rect const& rect, Color const& stroke_color, float stroke_width, StrokeStyle stroke) { HRESULT hr = S_OK; if (!solid_color_brush_ || !device_context_) @@ -437,7 +576,7 @@ namespace kiwano D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1::Matrix3x2F::Identity(), properties.opacity, - solid_color_brush_.get(), + nullptr, D2D1_LAYER_OPTIONS_NONE ), layer.get() diff --git a/src/kiwano/renderer/render.h b/src/kiwano/renderer/render.h index c796a363..50c9373c 100644 --- a/src/kiwano/renderer/render.h +++ b/src/kiwano/renderer/render.h @@ -27,8 +27,8 @@ #include "../2d/TextStyle.hpp" #include "helper.hpp" #include "Image.h" +#include "Geometry.h" #include "TextRenderer.h" -#include "D2DDeviceResources.h" #if defined(KGE_USE_DIRECTX10) # include "D3D10DeviceResources.h" @@ -56,21 +56,48 @@ namespace kiwano ComPtr& layer ); + void CreateLineGeometry( + Geometry& geo, + Point const& begin_pos, + Point const& end_pos + ); + + void CreateRectGeometry( + Geometry& geo, + Rect const& rect + ); + + void CreateRoundedRectGeometry( + Geometry& geo, + Rect const& rect, + Vec2 const& radius + ); + + void CreateEllipseGeometry( + Geometry& geo, + Point const& center, + Vec2 const& radius + ); + + void CreatePathGeometrySink( + GeometrySink& sink + ); + void DrawGeometry( - ComPtr const& geometry, + Geometry const& geometry, const Color& stroke_color, float stroke_width, StrokeStyle stroke = StrokeStyle::Miter ); void FillGeometry( - ComPtr const& geometry, + Geometry const& geometry, Color const& fill_color ); void DrawRectangle( Rect const& rect, - const Color& stroke_color, + Color const& stroke_color, float stroke_width, StrokeStyle stroke = StrokeStyle::Miter );