Update TextRenderer & Geometry & GeometrySink

This commit is contained in:
Nomango 2019-12-29 18:58:22 +08:00
parent c50755bb4b
commit 4fe6e9cd3f
36 changed files with 1151 additions and 609 deletions

View File

@ -61,6 +61,7 @@
<ClInclude Include="..\..\src\kiwano\renderer\Color.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Font.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Geometry.h" />
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h" />
<ClInclude Include="..\..\src\kiwano\renderer\GifImage.h" />
<ClInclude Include="..\..\src\kiwano\renderer\StrokeStyle.h" />
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp" />
@ -127,6 +128,7 @@
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Font.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Geometry.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\GifImage.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Texture.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\TextureCache.cpp" />

View File

@ -270,6 +270,9 @@
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h">
<Filter>renderer\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h">
<Filter>renderer</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp">
@ -452,5 +455,8 @@
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp">
<Filter>renderer</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -129,6 +129,7 @@ namespace kiwano
void Actor::PrepareToRender(RenderTarget* rt)
{
rt->SetTransform(transform_matrix_);
rt->SetBrushOpacity(GetDisplayedOpacity());
}
void Actor::RenderBorder(RenderTarget* rt)

View File

@ -21,7 +21,7 @@
#pragma once
#include <kiwano/2d/Actor.h>
#include <kiwano/renderer/RenderTarget.h>
#include <kiwano/renderer/GeometrySink.h>
namespace kiwano
{
@ -133,7 +133,7 @@ namespace kiwano
/// \~chinese
/// @brief 结束路径
/// @param closed 路径是否闭合
void EndPath(bool closed = true);
void EndPath(bool closed = false);
/// \~chinese
/// @brief 添加一条线段

View File

@ -53,6 +53,7 @@ namespace kiwano
SetResponsible(true);
SetCascadeOpacityEnabled(true);
background_brush_ = new Brush;
background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f));
debug_text_ = new TextActor;
@ -65,6 +66,7 @@ namespace kiwano
style.font_weight = FontWeight::Normal;
style.line_spacing = 20.f;
debug_text_->SetStyle(style);
debug_text_->SetFillColor(Color::White);
AddListener<MouseHoverEvent>([=](Event&) { SetOpacity(0.4f); });
AddListener<MouseOutEvent>([=](Event&) { SetOpacity(1.f); });

View File

@ -174,9 +174,9 @@ namespace kiwano
loop_count_++;
}
if (frame_.raw)
if (frame_.texture)
{
frame_rt_->DrawTexture(*frame_.raw, nullptr, &frame_.rect);
frame_rt_->DrawTexture(*frame_.texture, nullptr, &frame_.rect);
}
frame_rt_->EndDraw();

View File

@ -49,7 +49,7 @@ namespace kiwano
bool ShapeActor::ContainsPoint(const Point& point) const
{
return geo_.ContainsPoint(point, GetTransformMatrix());
return geo_.ContainsPoint(point, &GetTransformMatrix());
}
void ShapeActor::SetStrokeWidth(float width)

View File

@ -22,6 +22,7 @@
#include <kiwano/2d/Actor.h>
#include <kiwano/renderer/Brush.h>
#include <kiwano/renderer/Geometry.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/renderer/StrokeStyle.h>
namespace kiwano

View File

@ -76,7 +76,7 @@ namespace kiwano
void Sprite::OnRender(RenderTarget* rt)
{
rt->DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds(), GetDisplayedOpacity());
rt->DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
}
bool Sprite::CheckVisibilty(RenderTarget* rt) const

View File

@ -48,6 +48,8 @@ namespace kiwano
void Stage::RenderBorder(RenderTarget* rt)
{
rt->SetBrushOpacity(1.0f);
if (!border_fill_brush_)
{
border_fill_brush_ = new Brush;

View File

@ -27,6 +27,19 @@ namespace kiwano
namespace
{
TextStyle text_default_style;
void InitDefaultTextStyle()
{
static bool inited = false;
if (!inited)
{
inited = true;
// 默认使用白色画刷填充文字
text_default_style.fill_brush = new Brush;
text_default_style.fill_brush->SetColor(Color::White);
}
}
}
void TextActor::SetDefaultStyle(TextStyle const & style)
@ -34,6 +47,11 @@ namespace kiwano
text_default_style = style;
}
const TextStyle& TextActor::GetDefaultStyle()
{
return text_default_style;
}
TextActor::TextActor()
: TextActor(String())
{
@ -44,8 +62,12 @@ namespace kiwano
{
}
TextActor::TextActor(String const& text, const TextStyle & style)
TextActor::TextActor(String const& text, const TextStyle& style)
: show_underline_(false)
, show_strikethrough_(false)
{
InitDefaultTextStyle();
SetText(text);
SetStyle(style);
}
@ -60,10 +82,22 @@ namespace kiwano
}
void TextActor::OnUpdate(Duration dt)
{
UpdateLayout();
}
void TextActor::UpdateLayout()
{
if (text_layout_.IsDirty())
{
text_layout_.Update();
if (show_underline_)
text_layout_.SetUnderline(true, 0, text_layout_.GetText().length());
if (show_strikethrough_)
text_layout_.SetStrikethrough(true, 0, text_layout_.GetText().length());
SetSize(text_layout_.GetLayoutSize());
}
}
@ -72,4 +106,24 @@ namespace kiwano
{
return text_layout_.IsValid() && Actor::CheckVisibilty(rt);
}
void TextActor::SetFillColor(Color const& color)
{
if (!text_layout_.GetFillBrush())
{
BrushPtr brush = new Brush;
text_layout_.SetFillBrush(brush);
}
text_layout_.GetFillBrush()->SetColor(color);
}
void TextActor::SetOutlineColor(Color const& outline_color)
{
if (!text_layout_.GetOutlineBrush())
{
BrushPtr brush = new Brush;
text_layout_.SetOutlineBrush(brush);
}
text_layout_.GetOutlineBrush()->SetColor(outline_color);
}
}

View File

@ -69,6 +69,14 @@ namespace kiwano
/// @brief 获取文本布局
const TextLayout& GetLayout() const;
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief 获取描边画刷
BrushPtr GetOutlineBrush() const;
/// \~chinese
/// @brief 获取字体
FontPtr GetFont() const;
@ -145,10 +153,19 @@ namespace kiwano
/// @brief 设置是否显示删除线(默认值为 false
void SetStrikethrough(bool enable);
/// \~chinese
/// @brief 更新文字布局
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
void UpdateLayout();
/// \~chinese
/// @brief 设置默认文字样式
static void SetDefaultStyle(TextStyle const& style);
/// \~chinese
/// @brief 获取默认文字样式
static const TextStyle& GetDefaultStyle();
void OnRender(RenderTarget* rt) override;
void OnUpdate(Duration dt) override;
@ -157,6 +174,8 @@ namespace kiwano
bool CheckVisibilty(RenderTarget* rt) const override;
private:
bool show_underline_;
bool show_strikethrough_;
TextLayout text_layout_;
};
@ -182,6 +201,16 @@ namespace kiwano
return text_layout_;
}
inline BrushPtr TextActor::GetFillBrush() const
{
return text_layout_.GetFillBrush();
}
inline BrushPtr TextActor::GetOutlineBrush() const
{
return text_layout_.GetOutlineBrush();
}
inline void TextActor::SetText(String const& text)
{
text_layout_.SetText(text);
@ -234,12 +263,12 @@ namespace kiwano
inline void TextActor::SetUnderline(bool enable)
{
text_layout_.SetUnderline(enable, 0, text_layout_.GetText().length());
show_underline_ = enable;
}
inline void TextActor::SetStrikethrough(bool enable)
{
text_layout_.SetStrikethrough(enable, 0, text_layout_.GetText().length());
show_strikethrough_ = enable;
}
inline void TextActor::SetFillBrush(BrushPtr brush)
@ -247,21 +276,11 @@ namespace kiwano
text_layout_.SetFillBrush(brush);
}
inline void TextActor::SetFillColor(Color const& color)
{
text_layout_.SetFillColor(color);
}
inline void TextActor::SetOutlineBrush(BrushPtr brush)
{
text_layout_.SetOutlineBrush(brush);
}
inline void TextActor::SetOutlineColor(Color const& outline_color)
{
text_layout_.SetOutlineColor(outline_color);
}
inline void TextActor::SetOutlineWidth(float outline_width)
{
text_layout_.SetOutlineWidth(outline_width);

View File

@ -258,19 +258,6 @@ namespace kiwano
return TweenHelper(new kiwano::ActionWalk(duration, path, rotating, start, end));
}
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param sink 几何形状生成器
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
static inline TweenHelper
Walk(Duration duration, GeometrySink& sink, bool rotating = false, float start = 0.f, float end = 1.f)
{
return TweenHelper(new kiwano::ActionWalk(duration, sink.GetGeometry(), rotating, start, end));
}
/// \~chinese
/// @brief 构建帧动画
/// @param duration 动画时长

