Add NativeObject & NativePtr

This commit is contained in:
Nomango 2020-02-16 20:14:01 +08:00
parent 1cb97ba0b2
commit 14df3ae55e
44 changed files with 1037 additions and 1095 deletions

View File

@ -78,13 +78,15 @@
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\NativePtr.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\RendererImpl.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\RendererImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\Font.h" /> <ClInclude Include="..\..\src\kiwano\render\Font.h" />
<ClInclude Include="..\..\src\kiwano\render\NativeObject.h" />
<ClInclude Include="..\..\src\kiwano\render\Shape.h" /> <ClInclude Include="..\..\src\kiwano\render\Shape.h" />
<ClInclude Include="..\..\src\kiwano\render\ShapeSink.h" /> <ClInclude Include="..\..\src\kiwano\render\ShapeMaker.h" />
<ClInclude Include="..\..\src\kiwano\render\GifImage.h" /> <ClInclude Include="..\..\src\kiwano\render\GifImage.h" />
<ClInclude Include="..\..\src\kiwano\render\Layer.h" /> <ClInclude Include="..\..\src\kiwano\render\Layer.h" />
<ClInclude Include="..\..\src\kiwano\render\RenderContext.h" /> <ClInclude Include="..\..\src\kiwano\render\RenderContext.h" />
@ -158,7 +160,7 @@
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.cpp" /> <ClCompile Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Font.cpp" /> <ClCompile Include="..\..\src\kiwano\render\Font.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Shape.cpp" /> <ClCompile Include="..\..\src\kiwano\render\Shape.cpp" />
<ClCompile Include="..\..\src\kiwano\render\ShapeSink.cpp" /> <ClCompile Include="..\..\src\kiwano\render\ShapeMaker.cpp" />
<ClCompile Include="..\..\src\kiwano\render\GifImage.cpp" /> <ClCompile Include="..\..\src\kiwano\render\GifImage.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Layer.cpp" /> <ClCompile Include="..\..\src\kiwano\render\Layer.cpp" />
<ClCompile Include="..\..\src\kiwano\render\RenderContext.cpp" /> <ClCompile Include="..\..\src\kiwano\render\RenderContext.cpp" />

View File

@ -252,9 +252,6 @@
<ClInclude Include="..\..\src\kiwano\render\Shape.h"> <ClInclude Include="..\..\src\kiwano\render\Shape.h">
<Filter>render</Filter> <Filter>render</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\kiwano\render\ShapeSink.h">
<Filter>render</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\math\Transform.hpp"> <ClInclude Include="..\..\src\kiwano\math\Transform.hpp">
<Filter>math</Filter> <Filter>math</Filter>
</ClInclude> </ClInclude>
@ -318,6 +315,15 @@
<ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h"> <ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h">
<Filter>core</Filter> <Filter>core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\kiwano\render\NativeObject.h">
<Filter>render</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\DirectX\NativePtr.h">
<Filter>render\DirectX</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\ShapeMaker.h">
<Filter>render</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
@ -500,9 +506,6 @@
<ClCompile Include="..\..\src\kiwano\render\Shape.cpp"> <ClCompile Include="..\..\src\kiwano\render\Shape.cpp">
<Filter>render</Filter> <Filter>render</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\kiwano\render\ShapeSink.cpp">
<Filter>render</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\TextureRenderContext.cpp"> <ClCompile Include="..\..\src\kiwano\render\TextureRenderContext.cpp">
<Filter>render</Filter> <Filter>render</Filter>
</ClCompile> </ClCompile>
@ -533,5 +536,8 @@
<ClCompile Include="..\..\src\kiwano\core\String.cpp"> <ClCompile Include="..\..\src\kiwano\core\String.cpp">
<Filter>core</Filter> <Filter>core</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\kiwano\render\ShapeMaker.cpp">
<Filter>render</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -154,7 +154,7 @@ void Actor::RenderBorder(RenderContext& ctx)
ctx.FillRectangle(bounds); ctx.FillRectangle(bounds);
ctx.SetCurrentBrush(GetStage()->GetBorderStrokeBrush()); ctx.SetCurrentBrush(GetStage()->GetBorderStrokeBrush());
ctx.DrawRectangle(bounds, nullptr, 2.f); ctx.DrawRectangle(bounds);
} }
for (auto& child : children_) for (auto& child : children_)

View File

@ -48,8 +48,6 @@ CanvasPtr Canvas::Create(Size const& size)
Canvas::Canvas() Canvas::Canvas()
: cache_expired_(false) : cache_expired_(false)
, stroke_width_(1.0f)
, stroke_style_()
{ {
} }
@ -95,10 +93,13 @@ void Canvas::SetBrushTransform(Matrix3x2 const& transform)
ctx_->SetTransform(transform); ctx_->SetTransform(transform);
} }
void Canvas::PushLayer(Layer& layer) void Canvas::PushLayer(LayerPtr layer)
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->PushLayer(layer); if (layer)
{
ctx_->PushLayer(*layer);
}
} }
void Canvas::PopLayer() void Canvas::PopLayer()
@ -125,7 +126,8 @@ void Canvas::DrawShape(ShapePtr shape)
if (shape) if (shape)
{ {
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawShape(*shape, stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawShape(*shape);
cache_expired_ = true; cache_expired_ = true;
} }
} }
@ -134,7 +136,8 @@ void Canvas::DrawLine(Point const& begin, Point const& end)
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawLine(begin, end, stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawLine(begin, end);
cache_expired_ = true; cache_expired_ = true;
} }
@ -142,7 +145,8 @@ void Canvas::DrawCircle(Point const& center, float radius)
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawEllipse(center, Vec2(radius, radius), stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawEllipse(center, Vec2(radius, radius));
cache_expired_ = true; cache_expired_ = true;
} }
@ -150,7 +154,8 @@ void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawEllipse(center, radius, stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawEllipse(center, radius);
cache_expired_ = true; cache_expired_ = true;
} }
@ -158,7 +163,8 @@ void Canvas::DrawRect(Rect const& rect)
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawRectangle(rect, stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawRectangle(rect);
cache_expired_ = true; cache_expired_ = true;
} }
@ -166,7 +172,8 @@ void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawRoundedRectangle(rect, radius, stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawRoundedRectangle(rect, radius);
cache_expired_ = true; cache_expired_ = true;
} }
@ -243,39 +250,40 @@ void Canvas::DrawTextLayout(TextLayoutPtr layout, Point const& point)
void Canvas::BeginPath(Point const& begin_pos) void Canvas::BeginPath(Point const& begin_pos)
{ {
shape_sink_.BeginPath(begin_pos); shape_maker_.BeginPath(begin_pos);
} }
void Canvas::EndPath(bool closed) void Canvas::EndPath(bool closed)
{ {
shape_sink_.EndPath(closed); shape_maker_.EndPath(closed);
} }
void Canvas::AddLine(Point const& point) void Canvas::AddLine(Point const& point)
{ {
shape_sink_.AddLine(point); shape_maker_.AddLine(point);
} }
void Canvas::AddLines(Vector<Point> const& points) void Canvas::AddLines(Vector<Point> const& points)
{ {
shape_sink_.AddLines(points); shape_maker_.AddLines(points);
} }
void Canvas::AddBezier(Point const& point1, Point const& point2, Point const& point3) void Canvas::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{ {
shape_sink_.AddBezier(point1, point2, point3); shape_maker_.AddBezier(point1, point2, point3);
} }
void Canvas::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small) void Canvas::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{ {
shape_sink_.AddArc(point, radius, rotation, clockwise, is_small); shape_maker_.AddArc(point, radius, rotation, clockwise, is_small);
} }
void Canvas::StrokePath() void Canvas::StrokePath()
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(stroke_brush_); ctx_->SetCurrentBrush(stroke_brush_);
ctx_->DrawShape(*shape_sink_.GetShape(), stroke_style_, stroke_width_); ctx_->SetCurrentStrokeStyle(stroke_style_);
ctx_->DrawShape(*shape_maker_.GetShape());
cache_expired_ = true; cache_expired_ = true;
} }
@ -283,7 +291,7 @@ void Canvas::FillPath()
{ {
KGE_ASSERT(ctx_); KGE_ASSERT(ctx_);
ctx_->SetCurrentBrush(fill_brush_); ctx_->SetCurrentBrush(fill_brush_);
ctx_->FillShape(*shape_sink_.GetShape()); ctx_->FillShape(*shape_maker_.GetShape());
cache_expired_ = true; cache_expired_ = true;
} }

View File

@ -20,7 +20,7 @@
#pragma once #pragma once
#include <kiwano/2d/Actor.h> #include <kiwano/2d/Actor.h>
#include <kiwano/render/ShapeSink.h> #include <kiwano/render/ShapeMaker.h>
#include <kiwano/render/TextureRenderContext.h> #include <kiwano/render/TextureRenderContext.h>
namespace kiwano namespace kiwano
@ -209,11 +209,6 @@ public:
/// @param[in] brush 轮廓画刷 /// @param[in] brush 轮廓画刷
void SetStrokeBrush(BrushPtr brush); void SetStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置轮廓宽度
/// @param width 轮廓宽度
void SetStrokeWidth(float width);
/// \~chinese /// \~chinese
/// @brief 设置轮廓样式 /// @brief 设置轮廓样式
/// @param stroke_style 轮廓样式 /// @param stroke_style 轮廓样式
@ -237,7 +232,7 @@ public:
/// \~chinese /// \~chinese
/// @brief 添加一个图层 /// @brief 添加一个图层
/// @param layer 图层 /// @param layer 图层
void PushLayer(Layer& layer); void PushLayer(LayerPtr layer);
/// \~chinese /// \~chinese
/// @brief 删除最近添加的图层 /// @brief 删除最近添加的图层
@ -252,10 +247,6 @@ public:
/// @brief 删除最近添加的裁剪区域 /// @brief 删除最近添加的裁剪区域
void PopClipRect(); void PopClipRect();
/// \~chinese
/// @brief 获取轮廓宽度
float GetStrokeWidth() const;
/// \~chinese /// \~chinese
/// @brief 获取填充画刷 /// @brief 获取填充画刷
BrushPtr GetFillBrush() const; BrushPtr GetFillBrush() const;
@ -280,9 +271,8 @@ private:
void UpdateCache() const; void UpdateCache() const;
private: private:
float stroke_width_;
StrokeStylePtr stroke_style_; StrokeStylePtr stroke_style_;
ShapeSink shape_sink_; ShapeMaker shape_maker_;
BrushPtr fill_brush_; BrushPtr fill_brush_;
BrushPtr stroke_brush_; BrushPtr stroke_brush_;
@ -293,16 +283,6 @@ private:
/** @} */ /** @} */
inline float Canvas::GetStrokeWidth() const
{
return stroke_width_;
}
inline void Canvas::SetStrokeWidth(float width)
{
stroke_width_ = std::max(width, 0.f);
}
inline void Canvas::SetStrokeStyle(StrokeStylePtr stroke_style) inline void Canvas::SetStrokeStyle(StrokeStylePtr stroke_style)
{ {
stroke_style_ = stroke_style; stroke_style_ = stroke_style;

View File

@ -40,8 +40,14 @@ LayerActor::~LayerActor() {}
void LayerActor::SetOpacity(float opacity) void LayerActor::SetOpacity(float opacity)
{ {
// Actor::SetOpacity(opacity); if (layer_)
layer_.SetOpacity(opacity); {
layer_->SetOpacity(opacity);
}
else
{
Actor::SetOpacity(opacity);
}
} }
bool LayerActor::DispatchEvent(Event* evt) bool LayerActor::DispatchEvent(Event* evt)
@ -58,11 +64,16 @@ bool LayerActor::DispatchEvent(Event* evt)
void LayerActor::Render(RenderContext& ctx) void LayerActor::Render(RenderContext& ctx)
{ {
ctx.PushLayer(layer_); if (layer_)
{
Actor::Render(ctx); ctx.PushLayer(*layer_);
Actor::Render(ctx);
ctx.PopLayer(); ctx.PopLayer();
}
else
{
Actor::Render(ctx);
}
} }
bool LayerActor::CheckVisibility(RenderContext& ctx) const bool LayerActor::CheckVisibility(RenderContext& ctx) const

View File

@ -52,17 +52,13 @@ public:
bool IsSwallowEventsEnabled() const; bool IsSwallowEventsEnabled() const;
/// \~chinese /// \~chinese
/// @brief 获取图层区域 /// @brief 获取图层
Layer const& GetLayer() const; LayerPtr GetLayer() const;
/// \~chinese
/// @brief 获取图层区域
Layer& GetLayer();
/// \~chinese /// \~chinese
/// @brief 设置图层 /// @brief 设置图层
/// @param layer 图层 /// @param layer 图层
void SetLayer(Layer const& layer); void SetLayer(LayerPtr layer);
/// \~chinese /// \~chinese
/// @brief 设置消息吞没功能 /// @brief 设置消息吞没功能
@ -82,8 +78,8 @@ protected:
bool CheckVisibility(RenderContext& ctx) const override; bool CheckVisibility(RenderContext& ctx) const override;
private: private:
bool swallow_; bool swallow_;
Layer layer_; LayerPtr layer_;
}; };
/** @} */ /** @} */
@ -98,17 +94,12 @@ inline void LayerActor::SetSwallowEvents(bool enabled)
swallow_ = enabled; swallow_ = enabled;
} }
inline void LayerActor::SetLayer(Layer const& layer) inline void LayerActor::SetLayer(LayerPtr layer)
{ {
layer_ = layer; layer_ = layer;
} }
inline Layer const& LayerActor::GetLayer() const inline LayerPtr LayerActor::GetLayer() const
{
return layer_;
}
inline Layer& LayerActor::GetLayer()
{ {
return layer_; return layer_;
} }

View File

@ -58,8 +58,6 @@ ShapeActorPtr ShapeActor::Create(ShapePtr shape, BrushPtr fill_brush, BrushPtr s
} }
ShapeActor::ShapeActor() ShapeActor::ShapeActor()
: stroke_width_(1.f)
, stroke_style_()
{ {
} }
@ -108,7 +106,8 @@ void ShapeActor::OnRender(RenderContext& ctx)
if (stroke_brush_) if (stroke_brush_)
{ {
ctx.SetCurrentBrush(stroke_brush_); ctx.SetCurrentBrush(stroke_brush_);
ctx.DrawShape(*shape_, stroke_style_, stroke_width_ * 2 /* twice width for widening */); ctx.SetCurrentStrokeStyle(stroke_style_);
ctx.DrawShape(*shape_);
} }
if (fill_brush_) if (fill_brush_)
@ -296,7 +295,12 @@ void PolygonActor::SetVertices(Vector<Point> const& points)
{ {
if (points.size() > 1) if (points.size() > 1)
{ {
SetShape(ShapeSink().BeginPath(points[0]).AddLines(&points[1], points.size() - 1).EndPath(true).GetShape()); ShapeMakerPtr maker = ShapeMaker::Create();
maker->BeginPath(points[0]);
maker->AddLines(&points[1], points.size() - 1);
maker->EndPath(true);
SetShape(maker->GetShape());
} }
} }

