// 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 #include #include namespace kiwano { CanvasPtr Canvas::Create(Size const& size) { CanvasPtr ptr = new (std::nothrow) Canvas; if (ptr) { try { ptr->ctx_ = TextureRenderContext::Create(); ptr->stroke_brush_ = Brush::Create(Color::White); ptr->fill_brush_ = Brush::Create(Color::White); ptr->SetSize(ptr->ctx_->GetSize()); } catch (std::exception) { return nullptr; } } return ptr; } Canvas::Canvas() : cache_expired_(false) , stroke_width_(1.0f) , stroke_style_() { } void Canvas::BeginDraw() { KGE_ASSERT(ctx_); ctx_->BeginDraw(); } void Canvas::EndDraw() { KGE_ASSERT(ctx_); ctx_->EndDraw(); cache_expired_ = true; } void Canvas::OnRender(RenderContext& ctx) { UpdateCache(); if (texture_cached_ && texture_cached_->IsValid()) { PrepareToRender(ctx); ctx.DrawTexture(*texture_cached_, nullptr, &GetBounds()); } } void Canvas::SetBrush(BrushPtr brush) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(brush); } void Canvas::SetBrushTransform(Transform const& transform) { KGE_ASSERT(ctx_); ctx_->SetTransform(transform.ToMatrix()); } void Canvas::SetBrushTransform(Matrix3x2 const& transform) { KGE_ASSERT(ctx_); ctx_->SetTransform(transform); } void Canvas::PushLayerArea(LayerArea& area) { KGE_ASSERT(ctx_); ctx_->PushLayer(area); } void Canvas::PopLayerArea() { KGE_ASSERT(ctx_); ctx_->PopLayer(); } void Canvas::PushClipRect(Rect const& clip_rect) { KGE_ASSERT(ctx_); ctx_->PushClipRect(clip_rect); } void Canvas::PopClipRect() { KGE_ASSERT(ctx_); ctx_->PopClipRect(); } void Canvas::DrawShape(ShapePtr shape) { KGE_ASSERT(ctx_); if (shape) { ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawShape(*shape, stroke_style_, stroke_width_); cache_expired_ = true; } } void Canvas::DrawLine(Point const& begin, Point const& end) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawLine(begin, end, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawCircle(Point const& center, float radius) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawEllipse(center, Vec2(radius, radius), stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawEllipse(Point const& center, Vec2 const& radius) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawEllipse(center, radius, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawRect(Rect const& rect) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawRectangle(rect, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawRoundedRectangle(rect, radius, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::FillShape(ShapePtr shape) { KGE_ASSERT(ctx_); if (shape) { ctx_->SetCurrentBrush(fill_brush_); ctx_->FillShape(*shape); cache_expired_ = true; } } void Canvas::FillCircle(Point const& center, float radius) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillEllipse(center, Vec2(radius, radius)); cache_expired_ = true; } void Canvas::FillEllipse(Point const& center, Vec2 const& radius) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillEllipse(center, radius); cache_expired_ = true; } void Canvas::FillRect(Rect const& rect) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillRectangle(rect); cache_expired_ = true; } void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius) { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillRoundedRectangle(rect, radius); cache_expired_ = true; } void Canvas::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect) { KGE_ASSERT(ctx_); if (texture) { ctx_->DrawTexture(*texture, src_rect, dest_rect); cache_expired_ = true; } } void Canvas::DrawTextLayout(String const& text, Point const& point) { if (text.empty()) return; TextLayout layout; layout.SetStyle(text_style_); layout.SetText(text); DrawTextLayout(layout, point); } void Canvas::DrawTextLayout(TextLayout const& layout, Point const& point) { KGE_ASSERT(ctx_); ctx_->DrawTextLayout(layout, point); } void Canvas::BeginPath(Point const& begin_pos) { shape_sink_.BeginPath(begin_pos); } void Canvas::EndPath(bool closed) { shape_sink_.EndPath(closed); } void Canvas::AddLine(Point const& point) { shape_sink_.AddLine(point); } void Canvas::AddLines(Vector const& points) { shape_sink_.AddLines(points); } void Canvas::AddBezier(Point const& point1, Point const& point2, Point const& point3) { shape_sink_.AddBezier(point1, point2, point3); } void Canvas::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small) { shape_sink_.AddArc(point, radius, rotation, clockwise, is_small); } void Canvas::StrokePath() { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); ctx_->DrawShape(*shape_sink_.GetShape(), stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::FillPath() { KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillShape(*shape_sink_.GetShape()); cache_expired_ = true; } void Canvas::Clear() { KGE_ASSERT(ctx_); ctx_->Clear(); cache_expired_ = true; } void Canvas::Clear(Color const& clear_color) { KGE_ASSERT(ctx_); ctx_->Clear(clear_color); cache_expired_ = true; } void Canvas::ResizeAndClear(Size size) { ctx_ = TextureRenderContext::Create(size); } TexturePtr Canvas::ExportToTexture() const { UpdateCache(); return texture_cached_; } void Canvas::UpdateCache() const { if (cache_expired_ && ctx_) { if (!texture_cached_) { texture_cached_ = new Texture; } if (ctx_->GetOutput(*texture_cached_)) { cache_expired_ = false; } } } } // namespace kiwano