add: finished the Canvas

minor fixes
This commit is contained in:
Haibo 2018-11-18 20:26:41 +08:00 committed by Nomango
parent 18990c3ee6
commit 7b67d49c93
22 changed files with 759 additions and 495 deletions

View File

@ -21,91 +21,159 @@
#include "Canvas.h" #include "Canvas.h"
#include "render.h" #include "render.h"
#include "logs.h" #include "logs.h"
#include "Image.h"
namespace easy2d namespace easy2d
{ {
//------------------------------------------------------- Canvas::Canvas()
// CanvasBrush : cache_expired_(false)
//-------------------------------------------------------
CanvasBrush::CanvasBrush()
: render_target_(nullptr)
, fill_brush_(nullptr)
, line_brush_(nullptr)
, stroke_style_(nullptr)
, stroke_width_(1.0f) , stroke_width_(1.0f)
, stroke_(StrokeStyle::Miter)
{ {
auto graphics = devices::Graphics::Instance();
render_target_ = graphics->GetRenderTarget();
ThrowIfFailed( ThrowIfFailed(
graphics->CreateSolidColorBrush(fill_brush_) devices::Graphics::Instance()->CreateBitmapRenderTarget(render_target_)
);
auto properties = D2D1::BrushProperties();
ThrowIfFailed(
render_target_->CreateSolidColorBrush(
Color(Color::White, 0.f),
properties,
&fill_brush_)
); );
ThrowIfFailed( ThrowIfFailed(
graphics->CreateSolidColorBrush(line_brush_) render_target_->CreateSolidColorBrush(
Color(Color::White),
properties,
&stroke_brush_)
); );
this->SetStrokeStyle(stroke_); ThrowIfFailed(
render_target_->CreateSolidColorBrush(
Color(Color::White),
properties,
&text_brush_)
);
ThrowIfFailed(
devices::Graphics::Instance()->CreateTextRenderer(
text_renderer_,
render_target_,
text_brush_
)
);
SetTextStyle(Font{}, TextStyle{});
} }
CanvasBrush::~CanvasBrush() Canvas::Canvas(float width, float height)
: Canvas()
{
this->SetSize(width, height);
}
Canvas::Canvas(Size const & size)
: Canvas(size.width, size.height)
{ {
} }
void CanvasBrush::SetLineColor(Color const& color) Canvas::~Canvas()
{ {
line_brush_->SetColor(D2D_COLOR_F(color));
} }
void CanvasBrush::SetFillColor(Color const& color) void Canvas::BeginDraw()
{ {
fill_brush_->SetColor(D2D_COLOR_F(color)); render_target_->BeginDraw();
} }
void CanvasBrush::SetStrokeWidth(float width) void Canvas::EndDraw()
{
ThrowIfFailed(
render_target_->EndDraw()
);
cache_expired_ = true;
}
void Canvas::OnDraw()
{
if (cache_expired_)
{
GetBitmap();
}
if (bitmap_cached_)
{
devices::Graphics::Instance()->DrawBitmap(bitmap_cached_);
}
}
void Canvas::SetStrokeColor(Color const& color)
{
stroke_brush_->SetColor(color);
}
void Canvas::SetFillColor(Color const& color)
{
fill_brush_->SetColor(color);
}
void Canvas::SetStrokeWidth(float width)
{ {
stroke_width_ = std::max(width, 0.f); stroke_width_ = std::max(width, 0.f);
} }
void CanvasBrush::SetStrokeStyle(StrokeStyle stroke) void Canvas::SetOutlineJoinStyle(StrokeStyle outline_join)
{ {
stroke_style_ = devices::Graphics::Instance()->GetStrokeStyle(stroke); outline_join_style_ = devices::Graphics::Instance()->GetStrokeStyle(outline_join);
} }
Color CanvasBrush::GetLineColor() const void Canvas::SetTextStyle(Font const& font, TextStyle const & text_style)
{ {
return line_brush_->GetColor(); text_font_ = font;
text_style_ = text_style;
text_renderer_->SetTextStyle(
text_style_.color,
text_style_.outline,
text_style_.outline_color,
text_style_.outline_width,
devices::Graphics::Instance()->GetStrokeStyle(text_style_.outline_stroke).Get()
);
} }
Color CanvasBrush::GetFillColor() const Color Canvas::GetStrokeColor() const
{
return stroke_brush_->GetColor();
}
Color Canvas::GetFillColor() const
{ {
return fill_brush_->GetColor(); return fill_brush_->GetColor();
} }
float CanvasBrush::GetStrokeWidth() const float Canvas::GetStrokeWidth() const
{ {
return stroke_width_; return stroke_width_;
} }
StrokeStyle CanvasBrush::GetStrokeStyle() const void Canvas::SetBrushTransform(math::Matrix const & transform)
{ {
return stroke_; render_target_->SetTransform(ConvertToD2DMatrix(transform));
} }
void CanvasBrush::DrawLine(const Point & begin, const Point & end) void Canvas::DrawLine(const Point & begin, const Point & end)
{ {
render_target_->DrawLine( render_target_->DrawLine(
D2D1::Point2F(begin.x, begin.y), D2D1::Point2F(begin.x, begin.y),
D2D1::Point2F(end.x, end.y), D2D1::Point2F(end.x, end.y),
line_brush_.Get(), stroke_brush_.Get(),
stroke_width_, stroke_width_,
stroke_style_.Get() outline_join_style_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::DrawCircle(const Point & center, float radius) void Canvas::DrawCircle(const Point & center, float radius)
{ {
render_target_->DrawEllipse( render_target_->DrawEllipse(
D2D1::Ellipse( D2D1::Ellipse(
@ -116,13 +184,14 @@ namespace easy2d
radius, radius,
radius radius
), ),
line_brush_.Get(), stroke_brush_.Get(),
stroke_width_, stroke_width_,
stroke_style_.Get() outline_join_style_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::DrawEllipse(const Point & center, float radius_x, float radius_y) void Canvas::DrawEllipse(const Point & center, float radius_x, float radius_y)
{ {
render_target_->DrawEllipse( render_target_->DrawEllipse(
D2D1::Ellipse( D2D1::Ellipse(
@ -133,13 +202,14 @@ namespace easy2d
radius_x, radius_x,
radius_y radius_y
), ),
line_brush_.Get(), stroke_brush_.Get(),
stroke_width_, stroke_width_,
stroke_style_.Get() outline_join_style_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::DrawRect(const Rect & rect) void Canvas::DrawRect(const Rect & rect)
{ {
render_target_->DrawRectangle( render_target_->DrawRectangle(
D2D1::RectF( D2D1::RectF(
@ -148,13 +218,14 @@ namespace easy2d
rect.origin.x + rect.size.width, rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height rect.origin.y + rect.size.height
), ),
line_brush_.Get(), stroke_brush_.Get(),
stroke_width_, stroke_width_,
stroke_style_.Get() outline_join_style_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::DrawRoundedRect(const Rect & rect, float radius_x, float radius_y) void Canvas::DrawRoundedRect(const Rect & rect, float radius_x, float radius_y)
{ {
render_target_->DrawRoundedRectangle( render_target_->DrawRoundedRectangle(
D2D1::RoundedRect( D2D1::RoundedRect(
@ -167,13 +238,62 @@ namespace easy2d
radius_x, radius_x,
radius_y radius_y
), ),
line_brush_.Get(), stroke_brush_.Get(),
stroke_width_, stroke_width_,
stroke_style_.Get() outline_join_style_.Get()
);
cache_expired_ = true;
}
void Canvas::DrawImage(spImage const & image, float opacity)
{
if (image->GetBitmap())
{
render_target_->DrawBitmap(
image->GetBitmap().Get(),
Rect{ Point{}, image->GetSize() },
opacity,
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
image->GetCropRect()
);
cache_expired_ = true;
}
}
void Canvas::DrawText(String const & text, Point const & point)
{
if (text.empty())
return;
auto graphics = devices::Graphics::Instance();
cpTextFormat text_format;
ThrowIfFailed(
graphics->CreateTextFormat(
text_format,
text_font_,
text_style_
)
);
cpTextLayout text_layout;
Size layout_size;
ThrowIfFailed(
graphics->CreateTextLayout(
text_layout,
layout_size,
text,
text_format,
text_style_
)
);
ThrowIfFailed(
text_layout->Draw(nullptr, text_renderer_.Get(), point.x, point.y)
); );
} }
void CanvasBrush::FillCircle(const Point & center, float radius) void Canvas::FillCircle(const Point & center, float radius)
{ {
render_target_->FillEllipse( render_target_->FillEllipse(
D2D1::Ellipse( D2D1::Ellipse(
@ -186,9 +306,10 @@ namespace easy2d
), ),
fill_brush_.Get() fill_brush_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::FillEllipse(const Point & center, float radius_x, float radius_y) void Canvas::FillEllipse(const Point & center, float radius_x, float radius_y)
{ {
render_target_->FillEllipse( render_target_->FillEllipse(
D2D1::Ellipse( D2D1::Ellipse(
@ -201,9 +322,10 @@ namespace easy2d
), ),
fill_brush_.Get() fill_brush_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::FillRect(const Rect & rect) void Canvas::FillRect(const Rect & rect)
{ {
render_target_->FillRectangle( render_target_->FillRectangle(
D2D1::RectF( D2D1::RectF(
@ -214,9 +336,10 @@ namespace easy2d
), ),
fill_brush_.Get() fill_brush_.Get()
); );
cache_expired_ = true;
} }
void CanvasBrush::FillRoundedRect(const Rect & rect, float radius_x, float radius_y) void Canvas::FillRoundedRect(const Rect & rect, float radius_x, float radius_y)
{ {
render_target_->FillRoundedRectangle( render_target_->FillRoundedRectangle(
D2D1::RoundedRect( D2D1::RoundedRect(
@ -231,38 +354,115 @@ namespace easy2d
), ),
fill_brush_.Get() fill_brush_.Get()
); );
cache_expired_ = true;
} }
void Canvas::BeginPath(Point const& begin_pos)
//-------------------------------------------------------
// Canvas
//-------------------------------------------------------
Canvas::Canvas()
{ {
current_geometry_ = nullptr;
ThrowIfFailed(
devices::Graphics::Instance()->CreatePathGeometry(current_geometry_)
);
ThrowIfFailed(
current_geometry_->Open(&current_sink_)
);
current_sink_->BeginFigure(begin_pos, D2D1_FIGURE_BEGIN_FILLED);
} }
Canvas::Canvas(float width, float height) void Canvas::EndPath(bool closed)
{ {
this->SetClipEnabled(true); if (current_sink_)
this->SetWidth(width); {
this->SetHeight(height); current_sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
ThrowIfFailed(
current_sink_->Close()
);
current_sink_ = nullptr;
}
} }
Canvas::~Canvas() void Canvas::AddLine(Point const & point)
{ {
if (current_sink_)
current_sink_->AddLine(point);
} }
void Canvas::SetBrush(spCanvasBrush const & brush) void Canvas::AddLines(std::vector<Point> const& points)
{ {
brush_ = brush; if (current_sink_)
{
if (!points.empty())
{
size_t size = points.size();
std::vector<D2D1_POINT_2F> d2d_points(size);
for (size_t i = 0; i < size; ++i)
{
d2d_points[i] = points[i];
}
current_sink_->AddLines(
&d2d_points[0],
static_cast<UINT32>(size)
);
}
}
} }
void Canvas::OnDraw() void Canvas::AddBezier(Point const & point1, Point const & point2, Point const & point3)
{ {
if (!brush_) if (current_sink_)
brush_ = new CanvasBrush; {
current_sink_->AddBezier(
OnDraw(*brush_); D2D1::BezierSegment(
point1,
point2,
point3
)
);
}
} }
void Canvas::StrokePath()
{
render_target_->DrawGeometry(
current_geometry_.Get(),
stroke_brush_.Get(),
stroke_width_,
outline_join_style_.Get()
);
cache_expired_ = true;
}
void Canvas::FillPath()
{
render_target_->FillGeometry(
current_geometry_.Get(),
fill_brush_.Get()
);
cache_expired_ = true;
}
spImage Canvas::ExportToImage() const
{
auto image = new Image(GetBitmap());
image->Crop(Rect(Point{}, this->GetSize()));
return image;
}
cpBitmap const& easy2d::Canvas::GetBitmap() const
{
if (cache_expired_)
{
bitmap_cached_ = nullptr;
ThrowIfFailed(
render_target_->GetBitmap(&bitmap_cached_)
);
cache_expired_ = false;
}
return bitmap_cached_;
}
} }

View File

@ -20,19 +20,37 @@
#pragma once #pragma once
#include "Node.h" #include "Node.h"
#include "Font.hpp"
#include "TextStyle.hpp"
#include "TextRenderer.h"
#undef DrawText
namespace easy2d namespace easy2d
{ {
E2D_DECLARE_SMART_PTR(CanvasBrush); // 画布
class Canvas
// ť­ąĘ : public Node
class CanvasBrush
: public RefCounter
{ {
public: public:
CanvasBrush(); Canvas();
virtual ~CanvasBrush(); Canvas(
Size const& size
);
Canvas(
float width,
float height
);
virtual ~Canvas();
// 开始绘图
void BeginDraw();
// 结束绘图
void EndDraw();
// ť­ÖąĎß // ť­ÖąĎß
void DrawLine( void DrawLine(
@ -65,6 +83,18 @@ namespace easy2d
float radius_y float radius_y
); );
// 画图片
void DrawImage(
spImage const& image,
float opacity = 1.f
);
// 画文字
void DrawText(
String const& text, /* 文字 */
Point const& point /* 文字位置 */
);
// ĚîłäÔ˛ĐÎ // ĚîłäÔ˛ĐÎ
void FillCircle( void FillCircle(
const Point& center, const Point& center,
@ -90,72 +120,100 @@ namespace easy2d
float radius_y float radius_y
); );
// ÉčÖĂĎßĚőŃŐÉŤ // 开始绘制路径
void SetLineColor( void BeginPath(
const Color& color Point const& begin_pos /* 路径起始点 */
); );
// 结束路径
void EndPath(
bool closed = true /* 路径是否闭合 */
);
// 添加一条线段
void AddLine(
Point const& point /* 端点 */
);
// 添加多条线段
void AddLines(
std::vector<Point> const& points
);
// 添加一条三次方贝塞尔曲线
void AddBezier(
Point const& point1, /* 贝塞尔曲线的第一个控制点 */
Point const& point2, /* 贝塞尔曲线的第二个控制点 */
Point const& point3 /* 贝塞尔曲线的终点 */
);
// 路径描边
void StrokePath();
// 路径填充
void FillPath();
// ÉčÖĂĚîłäŃŐÉŤ // ÉčÖĂĚîłäŃŐÉŤ
void SetFillColor( void SetFillColor(
const Color& color const Color& color
); );
// 设置线条颜色
void SetStrokeColor(
const Color& color
);
// ÉčÖĂĎßĚőżíśČ // ÉčÖĂĎßĚőżíśČ
void SetStrokeWidth( void SetStrokeWidth(
float width float width
); );
// ÉčÖĂĎßĚőĎཝŃůĘ˝ // ÉčÖĂĎßĚőĎཝŃůĘ˝
void SetStrokeStyle( void SetOutlineJoinStyle(
StrokeStyle stroke StrokeStyle outline_join
); );
// ťńČĄĎßĚőŃŐÉŤ // 设置文字画刷样式
Color GetLineColor() const; void SetTextStyle(
Font const& font,
TextStyle const& text_style
);
// ťńČĄĚîłäŃŐÉŤ // ťńČĄĚîłäŃŐÉŤ
Color GetFillColor() const; Color GetFillColor() const;
// 获取线条颜色
Color GetStrokeColor() const;
// ťńČĄĎßĚőżíśČ // ťńČĄĎßĚőżíśČ
float GetStrokeWidth() const; float GetStrokeWidth() const;
// ťńČĄĎßĚőĎཝŃůĘ˝ // 变换画笔
StrokeStyle GetStrokeStyle() const; void SetBrushTransform(
math::Matrix const& transform
protected:
float stroke_width_;
StrokeStyle stroke_;
cpRenderTarget render_target_;
cpSolidColorBrush fill_brush_;
cpSolidColorBrush line_brush_;
cpStrokeStyle stroke_style_;
};
// ť­˛ź
class Canvas
: public Node
{
public:
Canvas();
Canvas(
float width,
float height
); );
virtual ~Canvas(); // 导出为图片
spImage ExportToImage() const;
virtual void OnDraw(CanvasBrush& brush) = 0;
// ÉčÖĂť­Ë˘
void SetBrush(
spCanvasBrush const& brush
);
virtual void OnDraw() override; virtual void OnDraw() override;
private: protected:
spCanvasBrush brush_; cpBitmap const& GetBitmap() const;
protected:
mutable bool cache_expired_;
mutable cpBitmap bitmap_cached_;
float stroke_width_;
Font text_font_;
TextStyle text_style_;
cpPathGeometry current_geometry_;
cpGeometrySink current_sink_;
cpStrokeStyle outline_join_style_;
cpSolidColorBrush fill_brush_;
cpSolidColorBrush stroke_brush_;
cpSolidColorBrush text_brush_;
cpTextRenderer text_renderer_;
cpBitmapRenderTarget render_target_;
}; };
} }

View File

@ -118,10 +118,10 @@ namespace easy2d
const auto window = Window::Instance(); const auto window = Window::Instance();
::ShowWindow(window->GetHandle(), SW_SHOWNORMAL); ::ShowWindow(window->GetHandle(), SW_SHOWNORMAL);
::UpdateWindow(window->GetHandle()); ::UpdateWindow(window->GetHandle());
window->Poll();
const int64_t min_interval = 5; const int64_t min_interval = 5;
auto last = time::Now(); auto last = time::Now();
MSG msg = {};
while (!quit_) while (!quit_)
{ {
@ -142,11 +142,7 @@ namespace easy2d
UpdateScene(dt); UpdateScene(dt);
DrawScene(); DrawScene();
while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) window->Poll();
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
} }
else else
{ {
@ -279,16 +275,16 @@ namespace easy2d
if (debug_enabled_) if (debug_enabled_)
{ {
graphics->SetTransform(math::Matrix());
graphics->SetOpacity(1.f);
if (curr_scene_) if (curr_scene_)
{ {
graphics->SetTransform(math::Matrix());
graphics->SetBrushOpacity(1.f);
curr_scene_->DrawBorder(); curr_scene_->DrawBorder();
} }
if (next_scene_) if (next_scene_)
{ {
graphics->SetTransform(math::Matrix());
graphics->SetBrushOpacity(1.f);
next_scene_->DrawBorder(); next_scene_->DrawBorder();
} }

View File

@ -32,51 +32,51 @@ namespace easy2d
} }
Image::Image(Resource const& res) Image::Image(Resource const& res)
: bitmap_(nullptr) : Image()
, crop_rect_()
{ {
this->Load(res); this->Load(res);
} }
Image::Image(Resource const& res, Rect const& crop_rect) Image::Image(Resource const& res, Rect const& crop_rect)
: bitmap_(nullptr) : Image()
, crop_rect_()
{ {
this->Load(res); this->Load(res);
this->Crop(crop_rect); this->Crop(crop_rect);
} }
Image::Image(String const& file_name) Image::Image(String const& file_name)
: bitmap_(nullptr) : Image()
, crop_rect_()
{ {
this->Load(file_name); this->Load(file_name);
} }
Image::Image(String const& file_name, const Rect & crop_rect) Image::Image(String const& file_name, const Rect & crop_rect)
: bitmap_(nullptr) : Image()
, crop_rect_()
{ {
this->Load(file_name); this->Load(file_name);
this->Crop(crop_rect); this->Crop(crop_rect);
} }
Image::Image(cpBitmap const & bitmap)
: Image()
{
SetBitmap(bitmap);
}
Image::~Image() Image::~Image()
{ {
} }
bool Image::Load(Resource const& res) bool Image::Load(Resource const& res)
{ {
HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromResource(bitmap_, res); cpBitmap bitmap;
HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromResource(bitmap, res);
if (FAILED(hr)) if (FAILED(hr))
{ {
logs::Errorln(hr, "Load Image from resource failed!"); logs::Errorln(hr, "Load Image from resource failed!");
return false; return false;
} }
SetBitmap(bitmap);
crop_rect_.origin.x = crop_rect_.origin.y = 0;
crop_rect_.size.width = bitmap_->GetSize().width;
crop_rect_.size.height = bitmap_->GetSize().height;
return true; return true;
} }
@ -93,16 +93,15 @@ namespace easy2d
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径 // 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String image_file_path = image_file.GetPath(); String image_file_path = image_file.GetPath();
HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromFile(bitmap_, image_file_path); cpBitmap bitmap;
HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromFile(bitmap, image_file_path);
if (FAILED(hr)) if (FAILED(hr))
{ {
logs::Errorln(hr, "Load Image from file failed!"); logs::Errorln(hr, "Load Image from file failed!");
return false; return false;
} }
crop_rect_.origin.x = crop_rect_.origin.y = 0; SetBitmap(bitmap);
crop_rect_.size.width = bitmap_->GetSize().width;
crop_rect_.size.height = bitmap_->GetSize().height;
return true; return true;
} }
@ -192,4 +191,15 @@ namespace easy2d
return bitmap_; return bitmap_;
} }
void Image::SetBitmap(cpBitmap const & bitmap)
{
if (bitmap)
{
bitmap_ = bitmap;
crop_rect_.origin.x = crop_rect_.origin.y = 0;
crop_rect_.size.width = bitmap_->GetSize().width;
crop_rect_.size.height = bitmap_->GetSize().height;
}
}
} }

View File

@ -49,6 +49,10 @@ namespace easy2d
Rect const& crop_rect /* ²Ã¼ô¾ØÐÎ */ Rect const& crop_rect /* ²Ã¼ô¾ØÐÎ */
); );
explicit Image(
cpBitmap const& bitmap
);
virtual ~Image(); virtual ~Image();
// ¼ÓÔØÍ¼Æ¬×ÊÔ´ // ¼ÓÔØÍ¼Æ¬×ÊÔ´
@ -98,6 +102,11 @@ namespace easy2d
cpBitmap const& GetBitmap() const; cpBitmap const& GetBitmap() const;
protected:
void SetBitmap(
cpBitmap const& bitmap
);
protected: protected:
Rect crop_rect_; Rect crop_rect_;
cpBitmap bitmap_; cpBitmap bitmap_;

View File

@ -48,8 +48,8 @@ namespace easy2d
, dirty_transform_(false) , dirty_transform_(false)
, order_(0) , order_(0)
, transform_() , transform_()
, opacity_(1.f)
, display_opacity_(1.f) , display_opacity_(1.f)
, real_opacity_(1.f)
, children_() , children_()
, initial_matrix_() , initial_matrix_()
, final_matrix_() , final_matrix_()
@ -75,14 +75,16 @@ namespace easy2d
graphics->PushClip(final_matrix_, transform_.size); graphics->PushClip(final_matrix_, transform_.size);
} }
UpdateTransform();
if (children_.IsEmpty()) if (children_.IsEmpty())
{ {
graphics->SetTransform(final_matrix_); graphics->SetTransform(final_matrix_);
graphics->SetOpacity(display_opacity_);
OnDraw(); OnDraw();
} }
else else
{ {
// ×Ó½ÚµãÅÅÐò
if (dirty_sort_) if (dirty_sort_)
{ {
children_.Sort( children_.Sort(
@ -107,6 +109,7 @@ namespace easy2d
} }
graphics->SetTransform(final_matrix_); graphics->SetTransform(final_matrix_);
graphics->SetOpacity(display_opacity_);
OnDraw(); OnDraw();
for (spNode next; child; child = next) for (spNode next; child; child = next)
@ -129,7 +132,6 @@ namespace easy2d
OnUpdate(dt); OnUpdate(dt);
UpdateActions(this, dt); UpdateActions(this, dt);
UpdateTasks(dt); UpdateTasks(dt);
UpdateTransform();
} }
else else
{ {
@ -151,7 +153,6 @@ namespace easy2d
OnUpdate(dt); OnUpdate(dt);
UpdateActions(this, dt); UpdateActions(this, dt);
UpdateTasks(dt); UpdateTasks(dt);
UpdateTransform();
for (spNode next; child; child = next) for (spNode next; child; child = next)
{ {
@ -167,7 +168,7 @@ namespace easy2d
{ {
if (border_) if (border_)
{ {
devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.f, 1.5f); devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.5f);
} }
for (auto child = children_.First(); child; child = child->NextItem()) for (auto child = children_.First(); child; child = child->NextItem())
@ -248,7 +249,7 @@ namespace easy2d
{ {
if (parent_) if (parent_)
{ {
display_opacity_ = real_opacity_ * parent_->display_opacity_; display_opacity_ = opacity_ * parent_->display_opacity_;
} }
for (auto child = children_.First(); child; child = child->NextItem()) for (auto child = children_.First(); child; child = child->NextItem())
{ {
@ -256,106 +257,6 @@ namespace easy2d
} }
} }
bool Node::IsVisible() const
{
return visible_;
}
String const& Node::GetName() const
{
return name_;
}
size_t Node::GetHashName() const
{
return hash_name_;
}
const Point& Node::GetPosition() const
{
return transform_.position;
}
float Node::GetWidth() const
{
return transform_.size.width * transform_.scale.x;
}
float Node::GetHeight() const
{
return transform_.size.height * transform_.scale.y;
}
float Node::GetRealWidth() const
{
return transform_.size.width;
}
float Node::GetRealHeight() const
{
return transform_.size.height;
}
const Size& Node::GetRealSize() const
{
return transform_.size;
}
float Node::GetPivotX() const
{
return transform_.pivot.x;
}
float Node::GetPivotY() const
{
return transform_.pivot.y;
}
Size Node::GetSize() const
{
return Size{ GetWidth(), GetHeight() };
}
float Node::GetScaleX() const
{
return transform_.scale.x;
}
float Node::GetScaleY() const
{
return transform_.scale.y;
}
float Node::GetSkewX() const
{
return transform_.skew.x;
}
float Node::GetSkewY() const
{
return transform_.skew.y;
}
float Node::GetRotation() const
{
return transform_.rotation;
}
float Node::GetOpacity() const
{
return real_opacity_;
}
float Node::GetDisplayOpacity() const
{
return display_opacity_;
}
int Node::GetOrder() const
{
return order_;
}
void Node::SetOrder(int order) void Node::SetOrder(int order)
{ {
if (order_ == order) if (order_ == order)
@ -459,10 +360,10 @@ namespace easy2d
void Node::SetOpacity(float opacity) void Node::SetOpacity(float opacity)
{ {
if (real_opacity_ == opacity) if (opacity_ == opacity)
return; return;
display_opacity_ = real_opacity_ = std::min(std::max(opacity, 0.f), 1.f); display_opacity_ = opacity_ = std::min(std::max(opacity, 0.f), 1.f);
// ¸üнڵã͸Ã÷¶È // ¸üнڵã͸Ã÷¶È
UpdateOpacity(); UpdateOpacity();
} }
@ -566,11 +467,6 @@ namespace easy2d
} }
} }
spNode Node::GetParent() const
{
return parent_;
}
Rect Node::GetBounds() Rect Node::GetBounds()
{ {
return Rect(Point{}, transform_.size); return Rect(Point{}, transform_.size);

View File

@ -59,71 +59,59 @@ namespace easy2d
virtual void OnUpdate(Duration const& dt) {} virtual void OnUpdate(Duration const& dt) {}
// 获取节点显示状态 // 获取节点显示状态
bool IsVisible() const; bool IsVisible() const { return visible_; }
// 获取节点名称 // 获取节点名称
String const& GetName() const; String const& GetName() const { return name_; }
// 获取节点名称的 Hash 值 // 获取节点名称的 Hash 值
size_t GetHashName() const; size_t GetHashName() const { return hash_name_; }
// 获取节点绘图顺序 // 获取节点绘图顺序
int GetOrder() const; int GetOrder() const { return order_; }
// 获取节点坐标 // 获取节点坐标
const Point& GetPosition() const; virtual const Point& GetPosition() const { return transform_.position; }
// 获取节点宽度 // 获取节点宽度
float GetWidth() const; virtual float GetWidth() const { return transform_.size.width * transform_.scale.x; }
// 获取节点高度 // 获取节点高度
float GetHeight() const; virtual float GetHeight() const { return transform_.size.height * transform_.scale.y; }
// 获取节点宽度(不考虑缩放)
float GetRealWidth() const;
// 获取节点高度(不考虑缩放)
float GetRealHeight() const;
// 获取节点大小(不考虑缩放)
const Size& GetRealSize() const;
// 获取节点的支点
float GetPivotX() const;
// 获取节点的支点
float GetPivotY() const;
// 获取节点大小 // 获取节点大小
Size GetSize() const; Size GetSize() const { return Size{ GetWidth(), GetHeight() }; }
// 获取节点的支点
virtual float GetPivotX() const { return transform_.pivot.x; }
// 获取节点的支点
virtual float GetPivotY() const { return transform_.pivot.y; }
// 获取节点横向缩放比例 // 获取节点横向缩放比例
float GetScaleX() const; virtual float GetScaleX() const { return transform_.scale.x; }
// 获取节点纵向缩放比例 // 获取节点纵向缩放比例
float GetScaleY() const; virtual float GetScaleY() const { return transform_.scale.y; }
// 获取节点横向错切角度 // 获取节点横向错切角度
float GetSkewX() const; virtual float GetSkewX() const { return transform_.skew.x; }
// 获取节点纵向错切角度 // 获取节点纵向错切角度
float GetSkewY() const; virtual float GetSkewY() const { return transform_.skew.y; }
// 获取节点旋转角度 // 获取节点旋转角度
float GetRotation() const; virtual float GetRotation() const { return transform_.rotation; }
// 获取节点透明度 // 获取节点透明度
float GetOpacity() const; virtual float GetOpacity() const { return opacity_; }
// 获取显示透明度
float GetDisplayOpacity() const;
// 获取父节点
spNode GetParent() const;
// 获取包围盒 // 获取包围盒
virtual Rect GetBounds(); virtual Rect GetBounds();
// 获取父节点
virtual spNode GetParent() const { return parent_; }
// 设置节点是否显示 // 设置节点是否显示
void SetVisible( void SetVisible(
bool val bool val
@ -248,7 +236,7 @@ namespace easy2d
); );
// 修改节点宽度 // 修改节点宽度
virtual void SetWidth( void SetWidth(
float width float width
); );
@ -367,7 +355,7 @@ namespace easy2d
String name_; String name_;
size_t hash_name_; size_t hash_name_;
float display_opacity_; float display_opacity_;
float real_opacity_; float opacity_;
int order_; int order_;
bool visible_; bool visible_;
bool clip_enabled_; bool clip_enabled_;

View File

@ -129,15 +129,9 @@ namespace easy2d
void Sprite::OnDraw() void Sprite::OnDraw()
{ {
if (image_ && image_->GetBitmap()) if (image_)
{ {
auto crop_pos = image_->GetCropPos(); devices::Graphics::Instance()->DrawImage(image_);
devices::Graphics::Instance()->DrawImage(
image_,
GetDisplayOpacity(),
Rect(Point(), GetTransform().size),
Rect(crop_pos, GetTransform().size)
);
} }
} }
} }

View File

@ -44,7 +44,6 @@ namespace easy2d
Text::Text() Text::Text()
: font_(text_default_font) : font_(text_default_font)
, style_(text_default_style) , style_(text_default_style)
, dirty_layout_(false)
{ {
} }
@ -67,8 +66,8 @@ namespace easy2d
: font_(font) : font_(font)
, style_(style) , style_(style)
, text_(text) , text_(text)
, dirty_layout_(true)
{ {
UpdateLayout();
} }
Text::~Text() Text::~Text()
@ -127,7 +126,6 @@ namespace easy2d
int Text::GetLineCount() int Text::GetLineCount()
{ {
UpdateLayout();
if (text_layout_) if (text_layout_)
{ {
DWRITE_TEXT_METRICS metrics; DWRITE_TEXT_METRICS metrics;
@ -139,12 +137,6 @@ namespace easy2d
return 0; return 0;
} }
Rect Text::GetBounds()
{
UpdateLayout();
return Node::GetBounds();
}
bool Text::IsItalic() const bool Text::IsItalic() const
{ {
return font_.italic; return font_.italic;
@ -168,19 +160,19 @@ namespace easy2d
void Text::SetText(String const& text) void Text::SetText(String const& text)
{ {
text_ = text; text_ = text;
dirty_layout_ = true; UpdateLayout();
} }
void Text::SetStyle(const TextStyle& style) void Text::SetStyle(const TextStyle& style)
{ {
style_ = style; style_ = style;
dirty_layout_ = true; UpdateLayout();
} }
void Text::SetFont(const Font & font) void Text::SetFont(const Font & font)
{ {
font_ = font; font_ = font;
dirty_layout_ = true; UpdateLayout();
} }
void Text::SetFontFamily(String const& family) void Text::SetFontFamily(String const& family)
@ -188,7 +180,7 @@ namespace easy2d
if (font_.family != family) if (font_.family != family)
{ {
font_.family = family; font_.family = family;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -197,7 +189,7 @@ namespace easy2d
if (font_.size != size) if (font_.size != size)
{ {
font_.size = size; font_.size = size;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -206,7 +198,7 @@ namespace easy2d
if (font_.weight != weight) if (font_.weight != weight)
{ {
font_.weight = weight; font_.weight = weight;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -220,7 +212,7 @@ namespace easy2d
if (font_.italic != val) if (font_.italic != val)
{ {
font_.italic = val; font_.italic = val;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -229,7 +221,7 @@ namespace easy2d
if (style_.wrap != wrap) if (style_.wrap != wrap)
{ {
style_.wrap = wrap; style_.wrap = wrap;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -238,7 +230,7 @@ namespace easy2d
if (style_.wrap_width != wrap_width) if (style_.wrap_width != wrap_width)
{ {
style_.wrap_width = std::max(wrap_width, 0.f); style_.wrap_width = std::max(wrap_width, 0.f);
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -247,7 +239,7 @@ namespace easy2d
if (style_.line_spacing != line_spacing) if (style_.line_spacing != line_spacing)
{ {
style_.line_spacing = line_spacing; style_.line_spacing = line_spacing;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -256,7 +248,7 @@ namespace easy2d
if (style_.alignment != align) if (style_.alignment != align)
{ {
style_.alignment = align; style_.alignment = align;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -265,7 +257,7 @@ namespace easy2d
if (style_.underline != underline) if (style_.underline != underline)
{ {
style_.underline = underline; style_.underline = underline;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -274,7 +266,7 @@ namespace easy2d
if (style_.strikethrough != strikethrough) if (style_.strikethrough != strikethrough)
{ {
style_.strikethrough = strikethrough; style_.strikethrough = strikethrough;
dirty_layout_ = true; UpdateLayout();
} }
} }
@ -303,7 +295,6 @@ namespace easy2d
if (text_layout_) if (text_layout_)
{ {
auto graphics = devices::Graphics::Instance(); auto graphics = devices::Graphics::Instance();
graphics->SetBrushOpacity(GetDisplayOpacity());
graphics->SetTextStyle( graphics->SetTextStyle(
style_.color, style_.color,
style_.outline, style_.outline,
@ -315,17 +306,8 @@ namespace easy2d
} }
} }
void Text::Update(Duration const & dt)
{
UpdateLayout();
Node::Update(dt);
}
void Text::UpdateLayout() void Text::UpdateLayout()
{ {
if (!dirty_layout_)
return;
text_format_ = nullptr; text_format_ = nullptr;
text_layout_ = nullptr; text_layout_ = nullptr;
@ -337,75 +319,22 @@ namespace easy2d
ThrowIfFailed( ThrowIfFailed(
graphics->CreateTextFormat( graphics->CreateTextFormat(
text_format_, text_format_,
font_ font_,
style_
) )
); );
if (style_.line_spacing == 0.f) Size layout_size;
{ ThrowIfFailed(
text_format_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); graphics->CreateTextLayout(
} text_layout_,
else layout_size,
{ text_,
text_format_->SetLineSpacing( text_format_,
DWRITE_LINE_SPACING_METHOD_UNIFORM, style_
style_.line_spacing, )
style_.line_spacing * 0.8f );
);
}
text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment));
text_format_->SetWordWrapping(style_.wrap ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP);
if (style_.wrap) this->SetSize(layout_size);
{
ThrowIfFailed(
graphics->CreateTextLayout(
text_layout_,
text_,
text_format_,
style_.wrap_width
)
);
DWRITE_TEXT_METRICS metrics;
text_layout_->GetMetrics(&metrics);
this->SetSize(metrics.layoutWidth, metrics.height);
}
else
{
ThrowIfFailed(
graphics->CreateTextLayout(
text_layout_,
text_,
text_format_,
0
)
);
DWRITE_TEXT_METRICS metrics;
text_layout_->GetMetrics(&metrics);
this->SetSize(metrics.width, metrics.height);
ThrowIfFailed(
graphics->CreateTextLayout(
text_layout_,
text_,
text_format_,
metrics.width
)
);
}
DWRITE_TEXT_RANGE range = { 0, static_cast<UINT32>(text_.length()) };
if (style_.underline)
{
text_layout_->SetUnderline(true, range);
}
if (style_.strikethrough)
{
text_layout_->SetStrikethrough(true, range);
}
dirty_layout_ = false;
} }
} }

View File

@ -87,9 +87,6 @@ namespace easy2d
// 获取文本显示行数 // 获取文本显示行数
int GetLineCount(); int GetLineCount();
// 삿혤관鍋분
virtual Rect GetBounds() override;
// 是否是斜体 // 是否是斜体
bool IsItalic() const; bool IsItalic() const;
@ -202,20 +199,16 @@ namespace easy2d
TextStyle const& style TextStyle const& style
); );
// 斡횡匡俚
virtual void OnDraw() override; virtual void OnDraw() override;
protected: protected:
virtual void Update(Duration const& dt) override;
void UpdateLayout(); void UpdateLayout();
protected: protected:
String text_; String text_;
Font font_; Font font_;
TextStyle style_; TextStyle style_;
bool dirty_layout_; cpTextFormat text_format_;
cpTextFormat text_format_; cpTextLayout text_layout_;
cpTextLayout text_layout_;
}; };
} }

View File

@ -24,7 +24,7 @@
namespace easy2d namespace easy2d
{ {
ITextRenderer::ITextRenderer(ID2D1Factory* pD2DFactory, ID2D1HwndRenderTarget* pRT, ID2D1SolidColorBrush* pBrush) ITextRenderer::ITextRenderer(ID2D1Factory* pD2DFactory, ID2D1RenderTarget* pRT, ID2D1SolidColorBrush* pBrush)
: cRefCount_(0) : cRefCount_(0)
, pD2DFactory_(pD2DFactory) , pD2DFactory_(pD2DFactory)
, pRT_(pRT) , pRT_(pRT)
@ -50,7 +50,7 @@ namespace easy2d
HRESULT ITextRenderer::Create( HRESULT ITextRenderer::Create(
ITextRenderer** ppTextRenderer, ITextRenderer** ppTextRenderer,
ID2D1Factory* pD2DFactory, ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT, ID2D1RenderTarget* pRT,
ID2D1SolidColorBrush* pBrush) ID2D1SolidColorBrush* pBrush)
{ {
*ppTextRenderer = new (std::nothrow) ITextRenderer(pD2DFactory, pRT, pBrush); *ppTextRenderer = new (std::nothrow) ITextRenderer(pD2DFactory, pRT, pBrush);

View File

@ -30,7 +30,7 @@ namespace easy2d
static HRESULT Create( static HRESULT Create(
ITextRenderer** ppTextRenderer, ITextRenderer** ppTextRenderer,
ID2D1Factory* pD2DFactory, ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT, ID2D1RenderTarget* pRT,
ID2D1SolidColorBrush* pBrush ID2D1SolidColorBrush* pBrush
); );
@ -104,7 +104,7 @@ namespace easy2d
private: private:
ITextRenderer( ITextRenderer(
ID2D1Factory* pD2DFactory, ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT, ID2D1RenderTarget* pRT,
ID2D1SolidColorBrush* pBrush ID2D1SolidColorBrush* pBrush
); );
@ -117,10 +117,10 @@ namespace easy2d
FLOAT fOutlineWidth; FLOAT fOutlineWidth;
BOOL bShowOutline_; BOOL bShowOutline_;
ID2D1Factory* pD2DFactory_; ID2D1Factory* pD2DFactory_;
ID2D1HwndRenderTarget* pRT_; ID2D1RenderTarget* pRT_;
ID2D1SolidColorBrush* pBrush_; ID2D1SolidColorBrush* pBrush_;
ID2D1StrokeStyle* pCurrStrokeStyle_; ID2D1StrokeStyle* pCurrStrokeStyle_;
}; };
} }
E2D_DECLARE_D2D_SMART_PTR(easy2d::ITextRenderer, spTextRenderer); E2D_DECLARE_D2D_SMART_PTR(easy2d::ITextRenderer, cpTextRenderer);

View File

@ -65,4 +65,13 @@ namespace easy2d
pivot == other.pivot; pivot == other.pivot;
} }
}; };
inline D2D1_MATRIX_3X2_F ConvertToD2DMatrix(math::Matrix const& matrix)
{
return D2D1_MATRIX_3X2_F{
matrix.m[0], matrix.m[1],
matrix.m[2], matrix.m[3],
matrix.m[4], matrix.m[5]
};
}
} }

View File

@ -36,12 +36,16 @@ namespace easy2d
E2D_DECLARE_D2D_SMART_PTR(IWICImagingFactory, cpImagingFactory); E2D_DECLARE_D2D_SMART_PTR(IWICImagingFactory, cpImagingFactory);
E2D_DECLARE_D2D_SMART_PTR(IDWriteFactory, cpWriteFactory); E2D_DECLARE_D2D_SMART_PTR(IDWriteFactory, cpWriteFactory);
E2D_DECLARE_D2D_SMART_PTR(ID2D1SolidColorBrush, cpSolidColorBrush); E2D_DECLARE_D2D_SMART_PTR(ID2D1SolidColorBrush, cpSolidColorBrush);
E2D_DECLARE_D2D_SMART_PTR(ID2D1HwndRenderTarget, cpRenderTarget); E2D_DECLARE_D2D_SMART_PTR(ID2D1RenderTarget, cpRenderTarget);
E2D_DECLARE_D2D_SMART_PTR(ID2D1HwndRenderTarget, cpHwndRenderTarget);
E2D_DECLARE_D2D_SMART_PTR(ID2D1BitmapRenderTarget, cpBitmapRenderTarget);
E2D_DECLARE_D2D_SMART_PTR(ID2D1StrokeStyle, cpStrokeStyle); E2D_DECLARE_D2D_SMART_PTR(ID2D1StrokeStyle, cpStrokeStyle);
E2D_DECLARE_D2D_SMART_PTR(ID2D1Layer, cpLayer); E2D_DECLARE_D2D_SMART_PTR(ID2D1Layer, cpLayer);
E2D_DECLARE_D2D_SMART_PTR(ID2D1Bitmap, cpBitmap); E2D_DECLARE_D2D_SMART_PTR(ID2D1Bitmap, cpBitmap);
E2D_DECLARE_D2D_SMART_PTR(ID2D1Geometry, cpGeometry); E2D_DECLARE_D2D_SMART_PTR(ID2D1Geometry, cpGeometry);
E2D_DECLARE_D2D_SMART_PTR(ID2D1PathGeometry, cpPathGeometry);
E2D_DECLARE_D2D_SMART_PTR(ID2D1GeometrySink, cpGeometrySink);
E2D_DECLARE_D2D_SMART_PTR(IDWriteTextFormat, cpTextFormat); E2D_DECLARE_D2D_SMART_PTR(IDWriteTextFormat, cpTextFormat);
E2D_DECLARE_D2D_SMART_PTR(IDWriteTextLayout, cpTextLayout); E2D_DECLARE_D2D_SMART_PTR(IDWriteTextLayout, cpTextLayout);

View File

@ -22,6 +22,8 @@
#include "logs.h" #include "logs.h"
#include <ctime> #include <ctime>
#include <iomanip> #include <iomanip>
#include <iostream>
#include <sstream>
namespace easy2d namespace easy2d
{ {

View File

@ -20,9 +20,6 @@
#pragma once #pragma once
#include "macros.h" #include "macros.h"
#include <iostream>
#include <sstream>
#include <stdexcept>
#ifndef E2D_LOG #ifndef E2D_LOG
# ifdef E2D_DEBUG # ifdef E2D_DEBUG

View File

@ -27,7 +27,7 @@ namespace easy2d
protected: protected:
Noncopyable() = default; Noncopyable() = default;
~Noncopyable() {}; virtual ~Noncopyable() {};
private: private:
Noncopyable(const Noncopyable&) = delete; Noncopyable(const Noncopyable&) = delete;

View File

@ -24,27 +24,17 @@
#include "logs.h" #include "logs.h"
#include "modules.h" #include "modules.h"
#include "Image.h" #include "Image.h"
#include "Transform.hpp"
namespace easy2d namespace easy2d
{ {
namespace devices namespace devices
{ {
namespace
{
inline D2D1_MATRIX_3X2_F ConvertToD2DMatrix(math::Matrix const& matrix)
{
return D2D1_MATRIX_3X2_F{
matrix.m[0], matrix.m[1],
matrix.m[2], matrix.m[3],
matrix.m[4], matrix.m[5]
};
}
}
GraphicsDevice::GraphicsDevice() GraphicsDevice::GraphicsDevice()
: fps_text_format_(nullptr) : fps_text_format_(nullptr)
, fps_text_layout_(nullptr) , fps_text_layout_(nullptr)
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) , clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
, opacity_(1.f)
, initialized(false) , initialized(false)
{ {
ZeroMemory(&d2d, sizeof(D2DResources)); ZeroMemory(&d2d, sizeof(D2DResources));
@ -207,13 +197,21 @@ namespace easy2d
return hr; return hr;
} }
HRESULT GraphicsDevice::CreateTextFormat(cpTextFormat& text_format, Font const& font) const HRESULT GraphicsDevice::CreatePathGeometry(cpPathGeometry & geometry) const
{
if (!d2d.factory)
return E_UNEXPECTED;
return d2d.factory->CreatePathGeometry(&geometry);
}
HRESULT GraphicsDevice::CreateTextFormat(cpTextFormat & text_format, Font const & font, TextStyle const & text_style) const
{ {
if (!d2d.write_factory) if (!d2d.write_factory)
return E_UNEXPECTED; return E_UNEXPECTED;
text_format = nullptr; cpTextFormat text_format_tmp;
return d2d.write_factory->CreateTextFormat( HRESULT hr = d2d.write_factory->CreateTextFormat(
font.family.c_str(), font.family.c_str(),
nullptr, nullptr,
DWRITE_FONT_WEIGHT(font.weight), DWRITE_FONT_WEIGHT(font.weight),
@ -221,26 +219,128 @@ namespace easy2d
DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
font.size, font.size,
L"", L"",
&text_format &text_format_tmp
);; );
if (SUCCEEDED(hr))
{
if (text_style.line_spacing == 0.f)
{
text_format_tmp->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
}
else
{
text_format_tmp->SetLineSpacing(
DWRITE_LINE_SPACING_METHOD_UNIFORM,
text_style.line_spacing,
text_style.line_spacing * 0.8f
);
}
text_format_tmp->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(text_style.alignment));
text_format_tmp->SetWordWrapping(text_style.wrap ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP);
text_format = text_format_tmp;
}
return hr;
} }
HRESULT GraphicsDevice::CreateTextLayout(cpTextLayout& text_layout, String const& text, cpTextFormat const& text_format, float wrap_width) const HRESULT GraphicsDevice::CreateTextLayout(cpTextLayout & text_layout, Size& layout_size, String const & text, cpTextFormat const& text_format, TextStyle const & text_style) const
{ {
if (!d2d.write_factory) if (!d2d.write_factory)
return E_UNEXPECTED; return E_UNEXPECTED;
text_layout = nullptr; text_layout = nullptr;
HRESULT hr;
cpTextLayout text_layout_tmp;
UINT32 length = static_cast<UINT32>(text.length()); UINT32 length = static_cast<UINT32>(text.length());
return d2d.write_factory->CreateTextLayout(
text.c_str(), if (text_style.wrap)
length, {
text_format.Get(), hr = d2d.write_factory->CreateTextLayout(
wrap_width, text.c_str(),
0, length,
&text_layout text_format.Get(),
text_style.wrap_width,
0,
&text_layout_tmp
);
}
else
{
hr = d2d.write_factory->CreateTextLayout(
text.c_str(),
length,
text_format.Get(),
0,
0,
&text_layout_tmp
);
DWRITE_TEXT_METRICS metrics;
text_layout_tmp->GetMetrics(&metrics);
if (SUCCEEDED(hr))
{
text_layout_tmp = nullptr;
hr = d2d.write_factory->CreateTextLayout(
text.c_str(),
length,
text_format.Get(),
metrics.width,
0,
&text_layout_tmp
);
}
}
if (SUCCEEDED(hr))
{
DWRITE_TEXT_METRICS metrics;
text_layout_tmp->GetMetrics(&metrics);
if (text_style.wrap)
{
layout_size = Size(metrics.layoutWidth, metrics.height);
}
else
{
layout_size = Size(metrics.width, metrics.height);
}
DWRITE_TEXT_RANGE range = { 0, length };
if (text_style.underline)
{
text_layout_tmp->SetUnderline(true, range);
}
if (text_style.strikethrough)
{
text_layout_tmp->SetStrikethrough(true, range);
}
text_layout = text_layout_tmp;
}
return hr;
}
HRESULT GraphicsDevice::CreateTextRenderer(
cpTextRenderer& text_renderer,
cpRenderTarget const& render_target,
cpSolidColorBrush const& brush
)
{
if (!d2d.factory)
return E_UNEXPECTED;
cpTextRenderer text_renderer_tmp;
HRESULT hr = ITextRenderer::Create(
&text_renderer_tmp,
d2d.factory.Get(),
render_target.Get(),
brush.Get()
); );
if (SUCCEEDED(hr))
text_renderer = text_renderer_tmp;
return hr;
} }
HRESULT GraphicsDevice::CreateLayer(cpLayer& layer) HRESULT GraphicsDevice::CreateLayer(cpLayer& layer)
@ -267,7 +367,6 @@ namespace easy2d
HRESULT GraphicsDevice::DrawGeometry( HRESULT GraphicsDevice::DrawGeometry(
cpGeometry const& geometry, cpGeometry const& geometry,
Color const& border_color, Color const& border_color,
float opacity,
float stroke_width, float stroke_width,
StrokeStyle stroke StrokeStyle stroke
) )
@ -277,7 +376,6 @@ namespace easy2d
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.solid_brush->SetColor(border_color); d2d.solid_brush->SetColor(border_color);
d2d.solid_brush->SetOpacity(opacity);
d2d.render_target->DrawGeometry( d2d.render_target->DrawGeometry(
geometry.Get(), geometry.Get(),
d2d.solid_brush.Get(), d2d.solid_brush.Get(),
@ -287,6 +385,24 @@ namespace easy2d
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::DrawImage(spImage const & image)
{
if (!d2d.render_target)
return E_UNEXPECTED;
if (!image->GetBitmap())
return S_OK;
d2d.render_target->DrawBitmap(
image->GetBitmap().Get(),
D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()),
opacity_,
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
image->GetCropRect()
);
return S_OK;
}
cpStrokeStyle const& GraphicsDevice::GetStrokeStyle(StrokeStyle stroke) const cpStrokeStyle const& GraphicsDevice::GetStrokeStyle(StrokeStyle stroke) const
{ {
switch (stroke) switch (stroke)
@ -304,27 +420,21 @@ namespace easy2d
return d2d.miter_stroke_style; return d2d.miter_stroke_style;
} }
cpRenderTarget const & GraphicsDevice::GetRenderTarget() const HRESULT GraphicsDevice::DrawBitmap(
{ cpBitmap const& bitmap
return d2d.render_target;
}
HRESULT GraphicsDevice::DrawImage(
spImage const& image,
float opacity,
const Rect & dest_rect,
const Rect & source_rect
) )
{ {
if (!d2d.render_target) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
// Do not crop bitmap
auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height);
d2d.render_target->DrawBitmap( d2d.render_target->DrawBitmap(
image->GetBitmap().Get(), bitmap.Get(),
dest_rect, rect,
opacity, opacity_,
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
source_rect rect
); );
return S_OK; return S_OK;
} }
@ -389,6 +499,17 @@ namespace easy2d
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::GetSize(Size & size)
{
if (!d2d.render_target)
return E_UNEXPECTED;
auto rtsize = d2d.render_target->GetSize();
size.width = rtsize.width;
size.height = rtsize.height;
return S_OK;
}
HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path) HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path)
{ {
if (d2d.imaging_factory == nullptr || if (d2d.imaging_factory == nullptr ||
@ -568,6 +689,15 @@ namespace easy2d
return hr; return hr;
} }
HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt)
{
if (!d2d.render_target)
return E_UNEXPECTED;
brt = nullptr;
return d2d.render_target->CreateCompatibleRenderTarget(&brt);
}
HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height)
{ {
if (!d2d.render_target) if (!d2d.render_target)
@ -586,11 +716,12 @@ namespace easy2d
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::SetBrushOpacity(float opacity) HRESULT GraphicsDevice::SetOpacity(float opacity)
{ {
if (!d2d.render_target) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
opacity_ = opacity;
d2d.solid_brush->SetOpacity(opacity); d2d.solid_brush->SetOpacity(opacity);
return S_OK; return S_OK;
} }
@ -631,7 +762,16 @@ namespace easy2d
if (!fps_text_format_) if (!fps_text_format_)
{ {
ThrowIfFailed( ThrowIfFailed(
CreateTextFormat(fps_text_format_, Font{ L"", 20 }) d2d.write_factory->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&fps_text_format_
)
); );
fps_text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); fps_text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
@ -646,8 +786,16 @@ namespace easy2d
last_render_time_ = time::Now(); last_render_time_ = time::Now();
render_times_ = 0; render_times_ = 0;
fps_text_layout_ = nullptr;
ThrowIfFailed( ThrowIfFailed(
CreateTextLayout(fps_text_layout_, fps_text, fps_text_format_, 0) d2d.write_factory->CreateTextLayout(
fps_text,
len,
fps_text_format_.Get(),
0,
0,
&fps_text_layout_
)
); );
} }

View File

@ -24,6 +24,7 @@
#include "Font.hpp" #include "Font.hpp"
#include "Resource.h" #include "Resource.h"
#include "TextRenderer.h" #include "TextRenderer.h"
#include "TextStyle.hpp"
#include "../math/Matrix.hpp" #include "../math/Matrix.hpp"
namespace easy2d namespace easy2d
@ -37,9 +38,9 @@ namespace easy2d
cpFactory factory; cpFactory factory;
cpImagingFactory imaging_factory; cpImagingFactory imaging_factory;
cpWriteFactory write_factory; cpWriteFactory write_factory;
spTextRenderer text_renderer; cpTextRenderer text_renderer;
cpSolidColorBrush solid_brush; cpSolidColorBrush solid_brush;
cpRenderTarget render_target; cpHwndRenderTarget render_target;
cpStrokeStyle miter_stroke_style; cpStrokeStyle miter_stroke_style;
cpStrokeStyle bevel_stroke_style; cpStrokeStyle bevel_stroke_style;
cpStrokeStyle round_stroke_style; cpStrokeStyle round_stroke_style;
@ -76,18 +77,30 @@ namespace easy2d
const Size& size const Size& size
) const; ) const;
HRESULT CreatePathGeometry(
cpPathGeometry& geometry
) const;
HRESULT CreateTextFormat( HRESULT CreateTextFormat(
cpTextFormat& text_format, cpTextFormat& text_format,
Font const& font Font const& font,
TextStyle const& text_style
) const; ) const;
HRESULT CreateTextLayout( HRESULT CreateTextLayout(
cpTextLayout& text_layout, cpTextLayout& text_layout,
Size& layout_size,
String const& text, String const& text,
cpTextFormat const& text_format, cpTextFormat const& text_format,
float wrap_width TextStyle const& text_style
) const; ) const;
HRESULT CreateTextRenderer(
cpTextRenderer& text_renderer,
cpRenderTarget const& render_target,
cpSolidColorBrush const& brush
);
HRESULT CreateLayer( HRESULT CreateLayer(
cpLayer& layer cpLayer& layer
); );
@ -96,17 +109,29 @@ namespace easy2d
cpSolidColorBrush& brush cpSolidColorBrush& brush
) const; ) const;
HRESULT CreateBitmapFromFile(
cpBitmap& bitmap,
String const& file_path
);
HRESULT CreateBitmapFromResource(
cpBitmap& bitmap,
Resource const& res
);
HRESULT CreateBitmapRenderTarget(
cpBitmapRenderTarget& brt
);
cpStrokeStyle const& GetStrokeStyle( cpStrokeStyle const& GetStrokeStyle(
StrokeStyle stroke StrokeStyle stroke
) const; ) const;
cpRenderTarget const& GetRenderTarget() const;
HRESULT SetTransform( HRESULT SetTransform(
const math::Matrix& matrix const math::Matrix& matrix
); );
HRESULT SetBrushOpacity( HRESULT SetOpacity(
float opacity float opacity
); );
@ -121,16 +146,16 @@ namespace easy2d
HRESULT DrawGeometry( HRESULT DrawGeometry(
cpGeometry const& geometry, cpGeometry const& geometry,
const Color& border_color, const Color& border_color,
float opacity,
float stroke_width, float stroke_width,
StrokeStyle stroke = StrokeStyle::Miter StrokeStyle stroke = StrokeStyle::Miter
); );
HRESULT DrawImage( HRESULT DrawImage(
spImage const& image, spImage const& image
float opacity, );
const Rect& dest_rect,
const Rect& source_rect HRESULT DrawBitmap(
cpBitmap const& bitmap
); );
HRESULT DrawTextLayout( HRESULT DrawTextLayout(
@ -151,14 +176,8 @@ namespace easy2d
HRESULT PopLayer(); HRESULT PopLayer();
HRESULT CreateBitmapFromFile( HRESULT GetSize(
cpBitmap& bitmap, Size& size
String const& file_path
);
HRESULT CreateBitmapFromResource(
cpBitmap& bitmap,
Resource const& res
); );
HRESULT Resize( HRESULT Resize(
@ -174,12 +193,13 @@ namespace easy2d
~GraphicsDevice(); ~GraphicsDevice();
protected: protected:
bool initialized; bool initialized;
D2DResources d2d; float opacity_;
D2D1_COLOR_F clear_color_; D2DResources d2d;
cpTextFormat fps_text_format_; D2D1_COLOR_F clear_color_;
cpTextLayout fps_text_layout_; cpTextFormat fps_text_format_;
std::map<size_t, cpBitmap> bitmap_cache_; cpTextLayout fps_text_layout_;
std::map<size_t, cpBitmap> bitmap_cache_;
}; };
E2D_DECLARE_SINGLETON_TYPE(GraphicsDevice, Graphics); E2D_DECLARE_SINGLETON_TYPE(GraphicsDevice, Graphics);

View File

@ -220,6 +220,17 @@ namespace easy2d
return scale_y; return scale_y;
} }
void WindowImpl::Poll()
{
static MSG msg = {};
while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
namespace namespace
{ {
void GetContentScale(float* scale_x, float* scale_y) void GetContentScale(float* scale_x, float* scale_y)

View File

@ -24,8 +24,6 @@
namespace easy2d namespace easy2d
{ {
class WindowImpl class WindowImpl
: protected Noncopyable : protected Noncopyable
{ {
@ -67,6 +65,8 @@ namespace easy2d
float GetContentScaleY() const; float GetContentScaleY() const;
void Poll();
protected: protected:
WindowImpl(); WindowImpl();

View File

@ -177,9 +177,9 @@ namespace easy2d
float tx = math::Tan(angle_x); float tx = math::Tan(angle_x);
float ty = math::Tan(angle_y); float ty = math::Tan(angle_y);
return Matrix( return Matrix(
1.f, tx, 1.f, -ty,
ty, 1.f, -tx, 1.f,
-center.y * tx, -center.x * ty center.y * tx, center.x * ty
); );
} }
}; };