View File

@ -22,7 +22,7 @@
#include <kiwano/2d/Actor.h> #include <kiwano/2d/Actor.h>
#include <kiwano/render/Brush.h> #include <kiwano/render/Brush.h>
#include <kiwano/render/Shape.h> #include <kiwano/render/Shape.h>
#include <kiwano/render/ShapeSink.h> #include <kiwano/render/ShapeMaker.h>
#include <kiwano/render/StrokeStyle.h> #include <kiwano/render/StrokeStyle.h>
namespace kiwano namespace kiwano
@ -81,10 +81,6 @@ public:
/// @brief 获取轮廓画刷 /// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const; BrushPtr GetStrokeBrush() const;
/// \~chinese
/// @brief 获取线条宽度
float GetStrokeWidth() const;
/// \~chinese /// \~chinese
/// @brief 获取线条样式 /// @brief 获取线条样式
StrokeStylePtr GetStrokeStyle() const; StrokeStylePtr GetStrokeStyle() const;
@ -125,10 +121,6 @@ public:
/// @param[in] brush 轮廓画刷 /// @param[in] brush 轮廓画刷
void SetStrokeBrush(BrushPtr brush); void SetStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置线条宽度,默认为 1.0
void SetStrokeWidth(float width);
/// \~chinese /// \~chinese
/// @brief 设置线条样式 /// @brief 设置线条样式
void SetStrokeStyle(StrokeStylePtr stroke_style); void SetStrokeStyle(StrokeStylePtr stroke_style);
@ -145,7 +137,6 @@ protected:
private: private:
BrushPtr fill_brush_; BrushPtr fill_brush_;
BrushPtr stroke_brush_; BrushPtr stroke_brush_;
float stroke_width_;
StrokeStylePtr stroke_style_; StrokeStylePtr stroke_style_;
Rect bounds_; Rect bounds_;
ShapePtr shape_; ShapePtr shape_;
@ -381,11 +372,6 @@ inline BrushPtr ShapeActor::GetStrokeBrush() const
return stroke_brush_; return stroke_brush_;
} }
inline float ShapeActor::GetStrokeWidth() const
{
return stroke_width_;
}
inline StrokeStylePtr ShapeActor::GetStrokeStyle() const inline StrokeStylePtr ShapeActor::GetStrokeStyle() const
{ {
return stroke_style_; return stroke_style_;
@ -396,11 +382,6 @@ inline ShapePtr ShapeActor::GetShape() const
return shape_; return shape_;
} }
inline void ShapeActor::SetStrokeWidth(float width)
{
stroke_width_ = std::max(width, 0.f);
}
inline void ShapeActor::SetStrokeStyle(StrokeStylePtr stroke_style) inline void ShapeActor::SetStrokeStyle(StrokeStylePtr stroke_style)
{ {
stroke_style_ = stroke_style; stroke_style_ = stroke_style;

View File

@ -285,15 +285,6 @@ void TextActor::SetOutlineBrush(BrushPtr brush)
} }
} }
void TextActor::SetOutlineWidth(float outline_width)
{
if (style_.outline_width != outline_width)
{
style_.outline_width = outline_width;
layout_->SetDefaultOutlineWidth(outline_width);
}
}
void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke) void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke)
{ {
if (style_.outline_stroke != stroke) if (style_.outline_stroke != stroke)

View File

@ -146,10 +146,6 @@ public:
/// @brief 设置描边线条样式 /// @brief 设置描边线条样式
void SetOutlineStrokeStyle(StrokeStylePtr stroke); void SetOutlineStrokeStyle(StrokeStylePtr stroke);
/// \~chinese
/// @brief 设置文字描边线宽
void SetOutlineWidth(float outline_width);
/// \~chinese /// \~chinese
/// @brief 设置是否显示下划线(默认值为 false /// @brief 设置是否显示下划线(默认值为 false
void SetUnderline(bool enable); void SetUnderline(bool enable);

View File

@ -21,7 +21,7 @@
#pragma once #pragma once
#include <kiwano/2d/action/ActionTween.h> #include <kiwano/2d/action/ActionTween.h>
#include <kiwano/render/Shape.h> #include <kiwano/render/Shape.h>
#include <kiwano/render/ShapeSink.h> #include <kiwano/render/ShapeMaker.h>
namespace kiwano namespace kiwano
{ {

View File

@ -33,7 +33,7 @@ namespace kiwano
*/ */
struct DefaultSmartPtrRefProxy struct DefaultSmartPtrRefProxy
{ {
static inline void AddRef(RefCounter* ptr) static inline void Retain(RefCounter* ptr)
{ {
if (ptr) if (ptr)
ptr->Retain(); ptr->Retain();
@ -73,13 +73,13 @@ public:
SmartPtr(pointer_type p) SmartPtr(pointer_type p)
: ptr_(p) : ptr_(p)
{ {
typename _ProxyTy::AddRef(ptr_); typename _ProxyTy::Retain(ptr_);
} }
SmartPtr(const SmartPtr& other) SmartPtr(const SmartPtr& other)
: ptr_(other.ptr_) : ptr_(other.ptr_)
{ {
typename _ProxyTy::AddRef(ptr_); typename _ProxyTy::Retain(ptr_);
} }
SmartPtr(SmartPtr&& other) noexcept SmartPtr(SmartPtr&& other) noexcept
@ -97,7 +97,7 @@ public:
SmartPtr(const SmartPtr<_UTy, _ProxyTy>& other) SmartPtr(const SmartPtr<_UTy, _ProxyTy>& other)
{ {
ptr_ = const_cast<pointer_type>(dynamic_cast<const_pointer_type>(other.Get())); ptr_ = const_cast<pointer_type>(dynamic_cast<const_pointer_type>(other.Get()));
typename _ProxyTy::AddRef(ptr_); typename _ProxyTy::Retain(ptr_);
} }
inline pointer_type Get() noexcept inline pointer_type Get() noexcept

View File

@ -67,7 +67,7 @@
#include <kiwano/render/Color.h> #include <kiwano/render/Color.h>
#include <kiwano/render/Font.h> #include <kiwano/render/Font.h>
#include <kiwano/render/Shape.h> #include <kiwano/render/Shape.h>
#include <kiwano/render/ShapeSink.h> #include <kiwano/render/ShapeMaker.h>
#include <kiwano/render/Texture.h> #include <kiwano/render/Texture.h>
#include <kiwano/render/GifImage.h> #include <kiwano/render/GifImage.h>
#include <kiwano/render/Layer.h> #include <kiwano/render/Layer.h>

View File

@ -28,7 +28,7 @@ namespace kiwano
{ {
struct ComPtrProxy struct ComPtrProxy
{ {
static inline void AddRef(IUnknown* ptr) static inline void Retain(IUnknown* ptr)
{ {
if (ptr) if (ptr)
ptr->AddRef(); ptr->AddRef();

View File

@ -93,16 +93,19 @@ Brush::Brush()
void Brush::SetColor(Color const& color) void Brush::SetColor(Color const& color)
{ {
Renderer::GetInstance().CreateBrush(*this, color); Renderer::GetInstance().CreateBrush(*this, color);
type_ = Brush::Type::SolidColor;
} }
void Brush::SetStyle(LinearGradientStyle const& style) void Brush::SetStyle(LinearGradientStyle const& style)
{ {
Renderer::GetInstance().CreateBrush(*this, style); Renderer::GetInstance().CreateBrush(*this, style);
type_ = Brush::Type::LinearGradient;
} }
void Brush::SetStyle(RadialGradientStyle const& style) void Brush::SetStyle(RadialGradientStyle const& style)
{ {
Renderer::GetInstance().CreateBrush(*this, style); Renderer::GetInstance().CreateBrush(*this, style);
type_ = Brush::Type::RadialGradient;
} }
} // namespace kiwano } // namespace kiwano

View File

@ -19,8 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/core/ObjectBase.h> #include <kiwano/render/NativeObject.h>
#include <kiwano/render/DirectX/D2DDeviceResources.h>
namespace kiwano namespace kiwano
{ {
@ -85,7 +84,7 @@ struct RadialGradientStyle
* \~chinese * \~chinese
* @brief * @brief
*/ */
class KGE_API Brush : public virtual ObjectBase class KGE_API Brush : public NativeObject
{ {
public: public:
/// \~chinese /// \~chinese
@ -105,10 +104,6 @@ public:
Brush(); Brush();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 设置纯色画刷颜色 /// @brief 设置纯色画刷颜色
void SetColor(Color const& color); void SetColor(Color const& color);
@ -138,16 +133,6 @@ public:
private: private:
Type type_; Type type_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
void SetBrush(ComPtr<ID2D1Brush> brush, Type type);
ComPtr<ID2D1Brush> GetBrush() const;
private:
ComPtr<ID2D1Brush> raw_;
#endif
}; };
/** @} */ /** @} */
@ -157,26 +142,4 @@ inline Brush::Type Brush::GetType() const
return type_; return type_;
} }
inline bool Brush::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return raw_ != nullptr;
#else
return false; // not supported
#endif
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline void Brush::SetBrush(ComPtr<ID2D1Brush> brush, Type type)
{
type_ = type;
raw_ = brush;
}
inline ComPtr<ID2D1Brush> Brush::GetBrush() const
{
return raw_;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -0,0 +1,79 @@
// 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 <kiwano/render/NativeObject.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <unknwn.h>
namespace kiwano
{
class KGE_API NativePtr
{
public:
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
static inline ComPtr<_Ty> Get(const NativeObject* object)
{
if (object)
{
ComPtr<IUnknown> ptr = object->GetNativePointer<ComPtr<IUnknown>>();
if (ptr)
{
ComPtr<_Ty> native;
if (SUCCEEDED(ptr->QueryInterface<_Ty>(&native)))
return native;
}
}
return nullptr;
}
template <typename _Ty>
static inline ComPtr<_Ty> Get(const NativeObject& object)
{
return NativePtr::Get<_Ty>(&object);
}
template <typename _Ty>
static inline ComPtr<_Ty> Get(NativeObjectPtr object)
{
return NativePtr::Get<_Ty>(object.Get());
}
static inline void Set(NativeObject* object, ComPtr<IUnknown> com_ptr)
{
if (object)
{
object->SetNativePointer(com_ptr);
}
}
static inline void Set(NativeObject& object, ComPtr<IUnknown> com_ptr)
{
NativePtr::Set(&object, com_ptr);
}
static inline void Set(NativeObjectPtr object, ComPtr<IUnknown> com_ptr)
{
NativePtr::Set(object.Get(), com_ptr);
}
};
} // namespace kiwano

View File

@ -18,14 +18,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <kiwano/render/DirectX/RenderContextImpl.h> #include <kiwano/render/DirectX/RenderContextImpl.h>
#include <kiwano/render/DirectX/NativePtr.h>
#include <kiwano/core/Logger.h>
namespace kiwano namespace kiwano
{ {
RenderContextImpl::RenderContextImpl() RenderContextImpl::RenderContextImpl() {}
{}
RenderContextImpl::~RenderContextImpl() RenderContextImpl::~RenderContextImpl()
{ {
@ -99,12 +99,19 @@ void RenderContextImpl::DrawTexture(Texture const& texture, const Rect* src_rect
if (texture.IsValid()) if (texture.IsValid())
{ {
auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear) D2D1_BITMAP_INTERPOLATION_MODE mode;
? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR if (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
: D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; {
mode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
}
else
{
mode = D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
}
render_target_->DrawBitmap(texture.GetBitmap().Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, auto bitmap = NativePtr::Get<ID2D1Bitmap>(texture);
brush_opacity_, mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr); render_target_->DrawBitmap(bitmap.Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, brush_opacity_,
mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
@ -116,30 +123,28 @@ void RenderContextImpl::DrawTextLayout(TextLayout const& layout, Point const& of
if (layout.IsValid()) if (layout.IsValid())
{ {
ComPtr<ID2D1Brush> fill_brush; auto native = NativePtr::Get<IDWriteTextLayout>(layout);
ComPtr<ID2D1Brush> outline_brush; auto fill_brush = NativePtr::Get<ID2D1Brush>(layout.GetDefaultFillBrush());
ComPtr<ID2D1StrokeStyle> outline_stroke; auto outline_brush = NativePtr::Get<ID2D1Brush>(layout.GetDefaultOutlineBrush());
auto outline_stroke = NativePtr::Get<ID2D1StrokeStyle>(layout.GetDefaultOutlineStrokeStyle());
float outline_width = 1.0f;
if (layout.GetDefaultFillBrush()) if (fill_brush)
{ {
fill_brush = layout.GetDefaultFillBrush()->GetBrush();
fill_brush->SetOpacity(brush_opacity_); fill_brush->SetOpacity(brush_opacity_);
} }
if (layout.GetDefaultOutlineBrush()) if (outline_brush)
{ {
outline_brush = layout.GetDefaultOutlineBrush()->GetBrush();
outline_brush->SetOpacity(brush_opacity_); outline_brush->SetOpacity(brush_opacity_);
} }
if (layout.GetDefaultOutlineStrokeStyle()) if (layout.GetDefaultOutlineStrokeStyle())
{ {
outline_stroke = layout.GetDefaultOutlineStrokeStyle()->GetStrokeStyle(); outline_width = layout.GetDefaultOutlineStrokeStyle()->GetStrokeWidth();
} }
float outline_width = layout.GetDefaultOutlineWidth(); HRESULT hr = text_renderer_->DrawTextLayout(native.Get(), offset.x, offset.y, fill_brush.Get(),
HRESULT hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().Get(), offset.x, offset.y, fill_brush.Get(),
outline_brush.Get(), outline_width, outline_stroke.Get()); outline_brush.Get(), outline_width, outline_stroke.Get());
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -153,66 +158,79 @@ void RenderContextImpl::DrawTextLayout(TextLayout const& layout, Point const& of
} }
} }
void RenderContextImpl::DrawShape(Shape const& shape, StrokeStylePtr stroke, float stroke_width) void RenderContextImpl::DrawShape(Shape const& shape)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (shape.IsValid()) if (shape.IsValid())
{ {
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr; auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
render_target_->DrawGeometry(shape.GetGeometry().Get(), current_brush_->GetBrush().Get(), stroke_width, auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
stroke_style); auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
float stroke_width = current_stroke_ ? current_stroke_->GetStrokeWidth() : 1.0f;
render_target_->DrawGeometry(geometry.Get(), brush.Get(), stroke_width, stroke_style.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
} }
void RenderContextImpl::DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke, float stroke_width) void RenderContextImpl::DrawLine(Point const& point1, Point const& point2)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr; auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
current_brush_->GetBrush().Get(), stroke_width, stroke_style); float stroke_width = current_stroke_ ? current_stroke_->GetStrokeWidth() : 1.0f;
render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), brush.Get(), stroke_width,
stroke_style.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
void RenderContextImpl::DrawRectangle(Rect const& rect, StrokeStylePtr stroke, float stroke_width) void RenderContextImpl::DrawRectangle(Rect const& rect)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr; auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().Get(), stroke_width, auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
stroke_style); float stroke_width = current_stroke_ ? current_stroke_->GetStrokeWidth() : 1.0f;
render_target_->DrawRectangle(DX::ConvertToRectF(rect), brush.Get(), stroke_width, stroke_style.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
void RenderContextImpl::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke, void RenderContextImpl::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius)
float stroke_width)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr; auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
current_brush_->GetBrush().Get(), stroke_width, stroke_style); float stroke_width = current_stroke_ ? current_stroke_->GetStrokeWidth() : 1.0f;
render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get(),
stroke_width, stroke_style.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
void RenderContextImpl::DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke, float stroke_width) void RenderContextImpl::DrawEllipse(Point const& center, Vec2 const& radius)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr; auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
current_brush_->GetBrush().Get(), stroke_width, stroke_style); float stroke_width = current_stroke_ ? current_stroke_->GetStrokeWidth() : 1.0f;
render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get(),
stroke_width, stroke_style.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
@ -224,7 +242,9 @@ void RenderContextImpl::FillShape(Shape const& shape)
if (shape.IsValid()) if (shape.IsValid())
{ {
render_target_->FillGeometry(shape.GetGeometry().Get(), current_brush_->GetBrush().Get()); auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
render_target_->FillGeometry(geometry.Get(), brush.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
@ -235,7 +255,8 @@ void RenderContextImpl::FillRectangle(Rect const& rect)
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
render_target_->FillRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().Get()); auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->FillRectangle(DX::ConvertToRectF(rect), brush.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
@ -245,8 +266,8 @@ void RenderContextImpl::FillRoundedRectangle(Rect const& rect, Vec2 const& radiu
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
current_brush_->GetBrush().Get()); render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
@ -256,8 +277,8 @@ void RenderContextImpl::FillEllipse(Point const& center, Vec2 const& radius)
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
current_brush_->GetBrush().Get()); render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get());
IncreasePrimitivesCount(); IncreasePrimitivesCount();
} }
@ -272,7 +293,7 @@ void RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T<uint32_t> si
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetBitmap(saved_bitmap); NativePtr::Set(texture, saved_bitmap);
} }
KGE_THROW_IF_FAILED(hr, "Create texture failed"); KGE_THROW_IF_FAILED(hr, "Create texture failed");
@ -281,8 +302,17 @@ void RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T<uint32_t> si
void RenderContextImpl::PushClipRect(Rect const& clip_rect) void RenderContextImpl::PushClipRect(Rect const& clip_rect)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
render_target_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect),
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED); D2D1_ANTIALIAS_MODE mode;
if (antialias_)
{
mode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
}
else
{
mode = D2D1_ANTIALIAS_MODE_ALIASED;
}
render_target_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect), mode);
} }
void RenderContextImpl::PopClipRect() void RenderContextImpl::PopClipRect()
@ -294,35 +324,27 @@ void RenderContextImpl::PopClipRect()
void RenderContextImpl::PushLayer(Layer& layer) void RenderContextImpl::PushLayer(Layer& layer)
{ {
KGE_ASSERT(render_target_ && "Render target has not been initialized!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
if (!layer.IsValid())
{
ComPtr<ID2D1Layer> output;
HRESULT hr = render_target_->CreateLayer(&output); auto native = NativePtr::Get<ID2D1Layer>(layer);
auto mask = NativePtr::Get<ID2D1Geometry>(layer.GetMaskShape());
if (!native)
{
HRESULT hr = render_target_->CreateLayer(&native);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
layer.SetLayer(output); NativePtr::Set(layer, native);
}
else
{
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
} }
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
} }
if (layer.IsValid()) auto params = D2D1::LayerParameters(DX::ConvertToRectF(layer.GetClipRect()), mask.Get(),
{ antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
ComPtr<ID2D1Geometry> mask; DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
if (layer.GetMaskShape()) D2D1_LAYER_OPTIONS_NONE);
mask = layer.GetMaskShape()->GetGeometry();
render_target_->PushLayer( render_target_->PushLayer(params, native.Get());
D2D1::LayerParameters(DX::ConvertToRectF(layer.GetClipRect()), mask.Get(),
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
D2D1_LAYER_OPTIONS_NONE),
layer.GetLayer().Get());
}
} }
void RenderContextImpl::PopLayer() void RenderContextImpl::PopLayer()
@ -358,7 +380,7 @@ void RenderContextImpl::SetCurrentBrush(BrushPtr brush)
if (current_brush_ && current_brush_->IsValid()) if (current_brush_ && current_brush_->IsValid())
{ {
current_brush_->GetBrush()->SetOpacity(brush_opacity_); NativePtr::Get<ID2D1Brush>(current_brush_)->SetOpacity(brush_opacity_);
} }
} }

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include <kiwano/render/RenderContext.h> #include <kiwano/render/RenderContext.h>
#include <kiwano/render/DirectX/TextRenderer.h>
namespace kiwano namespace kiwano
{ {
@ -43,15 +44,15 @@ public:
void DrawTextLayout(TextLayout const& layout, Point const& offset) override; void DrawTextLayout(TextLayout const& layout, Point const& offset) override;
void DrawShape(Shape const& shape, StrokeStylePtr stroke, float stroke_width) override; void DrawShape(Shape const& shape) override;
void DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke, float stroke_width) override; void DrawLine(Point const& point1, Point const& point2) override;
void DrawRectangle(Rect const& rect, StrokeStylePtr stroke, float stroke_width) override; void DrawRectangle(Rect const& rect) override;
void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke, float stroke_width) override; void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius) override;
void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke, float stroke_width) override; void DrawEllipse(Point const& center, Vec2 const& radius) override;
void FillShape(Shape const& shape) override; void FillShape(Shape const& shape) override;