View File

@ -20,7 +20,8 @@
#pragma once
#include <kiwano/2d/action/ActionTween.h>
#include <kiwano/renderer/Geometry.h> // Geometry, GeometrySink
#include <kiwano/renderer/Geometry.h>
#include <kiwano/renderer/GeometrySink.h>
namespace kiwano
{

View File

@ -107,14 +107,6 @@ namespace kiwano
/// @brief ÉčÖĂžśĎň˝ĽąäŃůĘ˝
void SetStyle(RadialGradientStyle const& style);
/// \~chinese
/// @brief »ñȡ͸Ã÷¶È
float GetOpacity() const;
/// \~chinese
/// @brief ÉèÖÃ͸Ã÷¶È
void SetOpacity(float opacity);
public:
/// \~chinese
/// @brief ť­Ë˘ŔŕĐÍ
@ -131,6 +123,14 @@ namespace kiwano
Type GetType() const;
private:
/// \~chinese
/// @brief »ñȡ͸Ã÷¶È
float GetOpacity() const;
/// \~chinese
/// @brief ÉèÖÃ͸Ã÷¶È
void SetOpacity(float opacity);
void SetBrush(ComPtr<ID2D1Brush> brush, Type type);
ComPtr<ID2D1Brush> GetBrush() const;

View File

@ -28,10 +28,20 @@ namespace kiwano
}
bool Font::Load(String const& font_file)
{
return Load(Vector<String>{ font_file });
}
bool Font::Load(Resource const& font_resource)
{
return Load(Vector<Resource>{ font_resource });
}
bool Font::Load(Vector<String> const& font_file)
{
try
{
Renderer::instance().CreateFontCollection(*this, { font_file });
Renderer::instance().CreateFontCollection(*this, font_file);
}
catch (std::runtime_error&)
{
@ -40,11 +50,11 @@ namespace kiwano
return true;
}
bool Font::Load(Resource const& font_resource)
bool Font::Load(Vector<Resource> const& font_resource)
{
try
{
Renderer::instance().CreateFontCollection(*this, { font_resource });
Renderer::instance().CreateFontCollection(*this, font_resource);
}
catch (std::runtime_error&)
{

View File

@ -30,7 +30,10 @@ namespace kiwano
class Renderer;
// ΧΦΜε
/**
* \~chinese
* @brief
*/
class Font
: public ObjectBase
{
@ -39,10 +42,22 @@ namespace kiwano
public:
Font();
/// \~chinese
/// @brief 加载字体文件
bool Load(String const& font_file);
/// \~chinese
/// @brief 加载字体资源
bool Load(Resource const& font_resource);
/// \~chinese
/// @brief 加载多个字体文件
bool Load(Vector<String> const& font_file);
/// \~chinese
/// @brief 加载多个字体资源
bool Load(Vector<Resource> const& font_resource);
private:
ComPtr<IDWriteFontCollection> GetCollection() const;

View File

@ -19,16 +19,13 @@
// THE SOFTWARE.
#include <kiwano/renderer/Geometry.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/renderer/Renderer.h>
#include <kiwano/core/win32/helper.h>
namespace kiwano
{
//
// Geometry
//
Geometry::Geometry()
{
}
@ -92,32 +89,6 @@ namespace kiwano
geo_.reset();
}
void Geometry::CombineWith(GeometrySink& sink, Geometry input, CombineMode mode, Matrix3x2 const& input_matrix) const
{
if (geo_ && input.geo_)
{
ThrowIfFailed(
geo_->CombineWithGeometry(
input.geo_.get(),
D2D1_COMBINE_MODE(mode),
DX::ConvertToMatrix3x2F(input_matrix),
sink.GetGeometrySink().get()
)
);
}
}
Geometry Geometry::CombineWith(Geometry input, CombineMode mode, Matrix3x2 const& input_matrix) const
{
GeometrySink sink;
sink.Open();
CombineWith(sink, input, mode, input_matrix);
sink.Close();
return sink.GetGeometry();
}
float Geometry::ComputeArea() const
{
if (!geo_)
@ -129,7 +100,7 @@ namespace kiwano
return area;
}
bool Geometry::ContainsPoint(Point const& point, Matrix3x2 const& transform) const
bool Geometry::ContainsPoint(Point const& point, const Matrix3x2* transform) const
{
if (!geo_)
return false;
@ -139,6 +110,7 @@ namespace kiwano
geo_->FillContainsPoint(
DX::ConvertToPoint2F(point),
DX::ConvertToMatrix3x2F(transform),
D2D1_DEFAULT_FLATTENING_TOLERANCE,
&ret
);
return !!ret;
@ -179,136 +151,4 @@ namespace kiwano
return output;
}
//
// GeometrySink
//
GeometrySink::GeometrySink()
{
}
GeometrySink::~GeometrySink()
{
Close();
}
GeometrySink& GeometrySink::BeginPath(Point const& begin_pos)
{
if (!sink_)
{
Open();
}
sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
return (*this);
}
GeometrySink& GeometrySink::EndPath(bool closed)
{
if (sink_)
{
sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
Close();
}
return (*this);
}
GeometrySink& GeometrySink::AddLine(Point const& point)
{
if (!sink_) BeginPath();
sink_->AddLine(DX::ConvertToPoint2F(point));
return (*this);
}
GeometrySink& GeometrySink::AddLines(Vector<Point> const& points)
{
if (!sink_) BeginPath();
sink_->AddLines(
reinterpret_cast<const D2D_POINT_2F*>(&points[0]),
static_cast<uint32_t>(points.size())
);
return (*this);
}
GeometrySink& kiwano::GeometrySink::AddLines(const Point* points, size_t count)
{
if (!sink_) BeginPath();
sink_->AddLines(reinterpret_cast<const D2D_POINT_2F*>(points), UINT32(count));
return (*this);
}
GeometrySink& GeometrySink::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
if (!sink_) BeginPath();
sink_->AddBezier(
D2D1::BezierSegment(
DX::ConvertToPoint2F(point1),
DX::ConvertToPoint2F(point2),
DX::ConvertToPoint2F(point3)
)
);
return (*this);
}
GeometrySink& GeometrySink::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
if (!sink_) BeginPath();
sink_->AddArc(
D2D1::ArcSegment(
DX::ConvertToPoint2F(point),
DX::ConvertToSizeF(radius),
rotation,
clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE
)
);
return (*this);
}
Geometry GeometrySink::GetGeometry()
{
if (sink_)
{
EndPath();
}
Geometry geo;
geo.SetGeometry(path_geo_);
return geo;
}
void GeometrySink::Init()
{
if (!path_geo_)
{
Renderer::instance().CreateGeometrySink(*this);
}
}
void GeometrySink::Open()
{
Init();
if (!sink_)
{
ThrowIfFailed(path_geo_->Open(&sink_));
}
}
void GeometrySink::Close()
{
if (sink_)
{
ThrowIfFailed(sink_->Close());
sink_ = nullptr;
}
}
}

View File

@ -27,7 +27,10 @@ namespace kiwano
class Renderer;
class GeometrySink;
// 几何体
/**
* \~chinese
* @brief
*/
class KGE_API Geometry
{
friend class RenderTarget;
@ -37,179 +40,84 @@ namespace kiwano
public:
Geometry();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
// 获取外切包围盒
/// \~chinese
/// @brief 获取外切包围盒
Rect GetBoundingBox() const;
// 获取外切包围盒
Rect GetBoundingBox(
Matrix3x2 const& transform
) const;
/// \~chinese
/// @brief 获取外切包围盒
/// @param transform 二维变换
Rect GetBoundingBox(Matrix3x2 const& transform) const;
// 判断图形是否包含点
bool ContainsPoint(
Point const& point,
Matrix3x2 const& transform = Matrix3x2()
) const;
/// \~chinese
/// @brief 判断图形是否包含点
/// @param point 点
/// @param transform 应用到点上的二维变换
bool ContainsPoint(Point const& point, const Matrix3x2* transform = nullptr) const;
// 获取图形展开成一条直线的长度
/// \~chinese
/// @brief 获取图形展开成一条直线的长度
float GetLength() const;
// 计算面积
/// \~chinese
/// @brief 计算图形面积
float ComputeArea() const;
// 计算图形路径上点的位置和切线向量
bool ComputePointAtLength(
float length,
Point& point,
Vec2& tangent
) const;
/// \~chinese
/// @brief 计算图形上点的位置和切线向量
/// @param[in] length 点在图形上的位置,范围 [0.0 - 1.0]
/// @param[out] point 点的位置
/// @param[out] tangent 点的切线向量
bool ComputePointAtLength(float length, Point& point, Vec2& tangent) const;
// 清除形状
/// \~chinese
/// @brief 清除形状
void Clear();
public:
// 几何体组合模式
enum class CombineMode
{
Union, /* 并集 (A + B) */
Intersect, /* 交集 (A + B) */
Xor, /* 对称差集 ((A - B) + (B - A)) */
Exclude /* 差集 (A - B) */
};
/// \~chinese
/// @brief 创建线段
/// @param begin 线段起点
/// @param end 线段终点
static Geometry CreateLine(Point const& begin, Point const& end);
// 组合几何体
void CombineWith(
GeometrySink& sink,
Geometry input,
CombineMode mode,
Matrix3x2 const& input_matrix = Matrix3x2()
) const;
/// \~chinese
/// @brief 创建矩形
/// @param rect 矩形
static Geometry CreateRect(Rect const& rect);
// 组合几何体
Geometry CombineWith(
Geometry input,
CombineMode mode,
Matrix3x2 const& input_matrix = Matrix3x2()
) const;
/// \~chinese
/// @brief 创建圆角矩形
/// @param rect 矩形
/// @param radius 矩形圆角半径
static Geometry CreateRoundedRect(Rect const& rect, Vec2 const& radius);
public:
// 创建直线
static Geometry CreateLine(
Point const& begin,
Point const& end
);
/// \~chinese
/// @brief 创建圆形
/// @param center 圆形原点
/// @param radius 圆形半径
static Geometry CreateCircle(Point const& center, float radius);
// 创建矩形
static Geometry CreateRect(
Rect const& rect
);
// 创建圆角矩形
static Geometry CreateRoundedRect(
Rect const& rect,
Vec2 const& radius
);
// 创建圆形
static Geometry CreateCircle(
Point const& center,
float radius
);
// 创建椭圆形
static Geometry CreateEllipse(
Point const& center,
Vec2 const& radius
);
/// \~chinese
/// @brief 创建椭圆形
/// @param center 椭圆原点
/// @param radius 椭圆半径
static Geometry CreateEllipse(Point const& center, Vec2 const& radius);
private:
inline ComPtr<ID2D1Geometry> GetGeometry() const { return geo_; }
ComPtr<ID2D1Geometry> GetGeometry() const;
inline void SetGeometry(ComPtr<ID2D1Geometry> geometry) { geo_ = geometry; }
void SetGeometry(ComPtr<ID2D1Geometry> geometry);
private:
ComPtr<ID2D1Geometry> geo_;
};
inline ComPtr<ID2D1Geometry> Geometry::GetGeometry() const { return geo_; }
// 几何体生成器
class KGE_API GeometrySink
: protected Noncopyable
{
friend class Geometry;
friend class Renderer;
public:
GeometrySink();
~GeometrySink();
// 开始添加路径
GeometrySink& BeginPath(
Point const& begin_pos = Point{} /* 起始点 */
);
// 结束路径
GeometrySink& EndPath(
bool closed = false /* 路径是否闭合 */
);
// 添加一条线段
GeometrySink& AddLine(
Point const& point /* 端点 */
);
// 添加多条线段
GeometrySink& AddLines(
Vector<Point> const& points
);
// 添加多条线段
GeometrySink& AddLines(
const Point* points,
size_t count
);
// 添加一条三次方贝塞尔曲线
GeometrySink& AddBezier(
Point const& point1, /* 贝塞尔曲线的第一个控制点 */
Point const& point2, /* 贝塞尔曲线的第二个控制点 */
Point const& point3 /* 贝塞尔曲线的终点 */
);
// 添加弧线
GeometrySink& AddArc(
Point const& point, /* 终点 */
Size const& radius, /* 椭圆半径 */
float rotation, /* 椭圆旋转角度 */
bool clockwise = true, /* 顺时针 or 逆时针 */
bool is_small = true /* 是否取小于 180° 的弧 */
);
// 获取生成路径几何体
Geometry GetGeometry();
// 打开流
void Open();
// 关闭流
void Close();
private:
inline ComPtr<ID2D1PathGeometry> GetPathGeometry() const { return path_geo_; }
inline void SetPathGeometry(ComPtr<ID2D1PathGeometry> path) { path_geo_ = path; }
inline ComPtr<ID2D1GeometrySink> GetGeometrySink() const { return sink_; }
inline void SetGeometrySink(ComPtr<ID2D1GeometrySink> sink) { sink_ = sink; }
void Init();
private:
ComPtr<ID2D1PathGeometry> path_geo_;
ComPtr<ID2D1GeometrySink> sink_;
};
inline void Geometry::SetGeometry(ComPtr<ID2D1Geometry> geometry) { geo_ = geometry; }
}

