Add Geometry && add GeometrySink && rename ActionPath to ActionWalk

This commit is contained in:
Nomango 2019-08-14 21:38:37 +08:00
parent 5327159e99
commit 671719fb34
19 changed files with 968 additions and 700 deletions

View File

@ -2,9 +2,11 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="..\src\kiwano\2d\action\Action.h" />
<ClInclude Include="..\src\kiwano\2d\action\ActionDelay.h" />
<ClInclude Include="..\src\kiwano\2d\action\ActionGroup.h" />
<ClInclude Include="..\src\kiwano\2d\action\ActionHelper.h" />
<ClInclude Include="..\src\kiwano\2d\action\ActionManager.h" />
<ClInclude Include="..\src\kiwano\2d\action\ActionWalk.h" />
<ClInclude Include="..\src\kiwano\2d\action\ActionTween.h" />
<ClInclude Include="..\src\kiwano\2d\action\Animation.h" />
<ClInclude Include="..\src\kiwano\2d\Frame.h" />
@ -69,6 +71,7 @@
<ClInclude Include="..\src\kiwano\renderer\D3D10DeviceResources.h" />
<ClInclude Include="..\src\kiwano\renderer\D3D11DeviceResources.h" />
<ClInclude Include="..\src\kiwano\renderer\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\src\kiwano\renderer\Geometry.h" />
<ClInclude Include="..\src\kiwano\renderer\GifImage.h" />
<ClInclude Include="..\src\kiwano\renderer\helper.hpp" />
<ClInclude Include="..\src\kiwano\renderer\Image.h" />
@ -86,8 +89,10 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\kiwano\2d\action\Action.cpp" />
<ClCompile Include="..\src\kiwano\2d\action\ActionDelay.cpp" />
<ClCompile Include="..\src\kiwano\2d\action\ActionGroup.cpp" />
<ClCompile Include="..\src\kiwano\2d\action\ActionManager.cpp" />
<ClCompile Include="..\src\kiwano\2d\action\ActionWalk.cpp" />
<ClCompile Include="..\src\kiwano\2d\action\ActionTween.cpp" />
<ClCompile Include="..\src\kiwano\2d\action\Animation.cpp" />
<ClCompile Include="..\src\kiwano\2d\Canvas.cpp" />
@ -120,6 +125,7 @@
<ClCompile Include="..\src\kiwano\renderer\D2DDeviceResources.cpp" />
<ClCompile Include="..\src\kiwano\renderer\D3D10DeviceResources.cpp" />
<ClCompile Include="..\src\kiwano\renderer\D3D11DeviceResources.cpp" />
<ClCompile Include="..\src\kiwano\renderer\Geometry.cpp" />
<ClCompile Include="..\src\kiwano\renderer\GifImage.cpp" />
<ClCompile Include="..\src\kiwano\renderer\Image.cpp" />
<ClCompile Include="..\src\kiwano\renderer\ImageCache.cpp" />

View File