View File

@ -23,9 +23,10 @@
#include <kiwano/core/event/WindowEvent.h> #include <kiwano/core/event/WindowEvent.h>
#include <kiwano/platform/FileSystem.h> #include <kiwano/platform/FileSystem.h>
#include <kiwano/platform/Application.h> #include <kiwano/platform/Application.h>
#include <kiwano/render/ShapeSink.h> #include <kiwano/render/ShapeMaker.h>
#include <kiwano/render/DirectX/TextureRenderContextImpl.h> #include <kiwano/render/DirectX/TextureRenderContextImpl.h>
#include <kiwano/render/DirectX/RendererImpl.h> #include <kiwano/render/DirectX/RendererImpl.h>
#include <kiwano/render/DirectX/NativePtr.h>
namespace kiwano namespace kiwano
{ {
@ -226,7 +227,10 @@ void RendererImpl::CreateTexture(Texture& texture, String const& file_path)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetBitmap(bitmap); NativePtr::Set(texture, bitmap);
texture.SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
texture.SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
} }
} }
} }
@ -277,7 +281,10 @@ void RendererImpl::CreateTexture(Texture& texture, Resource const& resource)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetBitmap(bitmap); NativePtr::Set(texture, bitmap);
texture.SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
texture.SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
} }
} }
} }
@ -314,7 +321,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, String const& file_path)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
gif.SetDecoder(decoder); NativePtr::Set(gif, decoder);
} }
} }
@ -345,7 +352,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, Resource const& resource)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
gif.SetDecoder(decoder); NativePtr::Set(gif, decoder);
} }
} }
} }
@ -364,7 +371,9 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& g
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
if (gif.GetDecoder() == nullptr) auto decoder = NativePtr::Get<IWICBitmapDecoder>(gif);
if (!decoder)
{ {
hr = E_INVALIDARG; hr = E_INVALIDARG;
} }
@ -373,7 +382,7 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& g
{ {
ComPtr<IWICBitmapFrameDecode> wic_frame; ComPtr<IWICBitmapFrameDecode> wic_frame;
HRESULT hr = gif.GetDecoder()->GetFrame(UINT(frame_index), &wic_frame); hr = decoder->GetFrame(UINT(frame_index), &wic_frame);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -383,13 +392,16 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& g
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<ID2D1Bitmap> raw_bitmap; ComPtr<ID2D1Bitmap> bitmap;
hr = d2d_res_->CreateBitmapFromConverter(raw_bitmap, nullptr, converter); hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
frame.texture = new Texture; frame.texture = new Texture;
frame.texture->SetBitmap(raw_bitmap); NativePtr::Set(frame.texture, bitmap);
frame.texture->SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
frame.texture->SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
} }
} }
} }
@ -548,7 +560,7 @@ void RendererImpl::CreateFontCollection(Font& font, String const& file_path)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
font.SetCollection(font_collection); NativePtr::Set(font, font_collection);
} }
} }
} }
@ -579,7 +591,7 @@ void RendererImpl::CreateFontCollection(Font& font, Resource const& res)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
font.SetCollection(font_collection); NativePtr::Set(font, font_collection);
} }
} }
} }
@ -597,32 +609,32 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
if (content.empty()) if (content.empty())
{ {
layout.SetTextLayout(nullptr); layout.Clear();
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated); layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
return; return;
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IDWriteTextFormat> format; WideString font_family = style.font_family.empty() ? L"" : string::ToWide(style.font_family);
WideString font_family = style.font_family.empty() ? L"" : string::ToWide(style.font_family); DWRITE_FONT_WEIGHT font_weight = DWRITE_FONT_WEIGHT(style.font_weight);
DWRITE_FONT_WEIGHT font_weight = DWRITE_FONT_WEIGHT(style.font_weight); DWRITE_FONT_STYLE font_style = style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
DWRITE_FONT_STYLE font_style = style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; auto collection = NativePtr::Get<IDWriteFontCollection>(style.font);
IDWriteFontCollection* collection = style.font ? style.font->GetCollection().Get() : nullptr;
ComPtr<IDWriteTextFormat> format;
hr = d2d_res_->CreateTextFormat(format, font_family.c_str(), collection, font_weight, font_style, hr = d2d_res_->CreateTextFormat(format, font_family.c_str(), collection, font_weight, font_style,
DWRITE_FONT_STRETCH_NORMAL, style.font_size); DWRITE_FONT_STRETCH_NORMAL, style.font_size);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IDWriteTextLayout> output; WideString wide = string::ToWide(content);
WideString wide = string::ToWide(content);
ComPtr<IDWriteTextLayout> output;
hr = d2d_res_->CreateTextLayout(output, wide.c_str(), wide.length(), format); hr = d2d_res_->CreateTextLayout(output, wide.c_str(), wide.length(), format);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
layout.SetTextLayout(output); NativePtr::Set(layout, output);
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated); layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
} }
} }
@ -639,29 +651,29 @@ void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point c
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
ComPtr<ID2D1PathGeometry> path_geo;
ComPtr<ID2D1GeometrySink> path_sink;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<ID2D1PathGeometry> path_geo;
hr = d2d_res_->GetFactory()->CreatePathGeometry(&path_geo); hr = d2d_res_->GetFactory()->CreatePathGeometry(&path_geo);
}
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = path_geo->Open(&path_sink); ComPtr<ID2D1GeometrySink> path_sink;
} hr = path_geo->Open(&path_sink);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
path_sink->AddLine(DX::ConvertToPoint2F(end_pos)); path_sink->AddLine(DX::ConvertToPoint2F(end_pos));
path_sink->EndFigure(D2D1_FIGURE_END_OPEN); path_sink->EndFigure(D2D1_FIGURE_END_OPEN);
hr = path_sink->Close(); hr = path_sink->Close();
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
shape.SetGeometry(path_geo); NativePtr::Set(shape, path_geo);
}
}
} }
KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed"); KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed");
@ -683,7 +695,7 @@ void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
shape.SetGeometry(output); NativePtr::Set(shape, output);
} }
KGE_THROW_IF_FAILED(hr, "Create ID2D1RectangleGeometry failed"); KGE_THROW_IF_FAILED(hr, "Create ID2D1RectangleGeometry failed");
@ -706,7 +718,7 @@ void RendererImpl::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 c
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
shape.SetGeometry(output); NativePtr::Set(shape, output);
} }
KGE_THROW_IF_FAILED(hr, "Create ID2D1RoundedRectangleGeometry failed"); KGE_THROW_IF_FAILED(hr, "Create ID2D1RoundedRectangleGeometry failed");
@ -729,13 +741,13 @@ void RendererImpl::CreateEllipseShape(Shape& shape, Point const& center, Vec2 co
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
shape.SetGeometry(output); NativePtr::Set(shape, output);
} }
KGE_THROW_IF_FAILED(hr, "Create ID2D1EllipseGeometry failed"); KGE_THROW_IF_FAILED(hr, "Create ID2D1EllipseGeometry failed");
} }
void RendererImpl::CreateShapeSink(ShapeSink& sink) void RendererImpl::CreateShapeSink(ShapeMaker& maker)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!d2d_res_) if (!d2d_res_)
@ -743,17 +755,20 @@ void RendererImpl::CreateShapeSink(ShapeSink& sink)
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
ComPtr<ID2D1PathGeometry> output;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = d2d_res_->GetFactory()->CreatePathGeometry(&output); ComPtr<ID2D1PathGeometry> geometry;
}
if (SUCCEEDED(hr)) hr = d2d_res_->GetFactory()->CreatePathGeometry(&geometry);
{
sink.SetPathGeometry(output);
}
if (SUCCEEDED(hr))
{
ShapePtr shape = new Shape;
NativePtr::Set(shape, geometry);
maker.SetShape(shape);
}
}
KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed"); KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed");
} }
@ -769,9 +784,9 @@ void RendererImpl::CreateBrush(Brush& brush, Color const& color)
{ {
ComPtr<ID2D1SolidColorBrush> solid_brush; ComPtr<ID2D1SolidColorBrush> solid_brush;
if (brush.GetType() == Brush::Type::SolidColor && brush.GetBrush()) if (brush.GetType() == Brush::Type::SolidColor && brush.IsValid())
{ {
hr = brush.GetBrush()->QueryInterface(&solid_brush); hr = NativePtr::Get<ID2D1Brush>(brush)->QueryInterface(&solid_brush);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
solid_brush->SetColor(DX::ConvertToColorF(color)); solid_brush->SetColor(DX::ConvertToColorF(color));
@ -783,7 +798,7 @@ void RendererImpl::CreateBrush(Brush& brush, Color const& color)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
brush.SetBrush(solid_brush, Brush::Type::SolidColor); NativePtr::Set(brush, solid_brush);
} }
} }
} }
@ -815,7 +830,7 @@ void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
brush.SetBrush(output, Brush::Type::LinearGradient); NativePtr::Set(brush, output);
} }
} }
} }
@ -848,7 +863,7 @@ void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
brush.SetBrush(output, Brush::Type::RadialGradient); NativePtr::Set(brush, output);
} }
} }
} }
@ -856,8 +871,7 @@ void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style)
KGE_THROW_IF_FAILED(hr, "Create ID2D1RadialGradientBrush failed"); KGE_THROW_IF_FAILED(hr, "Create ID2D1RadialGradientBrush failed");
} }
void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style)
const float* dash_array, size_t dash_size, float dash_offset)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (!d2d_res_) if (!d2d_res_)
@ -867,16 +881,29 @@ void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, Li
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
D2D1_STROKE_STYLE_PROPERTIES style = D2D1_CAP_STYLE cap = D2D1_CAP_STYLE(stroke_style.GetCapStyle());
D2D1::StrokeStyleProperties(D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_LINE_JOIN line_join = D2D1_LINE_JOIN(stroke_style.GetLineJoinStyle());
D2D1_LINE_JOIN(line_join), 10.0f, D2D1_DASH_STYLE_CUSTOM, dash_offset); D2D1_DASH_STYLE dash_style = D2D1_DASH_STYLE_SOLID;
const float* dash_array = nullptr;
uint32_t dash_count = 0;
float dash_offset = stroke_style.GetDashOffset();
const auto& dashes = stroke_style.GetDashArray();
if (!dashes.empty())
{
dash_array = &dashes[0];
dash_count = uint32_t(dashes.size());
dash_style = D2D1_DASH_STYLE_CUSTOM;
}
auto params = D2D1::StrokeStyleProperties(cap, cap, cap, line_join, 10.0f, dash_style, dash_offset);
ComPtr<ID2D1StrokeStyle> output; ComPtr<ID2D1StrokeStyle> output;
hr = d2d_res_->GetFactory()->CreateStrokeStyle(style, dash_array, dash_size, &output); hr = d2d_res_->GetFactory()->CreateStrokeStyle(params, dash_array, dash_count, &output);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
stroke_style.SetStrokeStyle(output); NativePtr::Set(stroke_style, output);
} }
} }