View File

@ -0,0 +1,186 @@
// 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/renderer/GeometrySink.h>
#include <kiwano/renderer/Renderer.h>
#include <kiwano/core/win32/helper.h>
namespace kiwano
{
GeometrySink::GeometrySink()
{
}
GeometrySink::~GeometrySink()
{
Close();
}
void GeometrySink::Open()
{
if (!IsOpened())
{
path_geo_.reset();
Renderer::instance().CreateGeometrySink(*this);
ThrowIfFailed(path_geo_->Open(&sink_));
}
}
void GeometrySink::Close()
{
if (IsOpened())
{
ThrowIfFailed(sink_->Close());
sink_.reset();
}
}
bool GeometrySink::IsOpened() const
{
return sink_ != nullptr;
}
Geometry GeometrySink::GetGeometry()
{
Close();
Geometry geo;
geo.SetGeometry(path_geo_);
return geo;
}
GeometrySink& GeometrySink::AddGeometry(Geometry const& input, const Matrix3x2* input_matrix)
{
if (!IsOpened())
{
Open();
}
ComPtr<ID2D1Geometry> geo = input.geo_;
ThrowIfFailed(
geo->Outline(
DX::ConvertToMatrix3x2F(input_matrix),
D2D1_DEFAULT_FLATTENING_TOLERANCE,
sink_.get()
)
);
return (*this);
}
GeometrySink& GeometrySink::BeginPath(Point const& begin_pos)
{
if (!IsOpened())
{
Open();
}
sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
return (*this);
}
GeometrySink& GeometrySink::EndPath(bool closed)
{
KGE_ASSERT(sink_);
sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
return (*this);
}
GeometrySink& GeometrySink::AddLine(Point const& point)
{
KGE_ASSERT(sink_);
sink_->AddLine(DX::ConvertToPoint2F(point));
return (*this);
}
GeometrySink& GeometrySink::AddLines(Vector<Point> const& points)
{
KGE_ASSERT(sink_);
sink_->AddLines(
reinterpret_cast<const D2D_POINT_2F*>(&points[0]),
static_cast<uint32_t>(points.size())
);
return (*this);
}
GeometrySink& kiwano::GeometrySink::AddLines(const Point* points, size_t count)
{
KGE_ASSERT(sink_);
sink_->AddLines(reinterpret_cast<const D2D_POINT_2F*>(points), UINT32(count));
return (*this);
}
GeometrySink& GeometrySink::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
KGE_ASSERT(sink_);
sink_->AddBezier(
D2D1::BezierSegment(
DX::ConvertToPoint2F(point1),
DX::ConvertToPoint2F(point2),
DX::ConvertToPoint2F(point3)
)
);
return (*this);
}
GeometrySink& GeometrySink::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
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
)
);
return (*this);
}
GeometrySink& GeometrySink::Combine(Geometry const& geo_a, Geometry const& geo_b, CombineMode mode, const Matrix3x2* matrix)
{
if (!IsOpened())
{
Open();
}
ComPtr<ID2D1Geometry> geo_a_raw = geo_a.geo_;
ComPtr<ID2D1Geometry> geo_b_raw = geo_b.geo_;
ThrowIfFailed(
geo_a_raw->CombineWithGeometry(
geo_b_raw.get(),
D2D1_COMBINE_MODE(mode),
DX::ConvertToMatrix3x2F(matrix),
sink_.get()
)
);
return (*this);
}
void GeometrySink::Clear()
{
Close();
path_geo_.reset();
}
}

View File

