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\FontCollectionLoader.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\RendererImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.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\ShapeSink.h" />
<ClInclude Include="..\..\src\kiwano\render\ShapeMaker.h" />
<ClInclude Include="..\..\src\kiwano\render\GifImage.h" />
<ClInclude Include="..\..\src\kiwano\render\Layer.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\Font.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\Layer.cpp" />
<ClCompile Include="..\..\src\kiwano\render\RenderContext.cpp" />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -58,8 +58,6 @@ ShapeActorPtr ShapeActor::Create(ShapePtr shape, BrushPtr fill_brush, BrushPtr s
}
ShapeActor::ShapeActor()
: stroke_width_(1.f)
, stroke_style_()
{
}
@ -108,7 +106,8 @@ void ShapeActor::OnRender(RenderContext& ctx)
if (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_)
@ -296,7 +295,12 @@ void PolygonActor::SetVertices(Vector<Point> const& points)
{
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/render/Brush.h>
#include <kiwano/render/Shape.h>
#include <kiwano/render/ShapeSink.h>
#include <kiwano/render/ShapeMaker.h>
#include <kiwano/render/StrokeStyle.h>
namespace kiwano
@ -81,10 +81,6 @@ public:
/// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const;
/// \~chinese
/// @brief 获取线条宽度
float GetStrokeWidth() const;
/// \~chinese
/// @brief 获取线条样式
StrokeStylePtr GetStrokeStyle() const;
@ -125,10 +121,6 @@ public:
/// @param[in] brush 轮廓画刷
void SetStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置线条宽度,默认为 1.0
void SetStrokeWidth(float width);
/// \~chinese
/// @brief 设置线条样式
void SetStrokeStyle(StrokeStylePtr stroke_style);
@ -145,7 +137,6 @@ protected:
private:
BrushPtr fill_brush_;
BrushPtr stroke_brush_;
float stroke_width_;
StrokeStylePtr stroke_style_;
Rect bounds_;
ShapePtr shape_;
@ -381,11 +372,6 @@ inline BrushPtr ShapeActor::GetStrokeBrush() const
return stroke_brush_;
}
inline float ShapeActor::GetStrokeWidth() const
{
return stroke_width_;
}
inline StrokeStylePtr ShapeActor::GetStrokeStyle() const
{
return stroke_style_;
@ -396,11 +382,6 @@ inline ShapePtr ShapeActor::GetShape() const
return shape_;
}
inline void ShapeActor::SetStrokeWidth(float width)
{
stroke_width_ = std::max(width, 0.f);
}
inline void ShapeActor::SetStrokeStyle(StrokeStylePtr 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)
{
if (style_.outline_stroke != stroke)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,8 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/ObjectBase.h>
#include <kiwano/render/DirectX/D2DDeviceResources.h>
#include <kiwano/render/NativeObject.h>
namespace kiwano
{
@ -85,7 +84,7 @@ struct RadialGradientStyle
* \~chinese
* @brief
*/
class KGE_API Brush : public virtual ObjectBase
class KGE_API Brush : public NativeObject
{
public:
/// \~chinese
@ -105,10 +104,6 @@ public:
Brush();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 设置纯色画刷颜色
void SetColor(Color const& color);
@ -138,16 +133,6 @@ public:
private:
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_;
}
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

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
// THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <kiwano/render/DirectX/RenderContextImpl.h>
#include <kiwano/render/DirectX/NativePtr.h>
#include <kiwano/core/Logger.h>
namespace kiwano
{
RenderContextImpl::RenderContextImpl()
{}
RenderContextImpl::RenderContextImpl() {}
RenderContextImpl::~RenderContextImpl()
{
@ -99,12 +99,19 @@ void RenderContextImpl::DrawTexture(Texture const& texture, const Rect* src_rect
if (texture.IsValid())
{
auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
: D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
D2D1_BITMAP_INTERPOLATION_MODE mode;
if (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
{
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,
brush_opacity_, mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
auto bitmap = NativePtr::Get<ID2D1Bitmap>(texture);
render_target_->DrawBitmap(bitmap.Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, brush_opacity_,
mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
IncreasePrimitivesCount();
}
@ -116,30 +123,28 @@ void RenderContextImpl::DrawTextLayout(TextLayout const& layout, Point const& of
if (layout.IsValid())
{
ComPtr<ID2D1Brush> fill_brush;
ComPtr<ID2D1Brush> outline_brush;
ComPtr<ID2D1StrokeStyle> outline_stroke;
auto native = NativePtr::Get<IDWriteTextLayout>(layout);
auto fill_brush = NativePtr::Get<ID2D1Brush>(layout.GetDefaultFillBrush());
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_);
}
if (layout.GetDefaultOutlineBrush())
if (outline_brush)
{
outline_brush = layout.GetDefaultOutlineBrush()->GetBrush();
outline_brush->SetOpacity(brush_opacity_);
}
if (layout.GetDefaultOutlineStrokeStyle())
{
outline_stroke = layout.GetDefaultOutlineStrokeStyle()->GetStrokeStyle();
outline_width = layout.GetDefaultOutlineStrokeStyle()->GetStrokeWidth();
}
float outline_width = layout.GetDefaultOutlineWidth();
HRESULT hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().Get(), offset.x, offset.y, fill_brush.Get(),
HRESULT hr = text_renderer_->DrawTextLayout(native.Get(), offset.x, offset.y, fill_brush.Get(),
outline_brush.Get(), outline_width, outline_stroke.Get());
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(current_brush_ && "The brush used for rendering has not been set!");
if (shape.IsValid())
{
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
render_target_->DrawGeometry(shape.GetGeometry().Get(), current_brush_->GetBrush().Get(), stroke_width,
stroke_style);
auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
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();
}
}
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(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2),
current_brush_->GetBrush().Get(), stroke_width, stroke_style);
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
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();
}
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(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().Get(), stroke_width,
stroke_style);
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
float stroke_width = current_stroke_ ? current_stroke_->GetStrokeWidth() : 1.0f;
render_target_->DrawRectangle(DX::ConvertToRectF(rect), brush.Get(), stroke_width, stroke_style.Get());
IncreasePrimitivesCount();
}
void RenderContextImpl::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke,
float stroke_width)
void RenderContextImpl::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius)
{
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y),
current_brush_->GetBrush().Get(), stroke_width, stroke_style);
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
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();
}
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(current_brush_ && "The brush used for rendering has not been set!");
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y),
current_brush_->GetBrush().Get(), stroke_width, stroke_style);
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
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();
}
@ -224,7 +242,9 @@ void RenderContextImpl::FillShape(Shape const& shape)
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();
}
@ -235,7 +255,8 @@ void RenderContextImpl::FillRectangle(Rect const& rect)
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
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();
}
@ -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(current_brush_ && "The brush used for rendering has not been set!");
render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y),
current_brush_->GetBrush().Get());
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get());
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(current_brush_ && "The brush used for rendering has not been set!");
render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y),
current_brush_->GetBrush().Get());
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get());
IncreasePrimitivesCount();
}
@ -272,7 +293,7 @@ void RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T<uint32_t> si
if (SUCCEEDED(hr))
{
texture.SetBitmap(saved_bitmap);
NativePtr::Set(texture, saved_bitmap);
}
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)
{
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()
@ -294,35 +324,27 @@ void RenderContextImpl::PopClipRect()
void RenderContextImpl::PushLayer(Layer& layer)
{
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))
{
layer.SetLayer(output);
}
else
{
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
NativePtr::Set(layer, native);
}
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
}
if (layer.IsValid())
{
ComPtr<ID2D1Geometry> mask;
if (layer.GetMaskShape())
mask = layer.GetMaskShape()->GetGeometry();
auto params = 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);
render_target_->PushLayer(
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());
}
render_target_->PushLayer(params, native.Get());
}
void RenderContextImpl::PopLayer()
@ -358,7 +380,7 @@ void RenderContextImpl::SetCurrentBrush(BrushPtr brush)
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
#include <kiwano/render/RenderContext.h>
#include <kiwano/render/DirectX/TextRenderer.h>
namespace kiwano
{
@ -43,15 +44,15 @@ public:
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;

View File

@ -23,9 +23,10 @@
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/platform/FileSystem.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/RendererImpl.h>
#include <kiwano/render/DirectX/NativePtr.h>
namespace kiwano
{
@ -226,7 +227,10 @@ void RendererImpl::CreateTexture(Texture& texture, String const& file_path)
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))
{
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))
{
gif.SetDecoder(decoder);
NativePtr::Set(gif, decoder);
}
}
@ -345,7 +352,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, Resource const& resource)
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;
}
if (gif.GetDecoder() == nullptr)
auto decoder = NativePtr::Get<IWICBitmapDecoder>(gif);
if (!decoder)
{
hr = E_INVALIDARG;
}
@ -373,7 +382,7 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& g
{
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))
{
@ -383,13 +392,16 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& g
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> raw_bitmap;
hr = d2d_res_->CreateBitmapFromConverter(raw_bitmap, nullptr, converter);
ComPtr<ID2D1Bitmap> bitmap;
hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
if (SUCCEEDED(hr))
{
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))
{
font.SetCollection(font_collection);
NativePtr::Set(font, font_collection);
}
}
}
@ -579,7 +591,7 @@ void RendererImpl::CreateFontCollection(Font& font, Resource const& res)
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())
{
layout.SetTextLayout(nullptr);
layout.Clear();
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
return;
}
if (SUCCEEDED(hr))
{
ComPtr<IDWriteTextFormat> format;
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_STYLE font_style = style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
IDWriteFontCollection* collection = style.font ? style.font->GetCollection().Get() : nullptr;
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_STYLE font_style = style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
auto collection = NativePtr::Get<IDWriteFontCollection>(style.font);
ComPtr<IDWriteTextFormat> format;
hr = d2d_res_->CreateTextFormat(format, font_family.c_str(), collection, font_weight, font_style,
DWRITE_FONT_STRETCH_NORMAL, style.font_size);
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);
if (SUCCEEDED(hr))
{
layout.SetTextLayout(output);
NativePtr::Set(layout, output);
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
}
}
@ -639,29 +651,29 @@ void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point c
hr = E_UNEXPECTED;
}
ComPtr<ID2D1PathGeometry> path_geo;
ComPtr<ID2D1GeometrySink> path_sink;
if (SUCCEEDED(hr))
{
ComPtr<ID2D1PathGeometry> path_geo;
hr = d2d_res_->GetFactory()->CreatePathGeometry(&path_geo);
}
if (SUCCEEDED(hr))
{
hr = path_geo->Open(&path_sink);
}
if (SUCCEEDED(hr))
{
ComPtr<ID2D1GeometrySink> path_sink;
hr = path_geo->Open(&path_sink);
if (SUCCEEDED(hr))
{
path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
path_sink->AddLine(DX::ConvertToPoint2F(end_pos));
path_sink->EndFigure(D2D1_FIGURE_END_OPEN);
hr = path_sink->Close();
}
if (SUCCEEDED(hr))
{
path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
path_sink->AddLine(DX::ConvertToPoint2F(end_pos));
path_sink->EndFigure(D2D1_FIGURE_END_OPEN);
hr = path_sink->Close();
}
if (SUCCEEDED(hr))
{
shape.SetGeometry(path_geo);
if (SUCCEEDED(hr))
{
NativePtr::Set(shape, path_geo);
}
}
}
KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed");
@ -683,7 +695,7 @@ void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect)
if (SUCCEEDED(hr))
{
shape.SetGeometry(output);
NativePtr::Set(shape, output);
}
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))
{
shape.SetGeometry(output);
NativePtr::Set(shape, output);
}
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))
{
shape.SetGeometry(output);
NativePtr::Set(shape, output);
}
KGE_THROW_IF_FAILED(hr, "Create ID2D1EllipseGeometry failed");
}
void RendererImpl::CreateShapeSink(ShapeSink& sink)
void RendererImpl::CreateShapeSink(ShapeMaker& maker)
{
HRESULT hr = S_OK;
if (!d2d_res_)
@ -743,17 +755,20 @@ void RendererImpl::CreateShapeSink(ShapeSink& sink)
hr = E_UNEXPECTED;
}
ComPtr<ID2D1PathGeometry> output;
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetFactory()->CreatePathGeometry(&output);
}
ComPtr<ID2D1PathGeometry> geometry;
if (SUCCEEDED(hr))
{
sink.SetPathGeometry(output);
}
hr = d2d_res_->GetFactory()->CreatePathGeometry(&geometry);
if (SUCCEEDED(hr))
{
ShapePtr shape = new Shape;
NativePtr::Set(shape, geometry);
maker.SetShape(shape);
}
}
KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed");
}
@ -769,9 +784,9 @@ void RendererImpl::CreateBrush(Brush& brush, Color const& color)
{
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))
{
solid_brush->SetColor(DX::ConvertToColorF(color));
@ -783,7 +798,7 @@ void RendererImpl::CreateBrush(Brush& brush, Color const& color)
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))
{
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))
{
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");
}
void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
const float* dash_array, size_t dash_size, float dash_offset)
void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style)
{
HRESULT hr = S_OK;
if (!d2d_res_)
@ -867,16 +881,29 @@ void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, Li
if (SUCCEEDED(hr))
{
D2D1_STROKE_STYLE_PROPERTIES style =
D2D1::StrokeStyleProperties(D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap),
D2D1_LINE_JOIN(line_join), 10.0f, D2D1_DASH_STYLE_CUSTOM, dash_offset);
D2D1_CAP_STYLE cap = D2D1_CAP_STYLE(stroke_style.GetCapStyle());
D2D1_LINE_JOIN line_join = D2D1_LINE_JOIN(stroke_style.GetLineJoinStyle());
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;
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))
{
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 CreateShapeSink(ShapeSink& sink) override;
void CreateShapeSink(ShapeMaker& maker) override;
void CreateBrush(Brush& brush, Color const& color) override;
@ -76,8 +76,7 @@ public:
void CreateBrush(Brush& brush, RadialGradientStyle const& style) override;
void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, const float* dash_array,
size_t dash_size, float dash_offset) override;
void CreateStrokeStyle(StrokeStyle& stroke_style) override;
TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr) override;