View File

@ -68,7 +68,7 @@ public:
void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius) override; void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius) override;
void CreateShapeSink(ShapeSink& sink) override; void CreateShapeSink(ShapeMaker& maker) override;
void CreateBrush(Brush& brush, Color const& color) override; void CreateBrush(Brush& brush, Color const& color) override;
@ -76,8 +76,7 @@ public:
void CreateBrush(Brush& brush, RadialGradientStyle const& style) override; void CreateBrush(Brush& brush, RadialGradientStyle const& style) override;
void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, const float* dash_array, void CreateStrokeStyle(StrokeStyle& stroke_style) override;
size_t dash_size, float dash_offset) override;
TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr) override; TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr) override;

View File

@ -21,6 +21,7 @@
#include <kiwano/core/Logger.h> #include <kiwano/core/Logger.h>
#include <kiwano/render/Renderer.h> #include <kiwano/render/Renderer.h>
#include <kiwano/render/DirectX/TextureRenderContextImpl.h> #include <kiwano/render/DirectX/TextureRenderContextImpl.h>
#include <kiwano/render/DirectX/NativePtr.h>
namespace kiwano namespace kiwano
{ {
@ -37,7 +38,10 @@ bool TextureRenderContextImpl::GetOutput(Texture& texture)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
texture.SetBitmap(bitmap); NativePtr::Set(texture, bitmap);
texture.SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
texture.SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
} }
} }
return SUCCEEDED(hr); return SUCCEEDED(hr);

View File

@ -19,10 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/core/ObjectBase.h> #include <kiwano/render/NativeObject.h>
#include <kiwano/core/Resource.h> #include <kiwano/core/Resource.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <dwrite.h>
namespace kiwano namespace kiwano
{ {
@ -39,7 +37,7 @@ class Renderer;
* \~chinese * \~chinese
* @brief * @brief
*/ */
class Font : public virtual ObjectBase class Font : public NativeObject
{ {
friend class Renderer; friend class Renderer;
@ -61,43 +59,8 @@ public:
/// \~chinese /// \~chinese
/// @brief 加载字体资源 /// @brief 加载字体资源
bool Load(Resource const& resource); bool Load(Resource const& resource);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<IDWriteFontCollection> GetCollection() const;
void SetCollection(ComPtr<IDWriteFontCollection> collection);
private:
ComPtr<IDWriteFontCollection> collection_;
#endif
}; };
/** @} */ /** @} */
inline bool Font::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return collection_ != nullptr;
#else
return false; // not supported
#endif
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline ComPtr<IDWriteFontCollection> Font::GetCollection() const
{
return collection_;
}
inline void Font::SetCollection(ComPtr<IDWriteFontCollection> collection)
{
collection_ = collection;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -49,8 +49,6 @@ GifImagePtr GifImage::Create(Resource const& res)
GifImage::GifImage() GifImage::GifImage()
: frames_count_(0) : frames_count_(0)
, width_in_pixels_(0)
, height_in_pixels_(0)
{ {
} }
@ -63,7 +61,8 @@ bool GifImage::Load(String const& file_path)
if (GetGlobalMetadata()) if (GetGlobalMetadata())
return true; return true;
SetDecoder(nullptr); // Clear data
ResetNativePointer();
} }
return false; return false;
} }
@ -77,7 +76,8 @@ bool GifImage::Load(Resource const& res)
if (GetGlobalMetadata()) if (GetGlobalMetadata())
return true; return true;
SetDecoder(nullptr); // Clear data
ResetNativePointer();
} }
return false; return false;
} }
@ -89,20 +89,29 @@ GifImage::Frame GifImage::GetFrame(uint32_t index)
return frame; return frame;
} }
} // namespace kiwano
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
namespace kiwano
{
bool GifImage::GetGlobalMetadata() bool GifImage::GetGlobalMetadata()
{ {
HRESULT hr = decoder_ ? S_OK : E_FAIL; ComPtr<IWICBitmapDecoder> decoder = NativePtr::Get<IWICBitmapDecoder>(this);
HRESULT hr = decoder ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = decoder_->GetFrameCount(&frames_count_); hr = decoder->GetFrameCount(&frames_count_);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
ComPtr<IWICMetadataQueryReader> metadata_reader; ComPtr<IWICMetadataQueryReader> metadata_reader;
hr = decoder_->GetMetadataQueryReader(&metadata_reader); hr = decoder->GetMetadataQueryReader(&metadata_reader);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -164,20 +173,17 @@ bool GifImage::GetGlobalMetadata()
// 根据像素长宽比计算像素中的图像宽度和高度,只缩小图像 // 根据像素长宽比计算像素中的图像宽度和高度,只缩小图像
if (pixel_asp_ratio > 1.f) if (pixel_asp_ratio > 1.f)
{ {
width_in_pixels_ = width; size_in_pixels_ = { width, static_cast<uint32_t>(height / pixel_asp_ratio) };
height_in_pixels_ = static_cast<uint32_t>(height / pixel_asp_ratio);
} }
else else
{ {
width_in_pixels_ = static_cast<uint32_t>(width * pixel_asp_ratio); size_in_pixels_ = { static_cast<uint32_t>(width * pixel_asp_ratio), height };
height_in_pixels_ = height;
} }
} }
else else
{ {
// 值为 0, 所以像素比为 1 // 值为 0, 所以像素比为 1
width_in_pixels_ = width; size_in_pixels_ = { width, height };
height_in_pixels_ = height;
} }
} }
::PropVariantClear(&prop_val); ::PropVariantClear(&prop_val);

View File

@ -35,7 +35,7 @@ KGE_DECLARE_SMART_PTR(GifImage);
* \~chinese * \~chinese
* @brief GIF图像 * @brief GIF图像
*/ */
class KGE_API GifImage : public virtual ObjectBase class KGE_API GifImage : public NativeObject
{ {
public: public:
/// \~chinese /// \~chinese
@ -56,10 +56,6 @@ public:
/// @brief 加载GIF资源 /// @brief 加载GIF资源
bool Load(Resource const& res); bool Load(Resource const& res);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 获取像素宽度 /// @brief 获取像素宽度
uint32_t GetWidthInPixels() const; uint32_t GetWidthInPixels() const;
@ -68,6 +64,10 @@ public:
/// @brief 获取像素高度 /// @brief 获取像素高度
uint32_t GetHeightInPixels() const; uint32_t GetHeightInPixels() const;
/// \~chinese
/// @brief 获取像素大小
PixelSize GetSizeInPixels() const;
/// \~chinese /// \~chinese
/// @brief 获取帧数量 /// @brief 获取帧数量
uint32_t GetFramesCount() const; uint32_t GetFramesCount() const;
@ -105,18 +105,7 @@ private:
private: private:
uint32_t frames_count_; uint32_t frames_count_;
uint32_t width_in_pixels_; PixelSize size_in_pixels_;
uint32_t height_in_pixels_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<IWICBitmapDecoder> GetDecoder() const;
void SetDecoder(ComPtr<IWICBitmapDecoder> decoder);
private:
ComPtr<IWICBitmapDecoder> decoder_;
#endif
}; };
/** @} */ /** @} */
@ -128,12 +117,17 @@ inline GifImage::Frame::Frame()
inline uint32_t GifImage::GetWidthInPixels() const inline uint32_t GifImage::GetWidthInPixels() const
{ {
return width_in_pixels_; return size_in_pixels_.x;
} }
inline uint32_t GifImage::GetHeightInPixels() const inline uint32_t GifImage::GetHeightInPixels() const
{ {
return height_in_pixels_; return size_in_pixels_.y;
}
inline PixelSize GifImage::GetSizeInPixels() const
{
return size_in_pixels_;
} }
inline uint32_t GifImage::GetFramesCount() const inline uint32_t GifImage::GetFramesCount() const
@ -141,25 +135,4 @@ inline uint32_t GifImage::GetFramesCount() const
return frames_count_; return frames_count_;
} }
inline bool GifImage::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return decoder_ != nullptr;
#else
return false; // not supported
#endif
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline ComPtr<IWICBitmapDecoder> GifImage::GetDecoder() const
{
return decoder_;
}
inline void GifImage::SetDecoder(ComPtr<IWICBitmapDecoder> decoder)
{
decoder_ = decoder;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -24,6 +24,8 @@
namespace kiwano namespace kiwano
{ {
KGE_DECLARE_SMART_PTR(Layer);
/** /**
* \addtogroup Render * \addtogroup Render
* @{ * @{
@ -33,15 +35,11 @@ namespace kiwano
* \~chinese * \~chinese
* @brief * @brief
*/ */
class KGE_API Layer class KGE_API Layer : public NativeObject
{ {
public: public:
Layer(); Layer();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 获取图层裁剪区域 /// @brief 获取图层裁剪区域
Rect const& GetClipRect() const; Rect const& GetClipRect() const;
@ -79,29 +77,10 @@ private:
float opacity_; float opacity_;
ShapePtr mask_; ShapePtr mask_;
Matrix3x2 mask_transform_; Matrix3x2 mask_transform_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<ID2D1Layer> GetLayer() const;
void SetLayer(ComPtr<ID2D1Layer> layer);
private:
ComPtr<ID2D1Layer> layer_;
#endif
}; };
/** @} */ /** @} */
inline bool Layer::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return layer_ != nullptr;
#else
return false; // not supported
#endif
}
inline Rect const& Layer::GetClipRect() const inline Rect const& Layer::GetClipRect() const
{ {
return clip_rect_; return clip_rect_;
@ -142,16 +121,4 @@ inline void Layer::SetMaskTransform(Matrix3x2 const& matrix)
mask_transform_ = matrix; mask_transform_ = matrix;
} }
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline ComPtr<ID2D1Layer> Layer::GetLayer() const
{
return layer_;
}
inline void Layer::SetLayer(ComPtr<ID2D1Layer> layer)
{
layer_ = layer;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -0,0 +1,92 @@
// 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 <kiwano/core/ObjectBase.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/D2DDeviceResources.h>
#endif
namespace kiwano
{
KGE_DECLARE_SMART_PTR(NativeObject);
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API NativeObject : public virtual ObjectBase
{
public:
virtual bool IsValid() const;
Any GetNativePointer() const;
template <typename _NativeTy>
_NativeTy GetNativePointer() const;
void SetNativePointer(const Any& native_pointer);
void ResetNativePointer();
private:
Any native_pointer_;
};
/** @} */
inline bool NativeObject::IsValid() const
{
return native_pointer_.HasValue();
}
inline Any NativeObject::GetNativePointer() const
{
return native_pointer_;
}
template <typename _NativeTy>
inline _NativeTy NativeObject::GetNativePointer() const
{
if (native_pointer_.HasValue())
{
return native_pointer_.Cast<_NativeTy>();
}
return _NativeTy();
}
inline void NativeObject::SetNativePointer(const Any& native_pointer)
{
native_pointer_ = native_pointer;
}
inline void NativeObject::ResetNativePointer()
{
native_pointer_.Clear();
}
} // namespace kiwano

View File

@ -19,6 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/render/RenderContext.h> #include <kiwano/render/RenderContext.h>
#include <kiwano/render/Renderer.h>
namespace kiwano namespace kiwano
{ {
@ -105,4 +106,17 @@ void RenderContext::SetCurrentBrush(BrushPtr brush)
current_brush_ = brush; current_brush_ = brush;
} }
void RenderContext::SetCurrentStrokeStyle(StrokeStylePtr stroke)
{
if (current_stroke_ != stroke)
{
current_stroke_ = stroke;
if (current_stroke_ && !current_stroke_->IsValid())
{
Renderer::GetInstance().CreateStrokeStyle(*current_stroke_);
}
}
}
} // namespace kiwano } // namespace kiwano

View File

@ -26,7 +26,6 @@
#include <kiwano/render/Layer.h> #include <kiwano/render/Layer.h>
#include <kiwano/render/TextLayout.h> #include <kiwano/render/TextLayout.h>
#include <kiwano/render/Texture.h> #include <kiwano/render/Texture.h>
#include <kiwano/render/DirectX/TextRenderer.h>
namespace kiwano namespace kiwano
{ {
@ -87,42 +86,30 @@ public:
/// \~chinese /// \~chinese
/// @brief 绘制形状轮廓 /// @brief 绘制形状轮廓
/// @param shape 形状 /// @param shape 形状
/// @param stroke 线条样式 virtual void DrawShape(Shape const& shape) = 0;
/// @param stroke_width 线条宽度
virtual void DrawShape(Shape const& shape, StrokeStylePtr stroke, float stroke_width) = 0;
/// \~chinese /// \~chinese
/// @brief 绘制线段 /// @brief 绘制线段
/// @param point1 线段起点 /// @param point1 线段起点
/// @param point2 线段终点 /// @param point2 线段终点
/// @param stroke 线条样式 virtual void DrawLine(Point const& point1, Point const& point2) = 0;
/// @param stroke_width 线条宽度
virtual void DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke, float stroke_width) = 0;
/// \~chinese /// \~chinese
/// @brief 绘制矩形边框 /// @brief 绘制矩形边框
/// @param rect 矩形 /// @param rect 矩形
/// @param stroke 线条样式 virtual void DrawRectangle(Rect const& rect) = 0;
/// @param stroke_width 线条宽度
virtual void DrawRectangle(Rect const& rect, StrokeStylePtr stroke, float stroke_width) = 0;
/// \~chinese /// \~chinese
/// @brief 绘制圆角矩形边框 /// @brief 绘制圆角矩形边框
/// @param rect 矩形 /// @param rect 矩形
/// @param radius 圆角半径 /// @param radius 圆角半径
/// @param stroke 线条样式 virtual void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius) = 0;
/// @param stroke_width 线条宽度
virtual void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke,
float stroke_width) = 0;
/// \~chinese /// \~chinese
/// @brief 绘制椭圆边框 /// @brief 绘制椭圆边框
/// @param center 圆心 /// @param center 圆心
/// @param radius 椭圆半径 /// @param radius 椭圆半径
/// @param stroke 线条样式 virtual void DrawEllipse(Point const& center, Vec2 const& radius) = 0;
/// @param stroke_width 线条宽度
virtual void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke,
float stroke_width) = 0;
/// \~chinese /// \~chinese
/// @brief 填充形状 /// @brief 填充形状
@ -200,9 +187,13 @@ public:
virtual void SetBrushOpacity(float opacity); virtual void SetBrushOpacity(float opacity);
/// \~chinese /// \~chinese
/// @brief 设置当前画刷 /// @brief 设置当前使用的画刷
virtual void SetCurrentBrush(BrushPtr brush); virtual void SetCurrentBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置当前使用的线条样式
virtual void SetCurrentStrokeStyle(StrokeStylePtr stroke);
/// \~chinese /// \~chinese
/// @brief 设置抗锯齿模式 /// @brief 设置抗锯齿模式
virtual void SetAntialiasMode(bool enabled) = 0; virtual void SetAntialiasMode(bool enabled) = 0;
@ -265,6 +256,7 @@ protected:
float brush_opacity_; float brush_opacity_;
TextAntialiasMode text_antialias_; TextAntialiasMode text_antialias_;
BrushPtr current_brush_; BrushPtr current_brush_;
StrokeStylePtr current_stroke_;
Rect visible_size_; Rect visible_size_;
Matrix3x2 global_transform_; Matrix3x2 global_transform_;
mutable Status status_; mutable Status status_;

View File

@ -154,9 +154,9 @@ public:
/// \~chinese /// \~chinese
/// @brief 创建几何图形生成器内部资源 /// @brief 创建几何图形生成器内部资源
/// @param[out] sink 形状生成器 /// @param[out] maker 形状生成器
/// @throw kiwano::SystemError 创建失败时抛出 /// @throw kiwano::SystemError 创建失败时抛出
virtual void CreateShapeSink(ShapeSink& sink) = 0; virtual void CreateShapeSink(ShapeMaker& maker) = 0;
/// \~chinese /// \~chinese
/// @brief 创建纯色画刷内部资源 /// @brief 创建纯色画刷内部资源
@ -188,8 +188,7 @@ public:
/// @param[in] dash_size 虚线数组大小 /// @param[in] dash_size 虚线数组大小
/// @param[in] dash_offset 虚线偏移量 /// @param[in] dash_offset 虚线偏移量
/// @throw kiwano::SystemError 创建失败时抛出 /// @throw kiwano::SystemError 创建失败时抛出
virtual void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, virtual void CreateStrokeStyle(StrokeStyle& stroke_style) = 0;
const float* dash_array, size_t dash_size, float dash_offset) = 0;
/// \~chinese /// \~chinese
/// @brief 创建纹理渲染上下文 /// @brief 创建纹理渲染上下文

