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

View File

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

View File

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

View File

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

View File

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

View File

@ -174,9 +174,9 @@ namespace kiwano
loop_count_++; 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(); frame_rt_->EndDraw();

View File

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

View File

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

View File

@ -76,7 +76,7 @@ namespace kiwano
void Sprite::OnRender(RenderTarget* rt) 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 bool Sprite::CheckVisibilty(RenderTarget* rt) const

View File

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

View File

@ -27,6 +27,19 @@ namespace kiwano
namespace namespace
{ {
TextStyle text_default_style; 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) void TextActor::SetDefaultStyle(TextStyle const & style)
@ -34,6 +47,11 @@ namespace kiwano
text_default_style = style; text_default_style = style;
} }
const TextStyle& TextActor::GetDefaultStyle()
{
return text_default_style;
}
TextActor::TextActor() TextActor::TextActor()
: TextActor(String()) : 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); SetText(text);
SetStyle(style); SetStyle(style);
} }
@ -60,10 +82,22 @@ namespace kiwano
} }
void TextActor::OnUpdate(Duration dt) void TextActor::OnUpdate(Duration dt)
{
UpdateLayout();
}
void TextActor::UpdateLayout()
{ {
if (text_layout_.IsDirty()) if (text_layout_.IsDirty())
{ {
text_layout_.Update(); 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()); SetSize(text_layout_.GetLayoutSize());
} }
} }
@ -72,4 +106,24 @@ namespace kiwano
{ {
return text_layout_.IsValid() && Actor::CheckVisibilty(rt); 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 获取文本布局 /// @brief 获取文本布局
const TextLayout& GetLayout() const; const TextLayout& GetLayout() const;
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief 获取描边画刷
BrushPtr GetOutlineBrush() const;
/// \~chinese /// \~chinese
/// @brief 获取字体 /// @brief 获取字体
FontPtr GetFont() const; FontPtr GetFont() const;
@ -145,10 +153,19 @@ namespace kiwano
/// @brief 设置是否显示删除线(默认值为 false /// @brief 设置是否显示删除线(默认值为 false
void SetStrikethrough(bool enable); void SetStrikethrough(bool enable);
/// \~chinese
/// @brief 更新文字布局
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
void UpdateLayout();
/// \~chinese /// \~chinese
/// @brief 设置默认文字样式 /// @brief 设置默认文字样式
static void SetDefaultStyle(TextStyle const& style); static void SetDefaultStyle(TextStyle const& style);
/// \~chinese
/// @brief 获取默认文字样式
static const TextStyle& GetDefaultStyle();
void OnRender(RenderTarget* rt) override; void OnRender(RenderTarget* rt) override;
void OnUpdate(Duration dt) override; void OnUpdate(Duration dt) override;
@ -157,6 +174,8 @@ namespace kiwano
bool CheckVisibilty(RenderTarget* rt) const override; bool CheckVisibilty(RenderTarget* rt) const override;
private: private:
bool show_underline_;
bool show_strikethrough_;
TextLayout text_layout_; TextLayout text_layout_;
}; };
@ -182,6 +201,16 @@ namespace kiwano
return text_layout_; 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) inline void TextActor::SetText(String const& text)
{ {
text_layout_.SetText(text); text_layout_.SetText(text);
@ -234,12 +263,12 @@ namespace kiwano
inline void TextActor::SetUnderline(bool enable) inline void TextActor::SetUnderline(bool enable)
{ {
text_layout_.SetUnderline(enable, 0, text_layout_.GetText().length()); show_underline_ = enable;
} }
inline void TextActor::SetStrikethrough(bool 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) inline void TextActor::SetFillBrush(BrushPtr brush)
@ -247,21 +276,11 @@ namespace kiwano
text_layout_.SetFillBrush(brush); text_layout_.SetFillBrush(brush);
} }
inline void TextActor::SetFillColor(Color const& color)
{
text_layout_.SetFillColor(color);
}
inline void TextActor::SetOutlineBrush(BrushPtr brush) inline void TextActor::SetOutlineBrush(BrushPtr brush)
{ {
text_layout_.SetOutlineBrush(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) inline void TextActor::SetOutlineWidth(float outline_width)
{ {
text_layout_.SetOutlineWidth(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)); 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 /// \~chinese
/// @brief 构建帧动画 /// @brief 构建帧动画
/// @param duration 动画时长 /// @param duration 动画时长

View File

@ -20,7 +20,8 @@
#pragma once #pragma once
#include <kiwano/2d/action/ActionTween.h> #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 namespace kiwano
{ {

View File

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

View File

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

View File

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

View File

@ -19,16 +19,13 @@
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/renderer/Geometry.h> #include <kiwano/renderer/Geometry.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/renderer/Renderer.h> #include <kiwano/renderer/Renderer.h>
#include <kiwano/core/win32/helper.h> #include <kiwano/core/win32/helper.h>
namespace kiwano namespace kiwano
{ {
//
// Geometry
//
Geometry::Geometry() Geometry::Geometry()
{ {
} }
@ -92,32 +89,6 @@ namespace kiwano
geo_.reset(); 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 float Geometry::ComputeArea() const
{ {
if (!geo_) if (!geo_)
@ -129,7 +100,7 @@ namespace kiwano
return area; return area;
} }
bool Geometry::ContainsPoint(Point const& point, Matrix3x2 const& transform) const bool Geometry::ContainsPoint(Point const& point, const Matrix3x2* transform) const
{ {
if (!geo_) if (!geo_)
return false; return false;
@ -139,6 +110,7 @@ namespace kiwano
geo_->FillContainsPoint( geo_->FillContainsPoint(
DX::ConvertToPoint2F(point), DX::ConvertToPoint2F(point),
DX::ConvertToMatrix3x2F(transform), DX::ConvertToMatrix3x2F(transform),
D2D1_DEFAULT_FLATTENING_TOLERANCE,
&ret &ret
); );
return !!ret; return !!ret;
@ -179,136 +151,4 @@ namespace kiwano
return output; 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 Renderer;
class GeometrySink; class GeometrySink;
// 几何体 /**
* \~chinese
* @brief
*/
class KGE_API Geometry class KGE_API Geometry
{ {
friend class RenderTarget; friend class RenderTarget;
@ -37,179 +40,84 @@ namespace kiwano
public: public:
Geometry(); Geometry();
/// \~chinese
/// @brief 是否有效
bool IsValid() const; bool IsValid() const;
// 获取外切包围盒 /// \~chinese
/// @brief 获取外切包围盒
Rect GetBoundingBox() const; Rect GetBoundingBox() const;
// 获取外切包围盒 /// \~chinese
Rect GetBoundingBox( /// @brief 获取外切包围盒
Matrix3x2 const& transform /// @param transform 二维变换
) const; Rect GetBoundingBox(Matrix3x2 const& transform) const;
// 判断图形是否包含点 /// \~chinese
bool ContainsPoint( /// @brief 判断图形是否包含点
Point const& point, /// @param point 点
Matrix3x2 const& transform = Matrix3x2() /// @param transform 应用到点上的二维变换
) const; bool ContainsPoint(Point const& point, const Matrix3x2* transform = nullptr) const;
// 获取图形展开成一条直线的长度 /// \~chinese
/// @brief 获取图形展开成一条直线的长度
float GetLength() const; float GetLength() const;
// 计算面积 /// \~chinese
/// @brief 计算图形面积
float ComputeArea() const; float ComputeArea() const;
// 计算图形路径上点的位置和切线向量 /// \~chinese
bool ComputePointAtLength( /// @brief 计算图形上点的位置和切线向量
float length, /// @param[in] length 点在图形上的位置,范围 [0.0 - 1.0]
Point& point, /// @param[out] point 点的位置
Vec2& tangent /// @param[out] tangent 点的切线向量
) const; bool ComputePointAtLength(float length, Point& point, Vec2& tangent) const;
// 清除形状 /// \~chinese
/// @brief 清除形状
void Clear(); void Clear();
public: public:
// 几何体组合模式 /// \~chinese
enum class CombineMode /// @brief 创建线段
{ /// @param begin 线段起点
Union, /* 并集 (A + B) */ /// @param end 线段终点
Intersect, /* 交集 (A + B) */ static Geometry CreateLine(Point const& begin, Point const& end);
Xor, /* 对称差集 ((A - B) + (B - A)) */
Exclude /* 差集 (A - B) */
};
// 组合几何体 /// \~chinese
void CombineWith( /// @brief 创建矩形
GeometrySink& sink, /// @param rect 矩形
Geometry input, static Geometry CreateRect(Rect const& rect);
CombineMode mode,
Matrix3x2 const& input_matrix = Matrix3x2()
) const;
// 组合几何体 /// \~chinese
Geometry CombineWith( /// @brief 创建圆角矩形
Geometry input, /// @param rect 矩形
CombineMode mode, /// @param radius 矩形圆角半径
Matrix3x2 const& input_matrix = Matrix3x2() static Geometry CreateRoundedRect(Rect const& rect, Vec2 const& radius);
) const;
public: /// \~chinese
// 创建直线 /// @brief 创建圆形
static Geometry CreateLine( /// @param center 圆形原点
Point const& begin, /// @param radius 圆形半径
Point const& end static Geometry CreateCircle(Point const& center, float radius);
);
// 创建矩形 /// \~chinese
static Geometry CreateRect( /// @brief 创建椭圆形
Rect const& rect /// @param center 椭圆原点
); /// @param radius 椭圆半径
static Geometry CreateEllipse(Point const& center, Vec2 const& radius);
// 创建圆角矩形
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
);
private: 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: private:
ComPtr<ID2D1Geometry> geo_; ComPtr<ID2D1Geometry> geo_;
}; };
inline ComPtr<ID2D1Geometry> Geometry::GetGeometry() const { return geo_; }
// 几何体生成器 inline void Geometry::SetGeometry(ComPtr<ID2D1Geometry> geometry) { geo_ = geometry; }
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_;
};
} }

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); KGE_DECLARE_SMART_PTR(GifImage);
// GIF ͼÏñ /**
* \~chinese
* @brief GIF图像
*/
class KGE_API GifImage class KGE_API GifImage
: public ObjectBase : public ObjectBase
{ {
@ -37,37 +40,56 @@ namespace kiwano
public: public:
GifImage(); GifImage();
/// \~chinese
/// @brief 加载本地GIF图片
bool Load(String const& file_path); bool Load(String const& file_path);
/// \~chinese
/// @brief 加载GIF资源
bool Load(Resource const& res); bool Load(Resource const& res);
/// \~chinese
/// @brief 是否有效
bool IsValid() const; bool IsValid() const;
/// \~chinese
/// @brief 获取像素宽度
uint32_t GetWidthInPixels() const; uint32_t GetWidthInPixels() const;
/// \~chinese
/// @brief 获取像素高度
uint32_t GetHeightInPixels() const; uint32_t GetHeightInPixels() const;
/// \~chinese
/// @brief 获取帧数量
uint32_t GetFramesCount() const; uint32_t GetFramesCount() const;
public: public:
/// \~chinese
/// @brief GIF帧的处置方式
enum class DisposalType enum class DisposalType
{ {
Unknown, Unknown, ///< 未知
None, None, ///< 不处理
Background, Background, ///< 背景
Previous Previous ///< 恢复前一帧
}; };
/// \~chinese
/// @brief GIF帧
struct Frame struct Frame
{ {
Duration delay; Duration delay; ///< 帧延迟
TexturePtr raw; TexturePtr texture; ///< 帧图像
Rect rect; Rect rect; ///< 绘制区域
DisposalType disposal_type; DisposalType disposal_type; ///< 处置方式
Frame(); Frame();
}; };
/// \~chinese
/// @brief 获取GIF帧
/// @param index 帧下标
Frame GetFrame(uint32_t index); Frame GetFrame(uint32_t index);
private: 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; class RenderTarget;
// 暠꿔 /**
* \~chinese
* @brief
*/
class KGE_API LayerArea class KGE_API LayerArea
{ {
friend class RenderTarget; friend class RenderTarget;
@ -33,34 +36,46 @@ namespace kiwano
public: public:
LayerArea(); LayerArea();
/// \~chinese
/// @brief 是否有效
bool IsValid() const; 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>零暠꿔혐堵 /// \~chinese
inline void SetAreaRect(Rect const& area) { area_ = area; } /// @brief 设置图层透明度
void SetOpacity(float opacity);
// <20>零暠꿔拷츠똑 /// \~chinese
inline void SetOpacity(float opacity) { opacity_ = opacity; } /// @brief 设置几何蒙层
void SetMaskGeometry(Geometry const& mask);
// <20>零섯부촁꿔 /// \~chinese
inline void SetMaskGeometry(Geometry const& mask) { mask_ = mask; } /// @brief 设置几何蒙层变换
void SetMaskTransform(Matrix3x2 const& matrix);
// <20>零섯부촁꿔긴뻣
inline void SetMaskTransform(Matrix3x2 const& matrix) { mask_transform_ = matrix; }
private: 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: private:
Rect area_; Rect area_;
@ -69,4 +84,26 @@ namespace kiwano
Matrix3x2 mask_transform_; Matrix3x2 mask_transform_;
ComPtr<ID2D1Layer> layer_; 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() RenderTarget::RenderTarget()
: collecting_status_(false) : collecting_status_(false)
, fast_global_transform_(true) , fast_global_transform_(true)
, brush_opacity_(1.0f)
, antialias_(true) , antialias_(true)
, text_antialias_(TextAntialiasMode::GrayScale) , text_antialias_(TextAntialiasMode::GrayScale)
{ {
@ -290,12 +291,12 @@ namespace kiwano
IncreasePrimitivesCount(); 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!"); KGE_ASSERT(render_target_ && "Render target has not been initialized!");
@ -308,7 +309,7 @@ namespace kiwano
render_target_->DrawBitmap( render_target_->DrawBitmap(
texture.GetBitmap().get(), texture.GetBitmap().get(),
dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
opacity, brush_opacity_,
mode, mode,
src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr
); );
@ -321,23 +322,42 @@ namespace kiwano
{ {
KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!"); KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!");
const TextStyle& style = layout.GetStyle(); if (layout.IsValid())
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))
{ {
IncreasePrimitivesCount(); ComPtr<ID2D1Brush> fill_brush;
} ComPtr<ID2D1Brush> outline_brush;
else const TextStyle& style = layout.GetStyle();
{
KGE_ERROR(L"Failed to draw text layout with HRESULT of %08X", hr); 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; collecting_status_ = collecting;
} }
void RenderTarget::IncreasePrimitivesCount() const void RenderTarget::IncreasePrimitivesCount(uint32_t increase) const
{ {
if (collecting_status_) 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(RenderTarget);
KGE_DECLARE_SMART_PTR(TextureRenderTarget); KGE_DECLARE_SMART_PTR(TextureRenderTarget);
// 文字抗锯齿模式 /// \~chinese
/// @brief 文字抗锯齿模式
enum class TextAntialiasMode enum class TextAntialiasMode
{ {
Default, // 系统默认 Default, ///< 系统默认
ClearType, // ClearType 抗锯齿 ClearType, ///< ClearType 抗锯齿
GrayScale, // 灰度抗锯齿 GrayScale, ///< 灰度抗锯齿
None // 不启用抗锯齿 None ///< 不启用抗锯齿
}; };
// 渲染目标 /// \~chinese
/// @brief 渲染目标
/// @details 渲染目标将完成基础图元的绘制,并将绘制结果输出到特定的目标中(如窗口或纹理)
class KGE_API RenderTarget class KGE_API RenderTarget
: public ObjectBase : public ObjectBase
{ {
friend class Renderer; friend class Renderer;
public: public:
/// \~chinese
/// @brief 是否有效
bool IsValid() const; bool IsValid() const;
/// \~chinese
/// @brief 是否有效
void BeginDraw(); void BeginDraw();
/// \~chinese
/// @brief 是否有效
void EndDraw(); void EndDraw();
/// \~chinese
/// @brief 是否有效
void DrawGeometry( void DrawGeometry(
Geometry const& geometry, Geometry const& geometry,
float stroke_width, float stroke_width,
StrokeStyle stroke = StrokeStyle::Miter StrokeStyle stroke = StrokeStyle::Miter
); );
/// \~chinese
/// @brief 是否有效
void FillGeometry( void FillGeometry(
Geometry const& geometry Geometry const& geometry
); );
/// \~chinese
/// @brief 是否有效
void DrawLine( void DrawLine(
Point const& point1, Point const& point1,
Point const& point2, Point const& point2,
@ -76,16 +91,22 @@ namespace kiwano
StrokeStyle stroke = StrokeStyle::Miter StrokeStyle stroke = StrokeStyle::Miter
); );
/// \~chinese
/// @brief 是否有效
void DrawRectangle( void DrawRectangle(
Rect const& rect, Rect const& rect,
float stroke_width, float stroke_width,
StrokeStyle stroke = StrokeStyle::Miter StrokeStyle stroke = StrokeStyle::Miter
); );
/// \~chinese
/// @brief 是否有效
void FillRectangle( void FillRectangle(
Rect const& rect Rect const& rect
); );
/// \~chinese
/// @brief 是否有效
void DrawRoundedRectangle( void DrawRoundedRectangle(
Rect const& rect, Rect const& rect,
Vec2 const& radius, Vec2 const& radius,
@ -93,11 +114,15 @@ namespace kiwano
StrokeStyle stroke = StrokeStyle::Miter StrokeStyle stroke = StrokeStyle::Miter
); );
/// \~chinese
/// @brief 是否有效
void FillRoundedRectangle( void FillRoundedRectangle(
Rect const& rect, Rect const& rect,
Vec2 const& radius Vec2 const& radius
); );
/// \~chinese
/// @brief 是否有效
void DrawEllipse( void DrawEllipse(
Point const& center, Point const& center,
Vec2 const& radius, Vec2 const& radius,
@ -105,121 +130,179 @@ namespace kiwano
StrokeStyle stroke = StrokeStyle::Miter StrokeStyle stroke = StrokeStyle::Miter
); );
/// \~chinese
/// @brief 是否有效
void FillEllipse( void FillEllipse(
Point const& center, Point const& center,
Vec2 const& radius Vec2 const& radius
); );
/// \~chinese
/// @brief 是否有效
void DrawTexture( void DrawTexture(
Texture const& texture, Texture const& texture,
Rect const& src_rect, Rect const& src_rect,
Rect const& dest_rect, Rect const& dest_rect
float opacity = 1.0f
); );
/// \~chinese
/// @brief 是否有效
void DrawTexture( void DrawTexture(
Texture const& texture, Texture const& texture,
const Rect* src_rect = nullptr, const Rect* src_rect = nullptr,
const Rect* dest_rect = nullptr, const Rect* dest_rect = nullptr
float opacity = 1.0f
); );
/// \~chinese
/// @brief 是否有效
void DrawTextLayout( void DrawTextLayout(
TextLayout const& layout, TextLayout const& layout,
Point const& offset = Point{} Point const& offset = Point{}
); );
/// \~chinese
/// @brief 是否有效
void CreateTexture( void CreateTexture(
Texture& texture, Texture& texture,
math::Vec2T<uint32_t> size, math::Vec2T<uint32_t> size,
D2D1_PIXEL_FORMAT format D2D1_PIXEL_FORMAT format
); );
/// \~chinese
/// @brief 是否有效
void PushClipRect(Rect const& clip_rect); void PushClipRect(Rect const& clip_rect);
/// \~chinese
/// @brief 是否有效
void PopClipRect(); void PopClipRect();
/// \~chinese
/// @brief 是否有效
void PushLayer(LayerArea& layer); void PushLayer(LayerArea& layer);
/// \~chinese
/// @brief 是否有效
void PopLayer(); void PopLayer();
/// \~chinese
/// @brief 是否有效
void Clear(); void Clear();
/// \~chinese
/// @brief 是否有效
void Clear(Color const& clear_color); void Clear(Color const& clear_color);
/// \~chinese
/// @brief 是否有效
float GetBrushOpacity() const;
/// \~chinese
/// @brief 是否有效
BrushPtr GetCurrentBrush() const; BrushPtr GetCurrentBrush() const;
/// \~chinese
/// @brief 是否有效
Matrix3x2 GetGlobalTransform() const; Matrix3x2 GetGlobalTransform() const;
/// \~chinese
/// @brief 是否有效
void SetBrushOpacity(
float opacity
);
/// \~chinese
/// @brief 是否有效
void SetCurrentBrush( void SetCurrentBrush(
BrushPtr brush BrushPtr brush
); );
/// \~chinese
/// @brief 是否有效
void SetTransform( void SetTransform(
const Matrix3x2& matrix const Matrix3x2& matrix
); );
/// \~chinese
/// @brief 是否有效
void SetGlobalTransform( void SetGlobalTransform(
const Matrix3x2& matrix const Matrix3x2& matrix
); );
/// \~chinese
/// @brief 是否有效
void SetGlobalTransform( void SetGlobalTransform(
const Matrix3x2* matrix const Matrix3x2* matrix
); );
// 设置抗锯齿模式 /// \~chinese
/// @brief 设置抗锯齿模式
void SetAntialiasMode( void SetAntialiasMode(
bool enabled bool enabled
); );
// 设置文字抗锯齿模式 /// \~chinese
/// @brief 设置文字抗锯齿模式
void SetTextAntialiasMode( void SetTextAntialiasMode(
TextAntialiasMode mode TextAntialiasMode mode
); );
// 检查边界是否在视区内 /// \~chinese
/// @brief 检查边界是否在视区内
bool CheckVisibility( bool CheckVisibility(
Rect const& bounds, Rect const& bounds,
Matrix3x2 const& transform Matrix3x2 const& transform
); );
void Resize( /// \~chinese
Size const& size /// @brief 重设渲染目标大小
); void Resize(Size const& size);
public: public:
/// \~chinese
/// @brief 渲染目标状态
struct Status struct Status
{ {
int primitives; uint32_t primitives; ///< 渲染图元数量
Time start; Time start; ///< 渲染起始时间
Duration duration; Duration duration; ///< 渲染时长
Status() : primitives(0) {} Status();
}; };
/// \~chinese
/// @brief 启用或禁用状态收集功能
void SetCollectingStatus(bool collecting); void SetCollectingStatus(bool collecting);
void IncreasePrimitivesCount() const; /// \~chinese
/// @brief 获取渲染目标状态
inline Status const& GetStatus() const { return status_; } Status const& GetStatus() const;
protected: protected:
RenderTarget(); 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: private:
/// \~chinese
/// @brief 创建设备依赖资源
HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> rt); HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> rt);
/// \~chinese
/// @brief 销毁设备依赖资源
void DiscardDeviceResources(); void DiscardDeviceResources();
/// \~chinese
/// @brief 增加渲染图元数量
void IncreasePrimitivesCount(uint32_t increase = 1) const;
private: private:
bool antialias_; bool antialias_;
bool fast_global_transform_; bool fast_global_transform_;
float brush_opacity_;
TextAntialiasMode text_antialias_; TextAntialiasMode text_antialias_;
ComPtr<ITextRenderer> text_renderer_; ComPtr<ITextRenderer> text_renderer_;
ComPtr<ID2D1RenderTarget> render_target_; ComPtr<ID2D1RenderTarget> render_target_;
@ -250,6 +333,8 @@ namespace kiwano
/// \~chinese /// \~chinese
/// @brief »ñÈ¡äÖȾÊä³ö /// @brief »ñÈ¡äÖȾÊä³ö
/// @param[out] texture 纹理输出
/// @return 操作是否成功
bool GetOutput(Texture& texture); bool GetOutput(Texture& texture);
private: 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 inline BrushPtr RenderTarget::GetCurrentBrush() const
{ {
return current_brush_; return current_brush_;
@ -274,6 +386,11 @@ namespace kiwano
return global_transform_; return global_transform_;
} }
inline void RenderTarget::SetBrushOpacity(float opacity)
{
brush_opacity_ = opacity;
}
inline void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix) inline void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix)
{ {
SetGlobalTransform(&matrix); SetGlobalTransform(&matrix);
@ -282,6 +399,10 @@ namespace kiwano
inline void RenderTarget::SetCurrentBrush(BrushPtr brush) inline void RenderTarget::SetCurrentBrush(BrushPtr brush)
{ {
current_brush_ = brush; current_brush_ = brush;
if (current_brush_)
{
current_brush_->SetOpacity(brush_opacity_);
}
} }
inline bool TextureRenderTarget::IsValid() const inline bool TextureRenderTarget::IsValid() const

View File

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

View File

@ -41,11 +41,14 @@ namespace kiwano
typedef ID3D11DeviceResources ID3DDeviceResources; typedef ID3D11DeviceResources ID3DDeviceResources;
#endif #endif
// 渲染设置 /**
* \~chinese
* @brief
*/
struct RenderConfig struct RenderConfig
{ {
Color clear_color; // 清屏颜色 Color clear_color; ///< 清屏颜色
bool vsync; // 垂直同步 bool vsync; ///< 垂直同步
RenderConfig( RenderConfig(
Color clear_color = Color::Black, Color clear_color = Color::Black,
@ -54,7 +57,10 @@ namespace kiwano
}; };
// 渲染器 /**
* \~chinese
* @brief
*/
class KGE_API Renderer class KGE_API Renderer
: public Singleton<Renderer> : public Singleton<Renderer>
, public RenderComponent , public RenderComponent
@ -64,96 +70,173 @@ namespace kiwano
friend Singleton<Renderer>; friend Singleton<Renderer>;
public: public:
// 设置清屏颜色 /// \~chinese
void SetClearColor( /// @brief 获取清屏颜色
Color const& clear_color Color const& GetClearColor() const;
);
// 开启或关闭垂直同步 /// \~chinese
void SetVSyncEnabled( /// @brief 设置清屏颜色
bool enabled 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( void CreateTexture(
Texture& texture, Texture& texture,
String const& file_path String const& file_path
); );
/// \~chinese
/// @brief 创建纹理
/// @param[out] texture 纹理
/// @param[in] resource 图片资源
void CreateTexture( void CreateTexture(
Texture& texture, Texture& texture,
Resource const& resource Resource const& resource
); );
/// \~chinese
/// @brief 创建GIF图像
/// @param[out] gif GIF图像
/// @param[in] file_path 图片路径
void CreateGifImage( void CreateGifImage(
GifImage& gif, GifImage& gif,
String const& file_path String const& file_path
); );
/// \~chinese
/// @brief 创建GIF图像
/// @param[out] gif GIF图像
/// @param[in] resource 图片资源
void CreateGifImage( void CreateGifImage(
GifImage& gif, GifImage& gif,
Resource const& resource Resource const& resource
); );
/// \~chinese
/// @brief 创建GIF图像帧
/// @param[out] frame GIF图像帧
/// @param[in] gif GIF图像
/// @param[in] frame_index 帧下标
void CreateGifImageFrame( void CreateGifImageFrame(
GifImage::Frame& frame, GifImage::Frame& frame,
GifImage const& gif, GifImage const& gif,
size_t frame_index size_t frame_index
); );
/// \~chinese
/// @brief 创建字体集
/// @param[out] font 字体
/// @param[in] file_paths 字体文件路径
void CreateFontCollection( void CreateFontCollection(
Font& font, Font& font,
Vector<String> const& file_paths Vector<String> const& file_paths
); );
/// \~chinese
/// @brief 创建字体集
/// @param[out] font 字体
/// @param[in] res_arr 字体资源
void CreateFontCollection( void CreateFontCollection(
Font& font, Font& font,
Vector<Resource> const& res_arr Vector<Resource> const& res_arr
); );
/// \~chinese
/// @brief 创建文字格式
/// @param[out] layout 字体布局
void CreateTextFormat( void CreateTextFormat(
TextLayout& layout TextLayout& layout
); );
/// \~chinese
/// @brief 创建文字布局
/// @param[out] layout 字体布局
void CreateTextLayout( void CreateTextLayout(
TextLayout& layout TextLayout& layout
); );
/// \~chinese
/// @brief 创建线段形状
/// @param[out] geo 形状
/// @param[in] begin_pos 线段起点
/// @param[in] end_pos 线段终点
void CreateLineGeometry( void CreateLineGeometry(
Geometry& geo, Geometry& geo,
Point const& begin_pos, Point const& begin_pos,
Point const& end_pos Point const& end_pos
); );
/// \~chinese
/// @brief 创建矩形形状
/// @param[out] geo 形状
/// @param[in] rect 矩形大小
void CreateRectGeometry( void CreateRectGeometry(
Geometry& geo, Geometry& geo,
Rect const& rect Rect const& rect
); );
/// \~chinese
/// @brief 创建圆角矩形形状
/// @param[out] geo 形状
/// @param[in] rect 矩形大小
/// @param[in] radius 圆角半径
void CreateRoundedRectGeometry( void CreateRoundedRectGeometry(
Geometry& geo, Geometry& geo,
Rect const& rect, Rect const& rect,
Vec2 const& radius Vec2 const& radius
); );
/// \~chinese
/// @brief 创建椭圆形状
/// @param[out] geo 形状
/// @param[in] center 椭圆圆心
/// @param[in] radius 椭圆半径
void CreateEllipseGeometry( void CreateEllipseGeometry(
Geometry& geo, Geometry& geo,
Point const& center, Point const& center,
Vec2 const& radius Vec2 const& radius
); );
/// \~chinese
/// @brief 创建几何图形生成器
/// @param[out] sink 形状生成器
void CreateGeometrySink( void CreateGeometrySink(
GeometrySink& sink GeometrySink& sink
); );
/// \~chinese
/// @brief 创建纹理渲染目标
/// @param[out] render_target 渲染目标
void CreateTextureRenderTarget( void CreateTextureRenderTarget(
TextureRenderTargetPtr& render_target TextureRenderTargetPtr& render_target
); );
/// \~chinese
/// @brief 创建纯色画刷
/// @param[out] brush 画刷
/// @param[in] color 颜色
void CreateSolidBrush( void CreateSolidBrush(
Brush& brush, Brush& brush,
Color const& color Color const& color
); );
/// \~chinese
/// @brief 创建线性渐变画刷
/// @param[out] brush 画刷
/// @param[in] begin 渐变起始点
/// @param[in] end 渐变终止点
/// @param[in] stops 渐变转换点集合
/// @param[in] extend_mode 渐变扩充模式
void CreateLinearGradientBrush( void CreateLinearGradientBrush(
Brush& brush, Brush& brush,
Point const& begin, Point const& begin,
@ -162,6 +245,14 @@ namespace kiwano
GradientExtendMode extend_mode 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( void CreateRadialGradientBrush(
Brush& brush, Brush& brush,
Point const& center, Point const& center,
@ -171,9 +262,22 @@ namespace kiwano
GradientExtendMode extend_mode GradientExtendMode extend_mode
); );
void SetDpi( public:
float dpi /// \~chinese
); /// @brief 获取目标窗口
HWND GetTargetWindow() const;
/// \~chinese
/// @brief 获取渲染输出大小
Size const& GetOutputSize() const;
/// \~chinese
/// @brief 获取Direct2D设备资源
ID2DDeviceResources* GetD2DDeviceResources();
/// \~chinese
/// @brief 获取Direct3D设备资源
ID3DDeviceResources* GetD3DDeviceResources();
public: public:
void Init(RenderConfig const& config); void Init(RenderConfig const& config);
@ -188,17 +292,6 @@ namespace kiwano
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override; 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: private:
Renderer(); Renderer();
@ -221,4 +314,14 @@ namespace kiwano
ComPtr<IResourceFontFileLoader> res_font_file_loader_; ComPtr<IResourceFontFileLoader> res_font_file_loader_;
ComPtr<IResourceFontCollectionLoader> res_font_collection_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 获取文本布局大小 /// @brief 获取文本布局大小
Size GetLayoutSize() const; Size GetLayoutSize() const;
/// \~chinese
/// @brief »ñÈ¡Ìî³ä»­Ë¢
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief »ñÈ¡Ãè±ß»­Ë¢
BrushPtr GetOutlineBrush() const;
/// \~chinese /// \~chinese
/// @brief 设置文本 /// @brief 设置文本
void SetText(const String& text); void SetText(const String& text);
@ -96,10 +104,6 @@ namespace kiwano
/// @brief 设置文字填充画刷 /// @brief 设置文字填充画刷
void SetFillBrush(BrushPtr brush); void SetFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字填充颜色(默认值为 Color::White
void SetFillColor(Color const& color);
/// \~chinese /// \~chinese
/// @brief 设置文字斜体(默认值为 false /// @brief 设置文字斜体(默认值为 false
void SetItalic(bool italic); void SetItalic(bool italic);
@ -120,10 +124,6 @@ namespace kiwano
/// @brief 设置文字描边画刷 /// @brief 设置文字描边画刷
void SetOutlineBrush(BrushPtr brush); void SetOutlineBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字描边颜色
void SetOutlineColor(Color const& outline_color);
/// \~chinese /// \~chinese
/// @brief 设置文字描边线宽 /// @brief 设置文字描边线宽
void SetOutlineWidth(float outline_width); void SetOutlineWidth(float outline_width);
@ -173,7 +173,7 @@ namespace kiwano
inline bool TextLayout::IsValid() const inline bool TextLayout::IsValid() const
{ {
return !!text_layout_; return text_layout_ != nullptr;
} }
inline bool TextLayout::IsDirty() const inline bool TextLayout::IsDirty() const
@ -201,16 +201,21 @@ namespace kiwano
return text_layout_; 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) inline void TextLayout::SetFillBrush(BrushPtr brush)
{ {
style_.fill_brush = brush; style_.fill_brush = brush;
} }
inline void TextLayout::SetFillColor(Color const& color)
{
style_.SetFillColor(color);
}
inline void TextLayout::SetTextFormat(ComPtr<IDWriteTextFormat> format) inline void TextLayout::SetTextFormat(ComPtr<IDWriteTextFormat> format)
{ {
text_format_ = format; text_format_ = format;
@ -226,11 +231,6 @@ namespace kiwano
style_.outline_brush = brush; style_.outline_brush = brush;
} }
inline void TextLayout::SetOutlineColor(Color const& outline_color)
{
style_.SetOutlineColor(outline_color);
}
inline void TextLayout::SetOutlineWidth(float outline_width) inline void TextLayout::SetOutlineWidth(float outline_width)
{ {
style_.outline_width = outline_width; style_.outline_width = outline_width;

View File

@ -90,30 +90,16 @@ namespace kiwano
* @param font_family * @param font_family
* @param font_size * @param font_size
* @param font_weight * @param font_weight
* @param color Ìî³äÑÕÉ«
*/ */
TextStyle(const String& font_family, float font_size, uint32_t font_weight = FontWeight::Normal, Color color = Color::White); TextStyle(const String& font_family, float font_size, uint32_t font_weight = FontWeight::Normal);
void SetFillColor(Color const& color);
void SetOutlineColor(Color const& color);
}; };
inline TextStyle::TextStyle() inline TextStyle::TextStyle()
: font(nullptr) : TextStyle(String(), 18, FontWeight::Normal)
, 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)
{ {
} }
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(nullptr)
, font_family(font_family) , font_family(font_family)
, font_size(font_size) , 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) 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 TextureRenderTarget;
class Renderer; class Renderer;
// 插值模式 /**
// 插值模式指定了位图在缩放和旋转时像素颜色的计算方式 * \~chinese
// Linear (双线性插值): 对周围四个像素进行两次线性插值计算, 在图像放大时可能会模糊(默认) * @brief
// Nearest (最邻近插值): 取最邻近的像素点的颜色值 * @details
*/
enum class InterpolationMode enum class InterpolationMode
{ {
Linear, // 双线性插值 Linear, ///< 双线性插值,对周围四个像素进行两次线性插值计算, 在图像放大时可能会模糊
Nearest, // 最邻近插值 Nearest, ///< 最邻近插值,取最邻近的像素点的颜色
}; };
KGE_DECLARE_SMART_PTR(Texture); KGE_DECLARE_SMART_PTR(Texture);
// 纹理 /**
* \~chinese
* @brief
*/
class KGE_API Texture class KGE_API Texture
: public ObjectBase : public ObjectBase
{ {
@ -53,60 +57,81 @@ namespace kiwano
virtual ~Texture(); virtual ~Texture();
// 加载本地文件 /// \~chinese
bool Load( /// @brief 加载本地文件
String const& file_path bool Load(String const& file_path);
);
// 加载资源 /// \~chinese
bool Load( /// @brief 加载资源
Resource const& res bool Load(Resource const& res);
);
// 资源是否有效 /// \~chinese
/// @brief 是否有效
bool IsValid() const; bool IsValid() const;
// 获取宽度 /// \~chinese
/// @brief 获取纹理宽度
float GetWidth() const; float GetWidth() const;
// 获取高度 /// \~chinese
/// @brief 获取纹理高度
float GetHeight() const; float GetHeight() const;
// 获取大小 /// \~chinese
/// @brief 获取纹理大小
Size GetSize() const; Size GetSize() const;
// 获取像素宽度 /// \~chinese
/// @brief 获取像素宽度
uint32_t GetWidthInPixels() const; uint32_t GetWidthInPixels() const;
// 获取像素高度 /// \~chinese
/// @brief 获取像素高度
uint32_t GetHeightInPixels() const; uint32_t GetHeightInPixels() const;
// 获取像素大小 /// \~chinese
/// @brief 获取像素大小
math::Vec2T<uint32_t> GetSizeInPixels() const; math::Vec2T<uint32_t> GetSizeInPixels() const;
// 获取像素插值方式 /// \~chinese
/// @brief 获取像素插值方式
InterpolationMode GetBitmapInterpolationMode() const; InterpolationMode GetBitmapInterpolationMode() const;
// 获取像素格式 /// \~chinese
/// @brief 获取像素格式
D2D1_PIXEL_FORMAT GetPixelFormat() const; D2D1_PIXEL_FORMAT GetPixelFormat() const;
// 拷贝位图内存 /// \~chinese
/// @brief 拷贝纹理
/// @param copy_from 源纹理
void CopyFrom(TexturePtr 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); void CopyFrom(TexturePtr copy_from, Rect const& src_rect, Point const& dest_point);
// 设置像素插值方式 /// \~chinese
/// @brief 设置像素插值方式
void SetInterpolationMode(InterpolationMode mode); void SetInterpolationMode(InterpolationMode mode);
// 设置默认的像素插值方式 /// \~chinese
/// @brief 设置默认的像素插值方式
static void SetDefaultInterpolationMode(InterpolationMode mode); static void SetDefaultInterpolationMode(InterpolationMode mode);
/// \~chinese
/// @brief 获取默认的像素插值方式
static InterpolationMode GetDefaultInterpolationMode();
private: private:
// 获取源位图 /// \~chinese
/// @brief 获取源位图
ComPtr<ID2D1Bitmap> GetBitmap() const; ComPtr<ID2D1Bitmap> GetBitmap() const;
// 设置源位图 /// \~chinese
/// @brief 设置源位图
void SetBitmap(ComPtr<ID2D1Bitmap> bitmap); void SetBitmap(ComPtr<ID2D1Bitmap> bitmap);
private: private:

View File

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

View File

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

View File

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

View File

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