@ -0,0 +1,153 @@
// 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/renderer/Geometry.h>
namespace kiwano
{
class RenderTarget;
class Renderer;
/// \~chinese
/// @brief 几何形状组合方式
enum class CombineMode
{
Union, ///< 并集 (A + B)
Intersect, ///< 交集 (A + B)
Xor, ///< 对称差集 ((A - B) + (B - A))
Exclude ///< 差集 (A - B)
};
/// \~chinese
/// @brief 几何形状生成器
class KGE_API GeometrySink
: protected Noncopyable
{
friend class Renderer;
public:
GeometrySink();
~GeometrySink();
/// \~chinese
/// @brief 打开输入流
/// @details 打开流后可以使用
void Open();
/// \~chinese
/// @brief 关闭输入流
void Close();
/// \~chinese
/// @brief 输入流是否已经打开
bool IsOpened() const;
/// \~chinese
/// @brief 获取生成的几何形状
/// @note 若还未关闭输入流,则自动关闭
Geometry GetGeometry();
/// \~chinese
/// @brief 添加几何形状的轮廓
/// @param input 输入的形状
/// @param input_matrix 应用到输入形状上的二维变换
/// @note 若还未打开输入流,则自动打开
GeometrySink& AddGeometry(Geometry const& input, const Matrix3x2* input_matrix = nullptr);
/// \~chinese
/// @brief 开始添加路径
/// @param begin_pos 路径起始点
/// @note 若还未打开输入流,则自动打开
GeometrySink& BeginPath(Point const& begin_pos = Point());
/// \~chinese
/// @brief 结束路径
/// @param closed 路径是否闭合
GeometrySink& EndPath(bool closed = false);
/// \~chinese
/// @brief 添加一条线段
/// @param point 端点
GeometrySink& AddLine(Point const& point);
/// \~chinese
/// @brief 添加多条线段
/// @param points 端点集合
GeometrySink& AddLines(Vector<Point> const& points);
/// \~chinese
/// @brief 添加多条线段
/// @param points 端点数组
/// @param count 端点数量
GeometrySink& AddLines(const Point* points, size_t count);
/// \~chinese
/// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点
GeometrySink& AddBezier(Point const& point1, Point const& point2, Point const& point3);
/// \~chinese
/// @brief 添加弧线
/// @param point 终点
/// @param radius 椭圆半径
/// @param rotation 椭圆旋转角度
/// @param clockwise 顺时针 or 逆时针
/// @param is_small 是否取小于 180° 的弧
GeometrySink& AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
/// \~chinese
/// @brief 组合几何形状,并将结果输出到流中
/// @param geo_a 输入的形状A
/// @param geo_b 输入的形状B
/// @param mode 组合方式
/// @param matrix 应用到输入形状B上的二维变换
/// @note 若还未打开输入流,则自动打开
GeometrySink& Combine(Geometry const& geo_a, Geometry const& geo_b, CombineMode mode, const Matrix3x2* matrix = nullptr);
/// \~chinese
/// @brief 清空图形
void Clear();
private:
ComPtr<ID2D1PathGeometry> GetPathGeometry() const;
void SetPathGeometry(ComPtr<ID2D1PathGeometry> path);
ComPtr<ID2D1GeometrySink> GetGeometrySink() const;
void SetGeometrySink(ComPtr<ID2D1GeometrySink> sink);
private:
ComPtr<ID2D1PathGeometry> path_geo_;
ComPtr<ID2D1GeometrySink> sink_;
};
inline ComPtr<ID2D1PathGeometry> GeometrySink::GetPathGeometry() const { return path_geo_; }
inline void GeometrySink::SetPathGeometry(ComPtr<ID2D1PathGeometry> path) { path_geo_ = path; }
inline ComPtr<ID2D1GeometrySink> GeometrySink::GetGeometrySink() const { return sink_; }
inline void GeometrySink::SetGeometrySink(ComPtr<ID2D1GeometrySink> sink) { sink_ = sink; }
}

View File

@ -28,7 +28,10 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(GifImage);
// GIF ͼÏñ
/**
* \~chinese
* @brief GIF图像
*/
class KGE_API GifImage
: public ObjectBase
{
@ -37,37 +40,56 @@ namespace kiwano
public:
GifImage();
/// \~chinese
/// @brief 加载本地GIF图片
bool Load(String const& file_path);
/// \~chinese
/// @brief 加载GIF资源
bool Load(Resource const& res);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 获取像素宽度
uint32_t GetWidthInPixels() const;
/// \~chinese
/// @brief 获取像素高度
uint32_t GetHeightInPixels() const;
/// \~chinese
/// @brief 获取帧数量
uint32_t GetFramesCount() const;
public:
/// \~chinese
/// @brief GIF帧的处置方式
enum class DisposalType
{
Unknown,
None,
Background,
Previous
Unknown, ///< 未知
None, ///< 不处理
Background, ///< 背景
Previous ///< 恢复前一帧
};
/// \~chinese
/// @brief GIF帧
struct Frame
{
Duration delay;
TexturePtr raw;
Rect rect;
DisposalType disposal_type;
Duration delay; ///< 帧延迟
TexturePtr texture; ///< 帧图像
Rect rect; ///< 绘制区域
DisposalType disposal_type; ///< 处置方式
Frame();
};
/// \~chinese
/// @brief 获取GIF帧
/// @param index 帧下标
Frame GetFrame(uint32_t index);
private:

View File

@ -28,18 +28,4 @@ namespace kiwano
{
}
bool LayerArea::IsValid() const
{
return layer_ != nullptr;
}
Size LayerArea::GetSize() const
{
if (layer_)
{
return reinterpret_cast<Size const&>(layer_->GetSize());
}
return Size();
}
}

View File

@ -25,7 +25,10 @@ namespace kiwano
{
class RenderTarget;
// 暠꿔
/**
* \~chinese
* @brief
*/
class KGE_API LayerArea
{
friend class RenderTarget;
@ -33,34 +36,46 @@ namespace kiwano
public:
LayerArea();
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
Size GetSize() const;
/// \~chinese
/// @brief 获取图层区域
Rect const& GetAreaRect() const;
inline Rect const& GetAreaRect() const { return area_; }
/// \~chinese
/// @brief 获取图层透明度
float GetOpacity() const;
inline float GetOpacity() const { return opacity_; }
/// \~chinese
/// @brief 获取几何蒙层
Geometry const& GetMaskGeometry() const;
inline Geometry const& GetMaskGeometry() const { return mask_; }
/// \~chinese
/// @brief 获取几何蒙层变换
Matrix3x2 const& GetMaskTransform() const;
inline Matrix3x2 const& GetMaskTransform() const { return mask_transform_; }
/// \~chinese
/// @brief 设置图层区域
void SetAreaRect(Rect const& area);
// <20>零暠꿔혐堵
inline void SetAreaRect(Rect const& area) { area_ = area; }
/// \~chinese
/// @brief 设置图层透明度
void SetOpacity(float opacity);
// <20>零暠꿔拷츠똑
inline void SetOpacity(float opacity) { opacity_ = opacity; }
/// \~chinese
/// @brief 设置几何蒙层
void SetMaskGeometry(Geometry const& mask);
// <20>零섯부촁꿔
inline void SetMaskGeometry(Geometry const& mask) { mask_ = mask; }
// <20>零섯부촁꿔긴뻣
inline void SetMaskTransform(Matrix3x2 const& matrix) { mask_transform_ = matrix; }
/// \~chinese
/// @brief 设置几何蒙层变换
void SetMaskTransform(Matrix3x2 const& matrix);
private:
inline ComPtr<ID2D1Layer> GetLayer() const { return layer_; }
ComPtr<ID2D1Layer> GetLayer() const;
inline void SetLayer(ComPtr<ID2D1Layer> layer) { layer_ = layer; }
void SetLayer(ComPtr<ID2D1Layer> layer);
private:
Rect area_;
@ -69,4 +84,26 @@ namespace kiwano
Matrix3x2 mask_transform_;
ComPtr<ID2D1Layer> layer_;
};
inline bool LayerArea::IsValid() const { return layer_ != nullptr; }
inline Rect const& LayerArea::GetAreaRect() const { return area_; }
inline float LayerArea::GetOpacity() const { return opacity_; }
inline Geometry const& LayerArea::GetMaskGeometry() const { return mask_; }
inline Matrix3x2 const& LayerArea::GetMaskTransform() const { return mask_transform_; }
inline void LayerArea::SetAreaRect(Rect const& area) { area_ = area; }
inline void LayerArea::SetOpacity(float opacity) { opacity_ = opacity; }
inline void LayerArea::SetMaskGeometry(Geometry const& mask) { mask_ = mask; }
inline void LayerArea::SetMaskTransform(Matrix3x2 const& matrix) { mask_transform_ = matrix; }
inline ComPtr<ID2D1Layer> LayerArea::GetLayer() const { return layer_; }
inline void LayerArea::SetLayer(ComPtr<ID2D1Layer> layer) { layer_ = layer; }
}

View File

