From d9389226055ddbff61489eef7687fc1760b5aefa Mon Sep 17 00:00:00 2001 From: Nomango Date: Sat, 8 Feb 2020 00:17:31 +0800 Subject: [PATCH] Update TextureRenderContext --- projects/kiwano/kiwano.vcxproj | 2 + projects/kiwano/kiwano.vcxproj.filters | 6 + src/kiwano/2d/Actor.cpp | 2 +- src/kiwano/2d/Canvas.cpp | 135 ++++----- src/kiwano/2d/Canvas.h | 36 ++- src/kiwano/2d/GifSprite.cpp | 8 +- src/kiwano/2d/GifSprite.h | 2 +- src/kiwano/2d/ShapeActor.cpp | 2 +- src/kiwano/render/RenderContext.cpp | 326 ++++++++++----------- src/kiwano/render/RenderContext.h | 202 +++++++------ src/kiwano/render/Renderer.cpp | 13 +- src/kiwano/render/Renderer.h | 5 +- src/kiwano/render/TextureRenderContext.cpp | 82 ++++++ src/kiwano/render/TextureRenderContext.h | 89 ++++++ 14 files changed, 532 insertions(+), 378 deletions(-) create mode 100644 src/kiwano/render/TextureRenderContext.cpp create mode 100644 src/kiwano/render/TextureRenderContext.h diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index 86570ca7..f544ab77 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -84,6 +84,7 @@ + @@ -151,6 +152,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 4500b9b2..007fb85b 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -285,6 +285,9 @@ math + + render + @@ -482,5 +485,8 @@ render + + render + \ No newline at end of file diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 141d2fa6..faafeb80 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -154,7 +154,7 @@ void Actor::RenderBorder(RenderContext& ctx) ctx.FillRectangle(bounds); ctx.SetCurrentBrush(GetStage()->GetBorderStrokeBrush()); - ctx.DrawRectangle(bounds, 2.f); + ctx.DrawRectangle(bounds, nullptr, 2.f); } for (auto child = children_.first_item(); child; child = child->next_item()) diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index 1905fece..eb7715a6 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -25,9 +25,22 @@ namespace kiwano { -CanvasPtr Canvas::Create() +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); + } + catch (std::exception) + { + return nullptr; + } + } return ptr; } @@ -38,17 +51,15 @@ Canvas::Canvas() { } -Canvas::~Canvas() {} - void Canvas::BeginDraw() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->BeginDraw(); } void Canvas::EndDraw() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->EndDraw(); cache_expired_ = true; } @@ -68,116 +79,111 @@ void Canvas::OnRender(RenderContext& ctx) void Canvas::SetBrush(BrushPtr brush) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(brush); } -float Canvas::GetStrokeWidth() const -{ - return stroke_width_; -} - void Canvas::SetBrushTransform(Transform const& transform) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetTransform(transform.ToMatrix()); } void Canvas::SetBrushTransform(Matrix3x2 const& transform) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetTransform(transform); } void Canvas::PushLayerArea(LayerArea& area) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->PushLayer(area); } void Canvas::PopLayerArea() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->PopLayer(); } void Canvas::PushClipRect(Rect const& clip_rect) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->PushClipRect(clip_rect); } void Canvas::PopClipRect() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->PopClipRect(); } void Canvas::DrawShape(ShapePtr shape) { - if (!shape) - return; - - InitRenderTargetAndBrushs(); - ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawShape(*shape, stroke_width_, stroke_style_); - cache_expired_ = true; + 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) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawLine(begin, end, stroke_width_, stroke_style_); + ctx_->DrawLine(begin, end, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawCircle(Point const& center, float radius) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawEllipse(center, Vec2(radius, radius), stroke_width_, stroke_style_); + ctx_->DrawEllipse(center, Vec2(radius, radius), stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawEllipse(Point const& center, Vec2 const& radius) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawEllipse(center, radius, stroke_width_, stroke_style_); + ctx_->DrawEllipse(center, radius, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawRect(Rect const& rect) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawRectangle(rect, stroke_width_, stroke_style_); + ctx_->DrawRectangle(rect, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawRoundedRectangle(rect, radius, stroke_width_, stroke_style_); + ctx_->DrawRoundedRectangle(rect, radius, stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::FillShape(ShapePtr shape) { - if (!shape) - return; - - InitRenderTargetAndBrushs(); - ctx_->SetCurrentBrush(fill_brush_); - ctx_->FillShape(*shape); - cache_expired_ = true; + KGE_ASSERT(ctx_); + if (shape) + { + ctx_->SetCurrentBrush(fill_brush_); + ctx_->FillShape(*shape); + cache_expired_ = true; + } } void Canvas::FillCircle(Point const& center, float radius) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillEllipse(center, Vec2(radius, radius)); cache_expired_ = true; @@ -185,7 +191,7 @@ void Canvas::FillCircle(Point const& center, float radius) void Canvas::FillEllipse(Point const& center, Vec2 const& radius) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillEllipse(center, radius); cache_expired_ = true; @@ -193,7 +199,7 @@ void Canvas::FillEllipse(Point const& center, Vec2 const& radius) void Canvas::FillRect(Rect const& rect) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillRectangle(rect); cache_expired_ = true; @@ -201,7 +207,7 @@ void Canvas::FillRect(Rect const& rect) void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillRoundedRectangle(rect, radius); cache_expired_ = true; @@ -209,9 +215,9 @@ void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius) void Canvas::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect) { + KGE_ASSERT(ctx_); if (texture) { - InitRenderTargetAndBrushs(); ctx_->DrawTexture(*texture, src_rect, dest_rect); cache_expired_ = true; } @@ -230,7 +236,7 @@ void Canvas::DrawTextLayout(String const& text, Point const& point) void Canvas::DrawTextLayout(TextLayout const& layout, Point const& point) { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->DrawTextLayout(layout, point); } @@ -266,15 +272,15 @@ void Canvas::AddArc(Point const& point, Size const& radius, float rotation, bool void Canvas::StrokePath() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(stroke_brush_); - ctx_->DrawShape(*shape_sink_.GetShape(), stroke_width_, stroke_style_); + ctx_->DrawShape(*shape_sink_.GetShape(), stroke_style_, stroke_width_); cache_expired_ = true; } void Canvas::FillPath() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->SetCurrentBrush(fill_brush_); ctx_->FillShape(*shape_sink_.GetShape()); cache_expired_ = true; @@ -282,44 +288,29 @@ void Canvas::FillPath() void Canvas::Clear() { - InitRenderTargetAndBrushs(); + KGE_ASSERT(ctx_); ctx_->Clear(); cache_expired_ = true; } void Canvas::Clear(Color const& clear_color) { - InitRenderTargetAndBrushs(); + 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::InitRenderTargetAndBrushs() -{ - if (!ctx_) - { - Renderer::Instance().CreateTextureRenderTarget(ctx_); - } - - if (!stroke_brush_) - { - stroke_brush_ = new Brush; - stroke_brush_->SetColor(Color::White); - } - - if (!fill_brush_) - { - fill_brush_ = new Brush; - fill_brush_->SetColor(Color::White); - } -} - void Canvas::UpdateCache() const { if (cache_expired_ && ctx_) diff --git a/src/kiwano/2d/Canvas.h b/src/kiwano/2d/Canvas.h index 900aa6d3..fcc34ade 100644 --- a/src/kiwano/2d/Canvas.h +++ b/src/kiwano/2d/Canvas.h @@ -21,7 +21,7 @@ #pragma once #include #include -#include +#include namespace kiwano { @@ -35,20 +35,16 @@ KGE_DECLARE_SMART_PTR(Canvas); /** * \~chinese - * @brief 画布,用于绘制图元 + * @brief 画布 + * @details 用于绘制图形、图像、文字等各种类型的图元,同时可以将绘制内容导出至图像 */ class KGE_API Canvas : public Actor { public: /// \~chinese /// @brief 创建画布 - static CanvasPtr Create(); - - /// \~chinese - /// @brief 构建空画布 - Canvas(); - - virtual ~Canvas(); + /// @param size 画布大小 + static CanvasPtr Create(Size const& size); /// \~chinese /// @brief 开始绘图 @@ -272,6 +268,10 @@ public: /// @brief 获取轮廓画刷 BrushPtr GetStrokeBrush() const; + /// \~chinese + /// @brief 清空画布大小并重设画布大小 + void ResizeAndClear(Size size); + /// \~chinese /// @brief 导出纹理 TexturePtr ExportToTexture() const; @@ -279,7 +279,7 @@ public: void OnRender(RenderContext& ctx) override; private: - void InitRenderTargetAndBrushs(); + Canvas(); void UpdateCache() const; @@ -298,6 +298,11 @@ private: /** @} */ +inline float Canvas::GetStrokeWidth() const +{ + return stroke_width_; +} + inline void Canvas::SetStrokeWidth(float width) { stroke_width_ = std::max(width, 0.f); @@ -315,13 +320,19 @@ inline void Canvas::SetTextStyle(TextStyle const& text_style) inline void Canvas::SetStrokeColor(Color const& color) { - InitRenderTargetAndBrushs(); + if (!stroke_brush_) + { + stroke_brush_ = new Brush; + } stroke_brush_->SetColor(color); } inline void Canvas::SetFillColor(Color const& color) { - InitRenderTargetAndBrushs(); + if (!fill_brush_) + { + fill_brush_ = new Brush; + } fill_brush_->SetColor(color); } @@ -344,4 +355,5 @@ inline BrushPtr Canvas::GetStrokeBrush() const { return stroke_brush_; } + } // namespace kiwano diff --git a/src/kiwano/2d/GifSprite.cpp b/src/kiwano/2d/GifSprite.cpp index b8296d2d..a3575f7a 100644 --- a/src/kiwano/2d/GifSprite.cpp +++ b/src/kiwano/2d/GifSprite.cpp @@ -87,14 +87,14 @@ bool GifSprite::Load(GifImagePtr gif) loop_count_ = 0; frame_ = GifImage::Frame(); - SetSize(float(gif_->GetWidthInPixels()), float(gif_->GetHeightInPixels())); - if (!frame_rt_) { - Size frame_size = GetSize(); - Renderer::Instance().CreateTextureRenderTarget(frame_rt_, &frame_size); + Size frame_size = Size(float(gif_->GetWidthInPixels()), float(gif_->GetHeightInPixels())); + frame_rt_ = TextureRenderContext::Create(frame_size); } + SetSize(frame_rt_->GetSize()); + if (gif_->GetFramesCount() > 0) { ComposeNextFrame(); diff --git a/src/kiwano/2d/GifSprite.h b/src/kiwano/2d/GifSprite.h index 7b6de011..145f7af4 100644 --- a/src/kiwano/2d/GifSprite.h +++ b/src/kiwano/2d/GifSprite.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include namespace kiwano { diff --git a/src/kiwano/2d/ShapeActor.cpp b/src/kiwano/2d/ShapeActor.cpp index 34f0074d..ceebe316 100644 --- a/src/kiwano/2d/ShapeActor.cpp +++ b/src/kiwano/2d/ShapeActor.cpp @@ -91,7 +91,7 @@ void ShapeActor::OnRender(RenderContext& ctx) if (stroke_brush_) { ctx.SetCurrentBrush(stroke_brush_); - ctx.DrawShape(*shape_, stroke_width_ * 2 /* twice width for widening */, stroke_style_); + ctx.DrawShape(*shape_, stroke_style_, stroke_width_ * 2 /* twice width for widening */); } if (fill_brush_) diff --git a/src/kiwano/render/RenderContext.cpp b/src/kiwano/render/RenderContext.cpp index e8db988b..e2376083 100644 --- a/src/kiwano/render/RenderContext.cpp +++ b/src/kiwano/render/RenderContext.cpp @@ -23,9 +23,6 @@ namespace kiwano { -// -// RenderContext -// RenderContext::RenderContext() : collecting_status_(false) @@ -101,152 +98,6 @@ void RenderContext::EndDraw() } } -void RenderContext::DrawShape(Shape const& shape, float stroke_width, StrokeStylePtr stroke) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - if (shape.IsValid()) - { - if (stroke) - { - render_target_->DrawGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get(), stroke_width, - stroke->GetStrokeStyle().get()); - } - else - { - render_target_->DrawGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get(), stroke_width, - nullptr); - } - - IncreasePrimitivesCount(); - } -} - -void RenderContext::FillShape(Shape const& shape) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - if (shape.IsValid()) - { - render_target_->FillGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get()); - - IncreasePrimitivesCount(); - } -} - -void RenderContext::DrawLine(Point const& point1, Point const& point2, float stroke_width, StrokeStylePtr stroke) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - if (stroke) - { - render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), - current_brush_->GetBrush().get(), stroke_width, stroke->GetStrokeStyle().get()); - } - else - { - render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), - current_brush_->GetBrush().get(), stroke_width, nullptr); - } - - IncreasePrimitivesCount(); -} - -void RenderContext::DrawRectangle(Rect const& rect, float stroke_width, StrokeStylePtr stroke) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - if (stroke) - { - render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get(), stroke_width, - stroke->GetStrokeStyle().get()); - } - else - { - render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get(), stroke_width, - nullptr); - } - - IncreasePrimitivesCount(); -} - -void RenderContext::FillRectangle(Rect const& rect) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - render_target_->FillRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get()); - - IncreasePrimitivesCount(); -} - -void RenderContext::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, float stroke_width, - StrokeStylePtr stroke) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - if (stroke) - { - render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), - current_brush_->GetBrush().get(), stroke_width, - stroke->GetStrokeStyle().get()); - - } - else - { - render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), - current_brush_->GetBrush().get(), stroke_width, nullptr); - - } - IncreasePrimitivesCount(); -} - -void RenderContext::FillRoundedRectangle(Rect const& rect, Vec2 const& radius) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), - current_brush_->GetBrush().get()); - - IncreasePrimitivesCount(); -} - -void RenderContext::DrawEllipse(Point const& center, Vec2 const& radius, float stroke_width, StrokeStylePtr stroke) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - if (stroke) - { - render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), - current_brush_->GetBrush().get(), stroke_width, stroke->GetStrokeStyle().get()); - } - else - { - render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), - current_brush_->GetBrush().get(), stroke_width, nullptr); - } - - IncreasePrimitivesCount(); -} - -void RenderContext::FillEllipse(Point const& center, Vec2 const& radius) -{ - KGE_ASSERT(render_target_ && "Render target has not been initialized!"); - KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); - - render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), - current_brush_->GetBrush().get()); - - IncreasePrimitivesCount(); -} - void RenderContext::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect) { DrawTexture(texture, &src_rect, &dest_rect); @@ -316,6 +167,150 @@ void RenderContext::DrawTextLayout(TextLayout const& layout, Point const& offset } } +void RenderContext::DrawShape(Shape const& shape, StrokeStylePtr stroke, float stroke_width) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + if (shape.IsValid()) + { + if (stroke) + { + render_target_->DrawGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get(), stroke_width, + stroke->GetStrokeStyle().get()); + } + else + { + render_target_->DrawGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get(), stroke_width, + nullptr); + } + + IncreasePrimitivesCount(); + } +} + +void RenderContext::DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke, float stroke_width) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + if (stroke) + { + render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), + current_brush_->GetBrush().get(), stroke_width, stroke->GetStrokeStyle().get()); + } + else + { + render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), + current_brush_->GetBrush().get(), stroke_width, nullptr); + } + + IncreasePrimitivesCount(); +} + +void RenderContext::DrawRectangle(Rect const& rect, StrokeStylePtr stroke, float stroke_width) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + if (stroke) + { + render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get(), stroke_width, + stroke->GetStrokeStyle().get()); + } + else + { + render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get(), stroke_width, + nullptr); + } + + IncreasePrimitivesCount(); +} + +void RenderContext::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke, + float stroke_width) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + if (stroke) + { + render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), + current_brush_->GetBrush().get(), stroke_width, + stroke->GetStrokeStyle().get()); + } + else + { + render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), + current_brush_->GetBrush().get(), stroke_width, nullptr); + } + IncreasePrimitivesCount(); +} + +void RenderContext::DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke, float stroke_width) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + if (stroke) + { + render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), + current_brush_->GetBrush().get(), stroke_width, stroke->GetStrokeStyle().get()); + } + else + { + render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), + current_brush_->GetBrush().get(), stroke_width, nullptr); + } + + IncreasePrimitivesCount(); +} + +void RenderContext::FillShape(Shape const& shape) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + if (shape.IsValid()) + { + render_target_->FillGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get()); + + IncreasePrimitivesCount(); + } +} + +void RenderContext::FillRectangle(Rect const& rect) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + render_target_->FillRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get()); + + IncreasePrimitivesCount(); +} + +void RenderContext::FillRoundedRectangle(Rect const& rect, Vec2 const& radius) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), + current_brush_->GetBrush().get()); + + IncreasePrimitivesCount(); +} + +void RenderContext::FillEllipse(Point const& center, Vec2 const& radius) +{ + KGE_ASSERT(render_target_ && "Render target has not been initialized!"); + KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!"); + + render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), + current_brush_->GetBrush().get()); + + IncreasePrimitivesCount(); +} + void RenderContext::CreateTexture(Texture& texture, math::Vec2T size) { KGE_ASSERT(render_target_ && "Render target has not been initialized!"); @@ -396,6 +391,15 @@ void RenderContext::Clear(Color const& clear_color) render_target_->Clear(DX::ConvertToColorF(clear_color)); } +Size RenderContext::GetSize() const +{ + if (render_target_) + { + return reinterpret_cast(render_target_->GetSize()); + } + return Size(); +} + void RenderContext::SetTransform(const Matrix3x2& matrix) { KGE_ASSERT(render_target_ && "Render target has not been initialized!"); @@ -508,28 +512,4 @@ void RenderContext::RestoreDrawingState() } } -// -// TextureRenderContext -// - -TextureRenderContext::TextureRenderContext() {} - -bool TextureRenderContext::GetOutput(Texture& texture) -{ - HRESULT hr = E_FAIL; - - if (bitmap_rt_) - { - ComPtr bitmap; - - hr = bitmap_rt_->GetBitmap(&bitmap); - - if (SUCCEEDED(hr)) - { - texture.SetBitmap(bitmap); - } - } - return SUCCEEDED(hr); -} - } // namespace kiwano diff --git a/src/kiwano/render/RenderContext.h b/src/kiwano/render/RenderContext.h index ae908a68..6f45f207 100644 --- a/src/kiwano/render/RenderContext.h +++ b/src/kiwano/render/RenderContext.h @@ -33,7 +33,6 @@ namespace kiwano class Renderer; KGE_DECLARE_SMART_PTR(RenderContext); -KGE_DECLARE_SMART_PTR(TextureRenderContext); /** * \addtogroup Render @@ -64,120 +63,162 @@ public: bool IsValid() const; /// \~chinese - /// @brief 是否有效 + /// @brief 开始渲染 void BeginDraw(); /// \~chinese - /// @brief 是否有效 + /// @brief 结束渲染 void EndDraw(); /// \~chinese - /// @brief 是否有效 - void DrawShape(Shape const& shape, float stroke_width, StrokeStylePtr stroke = nullptr); - - /// \~chinese - /// @brief 是否有效 - void FillShape(Shape const& shape); - - /// \~chinese - /// @brief 是否有效 - void DrawLine(Point const& point1, Point const& point2, float stroke_width, StrokeStylePtr stroke = nullptr); - - /// \~chinese - /// @brief 是否有效 - void DrawRectangle(Rect const& rect, float stroke_width, StrokeStylePtr stroke = nullptr); - - /// \~chinese - /// @brief 是否有效 - void FillRectangle(Rect const& rect); - - /// \~chinese - /// @brief 是否有效 - void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, float stroke_width, - StrokeStylePtr stroke = nullptr); - - /// \~chinese - /// @brief 是否有效 - void FillRoundedRectangle(Rect const& rect, Vec2 const& radius); - - /// \~chinese - /// @brief 是否有效 - void DrawEllipse(Point const& center, Vec2 const& radius, float stroke_width, StrokeStylePtr stroke = nullptr); - - /// \~chinese - /// @brief 是否有效 - void FillEllipse(Point const& center, Vec2 const& radius); - - /// \~chinese - /// @brief 是否有效 + /// @brief 绘制纹理 + /// @param texture 纹理 + /// @param src_rect 源纹理裁剪矩形 + /// @param dest_rect 绘制的目标区域 void DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect); /// \~chinese - /// @brief 是否有效 + /// @brief 绘制纹理 + /// @param texture 纹理 + /// @param src_rect 源纹理裁剪矩形 + /// @param dest_rect 绘制的目标区域 void DrawTexture(Texture const& texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr); /// \~chinese - /// @brief 是否有效 - void DrawTextLayout(TextLayout const& layout, Point const& offset = Point{}); + /// @brief 绘制文本布局 + /// @param layout 文本布局 + /// @param offset 偏移量 + void DrawTextLayout(TextLayout const& layout, Point const& offset = Point()); /// \~chinese - /// @brief 是否有效 + /// @brief 绘制形状轮廓 + /// @param shape 形状 + /// @param stroke 线条样式 + /// @param stroke_width 线条宽度 + void DrawShape(Shape const& shape, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f); + + /// \~chinese + /// @brief 绘制线段 + /// @param point1 线段起点 + /// @param point2 线段终点 + /// @param stroke 线条样式 + /// @param stroke_width 线条宽度 + void DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f); + + /// \~chinese + /// @brief 绘制矩形边框 + /// @param rect 矩形 + /// @param stroke 线条样式 + /// @param stroke_width 线条宽度 + void DrawRectangle(Rect const& rect, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f); + + /// \~chinese + /// @brief 绘制圆角矩形边框 + /// @param rect 矩形 + /// @param radius 圆角半径 + /// @param stroke 线条样式 + /// @param stroke_width 线条宽度 + void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke = nullptr, + float stroke_width = 1.0f); + + /// \~chinese + /// @brief 绘制椭圆边框 + /// @param center 圆心 + /// @param radius 椭圆半径 + /// @param stroke 线条样式 + /// @param stroke_width 线条宽度 + void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke = nullptr, + float stroke_width = 1.0f); + + /// \~chinese + /// @brief 填充形状 + /// @param shape 形状 + void FillShape(Shape const& shape); + + /// \~chinese + /// @brief 填充矩形 + /// @param rect 矩形 + void FillRectangle(Rect const& rect); + + /// \~chinese + /// @brief 填充圆角矩形 + /// @param rect 矩形 + /// @param radius 圆角半径 + void FillRoundedRectangle(Rect const& rect, Vec2 const& radius); + + /// \~chinese + /// @brief 填充椭圆 + /// @param center 圆心 + /// @param radius 椭圆半径 + void FillEllipse(Point const& center, Vec2 const& radius); + + /// \~chinese + /// @brief 创建纹理 + /// @param texture 纹理 + /// @param size 纹理像素大小 void CreateTexture(Texture& texture, math::Vec2T size); /// \~chinese - /// @brief 是否有效 + /// @brief 设置绘制的裁剪区域 + /// @param clip_rect 裁剪矩形 void PushClipRect(Rect const& clip_rect); /// \~chinese - /// @brief 是否有效 + /// @brief 取消上一次设置的绘制裁剪区域 void PopClipRect(); /// \~chinese - /// @brief 是否有效 + /// @brief 设置图层区域 + /// @param layer 图层区域 void PushLayer(LayerArea& layer); /// \~chinese - /// @brief 是否有效 + /// @brief 取消上一次设置的图层区域 void PopLayer(); /// \~chinese - /// @brief 是否有效 + /// @brief 清空渲染内容 void Clear(); /// \~chinese - /// @brief 是否有效 + /// @brief 使用纯色清空渲染内容 + /// @param clear_color 清屏颜色 void Clear(Color const& clear_color); /// \~chinese - /// @brief 是否有效 + /// @brief 获取渲染区域大小 + Size GetSize() const; + + /// \~chinese + /// @brief 获取画刷透明度 float GetBrushOpacity() const; /// \~chinese - /// @brief 是否有效 + /// @brief 获取当前画刷 BrushPtr GetCurrentBrush() const; /// \~chinese - /// @brief 是否有效 + /// @brief 获取全局二维变换 Matrix3x2 GetGlobalTransform() const; /// \~chinese - /// @brief 是否有效 + /// @brief 设置画刷透明度 void SetBrushOpacity(float opacity); /// \~chinese - /// @brief 是否有效 + /// @brief 设置当前画刷 void SetCurrentBrush(BrushPtr brush); /// \~chinese - /// @brief 是否有效 + /// @brief 设置上下文的二维变换 void SetTransform(const Matrix3x2& matrix); /// \~chinese - /// @brief 是否有效 + /// @brief 设置全局二维变换 void SetGlobalTransform(const Matrix3x2& matrix); /// \~chinese - /// @brief 是否有效 + /// @brief 设置全局二维变换 void SetGlobalTransform(const Matrix3x2* matrix); /// \~chinese @@ -260,35 +301,6 @@ private: ComPtr drawing_state_; }; -/// \~chinese -/// @brief 纹理渲染上下文 -/// @details 纹理渲染上下文将渲染输出到一个纹理对象中 -class KGE_API TextureRenderContext : public RenderContext -{ - friend class Renderer; - -public: - /// \~chinese - /// @brief 是否有效 - bool IsValid() const; - - /// \~chinese - /// @brief 获取渲染输出 - /// @param[out] texture 纹理输出 - /// @return 操作是否成功 - bool GetOutput(Texture& texture); - -private: - TextureRenderContext(); - - ComPtr GetBitmapRenderTarget() const; - - void SetBitmapRenderTarget(ComPtr ctx); - -private: - ComPtr bitmap_rt_; -}; - /** @} */ inline RenderContext::Status::Status() @@ -347,18 +359,4 @@ inline void RenderContext::SetCurrentBrush(BrushPtr brush) } } -inline bool TextureRenderContext::IsValid() const -{ - return bitmap_rt_ != nullptr; -} - -inline ComPtr TextureRenderContext::GetBitmapRenderTarget() const -{ - return bitmap_rt_; -} - -inline void TextureRenderContext::SetBitmapRenderTarget(ComPtr ctx) -{ - bitmap_rt_ = ctx; -} } // namespace kiwano diff --git a/src/kiwano/render/Renderer.cpp b/src/kiwano/render/Renderer.cpp index 4d1652e8..9f01f0c0 100644 --- a/src/kiwano/render/Renderer.cpp +++ b/src/kiwano/render/Renderer.cpp @@ -751,7 +751,7 @@ void Renderer::CreateShapeSink(ShapeSink& sink) win32::ThrowIfFailed(hr); } -void Renderer::CreateTextureRenderTarget(TextureRenderContextPtr& render_context, const Size* desired_size) +void Renderer::CreateTextureRenderContext(TextureRenderContext& render_context, const Size* desired_size) { HRESULT hr = S_OK; if (!d2d_res_) @@ -759,8 +759,6 @@ void Renderer::CreateTextureRenderTarget(TextureRenderContextPtr& render_context hr = E_UNEXPECTED; } - TextureRenderContextPtr output = new TextureRenderContext; - if (SUCCEEDED(hr)) { ComPtr bitmap_rt; @@ -777,20 +775,15 @@ void Renderer::CreateTextureRenderTarget(TextureRenderContextPtr& render_context if (SUCCEEDED(hr)) { - hr = output->CreateDeviceResources(d2d_res_->GetFactory(), bitmap_rt); + hr = render_context.CreateDeviceResources(d2d_res_->GetFactory(), bitmap_rt); } if (SUCCEEDED(hr)) { - output->SetBitmapRenderTarget(bitmap_rt); + render_context.SetBitmapRenderTarget(bitmap_rt); } } - if (SUCCEEDED(hr)) - { - render_context = output; - } - win32::ThrowIfFailed(hr); } diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h index d3d78a82..f5e9e756 100644 --- a/src/kiwano/render/Renderer.h +++ b/src/kiwano/render/Renderer.h @@ -23,8 +23,9 @@ #include #include #include -#include #include +#include +#include #include #if defined(KGE_USE_DIRECTX10) @@ -168,7 +169,7 @@ public: /// @brief 创建纹理渲染上下文 /// @param[out] render_context 渲染上下文 /// @param[in] desired_size 期望的输出大小 - void CreateTextureRenderTarget(TextureRenderContextPtr& render_context, const Size* desired_size = nullptr); + void CreateTextureRenderContext(TextureRenderContext& render_context, const Size* desired_size = nullptr); /// \~chinese /// @brief 创建纯色画刷 diff --git a/src/kiwano/render/TextureRenderContext.cpp b/src/kiwano/render/TextureRenderContext.cpp new file mode 100644 index 00000000..e0c4e71c --- /dev/null +++ b/src/kiwano/render/TextureRenderContext.cpp @@ -0,0 +1,82 @@ +// Copyright (c) 2016-2019 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 +{ + +TextureRenderContextPtr TextureRenderContext::Create() +{ + TextureRenderContextPtr ptr = new TextureRenderContext; + if (ptr) + { + try + { + Renderer::Instance().CreateTextureRenderContext(*ptr); + } + catch (std::exception) + { + return nullptr; + } + } + return ptr; +} + +TextureRenderContextPtr TextureRenderContext::Create(Size const& desired_size) +{ + TextureRenderContextPtr ptr = new TextureRenderContext; + if (ptr) + { + try + { + Renderer::Instance().CreateTextureRenderContext(*ptr, &desired_size); + } + catch (std::exception) + { + return nullptr; + } + } + return ptr; +} + +TextureRenderContext::TextureRenderContext() {} + +bool TextureRenderContext::GetOutput(Texture& texture) +{ + HRESULT hr = E_FAIL; + + if (bitmap_rt_) + { + ComPtr bitmap; + + hr = bitmap_rt_->GetBitmap(&bitmap); + + if (SUCCEEDED(hr)) + { + texture.SetBitmap(bitmap); + } + } + return SUCCEEDED(hr); +} + +} // namespace kiwano diff --git a/src/kiwano/render/TextureRenderContext.h b/src/kiwano/render/TextureRenderContext.h new file mode 100644 index 00000000..ed412152 --- /dev/null +++ b/src/kiwano/render/TextureRenderContext.h @@ -0,0 +1,89 @@ +// Copyright (c) 2016-2019 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 + +namespace kiwano +{ +class Renderer; + +KGE_DECLARE_SMART_PTR(TextureRenderContext); + +/** + * \addtogroup Render + * @{ + */ + +/// \~chinese +/// @brief 纹理渲染上下文 +/// @details 纹理渲染上下文将渲染输出到一个纹理对象中 +class KGE_API TextureRenderContext : public RenderContext +{ + friend class Renderer; + +public: + /// \~chinese + /// @brief 创建纹理渲染上下文 + static TextureRenderContextPtr Create(); + + /// \~chinese + /// @brief 创建纹理渲染上下文 + /// @param size 期望的输出大小 + static TextureRenderContextPtr Create(Size const& desired_size); + + /// \~chinese + /// @brief 是否有效 + bool IsValid() const; + + /// \~chinese + /// @brief 获取渲染输出 + /// @param[out] texture 纹理输出 + /// @return 操作是否成功 + bool GetOutput(Texture& texture); + +private: + TextureRenderContext(); + + ComPtr GetBitmapRenderTarget() const; + + void SetBitmapRenderTarget(ComPtr ctx); + +private: + ComPtr bitmap_rt_; +}; + +/** @} */ + +inline bool TextureRenderContext::IsValid() const +{ + return bitmap_rt_ != nullptr; +} + +inline ComPtr TextureRenderContext::GetBitmapRenderTarget() const +{ + return bitmap_rt_; +} + +inline void TextureRenderContext::SetBitmapRenderTarget(ComPtr ctx) +{ + bitmap_rt_ = ctx; +} +} // namespace kiwano