View File

@ -19,22 +19,32 @@
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/render/Shape.h> #include <kiwano/render/Shape.h>
#include <kiwano/render/ShapeSink.h> #include <kiwano/render/ShapeMaker.h>
#include <kiwano/render/Renderer.h> #include <kiwano/render/Renderer.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
#endif
namespace kiwano namespace kiwano
{ {
Shape::Shape() {} Shape::Shape() {}
void Shape::Clear()
{
ResetNativePointer();
}
Rect Shape::GetBoundingBox() const Rect Shape::GetBoundingBox() const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
Rect bounds; Rect bounds;
if (geo_) auto geometry = NativePtr::Get<ID2D1Geometry>(this);
if (geometry)
{ {
// no matter it failed or not // no matter it failed or not
geo_->GetBounds(nullptr, DX::ConvertToRectF(&bounds)); geometry->GetBounds(nullptr, DX::ConvertToRectF(&bounds));
} }
return bounds; return bounds;
#else #else
@ -46,10 +56,11 @@ Rect Shape::GetBoundingBox(Matrix3x2 const& transform) const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
Rect bounds; Rect bounds;
if (geo_) auto geometry = NativePtr::Get<ID2D1Geometry>(this);
if (geometry)
{ {
// no matter it failed or not // no matter it failed or not
geo_->GetBounds(DX::ConvertToMatrix3x2F(transform), DX::ConvertToRectF(&bounds)); geometry->GetBounds(DX::ConvertToMatrix3x2F(transform), DX::ConvertToRectF(&bounds));
} }
return bounds; return bounds;
#else #else
@ -61,10 +72,11 @@ float Shape::GetLength() const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
float length = 0.f; float length = 0.f;
if (geo_) auto geometry = NativePtr::Get<ID2D1Geometry>(this);
if (geometry)
{ {
// no matter it failed or not // no matter it failed or not
geo_->ComputeLength(D2D1::Matrix3x2F::Identity(), &length); geometry->ComputeLength(D2D1::Matrix3x2F::Identity(), &length);
} }
return length; return length;
#else #else
@ -75,9 +87,10 @@ float Shape::GetLength() const
bool Shape::ComputePointAtLength(float length, Point& point, Vec2& tangent) const bool Shape::ComputePointAtLength(float length, Point& point, Vec2& tangent) const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (geo_) auto geometry = NativePtr::Get<ID2D1Geometry>(this);
if (geometry)
{ {
HRESULT hr = geo_->ComputePointAtLength(length, D2D1::Matrix3x2F::Identity(), DX::ConvertToPoint2F(&point), HRESULT hr = geometry->ComputePointAtLength(length, D2D1::Matrix3x2F::Identity(), DX::ConvertToPoint2F(&point),
DX::ConvertToPoint2F(&tangent)); DX::ConvertToPoint2F(&tangent));
return SUCCEEDED(hr); return SUCCEEDED(hr);
@ -88,25 +101,17 @@ bool Shape::ComputePointAtLength(float length, Point& point, Vec2& tangent) cons
#endif #endif
} }
void Shape::Clear()
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
geo_.Reset();
#else
return; // not supported
#endif
}
float Shape::ComputeArea() const float Shape::ComputeArea() const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (!geo_) auto geometry = NativePtr::Get<ID2D1Geometry>(this);
return 0.f; if (geometry)
{
float area = 0.f; float area = 0.f;
// no matter it failed or not // no matter it failed or not
geo_->ComputeArea(D2D1::Matrix3x2F::Identity(), &area); geometry->ComputeArea(D2D1::Matrix3x2F::Identity(), &area);
return area; }
return 0.f;
#else #else
return 0.0f; // not supported return 0.0f; // not supported
#endif #endif
@ -115,12 +120,13 @@ float Shape::ComputeArea() const
bool Shape::ContainsPoint(Point const& point, const Matrix3x2* transform) const bool Shape::ContainsPoint(Point const& point, const Matrix3x2* transform) const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (!geo_) auto geometry = NativePtr::Get<ID2D1Geometry>(this);
if (!geometry)
return false; return false;
BOOL ret = 0; BOOL ret = 0;
// no matter it failed or not // no matter it failed or not
geo_->FillContainsPoint(DX::ConvertToPoint2F(point), DX::ConvertToMatrix3x2F(transform), geometry->FillContainsPoint(DX::ConvertToPoint2F(point), DX::ConvertToMatrix3x2F(transform),
D2D1_DEFAULT_FLATTENING_TOLERANCE, &ret); D2D1_DEFAULT_FLATTENING_TOLERANCE, &ret);
return !!ret; return !!ret;
#else #else

View File

@ -19,12 +19,11 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/core/ObjectBase.h> #include <kiwano/render/NativeObject.h>
#include <kiwano/render/DirectX/D2DDeviceResources.h>
namespace kiwano namespace kiwano
{ {
class ShapeSink; class ShapeMaker;
KGE_DECLARE_SMART_PTR(Shape); KGE_DECLARE_SMART_PTR(Shape);
@ -37,9 +36,9 @@ KGE_DECLARE_SMART_PTR(Shape);
* \~chinese * \~chinese
* @brief * @brief
*/ */
class KGE_API Shape : public virtual ObjectBase class KGE_API Shape : public NativeObject
{ {
friend class ShapeSink; friend class ShapeMaker;
public: public:
/// \~chinese /// \~chinese
@ -73,10 +72,6 @@ public:
Shape(); Shape();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 获取外切包围盒 /// @brief 获取外切包围盒
Rect GetBoundingBox() const; Rect GetBoundingBox() const;
@ -110,39 +105,8 @@ public:
/// \~chinese /// \~chinese
/// @brief 清除形状 /// @brief 清除形状
void Clear(); void Clear();
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<ID2D1Geometry> GetGeometry() const;
void SetGeometry(ComPtr<ID2D1Geometry> shape);
private:
ComPtr<ID2D1Geometry> geo_;
#endif
}; };
/** @} */ /** @} */
inline bool Shape::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return geo_ != nullptr;
#else
return false; // not supported
#endif
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline ComPtr<ID2D1Geometry> Shape::GetGeometry() const
{
return geo_;
}
inline void Shape::SetGeometry(ComPtr<ID2D1Geometry> shape)
{
geo_ = shape;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -0,0 +1,224 @@
// 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 <kiwano/render/ShapeMaker.h>
#include <kiwano/render/Renderer.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
#endif
namespace kiwano
{
ShapeMakerPtr ShapeMaker::Create()
{
ShapeMakerPtr maker = new (std::nothrow) ShapeMaker;
return maker;
}
ShapeMaker::ShapeMaker() {}
ShapeMaker::~ShapeMaker()
{
Clear();
}
void ShapeMaker::Clear()
{
CloseStream();
ResetNativePointer();
}
ShapePtr ShapeMaker::GetShape()
{
return shape_;
}
bool ShapeMaker::IsStreamOpened() const
{
return IsValid();
}
void ShapeMaker::BeginPath(Point const& begin_pos)
{
if (!IsStreamOpened())
{
OpenStream();
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
#else
// not supported
#endif
}
void ShapeMaker::EndPath(bool closed)
{
KGE_ASSERT(IsStreamOpened());
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
#else
// not supported
#endif
this->CloseStream();
}
void ShapeMaker::AddLine(Point const& point)
{
KGE_ASSERT(IsStreamOpened());
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->AddLine(DX::ConvertToPoint2F(point));
#else
// not supported
#endif
}
void ShapeMaker::AddLines(Vector<Point> const& points)
{
KGE_ASSERT(IsStreamOpened());
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->AddLines(reinterpret_cast<const D2D_POINT_2F*>(&points[0]), static_cast<uint32_t>(points.size()));
#else
// not supported
#endif
}
void kiwano::ShapeMaker::AddLines(const Point* points, size_t count)
{
KGE_ASSERT(IsStreamOpened());
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->AddLines(reinterpret_cast<const D2D_POINT_2F*>(points), UINT32(count));
#else
// not supported
#endif
}
void ShapeMaker::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
KGE_ASSERT(IsStreamOpened());
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->AddBezier(
D2D1::BezierSegment(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), DX::ConvertToPoint2F(point3)));
#else
// not supported
#endif
}
void ShapeMaker::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
KGE_ASSERT(IsStreamOpened());
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
native->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));
#else
// not supported
#endif
}
ShapePtr ShapeMaker::Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mode, const Matrix3x2* matrix)
{
ShapeMakerPtr maker = ShapeMaker::Create();
maker->OpenStream();
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (shape_a && shape_b)
{
auto geo_a = NativePtr::Get<ID2D1Geometry>(shape_a);
auto geo_b = NativePtr::Get<ID2D1Geometry>(shape_b);
auto native = NativePtr::Get<ID2D1GeometrySink>(maker);
HRESULT hr = geo_a->CombineWithGeometry(geo_b.Get(), D2D1_COMBINE_MODE(mode), DX::ConvertToMatrix3x2F(matrix),
native.Get());
KGE_THROW_IF_FAILED(hr, "ID2D1Geometry::CombineWithGeometry failed");
}
#else
// not supported
#endif
maker->CloseStream();
return maker->GetShape();
}
void ShapeMaker::OpenStream()
{
if (IsStreamOpened())
return;
Renderer::GetInstance().CreateShapeSink(*this);
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto geometry = NativePtr::Get<ID2D1PathGeometry>(shape_);
if (geometry)
{
ComPtr<ID2D1GeometrySink> native;
HRESULT hr = geometry->Open(&native);
if (SUCCEEDED(hr))
{
NativePtr::Set(this, native);
}
KGE_THROW_IF_FAILED(hr, "ID2D1PathGeometry::Open failed");
}
#else
// not supported
#endif
}
void ShapeMaker::CloseStream()
{
if (!IsStreamOpened())
return;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
HRESULT hr = native->Close();
KGE_THROW_IF_FAILED(hr, "ID2D1PathGeometry::Close failed");
ResetNativePointer();
#else
return; // not supported
#endif
}
void ShapeMaker::SetShape(ShapePtr shape)
{
shape_ = shape;
}
} // namespace kiwano

View File