@ -31,6 +31,7 @@ namespace kiwano
RenderTarget::RenderTarget()
: collecting_status_(false)
, fast_global_transform_(true)
, brush_opacity_(1.0f)
, antialias_(true)
, text_antialias_(TextAntialiasMode::GrayScale)
{
@ -290,12 +291,12 @@ namespace kiwano
IncreasePrimitivesCount();
}
void RenderTarget::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect, float opacity)
void RenderTarget::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect)
{
DrawTexture(texture, &src_rect, &dest_rect, opacity);
DrawTexture(texture, &src_rect, &dest_rect);
}
void RenderTarget::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect, float opacity)
void RenderTarget::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect)
{
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
@ -308,7 +309,7 @@ namespace kiwano
render_target_->DrawBitmap(
texture.GetBitmap().get(),
dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
opacity,
brush_opacity_,
mode,
src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr
);
@ -321,23 +322,42 @@ namespace kiwano
{
KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!");
const TextStyle& style = layout.GetStyle();
text_renderer_->SetStyle(
style.fill_brush ? style.fill_brush->GetBrush().get() : nullptr,
style.outline_brush ? style.outline_brush->GetBrush().get() : nullptr,
style.outline_width,
GetStrokeStyle(style.outline_stroke).get()
);
HRESULT hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), offset.x, offset.y);
if (SUCCEEDED(hr))
if (layout.IsValid())
{
IncreasePrimitivesCount();
}
else
{
KGE_ERROR(L"Failed to draw text layout with HRESULT of %08X", hr);
ComPtr<ID2D1Brush> fill_brush;
ComPtr<ID2D1Brush> outline_brush;
const TextStyle& style = layout.GetStyle();
if (style.fill_brush)
{
fill_brush = style.fill_brush->GetBrush();
fill_brush->SetOpacity(brush_opacity_);
}
if (style.outline_brush)
{
outline_brush = style.outline_brush->GetBrush();
outline_brush->SetOpacity(brush_opacity_);
}
HRESULT hr = text_renderer_->DrawTextLayout(
layout.GetTextLayout().get(),
offset.x,
offset.y,
fill_brush.get(),
outline_brush.get(),
style.outline_width,
GetStrokeStyle(style.outline_stroke).get()
);
if (SUCCEEDED(hr))
{
IncreasePrimitivesCount(text_renderer_->GetLastPrimitivesCount());
}
else
{
KGE_ERROR(L"Failed to draw text layout with HRESULT of %08X", hr);
}
}
}
@ -525,11 +545,11 @@ namespace kiwano
collecting_status_ = collecting;
}
void RenderTarget::IncreasePrimitivesCount() const
void RenderTarget::IncreasePrimitivesCount(uint32_t increase) const
{
if (collecting_status_)
{
++status_.primitives;
status_.primitives += increase;
}
}

View File

@ -36,39 +36,54 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(RenderTarget);
KGE_DECLARE_SMART_PTR(TextureRenderTarget);
// 文字抗锯齿模式
/// \~chinese
/// @brief 文字抗锯齿模式
enum class TextAntialiasMode
{
Default, // 系统默认
ClearType, // ClearType 抗锯齿
GrayScale, // 灰度抗锯齿
None // 不启用抗锯齿
Default, ///< 系统默认
ClearType, ///< ClearType 抗锯齿
GrayScale, ///< 灰度抗锯齿
None ///< 不启用抗锯齿
};
// 渲染目标
/// \~chinese
/// @brief 渲染目标
/// @details 渲染目标将完成基础图元的绘制,并将绘制结果输出到特定的目标中(如窗口或纹理)
class KGE_API RenderTarget
: public ObjectBase
{
friend class Renderer;
public:
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 是否有效
void BeginDraw();
/// \~chinese
/// @brief 是否有效
void EndDraw();
/// \~chinese
/// @brief 是否有效
void DrawGeometry(
Geometry const& geometry,
float stroke_width,
StrokeStyle stroke = StrokeStyle::Miter
);
/// \~chinese
/// @brief 是否有效
void FillGeometry(
Geometry const& geometry
);
/// \~chinese
/// @brief 是否有效
void DrawLine(
Point const& point1,
Point const& point2,
@ -76,16 +91,22 @@ namespace kiwano
StrokeStyle stroke = StrokeStyle::Miter
);
/// \~chinese
/// @brief 是否有效
void DrawRectangle(
Rect const& rect,
float stroke_width,
StrokeStyle stroke = StrokeStyle::Miter
);
/// \~chinese
/// @brief 是否有效
void FillRectangle(
Rect const& rect
);
/// \~chinese
/// @brief 是否有效
void DrawRoundedRectangle(
Rect const& rect,
Vec2 const& radius,
@ -93,11 +114,15 @@ namespace kiwano
StrokeStyle stroke = StrokeStyle::Miter
);
/// \~chinese
/// @brief 是否有效
void FillRoundedRectangle(
Rect const& rect,
Vec2 const& radius
);
/// \~chinese
/// @brief 是否有效
void DrawEllipse(
Point const& center,
Vec2 const& radius,
@ -105,121 +130,179 @@ namespace kiwano
StrokeStyle stroke = StrokeStyle::Miter
);
/// \~chinese
/// @brief 是否有效
void FillEllipse(
Point const& center,
Vec2 const& radius
);
/// \~chinese
/// @brief 是否有效
void DrawTexture(
Texture const& texture,
Rect const& src_rect,
Rect const& dest_rect,
float opacity = 1.0f
Rect const& dest_rect
);
/// \~chinese
/// @brief 是否有效
void DrawTexture(
Texture const& texture,
const Rect* src_rect = nullptr,
const Rect* dest_rect = nullptr,
float opacity = 1.0f
const Rect* dest_rect = nullptr
);
/// \~chinese
/// @brief 是否有效
void DrawTextLayout(
TextLayout const& layout,
Point const& offset = Point{}
);
/// \~chinese
/// @brief 是否有效
void CreateTexture(
Texture& texture,
math::Vec2T<uint32_t> size,
D2D1_PIXEL_FORMAT format
);
/// \~chinese
/// @brief 是否有效
void PushClipRect(Rect const& clip_rect);
/// \~chinese
/// @brief 是否有效
void PopClipRect();
/// \~chinese
/// @brief 是否有效
void PushLayer(LayerArea& layer);
/// \~chinese
/// @brief 是否有效
void PopLayer();
/// \~chinese
/// @brief 是否有效
void Clear();
/// \~chinese
/// @brief 是否有效
void Clear(Color const& clear_color);
/// \~chinese
/// @brief 是否有效
float GetBrushOpacity() const;
/// \~chinese
/// @brief 是否有效
BrushPtr GetCurrentBrush() const;
/// \~chinese
/// @brief 是否有效
Matrix3x2 GetGlobalTransform() const;
/// \~chinese
/// @brief 是否有效
void SetBrushOpacity(
float opacity
);
/// \~chinese
/// @brief 是否有效
void SetCurrentBrush(
BrushPtr brush
);
/// \~chinese
/// @brief 是否有效
void SetTransform(
const Matrix3x2& matrix
);
/// \~chinese
/// @brief 是否有效
void SetGlobalTransform(
const Matrix3x2& matrix
);
/// \~chinese
/// @brief 是否有效
void SetGlobalTransform(
const Matrix3x2* matrix
);
// 设置抗锯齿模式
/// \~chinese
/// @brief 设置抗锯齿模式
void SetAntialiasMode(
bool enabled
);
// 设置文字抗锯齿模式
/// \~chinese
/// @brief 设置文字抗锯齿模式
void SetTextAntialiasMode(
TextAntialiasMode mode
);
// 检查边界是否在视区内
/// \~chinese
/// @brief 检查边界是否在视区内
bool CheckVisibility(
Rect const& bounds,
Matrix3x2 const& transform
);
void Resize(
Size const& size
);
/// \~chinese
/// @brief 重设渲染目标大小
void Resize(Size const& size);
public:
/// \~chinese
/// @brief 渲染目标状态
struct Status
{
int primitives;
Time start;
Duration duration;
uint32_t primitives; ///< 渲染图元数量
Time start; ///< 渲染起始时间
Duration duration; ///< 渲染时长
Status() : primitives(0) {}
Status();
};
/// \~chinese
/// @brief 启用或禁用状态收集功能
void SetCollectingStatus(bool collecting);
void IncreasePrimitivesCount() const;
inline Status const& GetStatus() const { return status_; }
/// \~chinese
/// @brief 获取渲染目标状态
Status const& GetStatus() const;
protected:
RenderTarget();
inline ComPtr<ID2D1RenderTarget> GetRenderTarget() const { KGE_ASSERT(render_target_); return render_target_; }
ComPtr<ID2D1RenderTarget> GetRenderTarget() const;
inline ComPtr<ITextRenderer> GetTextRenderer() const { KGE_ASSERT(text_renderer_); return text_renderer_; }
ComPtr<ITextRenderer> GetTextRenderer() const;
ComPtr<ID2D1StrokeStyle> GetStrokeStyle(StrokeStyle style);
ComPtr<ID2D1StrokeStyle> GetStrokeStyle(StrokeStyle style);
private:
/// \~chinese
/// @brief 创建设备依赖资源
HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> rt);
/// \~chinese
/// @brief 销毁设备依赖资源
void DiscardDeviceResources();
/// \~chinese
/// @brief 增加渲染图元数量
void IncreasePrimitivesCount(uint32_t increase = 1) const;
private:
bool antialias_;
bool fast_global_transform_;
float brush_opacity_;
TextAntialiasMode text_antialias_;
ComPtr<ITextRenderer> text_renderer_;
ComPtr<ID2D1RenderTarget> render_target_;
@ -250,6 +333,8 @@ namespace kiwano
/// \~chinese
/// @brief »ñÈ¡äÖȾÊä³ö
/// @param[out] texture 纹理输出
/// @return 操作是否成功
bool GetOutput(Texture& texture);
private:
@ -264,6 +349,33 @@ namespace kiwano
};
inline RenderTarget::Status::Status()
: primitives(0)
{
}
inline RenderTarget::Status const& RenderTarget::GetStatus() const
{
return status_;
}
inline ComPtr<ID2D1RenderTarget> RenderTarget::GetRenderTarget() const
{
KGE_ASSERT(render_target_);
return render_target_;
}
inline ComPtr<ITextRenderer> RenderTarget::GetTextRenderer() const
{
KGE_ASSERT(text_renderer_);
return text_renderer_;
}
inline float RenderTarget::GetBrushOpacity() const
{
return brush_opacity_;
}
inline BrushPtr RenderTarget::GetCurrentBrush() const
{
return current_brush_;
@ -274,6 +386,11 @@ namespace kiwano
return global_transform_;
}
inline void RenderTarget::SetBrushOpacity(float opacity)
{
brush_opacity_ = opacity;
}
inline void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix)
{
SetGlobalTransform(&matrix);
@ -282,6 +399,10 @@ namespace kiwano
inline void RenderTarget::SetCurrentBrush(BrushPtr brush)
{
current_brush_ = brush;
if (current_brush_)
{
current_brush_->SetOpacity(brush_opacity_);
}
}
inline bool TextureRenderTarget::IsValid() const

View File

@ -19,6 +19,7 @@
// THE SOFTWARE.
#include <kiwano/renderer/Renderer.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/core/Logger.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/platform/Window.h>
@ -66,58 +67,56 @@ namespace kiwano
if (SUCCEEDED(hr))
{
hr = ID3DDeviceResources::Create(&d3d_res_, hwnd_);
}
// Direct2D device resources
if (SUCCEEDED(hr))
{
hr = ID2DDeviceResources::Create(&d2d_res_, d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
}
// Direct2D device resources
if (SUCCEEDED(hr))
{
hr = ID2DDeviceResources::Create(&d2d_res_, d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
// DrawingStateBlock
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetFactory()->CreateDrawingStateBlock(
&drawing_state_block_
);
}
// DrawingStateBlock
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetFactory()->CreateDrawingStateBlock(&drawing_state_block_);
}
// Other device resources
if (SUCCEEDED(hr))
{
hr = CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
}
// Other device resources
if (SUCCEEDED(hr))
{
hr = CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
}
// FontFileLoader and FontCollectionLoader
if (SUCCEEDED(hr))
{
hr = IFontCollectionLoader::Create(&font_collection_loader_);
}
// FontFileLoader and FontCollectionLoader
if (SUCCEEDED(hr))
{
hr = IFontCollectionLoader::Create(&font_collection_loader_);
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(font_collection_loader_.get());
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(font_collection_loader_.get());
}
// ResourceFontFileLoader and ResourceFontCollectionLoader
if (SUCCEEDED(hr))
{
hr = IResourceFontFileLoader::Create(&res_font_file_loader_);
}
// ResourceFontFileLoader and ResourceFontCollectionLoader
if (SUCCEEDED(hr))
{
hr = IResourceFontFileLoader::Create(&res_font_file_loader_);
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDWriteFactory()->RegisterFontFileLoader(res_font_file_loader_.get());
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDWriteFactory()->RegisterFontFileLoader(res_font_file_loader_.get());
}
if (SUCCEEDED(hr))
{
hr = IResourceFontCollectionLoader::Create(&res_font_collection_loader_, res_font_file_loader_.get());
}
if (SUCCEEDED(hr))
{
hr = IResourceFontCollectionLoader::Create(&res_font_collection_loader_, res_font_file_loader_.get());
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(res_font_collection_loader_.get());
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(res_font_collection_loader_.get());
}
}
}
ThrowIfFailed(hr);
@ -424,8 +423,8 @@ namespace kiwano
if (SUCCEEDED(hr))
{
frame.raw = new Texture;
frame.raw->SetBitmap(raw_bitmap);
frame.texture = new Texture;
frame.texture->SetBitmap(raw_bitmap);
}
}
}
@ -847,7 +846,7 @@ namespace kiwano
if (SUCCEEDED(hr))
{
output = new TextureRenderTarget;
hr = output->CreateDeviceResources(bitmap_rt, d2d_res_);
hr = output->CreateDeviceResources(d2d_res_->GetFactory(), bitmap_rt);
}
if (SUCCEEDED(hr))

