2019-04-11 14:40:54 +08:00
|
|
|
// Copyright (c) 2016-2018 Kiwano - Nomango
|
2019-03-31 01:37:06 +08:00
|
|
|
//
|
|
|
|
|
// 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 "Canvas.h"
|
2019-08-14 21:52:49 +08:00
|
|
|
#include "../base/Logger.h"
|
|
|
|
|
#include "../renderer/Renderer.h"
|
2019-03-31 01:37:06 +08:00
|
|
|
|
2019-04-11 14:40:54 +08:00
|
|
|
namespace kiwano
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
|
|
|
|
Canvas::Canvas()
|
|
|
|
|
: cache_expired_(false)
|
|
|
|
|
, stroke_width_(1.0f)
|
2019-08-16 00:50:54 +08:00
|
|
|
, fill_color_(0, 0, 0)
|
|
|
|
|
, stroke_color_(Color::White)
|
|
|
|
|
, stroke_style_(StrokeStyle::Miter)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
Renderer::GetInstance()->CreateImageRenderTarget(rt_);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas::Canvas(float width, float height)
|
|
|
|
|
: Canvas()
|
|
|
|
|
{
|
|
|
|
|
this->SetSize(width, height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas::Canvas(Size const & size)
|
|
|
|
|
: Canvas(size.x, size.y)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas::~Canvas()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::BeginDraw()
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.BeginDraw();
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::EndDraw()
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.EndDraw();
|
2019-03-31 01:37:06 +08:00
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-14 00:28:25 +08:00
|
|
|
void Canvas::OnRender(Renderer* renderer)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
UpdateCache();
|
2019-03-31 01:37:06 +08:00
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
if (image_cached_.IsValid())
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-14 00:28:25 +08:00
|
|
|
PrepareRender(renderer);
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
Rect bitmap_rect(0.f, 0.f, image_cached_.GetWidth(), image_cached_.GetHeight());
|
|
|
|
|
renderer->DrawImage(image_cached_, bitmap_rect, bitmap_rect);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::SetStrokeColor(Color const& color)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_color_ = color;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::SetFillColor(Color const& color)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
fill_color_ = color;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::SetStrokeWidth(float width)
|
|
|
|
|
{
|
|
|
|
|
stroke_width_ = std::max(width, 0.f);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::SetStrokeStyle(StrokeStyle stroke_style)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_ = stroke_style;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::SetTextFont(Font const& font)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
|
|
|
|
text_font_ = font;
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
2019-03-31 01:37:06 +08:00
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::SetTextStyle(TextStyle const & text_style)
|
|
|
|
|
{
|
|
|
|
|
text_style_ = text_style;
|
|
|
|
|
}
|
2019-03-31 01:37:06 +08:00
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::SetBrushOpacity(float opacity)
|
|
|
|
|
{
|
|
|
|
|
rt_.SetOpacity(opacity);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Color Canvas::GetStrokeColor() const
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
return stroke_color_;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Color Canvas::GetFillColor() const
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
return fill_color_;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float Canvas::GetStrokeWidth() const
|
|
|
|
|
{
|
|
|
|
|
return stroke_width_;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
float Canvas::GetBrushOpacity() const
|
|
|
|
|
{
|
|
|
|
|
return rt_.GetOpacity();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::SetBrushTransform(Transform const& transform)
|
|
|
|
|
{
|
|
|
|
|
Matrix3x2 matrix = Matrix3x2::SRT(transform.position, transform.scale, transform.rotation);
|
|
|
|
|
if (!transform.skew.IsOrigin())
|
|
|
|
|
{
|
|
|
|
|
matrix = Matrix3x2::Skewing(transform.skew) * matrix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rt_.SetTransform(matrix);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-14 23:36:29 +08:00
|
|
|
void Canvas::SetBrushTransform(Matrix3x2 const & transform)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.SetTransform(transform);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawLine(Point const& begin, Point const& end)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.DrawLine(
|
|
|
|
|
begin,
|
|
|
|
|
end,
|
|
|
|
|
stroke_color_,
|
2019-03-31 01:37:06 +08:00
|
|
|
stroke_width_,
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawCircle(Point const& center, float radius)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.DrawEllipse(
|
|
|
|
|
center,
|
|
|
|
|
Vec2(radius, radius),
|
|
|
|
|
stroke_color_,
|
2019-03-31 01:37:06 +08:00
|
|
|
stroke_width_,
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.DrawEllipse(
|
|
|
|
|
center,
|
|
|
|
|
radius,
|
|
|
|
|
stroke_color_,
|
2019-03-31 01:37:06 +08:00
|
|
|
stroke_width_,
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawRect(Rect const& rect)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.DrawRectangle(
|
|
|
|
|
rect,
|
|
|
|
|
stroke_color_,
|
2019-03-31 01:37:06 +08:00
|
|
|
stroke_width_,
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
|
|
|
|
|
{
|
|
|
|
|
rt_.DrawRoundedRectangle(
|
|
|
|
|
rect,
|
|
|
|
|
radius,
|
|
|
|
|
stroke_color_,
|
2019-03-31 01:37:06 +08:00
|
|
|
stroke_width_,
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::FillCircle(Point const& center, float radius)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.FillEllipse(
|
|
|
|
|
center,
|
|
|
|
|
Vec2(radius, radius),
|
|
|
|
|
fill_color_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
2019-08-16 00:50:54 +08:00
|
|
|
cache_expired_ = true;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::FillEllipse(Point const& center, Vec2 const& radius)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.FillEllipse(
|
|
|
|
|
center,
|
|
|
|
|
radius,
|
|
|
|
|
fill_color_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::FillRect(Rect const& rect)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.FillRectangle(
|
|
|
|
|
rect,
|
|
|
|
|
fill_color_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.FillRoundedRectangle(
|
|
|
|
|
rect,
|
|
|
|
|
radius,
|
|
|
|
|
fill_color_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawImage(Image const& image, const Rect* src_rect, const Rect* dest_rect)
|
|
|
|
|
{
|
|
|
|
|
if (image.IsValid())
|
|
|
|
|
{
|
|
|
|
|
rt_.DrawImage(image, src_rect, dest_rect);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::DrawText(String const& text, Point const& point)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
if (text.empty())
|
|
|
|
|
return;
|
2019-03-31 01:37:06 +08:00
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
TextLayout layout(text, text_font_, text_style_);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.DrawTextLayout(layout, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::BeginPath(Point const& begin_pos)
|
|
|
|
|
{
|
|
|
|
|
geo_sink_.BeginPath(begin_pos);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::EndPath(bool closed)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
geo_sink_.EndPath(closed);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::AddLine(Point const & point)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
geo_sink_.AddLine(point);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-13 21:16:38 +08:00
|
|
|
void Canvas::AddLines(Vector<Point> const& points)
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
geo_sink_.AddLines(points);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::AddBezier(Point const & point1, Point const & point2, Point const & point3)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
geo_sink_.AddBezier(point1, point2, point3);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::AddArc(Point const & point, Point const & radius, float rotation, bool clockwise, bool is_small)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
geo_sink_.AddArc(point, radius, rotation, clockwise, is_small);
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::StrokePath()
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.DrawGeometry(
|
|
|
|
|
geo_sink_.GetGeometry(),
|
|
|
|
|
stroke_color_,
|
2019-03-31 01:37:06 +08:00
|
|
|
stroke_width_,
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_style_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::FillPath()
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.FillGeometry(
|
|
|
|
|
geo_sink_.GetGeometry(),
|
|
|
|
|
fill_color_
|
2019-03-31 01:37:06 +08:00
|
|
|
);
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::Clear()
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.Clear();
|
|
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::Clear(Color const& clear_color)
|
|
|
|
|
{
|
|
|
|
|
rt_.Clear(clear_color);
|
2019-03-31 01:37:06 +08:00
|
|
|
cache_expired_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
Image Canvas::ExportToImage() const
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
UpdateCache();
|
|
|
|
|
return image_cached_;
|
2019-03-31 01:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void Canvas::UpdateCache() const
|
2019-03-31 01:37:06 +08:00
|
|
|
{
|
|
|
|
|
if (cache_expired_)
|
|
|
|
|
{
|
2019-08-16 00:50:54 +08:00
|
|
|
rt_.GetOutput(image_cached_);
|
2019-03-31 01:37:06 +08:00
|
|
|
cache_expired_ = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 14:15:06 +08:00
|
|
|
}
|