@ -24,13 +24,15 @@
namespace kiwano namespace kiwano
{ {
KGE_DECLARE_SMART_PTR(ShapeMaker);
/** /**
* \addtogroup Render * \addtogroup Render
* @{ * @{
*/ */
/// \~chinese /// \~chinese
/// @brief 形状合方式 /// @brief 形状方式
enum class CombineMode enum class CombineMode
{ {
Union, ///< 并集 (A + B) Union, ///< 并集 (A + B)
@ -41,70 +43,57 @@ enum class CombineMode
/// \~chinese /// \~chinese
/// @brief 形状生成器 /// @brief 形状生成器
class KGE_API ShapeSink : protected Noncopyable class KGE_API ShapeMaker : public NativeObject
{ {
public: public:
ShapeSink();
~ShapeSink();
/// \~chinese /// \~chinese
/// @brief 打开输入流 /// @brief 创建形状生成器
void Open(); static ShapeMakerPtr Create();
/// \~chinese ShapeMaker();
/// @brief 关闭输入流
void Close();
/// \~chinese ~ShapeMaker();
/// @brief 输入流是否已经打开
bool IsOpened() const;
/// \~chinese /// \~chinese
/// @brief 获取生成的形状 /// @brief 获取生成的形状
/// @note 若还未关闭输入流,则自动关闭
ShapePtr GetShape(); ShapePtr GetShape();
/// \~chinese /// \~chinese
/// @brief 添加形状的轮廓 /// @brief 清空图形
/// @param input 输入的形状 void Clear();
/// @param input_matrix 应用到输入形状上的二维变换
/// @note 若还未打开输入流,则自动打开
ShapeSink& AddShape(ShapePtr input, const Matrix3x2* input_matrix = nullptr);
/// \~chinese /// \~chinese
/// @brief 开始添加路径 /// @brief 开始添加路径并打开输入流
/// @param begin_pos 路径起始点 /// @param begin_pos 路径起始点
/// @note 若还未打开输入流,则自动打开 void BeginPath(Point const& begin_pos = Point());
ShapeSink& BeginPath(Point const& begin_pos = Point());
/// \~chinese /// \~chinese
/// @brief 结束路径 /// @brief 结束路径并关闭输入流
/// @param closed 路径是否闭合 /// @param closed 路径是否闭合
ShapeSink& EndPath(bool closed = false); void EndPath(bool closed = false);
/// \~chinese /// \~chinese
/// @brief 添加一条线段 /// @brief 添加一条线段
/// @param point 端点 /// @param point 端点
ShapeSink& AddLine(Point const& point); void AddLine(Point const& point);
/// \~chinese /// \~chinese
/// @brief 添加多条线段 /// @brief 添加多条线段
/// @param points 端点集合 /// @param points 端点集合
ShapeSink& AddLines(Vector<Point> const& points); void AddLines(Vector<Point> const& points);
/// \~chinese /// \~chinese
/// @brief 添加多条线段 /// @brief 添加多条线段
/// @param points 端点数组 /// @param points 端点数组
/// @param count 端点数量 /// @param count 端点数量
ShapeSink& AddLines(const Point* points, size_t count); void AddLines(const Point* points, size_t count);
/// \~chinese /// \~chinese
/// @brief 添加一条三次方贝塞尔曲线 /// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点 /// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点 /// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点 /// @param point3 贝塞尔曲线的终点
ShapeSink& AddBezier(Point const& point1, Point const& point2, Point const& point3); void AddBezier(Point const& point1, Point const& point2, Point const& point3);
/// \~chinese /// \~chinese
/// @brief 添加弧线 /// @brief 添加弧线
@ -113,63 +102,42 @@ public:
/// @param rotation 椭圆旋转角度 /// @param rotation 椭圆旋转角度
/// @param clockwise 顺时针 or 逆时针 /// @param clockwise 顺时针 or 逆时针
/// @param is_small 是否取小于 180° 的弧 /// @param is_small 是否取小于 180° 的弧
ShapeSink& AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
bool is_small = true);
/// \~chinese /// \~chinese
/// @brief 合形状,并将结果输出到流中 /// @brief 形状
/// @param shape_a 输入的形状A /// @param shape_a 输入的形状A
/// @param shape_b 输入的形状B /// @param shape_b 输入的形状B
/// @param mode 合方式 /// @param mode 方式
/// @param matrix 应用到输入形状B上的二维变换 /// @param matrix 应用到输入形状B上的二维变换
/// @note 若还未打开输入流,则自动打开 /// @return 返回合并后的形状
ShapeSink& Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mode, const Matrix3x2* matrix = nullptr); static ShapePtr Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mode, const Matrix3x2* matrix = nullptr);
/// \~chinese /// \~chinese
/// @brief 清空图形 /// @brief 设置生成的形状
void Clear(); /// @note 应由系统调用该函数
void SetShape(ShapePtr shape);
private:
/// \~chinese
/// @brief 打开输入流
/// @note 应由系统调用该函数
void OpenStream();
/// \~chinese
/// @brief 关闭输入流
/// @note 应由系统调用该函数
void CloseStream();
/// \~chinese
/// @brief 输入流是否已经打开
/// @note 应由系统调用该函数
bool IsStreamOpened() const;
private: private:
ShapePtr shape_; ShapePtr shape_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<ID2D1PathGeometry> GetPathGeometry() const;
void SetPathGeometry(ComPtr<ID2D1PathGeometry> path);
ComPtr<ID2D1GeometrySink> GetGeometrySink() const;
void SetGeometrySink(ComPtr<ID2D1GeometrySink> sink);
private:
ComPtr<ID2D1GeometrySink> sink_;
ComPtr<ID2D1PathGeometry> path_geo_;
#endif
}; };
/** @} */ /** @} */
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline ComPtr<ID2D1PathGeometry> ShapeSink::GetPathGeometry() const
{
return path_geo_;
}
inline void ShapeSink::SetPathGeometry(ComPtr<ID2D1PathGeometry> path)
{
path_geo_ = path;
}
inline ComPtr<ID2D1GeometrySink> ShapeSink::GetGeometrySink() const
{
return sink_;
}
inline void ShapeSink::SetGeometrySink(ComPtr<ID2D1GeometrySink> sink)
{
sink_ = sink;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -1,220 +0,0 @@
// 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 <kiwano/render/ShapeSink.h>
#include <kiwano/render/Renderer.h>
namespace kiwano
{
ShapeSink::ShapeSink() {}
ShapeSink::~ShapeSink()
{
Close();
}
void ShapeSink::Open()
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (!IsOpened())
{
path_geo_.Reset();
Renderer::GetInstance().CreateShapeSink(*this);
KGE_THROW_IF_FAILED(path_geo_->Open(&sink_), "Open ID2D1GeometrySink failed");
}
#else
return; // not supported
#endif
}
void ShapeSink::Close()
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (IsOpened())
{
KGE_THROW_IF_FAILED(sink_->Close(), "Close ID2D1GeometrySink failed");
sink_.Reset();
}
shape_ = new Shape;
shape_->SetGeometry(path_geo_);
#else
return; // not supported
#endif
}
bool ShapeSink::IsOpened() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return sink_ != nullptr;
#else
return false; // not supported
#endif
}
ShapePtr ShapeSink::GetShape()
{
Close();
return shape_;
}
ShapeSink& ShapeSink::AddShape(ShapePtr input, const Matrix3x2* input_matrix)
{
if (!IsOpened())
{
Open();
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (input && input->IsValid())
{
ComPtr<ID2D1Geometry> geo = input->GetGeometry();
HRESULT hr =
geo->Outline(DX::ConvertToMatrix3x2F(input_matrix), D2D1_DEFAULT_FLATTENING_TOLERANCE, sink_.Get());
KGE_THROW_IF_FAILED(hr, "Get outline of ID2D1Geometry failed");
}
return (*this);
#else
return (*this); // not supported
#endif
}
ShapeSink& ShapeSink::BeginPath(Point const& begin_pos)
{
if (!IsOpened())
{
Open();
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
#else
// not supported
#endif
return (*this);
}
ShapeSink& ShapeSink::EndPath(bool closed)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(sink_);
sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
#else
// not supported
#endif
return (*this);
}
ShapeSink& ShapeSink::AddLine(Point const& point)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(sink_);
sink_->AddLine(DX::ConvertToPoint2F(point));
#else
// not supported
#endif
return (*this);
}
ShapeSink& ShapeSink::AddLines(Vector<Point> const& points)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(sink_);
sink_->AddLines(reinterpret_cast<const D2D_POINT_2F*>(&points[0]), static_cast<uint32_t>(points.size()));
#else
// not supported
#endif
return (*this);
}
ShapeSink& kiwano::ShapeSink::AddLines(const Point* points, size_t count)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(sink_);
sink_->AddLines(reinterpret_cast<const D2D_POINT_2F*>(points), UINT32(count));
#else
// not supported
#endif
return (*this);
}
ShapeSink& ShapeSink::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(sink_);
sink_->AddBezier(
D2D1::BezierSegment(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), DX::ConvertToPoint2F(point3)));
#else
// not supported
#endif
return (*this);
}
ShapeSink& ShapeSink::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(sink_);
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));
#else
// not supported
#endif
return (*this);
}
ShapeSink& ShapeSink::Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mode, const Matrix3x2* matrix)
{
if (!IsOpened())
{
Open();
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (shape_a && shape_b)
{
ComPtr<ID2D1Geometry> geo_a_raw = shape_a->geo_;
ComPtr<ID2D1Geometry> geo_b_raw = shape_b->geo_;
HRESULT hr = geo_a_raw->CombineWithGeometry(geo_b_raw.Get(), D2D1_COMBINE_MODE(mode),
DX::ConvertToMatrix3x2F(matrix), sink_.Get());
KGE_THROW_IF_FAILED(hr, "Combine ID2D1Geometry failed");
}
#else
// not supported
#endif
return (*this);
}
void ShapeSink::Clear()
{
Close();
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
path_geo_.Reset();
#else
// not supported
#endif
}
} // namespace kiwano

View File