View File

@ -41,11 +41,14 @@ namespace kiwano
typedef ID3D11DeviceResources ID3DDeviceResources;
#endif
// 渲染设置
/**
* \~chinese
* @brief
*/
struct RenderConfig
{
Color clear_color; // 清屏颜色
bool vsync; // 垂直同步
Color clear_color; ///< 清屏颜色
bool vsync; ///< 垂直同步
RenderConfig(
Color clear_color = Color::Black,
@ -54,7 +57,10 @@ namespace kiwano
};
// 渲染器
/**
* \~chinese
* @brief
*/
class KGE_API Renderer
: public Singleton<Renderer>
, public RenderComponent
@ -64,96 +70,173 @@ namespace kiwano
friend Singleton<Renderer>;
public:
// 设置清屏颜色
void SetClearColor(
Color const& clear_color
);
/// \~chinese
/// @brief 获取清屏颜色
Color const& GetClearColor() const;
// 开启或关闭垂直同步
void SetVSyncEnabled(
bool enabled
);
/// \~chinese
/// @brief 设置清屏颜色
void SetClearColor(Color const& clear_color);
/// \~chinese
/// @brief 开启或关闭垂直同步
void SetVSyncEnabled(bool enabled);
/// \~chinese
/// @brief 设置DPI
void SetDpi(float dpi);
/// \~chinese
/// @brief 创建纹理
/// @param[out] texture 纹理
/// @param[in] file_path 图片路径
void CreateTexture(
Texture& texture,
String const& file_path
);
/// \~chinese
/// @brief 创建纹理
/// @param[out] texture 纹理
/// @param[in] resource 图片资源
void CreateTexture(
Texture& texture,
Resource const& resource
);
/// \~chinese
/// @brief 创建GIF图像
/// @param[out] gif GIF图像
/// @param[in] file_path 图片路径
void CreateGifImage(
GifImage& gif,
String const& file_path
);
/// \~chinese
/// @brief 创建GIF图像
/// @param[out] gif GIF图像
/// @param[in] resource 图片资源
void CreateGifImage(
GifImage& gif,
Resource const& resource
);
/// \~chinese
/// @brief 创建GIF图像帧
/// @param[out] frame GIF图像帧
/// @param[in] gif GIF图像
/// @param[in] frame_index 帧下标
void CreateGifImageFrame(
GifImage::Frame& frame,
GifImage const& gif,
size_t frame_index
);
/// \~chinese
/// @brief 创建字体集
/// @param[out] font 字体
/// @param[in] file_paths 字体文件路径
void CreateFontCollection(
Font& font,
Vector<String> const& file_paths
);
/// \~chinese
/// @brief 创建字体集
/// @param[out] font 字体
/// @param[in] res_arr 字体资源
void CreateFontCollection(
Font& font,
Vector<Resource> const& res_arr
);
/// \~chinese
/// @brief 创建文字格式
/// @param[out] layout 字体布局
void CreateTextFormat(
TextLayout& layout
);
/// \~chinese
/// @brief 创建文字布局
/// @param[out] layout 字体布局
void CreateTextLayout(
TextLayout& layout
);
/// \~chinese
/// @brief 创建线段形状
/// @param[out] geo 形状
/// @param[in] begin_pos 线段起点
/// @param[in] end_pos 线段终点
void CreateLineGeometry(
Geometry& geo,
Point const& begin_pos,
Point const& end_pos
);
/// \~chinese
/// @brief 创建矩形形状
/// @param[out] geo 形状
/// @param[in] rect 矩形大小
void CreateRectGeometry(
Geometry& geo,
Rect const& rect
);
/// \~chinese
/// @brief 创建圆角矩形形状
/// @param[out] geo 形状
/// @param[in] rect 矩形大小
/// @param[in] radius 圆角半径
void CreateRoundedRectGeometry(
Geometry& geo,
Rect const& rect,
Vec2 const& radius
);
/// \~chinese
/// @brief 创建椭圆形状
/// @param[out] geo 形状
/// @param[in] center 椭圆圆心
/// @param[in] radius 椭圆半径
void CreateEllipseGeometry(
Geometry& geo,
Point const& center,
Vec2 const& radius
);
/// \~chinese
/// @brief 创建几何图形生成器
/// @param[out] sink 形状生成器
void CreateGeometrySink(
GeometrySink& sink
);
/// \~chinese
/// @brief 创建纹理渲染目标
/// @param[out] render_target 渲染目标
void CreateTextureRenderTarget(
TextureRenderTargetPtr& render_target
);
/// \~chinese
/// @brief 创建纯色画刷
/// @param[out] brush 画刷
/// @param[in] color 颜色
void CreateSolidBrush(
Brush& brush,
Color const& color
);
/// \~chinese
/// @brief 创建线性渐变画刷
/// @param[out] brush 画刷
/// @param[in] begin 渐变起始点
/// @param[in] end 渐变终止点
/// @param[in] stops 渐变转换点集合
/// @param[in] extend_mode 渐变扩充模式
void CreateLinearGradientBrush(
Brush& brush,
Point const& begin,
@ -162,6 +245,14 @@ namespace kiwano
GradientExtendMode extend_mode
);
/// \~chinese
/// @brief 创建径向渐变画刷
/// @param[out] brush 画刷
/// @param[in] center 径向渐变圆心
/// @param[in] offset 径向渐变偏移
/// @param[in] radius 径向渐变半径
/// @param[in] stops 渐变转换点集合
/// @param[in] extend_mode 渐变扩充模式
void CreateRadialGradientBrush(
Brush& brush,
Point const& center,
@ -171,9 +262,22 @@ namespace kiwano
GradientExtendMode extend_mode
);
void SetDpi(
float dpi
);
public:
/// \~chinese
/// @brief 获取目标窗口
HWND GetTargetWindow() const;
/// \~chinese
/// @brief 获取渲染输出大小
Size const& GetOutputSize() const;
/// \~chinese
/// @brief 获取Direct2D设备资源
ID2DDeviceResources* GetD2DDeviceResources();
/// \~chinese
/// @brief 获取Direct3D设备资源
ID3DDeviceResources* GetD3DDeviceResources();
public:
void Init(RenderConfig const& config);
@ -188,17 +292,6 @@ namespace kiwano
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
public:
inline HWND GetTargetWindow() const { return hwnd_; }
inline Size const& GetOutputSize() const { return output_size_; }
inline Color const& GetClearColor() const { return clear_color_; }
inline ID2DDeviceResources* GetD2DDeviceResources() { KGE_ASSERT(d2d_res_); return d2d_res_.get(); }
inline ID3DDeviceResources* GetD3DDeviceResources() { KGE_ASSERT(d3d_res_); return d3d_res_.get(); }
private:
Renderer();
@ -221,4 +314,14 @@ namespace kiwano
ComPtr<IResourceFontFileLoader> res_font_file_loader_;
ComPtr<IResourceFontCollectionLoader> res_font_collection_loader_;
};
inline HWND Renderer::GetTargetWindow() const { return hwnd_; }
inline Size const& Renderer::GetOutputSize() const { return output_size_; }
inline Color const& Renderer::GetClearColor() const { return clear_color_; }
inline ID2DDeviceResources* Renderer::GetD2DDeviceResources() { KGE_ASSERT(d2d_res_); return d2d_res_.get(); }
inline ID3DDeviceResources* Renderer::GetD3DDeviceResources() { KGE_ASSERT(d3d_res_); return d3d_res_.get(); }
}