View File

@ -21,6 +21,7 @@
#include <kiwano/core/Logger.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/render/DirectX/TextureRenderContextImpl.h>
#include <kiwano/render/DirectX/NativePtr.h>
namespace kiwano
{
@ -37,7 +38,10 @@ bool TextureRenderContextImpl::GetOutput(Texture& texture)
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);

View File

@ -19,10 +19,8 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/ObjectBase.h>
#include <kiwano/render/NativeObject.h>
#include <kiwano/core/Resource.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <dwrite.h>
namespace kiwano
{
@ -39,7 +37,7 @@ class Renderer;
* \~chinese
* @brief
*/
class Font : public virtual ObjectBase
class Font : public NativeObject
{
friend class Renderer;
@ -61,43 +59,8 @@ public:
/// \~chinese
/// @brief 加载字体资源
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

View File

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

View File

@ -35,7 +35,7 @@ KGE_DECLARE_SMART_PTR(GifImage);
* \~chinese
* @brief GIF图像
*/
class KGE_API GifImage : public virtual ObjectBase
class KGE_API GifImage : public NativeObject
{
public:
/// \~chinese
@ -56,10 +56,6 @@ public:
/// @brief 加载GIF资源
bool Load(Resource const& res);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 获取像素宽度
uint32_t GetWidthInPixels() const;
@ -68,6 +64,10 @@ public:
/// @brief 获取像素高度
uint32_t GetHeightInPixels() const;
/// \~chinese
/// @brief 获取像素大小
PixelSize GetSizeInPixels() const;
/// \~chinese
/// @brief 获取帧数量
uint32_t GetFramesCount() const;
@ -105,18 +105,7 @@ private:
private:
uint32_t frames_count_;
uint32_t width_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
PixelSize size_in_pixels_;
};
/** @} */
@ -128,12 +117,17 @@ inline GifImage::Frame::Frame()
inline uint32_t GifImage::GetWidthInPixels() const
{
return width_in_pixels_;
return size_in_pixels_.x;
}
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
@ -141,25 +135,4 @@ inline uint32_t GifImage::GetFramesCount() const
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

View File

@ -24,6 +24,8 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Layer);
/**
* \addtogroup Render
* @{
@ -33,15 +35,11 @@ namespace kiwano
* \~chinese
* @brief
*/
class KGE_API Layer
class KGE_API Layer : public NativeObject
{
public:
Layer();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 获取图层裁剪区域
Rect const& GetClipRect() const;
@ -79,29 +77,10 @@ private:
float opacity_;
ShapePtr mask_;
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
{
return clip_rect_;
@ -142,16 +121,4 @@ inline void Layer::SetMaskTransform(Matrix3x2 const& 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

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.
#include <kiwano/render/RenderContext.h>
#include <kiwano/render/Renderer.h>
namespace kiwano
{
@ -105,4 +106,17 @@ void RenderContext::SetCurrentBrush(BrushPtr 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

View File

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

View File

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

View File

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

View File

@ -19,12 +19,11 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/ObjectBase.h>
#include <kiwano/render/DirectX/D2DDeviceResources.h>
#include <kiwano/render/NativeObject.h>
namespace kiwano
{
class ShapeSink;
class ShapeMaker;
KGE_DECLARE_SMART_PTR(Shape);
@ -37,9 +36,9 @@ KGE_DECLARE_SMART_PTR(Shape);
* \~chinese
* @brief
*/
class KGE_API Shape : public virtual ObjectBase
class KGE_API Shape : public NativeObject
{
friend class ShapeSink;
friend class ShapeMaker;
public:
/// \~chinese
@ -73,10 +72,6 @@ public:
Shape();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 获取外切包围盒
Rect GetBoundingBox() const;
@ -110,39 +105,8 @@ public:
/// \~chinese
/// @brief 清除形状
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

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

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
{
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;
if (ptr)
{
ptr->SetStrokeWidth(width);
ptr->SetCapStyle(cap);
ptr->SetLineJoinStyle(line_join);
ptr->SetDashStyle(dash);
@ -37,12 +44,13 @@ StrokeStylePtr StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, DashSt
return ptr;
}
StrokeStylePtr StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, const float* dash_array, size_t dash_size,
float dash_offset)
StrokeStylePtr StrokeStyle::Create(float width, CapStyle cap, LineJoinStyle line_join, const float* dash_array,
size_t dash_size, float dash_offset)
{
StrokeStylePtr ptr = new (std::nothrow) StrokeStyle;
if (ptr)
{
ptr->SetStrokeWidth(width);
ptr->SetCapStyle(cap);
ptr->SetLineJoinStyle(line_join);
ptr->SetDashStyle(dash_array, dash_size);
@ -55,6 +63,7 @@ StrokeStyle::StrokeStyle()
: cap_(CapStyle::Flat)
, line_join_(LineJoinStyle::Miter)
, 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)
{
dash_array_ = dash_array;
style_.Reset();
}
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();
else
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

View File

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

View File

@ -21,6 +21,10 @@
#include <kiwano/render/Renderer.h>
#include <kiwano/render/TextLayout.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
#endif
namespace kiwano
{
TextLayoutPtr TextLayout::Create()
@ -41,7 +45,6 @@ TextLayoutPtr TextLayout::Create(const String& content, const TextStyle& style)
TextLayout::TextLayout()
: 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);
SetWrapWidth(style.wrap_width);
SetLineSpacing(style.line_spacing);
SetUnderline(style.show_underline, { 0, text.length() });
SetStrikethrough(style.show_strikethrough, { 0, text.length() });
SetDefaultFillBrush(style.fill_brush);
SetDefaultOutlineBrush(style.outline_brush);
SetDefaultOutlineWidth(style.outline_width);
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
{
@ -70,10 +77,13 @@ void TextLayout::Reset(const String& text, const TextStyle& style)
uint32_t TextLayout::GetLineCount() const
{
#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;
if (SUCCEEDED(GetTextLayout()->GetMetrics(&metrics)))
if (SUCCEEDED(native->GetMetrics(&metrics)))
{
return metrics.lineCount;
}
@ -87,10 +97,13 @@ uint32_t TextLayout::GetLineCount() const
Size TextLayout::GetLayoutSize() const
{
#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;
if (SUCCEEDED(GetTextLayout()->GetMetrics(&metrics)))
if (SUCCEEDED(native->GetMetrics(&metrics)))
{
return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height)
: Size(metrics.width, metrics.height);
@ -105,12 +118,14 @@ Size TextLayout::GetLayoutSize() const
void TextLayout::SetFont(FontPtr font, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
{
IDWriteFontCollection* collection = font ? font->GetCollection().Get() : nullptr;
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
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");
dirty_flag_ = DirtyFlag::Updated;
@ -123,12 +138,14 @@ void TextLayout::SetFont(FontPtr font, TextRange range)
void TextLayout::SetFontFamily(String const& family, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
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");
dirty_flag_ = DirtyFlag::Updated;
@ -141,10 +158,12 @@ void TextLayout::SetFontFamily(String const& family, TextRange range)
void TextLayout::SetFontSize(float size, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
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");
dirty_flag_ = DirtyFlag::Updated;
@ -157,12 +176,14 @@ void TextLayout::SetFontSize(float size, TextRange range)
void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
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");
dirty_flag_ = DirtyFlag::Updated;
@ -175,12 +196,14 @@ void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
void TextLayout::SetItalic(bool italic, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
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");
dirty_flag_ = DirtyFlag::Updated;
@ -193,10 +216,12 @@ void TextLayout::SetItalic(bool italic, TextRange range)
void TextLayout::SetUnderline(bool enable, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
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");
dirty_flag_ = DirtyFlag::Updated;
@ -209,10 +234,12 @@ void TextLayout::SetUnderline(bool enable, TextRange range)
void TextLayout::SetStrikethrough(bool enable, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
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");
dirty_flag_ = DirtyFlag::Updated;
@ -225,10 +252,13 @@ void TextLayout::SetStrikethrough(bool enable, TextRange range)
void TextLayout::SetFillBrush(BrushPtr brush, TextRange range)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
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");
dirty_flag_ = DirtyFlag::Updated;
@ -249,17 +279,6 @@ void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range)
#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)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
@ -274,8 +293,10 @@ void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range)
void TextLayout::SetAlignment(TextAlign align)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT();
switch (align)
@ -294,7 +315,7 @@ void TextLayout::SetAlignment(TextAlign align)
break;
}
HRESULT hr = text_layout_->SetTextAlignment(alignment);
HRESULT hr = native->SetTextAlignment(alignment);
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetTextAlignment failed");
dirty_flag_ = DirtyFlag::Updated;
@ -307,27 +328,29 @@ void TextLayout::SetAlignment(TextAlign align)
void TextLayout::SetWrapWidth(float wrap_width)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
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 (wrap_width > 0)
{
hr = text_layout_->SetMaxWidth(wrap_width);
hr = native->SetMaxWidth(wrap_width);
}
else
{
// Fix the layout width when the text does not wrap
DWRITE_TEXT_METRICS metrics;
hr = text_layout_->GetMetrics(&metrics);
hr = native->GetMetrics(&metrics);
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)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
KGE_ASSERT(text_layout_);
if (text_layout_)
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
HRESULT hr = S_OK;
float spacing = line_spacing;
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
{
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");

View File

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

View File

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

View File

@ -21,6 +21,10 @@
#include <kiwano/render/Renderer.h>
#include <kiwano/render/Texture.h>
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
#include <kiwano/render/DirectX/NativePtr.h>
#endif
namespace kiwano
{
@ -67,47 +71,15 @@ bool Texture::Load(Resource const& res)
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)
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
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");
}
@ -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 (IsValid() && copy_from)
{
HRESULT hr = bitmap_->CopyFromBitmap(
&D2D1::Point2U(uint32_t(dest_point.x), uint32_t(dest_point.y)), copy_from->GetBitmap().Get(),
&D2D1::RectU(uint32_t(src_rect.GetLeft()), uint32_t(src_rect.GetTop()), uint32_t(src_rect.GetRight()),
uint32_t(src_rect.GetBottom())));
auto native = NativePtr::Get<ID2D1Bitmap>(this);
auto native_to_copy = NativePtr::Get<ID2D1Bitmap>(copy_from);
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");
}

View File

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

View File

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