@ -24,11 +24,18 @@
namespace kiwano namespace kiwano
{ {
StrokeStylePtr StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, DashStyle dash, float dash_offset) StrokeStylePtr StrokeStyle::Create(float width, CapStyle cap, LineJoinStyle line_join)
{
return StrokeStyle::Create(width, cap, line_join, DashStyle::Solid);
}
StrokeStylePtr StrokeStyle::Create(float width, CapStyle cap, LineJoinStyle line_join, DashStyle dash,
float dash_offset)
{ {
StrokeStylePtr ptr = new (std::nothrow) StrokeStyle; StrokeStylePtr ptr = new (std::nothrow) StrokeStyle;
if (ptr) if (ptr)
{ {
ptr->SetStrokeWidth(width);
ptr->SetCapStyle(cap); ptr->SetCapStyle(cap);
ptr->SetLineJoinStyle(line_join); ptr->SetLineJoinStyle(line_join);
ptr->SetDashStyle(dash); ptr->SetDashStyle(dash);
@ -37,12 +44,13 @@ StrokeStylePtr StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, DashSt
return ptr; return ptr;
} }
StrokeStylePtr StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, const float* dash_array, size_t dash_size, StrokeStylePtr StrokeStyle::Create(float width, CapStyle cap, LineJoinStyle line_join, const float* dash_array,
float dash_offset) size_t dash_size, float dash_offset)
{ {
StrokeStylePtr ptr = new (std::nothrow) StrokeStyle; StrokeStylePtr ptr = new (std::nothrow) StrokeStyle;
if (ptr) if (ptr)
{ {
ptr->SetStrokeWidth(width);
ptr->SetCapStyle(cap); ptr->SetCapStyle(cap);
ptr->SetLineJoinStyle(line_join); ptr->SetLineJoinStyle(line_join);
ptr->SetDashStyle(dash_array, dash_size); ptr->SetDashStyle(dash_array, dash_size);
@ -55,6 +63,7 @@ StrokeStyle::StrokeStyle()
: cap_(CapStyle::Flat) : cap_(CapStyle::Flat)
, line_join_(LineJoinStyle::Miter) , line_join_(LineJoinStyle::Miter)
, dash_offset_(0.0f) , dash_offset_(0.0f)
, stroke_width_(1.0f)
{ {
} }
@ -100,7 +109,6 @@ void StrokeStyle::SetDashStyle(DashStyle dash_style)
void StrokeStyle::SetDashStyle(const Vector<float>& dash_array) void StrokeStyle::SetDashStyle(const Vector<float>& dash_array)
{ {
dash_array_ = dash_array; dash_array_ = dash_array;
style_.Reset();
} }
void StrokeStyle::SetDashStyle(const float* dash_array, size_t dash_size) void StrokeStyle::SetDashStyle(const float* dash_array, size_t dash_size)
@ -109,20 +117,6 @@ void StrokeStyle::SetDashStyle(const float* dash_array, size_t dash_size)
dash_array_.clear(); dash_array_.clear();
else else
dash_array_.assign(dash_array, dash_array + dash_size); dash_array_.assign(dash_array, dash_array + dash_size);
style_.Reset();
} }
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
ComPtr<ID2D1StrokeStyle> StrokeStyle::GetStrokeStyle() const
{
StrokeStyle& self = const_cast<StrokeStyle&>(*this);
if (dash_array_.empty())
Renderer::GetInstance().CreateStrokeStyle(self, cap_, line_join_, nullptr, 0, dash_offset_);
else
Renderer::GetInstance().CreateStrokeStyle(self, cap_, line_join_, &dash_array_[0], dash_array_.size(),
dash_offset_);
return style_;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -19,8 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/core/ObjectBase.h> #include <kiwano/render/NativeObject.h>
#include <kiwano/render/DirectX/D2DDeviceResources.h>
namespace kiwano namespace kiwano
{ {
@ -67,47 +66,59 @@ enum class DashStyle
/// \~chinese /// \~chinese
/// @brief 线条样式 /// @brief 线条样式
class StrokeStyle : public virtual ObjectBase class StrokeStyle : public NativeObject
{ {
public: public:
/// \~chinese /// \~chinese
/// @brief 创建线条样式 /// @brief 创建线条样式
/// @param width 线条宽度
/// @param cap 线条端点样式
/// @param line_join 线条交点样式
static StrokeStylePtr Create(float width, CapStyle cap = CapStyle::Flat,
LineJoinStyle line_join = LineJoinStyle::Miter);
/// \~chinese
/// @brief 创建线条样式
/// @param width 线条宽度
/// @param cap 线条端点样式 /// @param cap 线条端点样式
/// @param line_join 线条交点样式 /// @param line_join 线条交点样式
/// @param dash 线条虚线样式 /// @param dash 线条虚线样式
/// @param dash_offset 线条虚线偏移量 /// @param dash_offset 线条虚线偏移量
static StrokeStylePtr Create(CapStyle cap, LineJoinStyle line_join = LineJoinStyle::Miter, static StrokeStylePtr Create(float width, CapStyle cap, LineJoinStyle line_join, DashStyle dash,
DashStyle dash = DashStyle::Solid, float dash_offset = 0.0f); float dash_offset = 0.0f);
/// \~chinese /// \~chinese
/// @brief 创建线条样式 /// @brief 创建线条样式
/// @param width 线条宽度
/// @param cap 线条端点样式 /// @param cap 线条端点样式
/// @param line_join 线条交点样式 /// @param line_join 线条交点样式
/// @param dash_array 线条虚线的长度与间隙数组 /// @param dash_array 线条虚线的长度与间隙数组
/// @param dash_size 线条虚线数组大小 /// @param dash_size 线条虚线数组大小
/// @param dash_offset 线条虚线偏移量 /// @param dash_offset 线条虚线偏移量
static StrokeStylePtr Create(CapStyle cap, LineJoinStyle line_join = LineJoinStyle::Miter, static StrokeStylePtr Create(float width, CapStyle cap, LineJoinStyle line_join, const float* dash_array,
const float* dash_array = nullptr, size_t dash_size = 0, float dash_offset = 0.0f); size_t dash_size, float dash_offset = 0.0f);
/// \~chinese /// \~chinese
/// @brief 创建线条样式 /// @brief 创建线条样式
/// @tparam _DashSize 线条虚线数组大小 /// @tparam _DashSize 线条虚线数组大小
/// @param width 线条宽度
/// @param cap 线条端点样式 /// @param cap 线条端点样式
/// @param line_join 线条交点样式 /// @param line_join 线条交点样式
/// @param dash_array 线条虚线的长度与间隙数组 /// @param dash_array 线条虚线的长度与间隙数组
/// @param dash_offset 线条虚线偏移量 /// @param dash_offset 线条虚线偏移量
template <size_t _DashSize> template <size_t _DashSize>
static inline StrokeStylePtr Create(CapStyle cap, LineJoinStyle line_join = LineJoinStyle::Miter, static inline StrokeStylePtr Create(float width, CapStyle cap, LineJoinStyle line_join,
float (&dash_array)[_DashSize] = nullptr, float dash_offset = 0.0f) float (&dash_array)[_DashSize], float dash_offset = 0.0f)
{ {
return StrokeStyle::Create(cap, line_join, dash_array, _DashSize, dash_offset); return StrokeStyle::Create(width, cap, line_join, dash_array, _DashSize, dash_offset);
} }
StrokeStyle(); StrokeStyle();
/// \~chinese /// \~chinese
/// @brief 是否有效 /// @brief 获取线条宽度
bool IsValid() const; /// @param width 线条宽度
float GetStrokeWidth() const;
/// \~chinese /// \~chinese
/// @brief 获取线条端点样式 /// @brief 获取线条端点样式
@ -125,6 +136,11 @@ public:
/// @brief 获取虚线偏移量 /// @brief 获取虚线偏移量
float GetDashOffset() const; float GetDashOffset() const;
/// \~chinese
/// @brief 设置线条宽度
/// @param width 线条宽度
void SetStrokeWidth(float width);
/// \~chinese /// \~chinese
/// @brief 设置线条端点样式 /// @brief 设置线条端点样式
void SetCapStyle(CapStyle cap); void SetCapStyle(CapStyle cap);
@ -167,22 +183,18 @@ public:
private: private:
CapStyle cap_; CapStyle cap_;
LineJoinStyle line_join_; LineJoinStyle line_join_;
float stroke_width_;
float dash_offset_; float dash_offset_;
Vector<float> dash_array_; Vector<float> dash_array_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<ID2D1StrokeStyle> GetStrokeStyle() const;
void SetStrokeStyle(ComPtr<ID2D1StrokeStyle> style);
private:
ComPtr<ID2D1StrokeStyle> style_;
#endif
}; };
/** @} */ /** @} */
inline float StrokeStyle::GetStrokeWidth() const
{
return stroke_width_;
}
inline CapStyle StrokeStyle::GetCapStyle() const inline CapStyle StrokeStyle::GetCapStyle() const
{ {
return cap_; return cap_;
@ -203,38 +215,24 @@ inline float StrokeStyle::GetDashOffset() const
return dash_offset_; return dash_offset_;
} }
inline void StrokeStyle::SetStrokeWidth(float width)
{
stroke_width_ = width;
}
inline void StrokeStyle::SetCapStyle(CapStyle cap) inline void StrokeStyle::SetCapStyle(CapStyle cap)
{ {
cap_ = cap; cap_ = cap;
style_.Reset();
} }
inline void StrokeStyle::SetLineJoinStyle(LineJoinStyle line_join) inline void StrokeStyle::SetLineJoinStyle(LineJoinStyle line_join)
{ {
line_join_ = line_join; line_join_ = line_join;
style_.Reset();
} }
inline void StrokeStyle::SetDashOffset(float dash_offset) inline void StrokeStyle::SetDashOffset(float dash_offset)
{ {
dash_offset_ = dash_offset; dash_offset_ = dash_offset;
style_.Reset();
} }
inline bool StrokeStyle::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return style_ != nullptr;
#else
return false; // not supported
#endif
}
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline void StrokeStyle::SetStrokeStyle(ComPtr<ID2D1StrokeStyle> style)
{
style_ = style;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -21,6 +21,10 @@
#include <kiwano/render/Renderer.h> #include <kiwano/render/Renderer.h>
#include <kiwano/render/TextLayout.h> #include <kiwano/render/TextLayout.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
#endif
namespace kiwano namespace kiwano
{ {
TextLayoutPtr TextLayout::Create() TextLayoutPtr TextLayout::Create()
@ -41,7 +45,6 @@ TextLayoutPtr TextLayout::Create(const String& content, const TextStyle& style)
TextLayout::TextLayout() TextLayout::TextLayout()
: dirty_flag_(DirtyFlag::Clean) : dirty_flag_(DirtyFlag::Clean)
, default_outline_width_(0.0f)
{ {
} }
@ -54,12 +57,16 @@ void TextLayout::Reset(const String& text, const TextStyle& style)
SetAlignment(style.alignment); SetAlignment(style.alignment);
SetWrapWidth(style.wrap_width); SetWrapWidth(style.wrap_width);
SetLineSpacing(style.line_spacing); SetLineSpacing(style.line_spacing);
SetUnderline(style.show_underline, { 0, text.length() });
SetStrikethrough(style.show_strikethrough, { 0, text.length() });
SetDefaultFillBrush(style.fill_brush); SetDefaultFillBrush(style.fill_brush);
SetDefaultOutlineBrush(style.outline_brush); SetDefaultOutlineBrush(style.outline_brush);
SetDefaultOutlineWidth(style.outline_width);
SetDefaultOutlineStrokeStyle(style.outline_stroke); SetDefaultOutlineStrokeStyle(style.outline_stroke);
if (style.show_underline)
SetUnderline(style.show_underline, { 0, text.length() });
if (style.show_strikethrough)
SetStrikethrough(style.show_strikethrough, { 0, text.length() });
} }
else else
{ {
@ -70,10 +77,13 @@ void TextLayout::Reset(const String& text, const TextStyle& style)
uint32_t TextLayout::GetLineCount() const uint32_t TextLayout::GetLineCount() const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (text_layout_) auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{ {
DWRITE_TEXT_METRICS metrics; DWRITE_TEXT_METRICS metrics;
if (SUCCEEDED(GetTextLayout()->GetMetrics(&metrics))) if (SUCCEEDED(native->GetMetrics(&metrics)))
{ {
return metrics.lineCount; return metrics.lineCount;
} }
@ -87,10 +97,13 @@ uint32_t TextLayout::GetLineCount() const
Size TextLayout::GetLayoutSize() const Size TextLayout::GetLayoutSize() const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (text_layout_) auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{ {
DWRITE_TEXT_METRICS metrics; DWRITE_TEXT_METRICS metrics;
if (SUCCEEDED(GetTextLayout()->GetMetrics(&metrics))) if (SUCCEEDED(native->GetMetrics(&metrics)))
{ {
return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height) return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height)
: Size(metrics.width, metrics.height); : Size(metrics.width, metrics.height);
@ -105,12 +118,14 @@ Size TextLayout::GetLayoutSize() const
void TextLayout::SetFont(FontPtr font, TextRange range) void TextLayout::SetFont(FontPtr font, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
{
IDWriteFontCollection* collection = font ? font->GetCollection().Get() : nullptr;
HRESULT hr = text_layout_->SetFontCollection(collection, { range.start, range.length }); if (native)
{
ComPtr<IDWriteFontCollection> collection = NativePtr::Get<IDWriteFontCollection>(font);
HRESULT hr = native->SetFontCollection(collection.Get(), { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontCollection failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontCollection failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -123,12 +138,14 @@ void TextLayout::SetFont(FontPtr font, TextRange range)
void TextLayout::SetFontFamily(String const& family, TextRange range) void TextLayout::SetFontFamily(String const& family, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
WideString font_family = family.empty() ? L"" : string::ToWide(family); WideString font_family = family.empty() ? L"" : string::ToWide(family);
HRESULT hr = text_layout_->SetFontFamilyName(font_family.c_str(), { range.start, range.length }); HRESULT hr = native->SetFontFamilyName(font_family.c_str(), { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontFamilyName failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontFamilyName failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -141,10 +158,12 @@ void TextLayout::SetFontFamily(String const& family, TextRange range)
void TextLayout::SetFontSize(float size, TextRange range) void TextLayout::SetFontSize(float size, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
HRESULT hr = text_layout_->SetFontSize(size, { range.start, range.length }); HRESULT hr = native->SetFontSize(size, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontSize failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontSize failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -157,12 +176,14 @@ void TextLayout::SetFontSize(float size, TextRange range)
void TextLayout::SetFontWeight(uint32_t weight, TextRange range) void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
DWRITE_FONT_WEIGHT font_weight = DWRITE_FONT_WEIGHT(weight); DWRITE_FONT_WEIGHT font_weight = DWRITE_FONT_WEIGHT(weight);
HRESULT hr = text_layout_->SetFontWeight(font_weight, { range.start, range.length }); HRESULT hr = native->SetFontWeight(font_weight, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontWeight failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontWeight failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -175,12 +196,14 @@ void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
void TextLayout::SetItalic(bool italic, TextRange range) void TextLayout::SetItalic(bool italic, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
DWRITE_FONT_STYLE font_style = italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; DWRITE_FONT_STYLE font_style = italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
HRESULT hr = text_layout_->SetFontStyle(font_style, { range.start, range.length }); HRESULT hr = native->SetFontStyle(font_style, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontStyle failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontStyle failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -193,10 +216,12 @@ void TextLayout::SetItalic(bool italic, TextRange range)
void TextLayout::SetUnderline(bool enable, TextRange range) void TextLayout::SetUnderline(bool enable, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
HRESULT hr = text_layout_->SetUnderline(enable, { range.start, range.length }); HRESULT hr = native->SetUnderline(enable, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetUnderline failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetUnderline failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -209,10 +234,12 @@ void TextLayout::SetUnderline(bool enable, TextRange range)
void TextLayout::SetStrikethrough(bool enable, TextRange range) void TextLayout::SetStrikethrough(bool enable, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
HRESULT hr = text_layout_->SetStrikethrough(enable, { range.start, range.length }); HRESULT hr = native->SetStrikethrough(enable, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetStrikethrough failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetStrikethrough failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -225,10 +252,13 @@ void TextLayout::SetStrikethrough(bool enable, TextRange range)
void TextLayout::SetFillBrush(BrushPtr brush, TextRange range) void TextLayout::SetFillBrush(BrushPtr brush, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
HRESULT hr = text_layout_->SetDrawingEffect(brush->GetBrush().Get(), { range.start, range.length }); HRESULT hr =
native->SetDrawingEffect(NativePtr::Get<ID2D1Brush>(brush).Get(), { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetDrawingEffect failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetDrawingEffect failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -249,17 +279,6 @@ void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range)
#endif #endif
} }
void TextLayout::SetOutlineWidth(float width, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
// TODO
KGE_NOT_USED(range);
SetDefaultOutlineWidth(width);
#else
return; // not supported
#endif
}
void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range) void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
@ -274,8 +293,10 @@ void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range)
void TextLayout::SetAlignment(TextAlign align) void TextLayout::SetAlignment(TextAlign align)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT(); DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT();
switch (align) switch (align)
@ -294,7 +315,7 @@ void TextLayout::SetAlignment(TextAlign align)
break; break;
} }
HRESULT hr = text_layout_->SetTextAlignment(alignment); HRESULT hr = native->SetTextAlignment(alignment);
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetTextAlignment failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetTextAlignment failed");
dirty_flag_ = DirtyFlag::Updated; dirty_flag_ = DirtyFlag::Updated;
@ -307,27 +328,29 @@ void TextLayout::SetAlignment(TextAlign align)
void TextLayout::SetWrapWidth(float wrap_width) void TextLayout::SetWrapWidth(float wrap_width)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
DWRITE_WORD_WRAPPING wrapping = (wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP; DWRITE_WORD_WRAPPING wrapping = (wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP;
HRESULT hr = text_layout_->SetWordWrapping(wrapping); HRESULT hr = native->SetWordWrapping(wrapping);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
if (wrap_width > 0) if (wrap_width > 0)
{ {
hr = text_layout_->SetMaxWidth(wrap_width); hr = native->SetMaxWidth(wrap_width);
} }
else else
{ {
// Fix the layout width when the text does not wrap // Fix the layout width when the text does not wrap
DWRITE_TEXT_METRICS metrics; DWRITE_TEXT_METRICS metrics;
hr = text_layout_->GetMetrics(&metrics); hr = native->GetMetrics(&metrics);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = text_layout_->SetMaxWidth(metrics.width); hr = native->SetMaxWidth(metrics.width);
} }
} }
} }
@ -343,19 +366,21 @@ void TextLayout::SetWrapWidth(float wrap_width)
void TextLayout::SetLineSpacing(float line_spacing) void TextLayout::SetLineSpacing(float line_spacing)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_); auto native = NativePtr::Get<IDWriteTextLayout>(this);
if (text_layout_) KGE_ASSERT(native);
if (native)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
float spacing = line_spacing; float spacing = line_spacing;
if (spacing == 0.f) if (spacing == 0.f)
{ {
hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); hr = native->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
} }
else else
{ {
hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, spacing, spacing * 0.8f); hr = native->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, spacing, spacing * 0.8f);
} }
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetLineSpacing failed"); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetLineSpacing failed");

View File

@ -20,7 +20,7 @@
#pragma once #pragma once
#include <kiwano/math/Math.h> #include <kiwano/math/Math.h>
#include <kiwano/core/ObjectBase.h> #include <kiwano/render/NativeObject.h>
#include <kiwano/render/TextStyle.hpp> #include <kiwano/render/TextStyle.hpp>
namespace kiwano namespace kiwano
@ -35,7 +35,7 @@ KGE_DECLARE_SMART_PTR(TextLayout);
/// \~chinese /// \~chinese
/// @brief 文本布局 /// @brief 文本布局
class KGE_API TextLayout : public virtual ObjectBase class KGE_API TextLayout : public NativeObject
{ {
public: public:
/// \~chinese /// \~chinese
@ -52,10 +52,6 @@ public:
/// @brief 构造空的文本布局 /// @brief 构造空的文本布局
TextLayout(); TextLayout();
/// \~chinese
/// @brief 文本布局是否有效
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 文本布局是否陈旧 /// @brief 文本布局是否陈旧
bool IsDirty() const; bool IsDirty() const;
@ -86,10 +82,6 @@ public:
/// @brief 获取默认描边画刷 /// @brief 获取默认描边画刷
BrushPtr GetDefaultOutlineBrush() const; BrushPtr GetDefaultOutlineBrush() const;
/// \~chinese
/// @brief 获取默认描边宽度
float GetDefaultOutlineWidth() const;
/// \~chinese /// \~chinese
/// @brief 获取默认描边线条样式 /// @brief 获取默认描边线条样式
StrokeStylePtr GetDefaultOutlineStrokeStyle() const; StrokeStylePtr GetDefaultOutlineStrokeStyle() const;
@ -156,12 +148,6 @@ public:
/// @param range 文字范围 /// @param range 文字范围
void SetOutlineBrush(BrushPtr brush, TextRange range); void SetOutlineBrush(BrushPtr brush, TextRange range);
/// \~chinese
/// @brief 设置文字描边线宽
/// @param width 描边线宽
/// @param range 文字范围
void SetOutlineWidth(float width, TextRange range);
/// \~chinese /// \~chinese
/// @brief 设置描边线条样式 /// @brief 设置描边线条样式
/// @param stroke 线条样式 /// @param stroke 线条样式
@ -191,11 +177,6 @@ public:
/// @param brush 画刷 /// @param brush 画刷
void SetDefaultOutlineBrush(BrushPtr brush); void SetDefaultOutlineBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置默认文字描边线宽
/// @param width 描边线宽
void SetDefaultOutlineWidth(float width);
/// \~chinese /// \~chinese
/// @brief 设置默认描边线条样式 /// @brief 设置默认描边线条样式
/// @param stroke 线条样式 /// @param stroke 线条样式
@ -218,31 +199,11 @@ private:
DirtyFlag dirty_flag_; DirtyFlag dirty_flag_;
BrushPtr default_fill_brush_; BrushPtr default_fill_brush_;
BrushPtr default_outline_brush_; BrushPtr default_outline_brush_;
float default_outline_width_;
StrokeStylePtr default_outline_stroke_; StrokeStylePtr default_outline_stroke_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
ComPtr<IDWriteTextLayout> GetTextLayout() const;
void SetTextLayout(ComPtr<IDWriteTextLayout> layout);
private:
ComPtr<IDWriteTextLayout> text_layout_;
#endif
}; };
/** @} */ /** @} */
inline bool TextLayout::IsValid() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
return text_layout_ != nullptr;
#else
return false; // not supported
#endif
}
inline bool TextLayout::IsDirty() const inline bool TextLayout::IsDirty() const
{ {
return dirty_flag_ != DirtyFlag::Clean; return dirty_flag_ != DirtyFlag::Clean;
@ -250,12 +211,7 @@ inline bool TextLayout::IsDirty() const
inline void TextLayout::Clear() inline void TextLayout::Clear()
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX ResetNativePointer();
text_layout_ = nullptr;
dirty_flag_ = DirtyFlag::Updated;
#else
return; // not supported
#endif
} }
inline TextLayout::DirtyFlag TextLayout::GetDirtyFlag() const inline TextLayout::DirtyFlag TextLayout::GetDirtyFlag() const
@ -278,11 +234,6 @@ inline BrushPtr TextLayout::GetDefaultOutlineBrush() const
return default_outline_brush_; return default_outline_brush_;
} }
inline float TextLayout::GetDefaultOutlineWidth() const
{
return default_outline_width_;
}
inline StrokeStylePtr TextLayout::GetDefaultOutlineStrokeStyle() const inline StrokeStylePtr TextLayout::GetDefaultOutlineStrokeStyle() const
{ {
return default_outline_stroke_; return default_outline_stroke_;
@ -298,26 +249,9 @@ inline void TextLayout::SetDefaultOutlineBrush(BrushPtr brush)
default_outline_brush_ = brush; default_outline_brush_ = brush;
} }
inline void TextLayout::SetDefaultOutlineWidth(float width)
{
default_outline_width_ = width;
}
inline void TextLayout::SetDefaultOutlineStrokeStyle(StrokeStylePtr stroke) inline void TextLayout::SetDefaultOutlineStrokeStyle(StrokeStylePtr stroke)
{ {
default_outline_stroke_ = stroke; default_outline_stroke_ = stroke;
} }
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
inline ComPtr<IDWriteTextLayout> TextLayout::GetTextLayout() const
{
return text_layout_;
}
inline void TextLayout::SetTextLayout(ComPtr<IDWriteTextLayout> layout)
{
text_layout_ = layout;
}
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -78,8 +78,7 @@ public:
TextAlign alignment; ///< 对齐方式 TextAlign alignment; ///< 对齐方式
BrushPtr fill_brush; ///< 填充画刷 BrushPtr fill_brush; ///< 填充画刷
BrushPtr outline_brush; ///< 描边画刷 BrushPtr outline_brush; ///< 描边画刷
float outline_width; ///< 描边线宽 StrokeStylePtr outline_stroke; ///< 描边样式
StrokeStylePtr outline_stroke; ///< 描边线宽
float wrap_width; ///< 自动换行宽度 float wrap_width; ///< 自动换行宽度
float line_spacing; ///< 行间距 float line_spacing; ///< 行间距
bool show_underline; ///< 显示下划线 bool show_underline; ///< 显示下划线
@ -116,7 +115,6 @@ inline TextStyle::TextStyle(const String& font_family, float font_size, uint32_t
, font_weight(font_weight) , font_weight(font_weight)
, italic(false) , italic(false)
, alignment(TextAlign::Left) , alignment(TextAlign::Left)
, outline_width(1.0f)
, wrap_width(0) , wrap_width(0)
, line_spacing(0) , line_spacing(0)
, show_underline(false) , show_underline(false)

View File

@ -21,6 +21,10 @@
#include <kiwano/render/Renderer.h> #include <kiwano/render/Renderer.h>
#include <kiwano/render/Texture.h> #include <kiwano/render/Texture.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
#endif
namespace kiwano namespace kiwano
{ {
@ -67,47 +71,15 @@ bool Texture::Load(Resource const& res)
return IsValid(); return IsValid();
} }
float Texture::GetWidth() const
{
return size_.x;
}
float Texture::GetHeight() const
{
return size_.y;
}
Size Texture::GetSize() const
{
return size_;
}
uint32_t Texture::GetWidthInPixels() const
{
return size_in_pixels_.x;
}
uint32_t Texture::GetHeightInPixels() const
{
return size_in_pixels_.y;
}
math::Vec2T<uint32_t> Texture::GetSizeInPixels() const
{
return size_in_pixels_;
}
InterpolationMode Texture::GetBitmapInterpolationMode() const
{
return interpolation_mode_;
}
void Texture::CopyFrom(TexturePtr copy_from) void Texture::CopyFrom(TexturePtr copy_from)
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (IsValid() && copy_from) if (IsValid() && copy_from)
{ {
HRESULT hr = bitmap_->CopyFromBitmap(nullptr, copy_from->GetBitmap().Get(), nullptr); auto native = NativePtr::Get<ID2D1Bitmap>(this);
auto native_to_copy = NativePtr::Get<ID2D1Bitmap>(copy_from);
HRESULT hr = native->CopyFromBitmap(nullptr, native_to_copy.Get(), nullptr);
KGE_THROW_IF_FAILED(hr, "Copy texture data failed"); KGE_THROW_IF_FAILED(hr, "Copy texture data failed");
} }
@ -121,10 +93,13 @@ void Texture::CopyFrom(TexturePtr copy_from, Rect const& src_rect, Point const&
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (IsValid() && copy_from) if (IsValid() && copy_from)
{ {
HRESULT hr = bitmap_->CopyFromBitmap( auto native = NativePtr::Get<ID2D1Bitmap>(this);
&D2D1::Point2U(uint32_t(dest_point.x), uint32_t(dest_point.y)), copy_from->GetBitmap().Get(), auto native_to_copy = NativePtr::Get<ID2D1Bitmap>(copy_from);
&D2D1::RectU(uint32_t(src_rect.GetLeft()), uint32_t(src_rect.GetTop()), uint32_t(src_rect.GetRight()),
uint32_t(src_rect.GetBottom()))); HRESULT hr =
native->CopyFromBitmap(&D2D1::Point2U(uint32_t(dest_point.x), uint32_t(dest_point.y)), native_to_copy.Get(),
&D2D1::RectU(uint32_t(src_rect.GetLeft()), uint32_t(src_rect.GetTop()),
uint32_t(src_rect.GetRight()), uint32_t(src_rect.GetBottom())));
KGE_THROW_IF_FAILED(hr, "Copy texture data failed"); KGE_THROW_IF_FAILED(hr, "Copy texture data failed");
} }

View File

@ -19,9 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/Resource.h> #include <kiwano/core/Resource.h>
#include <kiwano/render/DirectX/D2DDeviceResources.h> #include <kiwano/render/NativeObject.h>
namespace kiwano namespace kiwano
{ {
@ -44,11 +43,15 @@ enum class InterpolationMode
Nearest ///< 最邻近插值,取最邻近的像素点的颜色值 Nearest ///< 最邻近插值,取最邻近的像素点的颜色值
}; };
/// \~chinese
/// @brief 像素大小
typedef math::Vec2T<uint32_t> PixelSize;
/** /**
* \~chinese * \~chinese
* @brief * @brief
*/ */
class KGE_API Texture : public virtual ObjectBase class KGE_API Texture : public NativeObject
{ {
public: public:
/// \~chinese /// \~chinese
@ -71,10 +74,6 @@ public:
/// @brief 加载资源 /// @brief 加载资源
bool Load(Resource const& res); bool Load(Resource const& res);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 获取纹理宽度 /// @brief 获取纹理宽度
float GetWidth() const; float GetWidth() const;
@ -97,11 +96,22 @@ public:
/// \~chinese /// \~chinese
/// @brief 获取像素大小 /// @brief 获取像素大小
math::Vec2T<uint32_t> GetSizeInPixels() const; PixelSize GetSizeInPixels() const;
/// \~chinese /// \~chinese
/// @brief 获取像素插值方式 /// @brief 获取像素插值方式
InterpolationMode GetBitmapInterpolationMode() const; InterpolationMode GetBitmapInterpolationMode() const;
/// \~chinese
/// @brief 设置大小
void SetSize(const Size& size);
/// \~chinese
/// @brief 设置像素大小
void SetSizeInPixels(const PixelSize& size);
/// \~chinese
/// @brief 设置像素插值方式
void SetInterpolationMode(InterpolationMode mode);
/// \~chinese /// \~chinese
/// @brief 拷贝纹理 /// @brief 拷贝纹理
@ -115,10 +125,6 @@ public:
/// @param dest_point 拷贝至目标位置 /// @param dest_point 拷贝至目标位置
void CopyFrom(TexturePtr copy_from, Rect const& src_rect, Point const& dest_point); void CopyFrom(TexturePtr copy_from, Rect const& src_rect, Point const& dest_point);
/// \~chinese
/// @brief 设置像素插值方式
void SetInterpolationMode(InterpolationMode mode);
/// \~chinese /// \~chinese
/// @brief 设置默认的像素插值方式 /// @brief 设置默认的像素插值方式
static void SetDefaultInterpolationMode(InterpolationMode mode); static void SetDefaultInterpolationMode(InterpolationMode mode);
@ -128,62 +134,58 @@ public:
static InterpolationMode GetDefaultInterpolationMode(); static InterpolationMode GetDefaultInterpolationMode();
private: private:
InterpolationMode interpolation_mode_; Size size_;
PixelSize size_in_pixels_;
InterpolationMode interpolation_mode_;
static InterpolationMode default_interpolation_mode_; static InterpolationMode default_interpolation_mode_;
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
public:
/// \~chinese
/// @brief 获取源位图
ComPtr<ID2D1Bitmap> GetBitmap() const;
/// \~chinese
/// @brief 设置源位图
void SetBitmap(ComPtr<ID2D1Bitmap> bitmap);
private:
ComPtr<ID2D1Bitmap> bitmap_;
Size size_;
math::Vec2T<uint32_t> size_in_pixels_;
#endif
}; };
/** @} */ /** @} */
inline bool Texture::IsValid() const inline float Texture::GetWidth() const
{ {
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX return size_.x;
return bitmap_ != nullptr;
#else
return false; // not supported
#endif
} }
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX inline float Texture::GetHeight() const
inline ComPtr<ID2D1Bitmap> Texture::GetBitmap() const
{ {
return bitmap_; return size_.y;
} }
inline void Texture::SetBitmap(ComPtr<ID2D1Bitmap> bitmap) inline Size Texture::GetSize() const
{ {
if (bitmap_ != bitmap) return size_;
{ }
bitmap_ = bitmap;
inline uint32_t Texture::GetWidthInPixels() const
if (bitmap_) {
{ return size_in_pixels_.x;
auto size = bitmap_->GetSize(); }
auto pixel_size = bitmap_->GetPixelSize();
inline uint32_t Texture::GetHeightInPixels() const
size_.x = size.width; {
size_.y = size.height; return size_in_pixels_.y;
size_in_pixels_.x = pixel_size.width; }
size_in_pixels_.y = pixel_size.height;
} inline PixelSize Texture::GetSizeInPixels() const
} {
return size_in_pixels_;
}
inline InterpolationMode Texture::GetBitmapInterpolationMode() const
{
return interpolation_mode_;
}
inline void Texture::SetSize(const Size& size)
{
size_ = size;
}
inline void Texture::SetSizeInPixels(const PixelSize& size)
{
size_in_pixels_ = size;
} }
#endif
} // namespace kiwano } // namespace kiwano

View File

@ -401,7 +401,7 @@ bool LoadXmlData(ResourceCache* loader, const XmlNode& elem)
int rows = 0, cols = 0, max_num = -1; int rows = 0, cols = 0, max_num = -1;
if (auto attr = image.attribute("id")) if (auto attr = image.attribute("id"))
id.assign(attr.value()); id = attr.value();
if (auto attr = image.attribute("type")) if (auto attr = image.attribute("type"))
type = attr.value(); type = attr.value();
if (auto attr = image.attribute("file")) if (auto attr = image.attribute("file"))
@ -452,7 +452,7 @@ bool LoadXmlData(ResourceCache* loader, const XmlNode& elem)
{ {
String id, file; String id, file;
if (auto attr = font.attribute("id")) if (auto attr = font.attribute("id"))
id.assign(attr.value()); id = attr.value();
if (auto attr = font.attribute("file")) if (auto attr = font.attribute("file"))
file = attr.value(); file = attr.value();