View File

@ -68,6 +68,14 @@ namespace kiwano
/// @brief 获取文本布局大小
Size GetLayoutSize() const;
/// \~chinese
/// @brief »ñÈ¡Ìî³ä»­Ë¢
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief »ñÈ¡Ãè±ß»­Ë¢
BrushPtr GetOutlineBrush() const;
/// \~chinese
/// @brief 设置文本
void SetText(const String& text);
@ -96,10 +104,6 @@ namespace kiwano
/// @brief 设置文字填充画刷
void SetFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字填充颜色(默认值为 Color::White
void SetFillColor(Color const& color);
/// \~chinese
/// @brief 设置文字斜体(默认值为 false
void SetItalic(bool italic);
@ -120,10 +124,6 @@ namespace kiwano
/// @brief 设置文字描边画刷
void SetOutlineBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字描边颜色
void SetOutlineColor(Color const& outline_color);
/// \~chinese
/// @brief 设置文字描边线宽
void SetOutlineWidth(float outline_width);
@ -173,7 +173,7 @@ namespace kiwano
inline bool TextLayout::IsValid() const
{
return !!text_layout_;
return text_layout_ != nullptr;
}
inline bool TextLayout::IsDirty() const
@ -201,16 +201,21 @@ namespace kiwano
return text_layout_;
}
inline BrushPtr TextLayout::GetFillBrush() const
{
return style_.fill_brush;
}
inline BrushPtr TextLayout::GetOutlineBrush() const
{
return style_.outline_brush;
}
inline void TextLayout::SetFillBrush(BrushPtr brush)
{
style_.fill_brush = brush;
}
inline void TextLayout::SetFillColor(Color const& color)
{
style_.SetFillColor(color);
}
inline void TextLayout::SetTextFormat(ComPtr<IDWriteTextFormat> format)
{
text_format_ = format;
@ -226,11 +231,6 @@ namespace kiwano
style_.outline_brush = brush;
}
inline void TextLayout::SetOutlineColor(Color const& outline_color)
{
style_.SetOutlineColor(outline_color);
}
inline void TextLayout::SetOutlineWidth(float outline_width)
{
style_.outline_width = outline_width;

View File

@ -90,30 +90,16 @@ namespace kiwano
* @param font_family
* @param font_size
* @param font_weight
* @param color Ìî³äÑÕÉ«
*/
TextStyle(const String& font_family, float font_size, uint32_t font_weight = FontWeight::Normal, Color color = Color::White);
void SetFillColor(Color const& color);
void SetOutlineColor(Color const& color);
TextStyle(const String& font_family, float font_size, uint32_t font_weight = FontWeight::Normal);
};
inline TextStyle::TextStyle()
: font(nullptr)
, font_family()
, font_size(18)
, font_weight(FontWeight::Normal)
, italic(false)
, alignment(TextAlign::Left)
, wrap_width(0)
, line_spacing(0)
, outline_width(1.0f)
, outline_stroke(StrokeStyle::Round)
: TextStyle(String(), 18, FontWeight::Normal)
{
}
inline TextStyle::TextStyle(const String& font_family, float font_size, uint32_t font_weight, Color color)
inline TextStyle::TextStyle(const String& font_family, float font_size, uint32_t font_weight)
: font(nullptr)
, font_family(font_family)
, font_size(font_size)
@ -127,22 +113,4 @@ namespace kiwano
{
}
inline void TextStyle::SetFillColor(Color const& color)
{
if (!fill_brush)
{
fill_brush = new Brush;
}
fill_brush->SetColor(color);
}
inline void TextStyle::SetOutlineColor(Color const& color)
{
if (!outline_brush)
{
outline_brush = new Brush;
}
outline_brush->SetColor(color);
}
}

View File

@ -176,6 +176,12 @@ namespace kiwano
void Texture::SetDefaultInterpolationMode(InterpolationMode mode)
{
default_interpolation_mode_ = mode;
}
InterpolationMode Texture::GetDefaultInterpolationMode()
{
return default_interpolation_mode_;
}
}

View File