@ -279,6 +279,15 @@
<ClInclude Include="..\src\kiwano\2d\ShapeActor.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\src\kiwano\renderer\Geometry.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\src\kiwano\2d\action\ActionDelay.h">
<Filter>2d\action</Filter>
</ClInclude>
<ClInclude Include="..\src\kiwano\2d\action\ActionWalk.h">
<Filter>2d\action</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\kiwano\ui\Button.cpp">
@ -425,5 +434,14 @@
<ClCompile Include="..\src\kiwano\2d\ShapeActor.cpp">
<Filter>2d</Filter>
</ClCompile>
<ClCompile Include="..\src\kiwano\renderer\Geometry.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\src\kiwano\2d\action\ActionDelay.cpp">
<Filter>2d\action</Filter>
</ClCompile>
<ClCompile Include="..\src\kiwano\2d\action\ActionWalk.cpp">
<Filter>2d\action</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -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<ID2D1Geometry> 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<ID2D1PathGeometry> path_geo;
ComPtr<ID2D1GeometrySink> 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<ID2D1RectangleGeometry> 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<ID2D1RoundedRectangleGeometry> 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)
if (geo_)
{
SetCircle(center, radius_);
}
void CircleActor::SetCircle(Point const& center, float radius)
{
ComPtr<ID2D1EllipseGeometry> geo;
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory();
if (SUCCEEDED(factory->CreateEllipseGeometry(
D2D1::Ellipse(
DX::ConvertToPoint2F(center),
radius,
radius),
&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)
if (geo_)
{
SetEllipse(center, radius_x_, radius_y_);
}
void EllipseActor::SetEllipse(Point const& center, float radius_x, float radius_y)
{
ComPtr<ID2D1EllipseGeometry> geo;
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory();
if (SUCCEEDED(factory->CreateEllipseGeometry(
D2D1::Ellipse(
DX::ConvertToPoint2F(center),
radius_x,
radius_y),
&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(&current_geometry_)
);
ThrowIfFailed(
current_geometry_->Open(&current_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<Point> const& points)
{
if (current_sink_ && !points.empty())
{
current_sink_->AddLines(
reinterpret_cast<const D2D_POINT_2F*>(&points[0]),
static_cast<UINT32>(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);
}
}

View File

@ -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<ID2D1Geometry> 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
);
// <20>零輕념奈<EB8590>
void SetFillColor(
const Color& color
@ -94,10 +76,10 @@ namespace kiwano
);
// <20>零近榴
inline void SetGeometry(ComPtr<ID2D1Geometry> geometry) { geo_ = geometry; }
inline void SetGeometry(Geometry geometry) { geo_ = geometry; }
// 삿혤近榴
inline ComPtr<ID2D1Geometry> GetGeometry() const { return geo_; }
inline Geometry GetGeometry() const { return geo_; }
void OnRender(Renderer* renderer) override;
@ -106,7 +88,7 @@ namespace kiwano
Color stroke_color_;
float stroke_width_;
StrokeStyle outline_join_;
ComPtr<ID2D1Geometry> geo_;
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<ID2D1PathGeometry> current_geometry_;
ComPtr<ID2D1GeometrySink> current_sink_;
GeometrySink sink_;
};
}

View File

@ -88,6 +88,7 @@ namespace kiwano
if (frame_ && renderer->CheckVisibility(size_, transform_matrix_))
{
PrepareRender(renderer);
renderer->DrawBitmap(frame_->GetImage()->GetBitmap(), frame_->GetCropRect(), GetBounds());
}
}

View File

@ -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_);
}
}

View File

@ -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;
};
}

View File

@ -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)
{

View File

@ -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<Point> const& points)
{
if (!path_beginning_)
{
BeginPath();
}
if (geo_sink_ && !points.empty())
{
geo_sink_->AddLines(
reinterpret_cast<const D2D_POINT_2F*>(&points[0]),
static_cast<UINT32>(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_);
}
}

View File

@ -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<Point> 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<ID2D1PathGeometry> GetGeometry() const { return geo_; }
// 设置几何路径
inline void SetGeometry(ComPtr<ID2D1PathGeometry> 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<ID2D1PathGeometry> geo_;
ComPtr<ID2D1GeometrySink> 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;
};
}

View File

@ -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<Point> 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);
}
}

View File

@ -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<Point> 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_;
};
}

View File

@ -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);

View File

@ -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"

View File

@ -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<ID2D1Geometry> 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<Point> const& points)
{
if (!sink_) BeginPath();
sink_->AddLines(
reinterpret_cast<const D2D_POINT_2F*>(&points[0]),
static_cast<UINT32>(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_);
}
}

View File

@ -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<ID2D1Geometry> geo);
public:
inline ComPtr<ID2D1Geometry> GetGeometry() const { return geo_; }
inline void SetGeometry(ComPtr<ID2D1Geometry> geometry) { geo_ = geometry; }
inline operator bool() const { return static_cast<bool>(geo_); }
protected:
ComPtr<ID2D1Geometry> 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<Point> 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<ID2D1PathGeometry> GetPathGeometry() const { return path_geo_; }
inline void SetPathGeometry(ComPtr<ID2D1PathGeometry> path) { path_geo_ = path; }
protected:
ComPtr<ID2D1PathGeometry> path_geo_;
ComPtr<ID2D1GeometrySink> sink_;
};
}

View File

@ -20,7 +20,7 @@
#pragma once
#include "../base/Resource.h"
#include "render.h" // ID2D1Bitmap
#include "D2DDeviceResources.h" // ID2D1Bitmap
namespace kiwano
{

View File

@ -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<ID2D1PathGeometry> path_geo;
ComPtr<ID2D1GeometrySink> 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<ID2D1RectangleGeometry> 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<ID2D1RoundedRectangleGeometry> 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<ID2D1EllipseGeometry> 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<ID2D1PathGeometry> output;
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetFactory()->CreatePathGeometry(&output);
}
if (SUCCEEDED(hr))
{
sink.SetPathGeometry(output);
}
ThrowIfFailed(hr);
}
void Renderer::DrawGeometry(
ComPtr<ID2D1Geometry> 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<ID2D1Geometry> 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()

View File

@ -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<ID2D1Layer>& 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<ID2D1Geometry> const& geometry,
Geometry const& geometry,
const Color& stroke_color,
float stroke_width,
StrokeStyle stroke = StrokeStyle::Miter
);
void FillGeometry(
ComPtr<ID2D1Geometry> 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
);