@ -28,19 +28,23 @@ namespace kiwano
class TextureRenderTarget;
class Renderer;
// 插值模式
// 插值模式指定了位图在缩放和旋转时像素颜色的计算方式
// Linear (双线性插值): 对周围四个像素进行两次线性插值计算, 在图像放大时可能会模糊(默认)
// Nearest (最邻近插值): 取最邻近的像素点的颜色值
/**
* \~chinese
* @brief
* @details
*/
enum class InterpolationMode
{
Linear, // 双线性插值
Nearest, // 最邻近插值
Linear, ///< 双线性插值,对周围四个像素进行两次线性插值计算, 在图像放大时可能会模糊
Nearest, ///< 最邻近插值,取最邻近的像素点的颜色
};
KGE_DECLARE_SMART_PTR(Texture);
// 纹理
/**
* \~chinese
* @brief
*/
class KGE_API Texture
: public ObjectBase
{
@ -53,60 +57,81 @@ namespace kiwano
virtual ~Texture();
// 加载本地文件
bool Load(
String const& file_path
);
/// \~chinese
/// @brief 加载本地文件
bool Load(String const& file_path);
// 加载资源
bool Load(
Resource const& res
);
/// \~chinese
/// @brief 加载资源
bool Load(Resource const& res);
// 资源是否有效
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
// 获取宽度
/// \~chinese
/// @brief 获取纹理宽度
float GetWidth() const;
// 获取高度
/// \~chinese
/// @brief 获取纹理高度
float GetHeight() const;
// 获取大小
/// \~chinese
/// @brief 获取纹理大小
Size GetSize() const;
// 获取像素宽度
/// \~chinese
/// @brief 获取像素宽度
uint32_t GetWidthInPixels() const;
// 获取像素高度
/// \~chinese
/// @brief 获取像素高度
uint32_t GetHeightInPixels() const;
// 获取像素大小
/// \~chinese
/// @brief 获取像素大小
math::Vec2T<uint32_t> GetSizeInPixels() const;
// 获取像素插值方式
/// \~chinese
/// @brief 获取像素插值方式
InterpolationMode GetBitmapInterpolationMode() const;
// 获取像素格式
/// \~chinese
/// @brief 获取像素格式
D2D1_PIXEL_FORMAT GetPixelFormat() const;
// 拷贝位图内存
/// \~chinese
/// @brief 拷贝纹理
/// @param copy_from 源纹理
void CopyFrom(TexturePtr copy_from);
// 拷贝位图内存
/// \~chinese
/// @brief 拷贝纹理
/// @param copy_from 源纹理
/// @param src_rect 源纹理裁剪矩形
/// @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);
/// \~chinese
/// @brief 获取默认的像素插值方式
static InterpolationMode GetDefaultInterpolationMode();
private:
// 获取源位图
/// \~chinese
/// @brief 获取源位图
ComPtr<ID2D1Bitmap> GetBitmap() const;
// 设置源位图
/// \~chinese
/// @brief 设置源位图
void SetBitmap(ComPtr<ID2D1Bitmap> bitmap);
private:

View File

@ -24,22 +24,50 @@
namespace kiwano
{
/**
* \~chinese
* @brief
*/
class KGE_API TextureCache
: public Singleton<TextureCache>
{
friend Singleton<TextureCache>;
public:
/// \~chinese
/// @brief 添加或获取纹理
TexturePtr AddOrGetTexture(String const& file_path);
/// \~chinese
/// @brief 添加或获取纹理
TexturePtr AddOrGetTexture(Resource const& res);
/// \~chinese
/// @brief 添加或获取GIF图像
GifImagePtr AddOrGetGifImage(String const& file_path);
/// \~chinese
/// @brief 添加或获取GIF图像
GifImagePtr AddOrGetGifImage(Resource const& res);
/// \~chinese
/// @brief 移除纹理缓存
void RemoveTexture(String const& file_path);
/// \~chinese
/// @brief 移除纹理缓存
void RemoveTexture(Resource const& res);
/// \~chinese
/// @brief 移除GIF图像缓存
void RemoveGifImage(String const& file_path);
/// \~chinese
/// @brief 移除GIF图像缓存
void RemoveGifImage(Resource const& res);
/// \~chinese
/// @brief 清空缓存
void Clear();
private:

View File

@ -332,7 +332,7 @@ namespace kiwano
device_context_->SetTarget(target_bitmap_.get());
}
}
return E_NOTIMPL;
return hr;
}
HRESULT D2DDeviceResources::SetDpi(float dpi)

View File

@ -35,7 +35,10 @@ namespace kiwano
_In_ ID2D1RenderTarget* pRT
);
STDMETHOD_(void, SetStyle)(
STDMETHOD(DrawTextLayout)(
_In_ IDWriteTextLayout* pTextLayout,
float fOriginX,
float fOriginY,
_In_opt_ ID2D1Brush* pFillBrush,
_In_opt_ ID2D1Brush* pOutlineBrush,
float fOutlineWidth,
@ -93,6 +96,8 @@ namespace kiwano
__out float* pixelsPerDip
);
STDMETHOD_(uint32_t, GetLastPrimitivesCount)();
public:
unsigned long STDMETHODCALLTYPE AddRef();
unsigned long STDMETHODCALLTYPE Release();
@ -103,6 +108,7 @@ namespace kiwano
private:
unsigned long cRefCount_;
uint32_t cPrimitivesCount_;
float fOutlineWidth_;
ComPtr<ID2D1Factory> pFactory_;
ComPtr<ID2D1RenderTarget> pRT_;
@ -144,6 +150,7 @@ namespace kiwano
TextRenderer::TextRenderer()
: cRefCount_(0)
, cPrimitivesCount_(0)
, fOutlineWidth_(1)
{
if (pRT_)
@ -172,16 +179,27 @@ namespace kiwano
return hr;
}
STDMETHODIMP_(void) TextRenderer::SetStyle(
STDMETHODIMP TextRenderer::DrawTextLayout(
_In_ IDWriteTextLayout* pTextLayout,
float fOriginX,
float fOriginY,
_In_opt_ ID2D1Brush* pFillBrush,
_In_opt_ ID2D1Brush* pOutlineBrush,
float fOutlineWidth,
_In_opt_ ID2D1StrokeStyle* pStrokeStyle)
{
if (!pTextLayout)
{
return E_INVALIDARG;
}
cPrimitivesCount_ = 0;
pFillBrush_ = pFillBrush;
pOutlineBrush_ = pOutlineBrush;
fOutlineWidth_ = fOutlineWidth;
pCurrStrokeStyle_ = pStrokeStyle;
return pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
}
STDMETHODIMP TextRenderer::DrawGlyphRun(
@ -260,6 +278,8 @@ namespace kiwano
fOutlineWidth_ * 2, // twice width for widening
pCurrStrokeStyle_.get()
);
++cPrimitivesCount_;
}
}
}
@ -272,6 +292,8 @@ namespace kiwano
glyphRun,
pFillBrush_.get()
);
++cPrimitivesCount_;
}
return hr;
}
@ -325,16 +347,20 @@ namespace kiwano
fOutlineWidth_ * 2,
pCurrStrokeStyle_.get()
);
++cPrimitivesCount_;
}
if (SUCCEEDED(hr))
if (SUCCEEDED(hr) && pFillBrush_)
{
pRT_->FillGeometry(
pTransformedGeometry.get(),
pFillBrush_.get()
);
++cPrimitivesCount_;
}
return S_OK;
return hr;
}
STDMETHODIMP TextRenderer::DrawStrikethrough(
@ -386,16 +412,20 @@ namespace kiwano
fOutlineWidth_ * 2,
pCurrStrokeStyle_.get()
);
++cPrimitivesCount_;
}
if (SUCCEEDED(hr))
if (SUCCEEDED(hr) && pFillBrush_)
{
pRT_->FillGeometry(
pTransformedGeometry.get(),
pFillBrush_.get()
);
++cPrimitivesCount_;
}
return S_OK;
return hr;
}
STDMETHODIMP TextRenderer::DrawInlineObject(
@ -451,6 +481,11 @@ namespace kiwano
return S_OK;
}
STDMETHODIMP_(uint32_t) TextRenderer::GetLastPrimitivesCount()
{
return cPrimitivesCount_;
}
STDMETHODIMP_(unsigned long) TextRenderer::AddRef()
{
return InterlockedIncrement(&cRefCount_);

View File

@ -32,11 +32,16 @@ namespace kiwano
_In_ ID2D1RenderTarget* pRT
);
STDMETHOD_(void, SetStyle)(
STDMETHOD(DrawTextLayout)(
_In_ IDWriteTextLayout* pTextLayout,
float fOriginX,
float fOriginY,
_In_opt_ ID2D1Brush* pFillBrush,
_In_opt_ ID2D1Brush* pOutlineBrush,
float fOutlineWidth,
_In_opt_ ID2D1StrokeStyle* pStrokeStyle
) PURE;
STDMETHOD_(uint32_t, GetLastPrimitivesCount)() PURE;
};
}