From 7f954e0c2c8394217676a027a20f5b8ba8e70dbe Mon Sep 17 00:00:00 2001 From: Nomango Date: Mon, 9 Sep 2019 16:20:40 +0800 Subject: [PATCH 1/2] remove ResolutionMode --- src/kiwano/2d/Actor.cpp | 2 +- src/kiwano/base/Event.hpp | 20 +++---- src/kiwano/platform/Application.cpp | 12 ++-- src/kiwano/renderer/Renderer.cpp | 89 +---------------------------- src/kiwano/renderer/Renderer.h | 30 +--------- 5 files changed, 19 insertions(+), 134 deletions(-) diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 49b0bd4d..3238fd43 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -128,7 +128,7 @@ namespace kiwano { if (show_border_ && !size_.IsOrigin()) { - Rect bounds = GetBounds(); + Rect bounds = GetBounds(); rt->SetTransform(transform_matrix_); rt->FillRectangle(bounds, Color(Color::Red, .4f)); diff --git a/src/kiwano/base/Event.hpp b/src/kiwano/base/Event.hpp index 88eb4d4b..b9ef63f3 100644 --- a/src/kiwano/base/Event.hpp +++ b/src/kiwano/base/Event.hpp @@ -45,7 +45,7 @@ namespace kiwano }; }; - static bool Check(UInt32 type); + static bool Check(Int32 type); }; // 键盘事件 @@ -65,7 +65,7 @@ namespace kiwano }; }; - static bool Check(UInt32 type); + static bool Check(Int32 type); }; // 窗口事件 @@ -96,7 +96,7 @@ namespace kiwano }; }; - static bool Check(UInt32 type); + static bool Check(Int32 type); }; // 自定义事件 @@ -110,7 +110,7 @@ namespace kiwano // 事件 struct KGE_API Event { - enum Type : UInt32 + enum Type : Int32 { First, @@ -144,34 +144,34 @@ namespace kiwano Last }; - UInt32 type; + Int32 type; Actor* target; union { MouseEvent mouse; KeyboardEvent key; - WindowEvent win; + WindowEvent window; CustomEvent custom; }; - Event(UInt32 type = Type::First) : type(type), target(nullptr) {} + Event(Int32 type = Type::First) : type(type), target(nullptr) {} }; // Check-functions - inline bool MouseEvent::Check(UInt32 type) + inline bool MouseEvent::Check(Int32 type) { return type > Event::MouseFirst && type < Event::MouseLast; } - inline bool KeyboardEvent::Check(UInt32 type) + inline bool KeyboardEvent::Check(Int32 type) { return type > Event::KeyFirst && type < Event::KeyLast; } - inline bool WindowEvent::Check(UInt32 type) + inline bool WindowEvent::Check(Int32 type) { return type > Event::WindowFirst && type < Event::WindowLast; } diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 3b127c28..87148dca 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -382,8 +382,8 @@ namespace kiwano Window::GetInstance()->UpdateWindowRect(); Event evt(Event::WindowResized); - evt.win.width = LOWORD(lparam); - evt.win.height = HIWORD(lparam); + evt.window.width = LOWORD(lparam); + evt.window.height = HIWORD(lparam); app->DispatchEvent(evt); } } @@ -395,8 +395,8 @@ namespace kiwano Int32 y = (Int32)(short)HIWORD(lparam); Event evt(Event::WindowMoved); - evt.win.x = x; - evt.win.y = y; + evt.window.x = x; + evt.window.y = y; app->DispatchEvent(evt); } break; @@ -408,7 +408,7 @@ namespace kiwano Window::GetInstance()->SetActive(active); Event evt(Event::WindowFocusChanged); - evt.win.focus = active; + evt.window.focus = active; app->DispatchEvent(evt); } break; @@ -418,7 +418,7 @@ namespace kiwano // KGE_LOG(L"Window title changed"); Event evt(Event::WindowTitleChanged); - evt.win.title = reinterpret_cast(lparam); + evt.window.title = reinterpret_cast(lparam); app->DispatchEvent(evt); } break; diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index 699ba874..cbcfee72 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -35,7 +35,6 @@ namespace kiwano : hwnd_(nullptr) , vsync_(true) , clear_color_(Color::Black) - , resolution_mode_(ResolutionMode::Fixed) { } @@ -54,7 +53,6 @@ namespace kiwano KGE_LOG(L"Creating device resources"); hwnd_ = Window::GetInstance()->GetHandle(); - resolution_ = output_size_ = Window::GetInstance()->GetSize(); d2d_res_ = nullptr; d3d_res_ = nullptr; @@ -71,19 +69,11 @@ namespace kiwano // Direct3D device resources if (SUCCEEDED(hr)) { -#if defined(KGE_USE_DIRECTX10) - hr = ID3D10DeviceResources::Create( + hr = ID3DDeviceResources::Create( &d3d_res_, d2d_res_.get(), hwnd_ ); -#else - hr = ID3D11DeviceResources::Create( - &d3d_res_, - d2d_res_.get(), - hwnd_ - ); -#endif } // DrawingStateBlock @@ -172,12 +162,6 @@ namespace kiwano hr = d3d_res_->ClearRenderTarget(clear_color_); } - if (SUCCEEDED(hr)) - { - SetTransform(Matrix3x2{}); - PushClipRect(Rect{ Point{}, resolution_ }); - } - ThrowIfFailed(hr); } @@ -193,8 +177,6 @@ namespace kiwano if (SUCCEEDED(hr)) { - PopClipRect(); - EndDraw(); render_target_->RestoreDrawingState(drawing_state_block_.get()); @@ -895,24 +877,6 @@ namespace kiwano vsync_ = enabled; } - void Renderer::SetResolution(Size const& resolution) - { - if (resolution_ != resolution) - { - resolution_ = resolution; - UpdateResolution(); - } - } - - void Renderer::SetResolutionMode(ResolutionMode mode) - { - if (resolution_mode_ != mode) - { - resolution_mode_ = mode; - UpdateResolution(); - } - } - void Renderer::SetClearColor(const Color& color) { clear_color_ = color; @@ -933,58 +897,7 @@ namespace kiwano hr = d3d_res_->SetLogicalSize(output_size_); } - if (SUCCEEDED(hr)) - { - UpdateResolution(); - } - ThrowIfFailed(hr); } - void Renderer::UpdateResolution() - { - switch (resolution_mode_) - { - case ResolutionMode::Fixed: - { - SetGlobalTransform(nullptr); - break; - } - - case ResolutionMode::Center: - { - Float32 left = math::Ceil((output_size_.x - resolution_.x) / 2); - Float32 top = math::Ceil((output_size_.y - resolution_.y) / 2); - SetGlobalTransform(Matrix3x2::Translation(Vec2{ left, top })); - break; - } - - case ResolutionMode::Stretch: - { - Float32 scalex = Float32(Int32((output_size_.x / resolution_.x) * 100 + 0.5f)) / 100; - Float32 scaley = Float32(Int32((output_size_.y / resolution_.y) * 100 + 0.5f)) / 100; - SetGlobalTransform(Matrix3x2::Scaling(Vec2{ scalex, scaley })); - break; - } - - case ResolutionMode::Adaptive: - { - Float32 scalex = Float32(Int32((output_size_.x / resolution_.x) * 100 + 0.5f)) / 100; - Float32 scaley = Float32(Int32((output_size_.y / resolution_.y) * 100 + 0.5f)) / 100; - if (scalex > scaley) - { - Float32 left = math::Ceil((output_size_.x - resolution_.x * scaley) / 2); - SetGlobalTransform(Matrix3x2::SRT(Vec2{ left, 0 }, Vec2{ scaley, scaley }, 0)); - } - else - { - Float32 top = math::Ceil((output_size_.y - resolution_.y * scalex) / 2); - SetGlobalTransform(Matrix3x2::SRT(Vec2{ 0, top }, Vec2{ scalex, scalex }, 0)); - - } - break; - } - } - } - } diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index 4e14f017..5cacf976 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -51,20 +51,8 @@ namespace kiwano ); }; - // 分辨率模式 - // 分辨率模式决定了将画面渲染到视区上的方式 - // Fixed (固定): 分辨率不随视区改变, 且画面始终与视区边界对齐(默认) - // Center (居中): 分辨率不随视区改变, 且画面始终在视区上居中 - // Stretch (拉伸): 分辨率始终随视区等比例拉伸 - // Adaptive (宽高自适应): 分辨率始终保持宽高比, 且尽可能的填充视区, 可能会出现黑色边界 - enum class ResolutionMode - { - Fixed, /* 固定 */ - Center, /* 居中 */ - Stretch, /* 拉伸 */ - Adaptive, /* 宽高自适应 */ - }; + // 渲染器 class KGE_API Renderer : public Singleton , public Component @@ -83,16 +71,6 @@ namespace kiwano bool enabled ); - // 设置画面分辨率 - void SetResolution( - Size const& resolution - ); - - // 设置分辨率模式 - void SetResolutionMode( - ResolutionMode mode - ); - public: void CreateTexture( Texture& texture, @@ -190,8 +168,6 @@ namespace kiwano inline Size const& GetOutputSize() const { return output_size_; } - inline Size const& GetResolution() const { return resolution_; } - inline Color const& GetClearColor() const { return clear_color_; } inline ID2DDeviceResources* GetD2DDeviceResources() const { KGE_ASSERT(d2d_res_); return d2d_res_.get(); } @@ -209,15 +185,11 @@ namespace kiwano void ResizeTarget(UInt32 width, UInt32 height); - void UpdateResolution(); - private: bool vsync_; HWND hwnd_; Color clear_color_; Size output_size_; - Size resolution_; - ResolutionMode resolution_mode_; ComPtr d2d_res_; ComPtr d3d_res_; From a4d4c3a10f8df93c5ea872604a13c6484f6368bd Mon Sep 17 00:00:00 2001 From: Nomango Date: Mon, 9 Sep 2019 22:02:53 +0800 Subject: [PATCH 2/2] Add Brush --- projects/kiwano.vcxproj | 2 + projects/kiwano.vcxproj.filters | 6 + src/kiwano/2d/Actor.cpp | 8 +- src/kiwano/2d/Canvas.cpp | 32 ++-- src/kiwano/2d/DebugActor.cpp | 3 +- src/kiwano/2d/Layer.cpp | 11 +- src/kiwano/2d/ShapeActor.cpp | 6 +- src/kiwano/platform/Application.cpp | 2 + src/kiwano/renderer/Brush.cpp | 142 ++++++++++++++++++ src/kiwano/renderer/Brush.h | 166 +++++++++++++++++++++ src/kiwano/renderer/RenderTarget.cpp | 109 +++++++------- src/kiwano/renderer/RenderTarget.h | 28 ++-- src/kiwano/renderer/Renderer.cpp | 115 +++++++++++++- src/kiwano/renderer/Renderer.h | 22 +++ src/kiwano/renderer/win32/TextRenderer.cpp | 12 +- src/kiwano/renderer/win32/TextRenderer.h | 8 +- 16 files changed, 560 insertions(+), 112 deletions(-) create mode 100644 src/kiwano/renderer/Brush.cpp create mode 100644 src/kiwano/renderer/Brush.h diff --git a/projects/kiwano.vcxproj b/projects/kiwano.vcxproj index 30e05eaf..5471ccdc 100644 --- a/projects/kiwano.vcxproj +++ b/projects/kiwano.vcxproj @@ -64,6 +64,7 @@ + @@ -127,6 +128,7 @@ + diff --git a/projects/kiwano.vcxproj.filters b/projects/kiwano.vcxproj.filters index de732345..84c50126 100644 --- a/projects/kiwano.vcxproj.filters +++ b/projects/kiwano.vcxproj.filters @@ -306,6 +306,9 @@ renderer + + renderer + @@ -482,5 +485,8 @@ renderer + + renderer + \ No newline at end of file diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 3238fd43..9bb197e1 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -131,8 +131,12 @@ namespace kiwano Rect bounds = GetBounds(); rt->SetTransform(transform_matrix_); - rt->FillRectangle(bounds, Color(Color::Red, .4f)); - rt->DrawRectangle(bounds, Color(Color::Red, .8f), 2.f); + + rt->SetDefaultBrushColor(Color(Color::Red, .4f)); + rt->FillRectangle(bounds); + + rt->SetDefaultBrushColor(Color(Color::Red, .8f)); + rt->DrawRectangle(bounds, 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 3a89408d..df128b82 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -149,10 +149,10 @@ namespace kiwano void Canvas::DrawLine(Point const& begin, Point const& end) { + rt_.SetDefaultBrushColor(stroke_color_); rt_.DrawLine( begin, end, - stroke_color_, stroke_width_, stroke_style_ ); @@ -161,10 +161,10 @@ namespace kiwano void Canvas::DrawCircle(Point const& center, Float32 radius) { + rt_.SetDefaultBrushColor(stroke_color_); rt_.DrawEllipse( center, Vec2(radius, radius), - stroke_color_, stroke_width_, stroke_style_ ); @@ -173,10 +173,10 @@ namespace kiwano void Canvas::DrawEllipse(Point const& center, Vec2 const& radius) { + rt_.SetDefaultBrushColor(stroke_color_); rt_.DrawEllipse( center, radius, - stroke_color_, stroke_width_, stroke_style_ ); @@ -185,9 +185,9 @@ namespace kiwano void Canvas::DrawRect(Rect const& rect) { + rt_.SetDefaultBrushColor(stroke_color_); rt_.DrawRectangle( rect, - stroke_color_, stroke_width_, stroke_style_ ); @@ -196,10 +196,10 @@ namespace kiwano void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius) { + rt_.SetDefaultBrushColor(stroke_color_); rt_.DrawRoundedRectangle( rect, radius, - stroke_color_, stroke_width_, stroke_style_ ); @@ -208,39 +208,39 @@ namespace kiwano void Canvas::FillCircle(Point const& center, Float32 radius) { + rt_.SetDefaultBrushColor(fill_color_); rt_.FillEllipse( center, - Vec2(radius, radius), - fill_color_ + Vec2(radius, radius) ); cache_expired_ = true; } void Canvas::FillEllipse(Point const& center, Vec2 const& radius) { + rt_.SetDefaultBrushColor(fill_color_); rt_.FillEllipse( center, - radius, - fill_color_ + radius ); cache_expired_ = true; } void Canvas::FillRect(Rect const& rect) { + rt_.SetDefaultBrushColor(fill_color_); rt_.FillRectangle( - rect, - fill_color_ + rect ); cache_expired_ = true; } void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius) { + rt_.SetDefaultBrushColor(fill_color_); rt_.FillRoundedRectangle( rect, - radius, - fill_color_ + radius ); cache_expired_ = true; } @@ -296,9 +296,9 @@ namespace kiwano void Canvas::StrokePath() { + rt_.SetDefaultBrushColor(stroke_color_); rt_.DrawGeometry( geo_sink_.GetGeometry(), - stroke_color_, stroke_width_, stroke_style_ ); @@ -307,9 +307,9 @@ namespace kiwano void Canvas::FillPath() { + rt_.SetDefaultBrushColor(fill_color_); rt_.FillGeometry( - geo_sink_.GetGeometry(), - fill_color_ + geo_sink_.GetGeometry() ); cache_expired_ = true; } diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index 565fdc5d..d5cac48a 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -78,7 +78,8 @@ namespace kiwano { PrepareRender(rt); - rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f }, background_color_); + rt->SetDefaultBrushColor(background_color_); + rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f }); } void DebugActor::OnUpdate(Duration dt) diff --git a/src/kiwano/2d/Layer.cpp b/src/kiwano/2d/Layer.cpp index 0c6e6d8e..da60b65f 100644 --- a/src/kiwano/2d/Layer.cpp +++ b/src/kiwano/2d/Layer.cpp @@ -84,14 +84,11 @@ namespace kiwano void Layer::Render(RenderTarget* rt) { - if (!children_.empty()) - { - PrepareRender(rt); + PrepareRender(rt); - rt->PushLayer(area_); - Actor::Render(rt); - rt->PopLayer(); - } + rt->PushLayer(area_); + Actor::Render(rt); + rt->PopLayer(); } void Layer::HandleMessages(Event const& evt) diff --git a/src/kiwano/2d/ShapeActor.cpp b/src/kiwano/2d/ShapeActor.cpp index b01477c0..362f658d 100644 --- a/src/kiwano/2d/ShapeActor.cpp +++ b/src/kiwano/2d/ShapeActor.cpp @@ -101,16 +101,16 @@ namespace kiwano { PrepareRender(rt); + rt->SetDefaultBrushColor(stroke_color_); rt->DrawGeometry( geo_, - stroke_color_, stroke_width_ * 2, // twice width for widening stroke_style_ ); + rt->SetDefaultBrushColor(fill_color_); rt->FillGeometry( - geo_, - fill_color_ + geo_ ); } } diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 87148dca..eef496e1 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -42,6 +42,7 @@ namespace kiwano } Config::Config(String const& title, UInt32 width, UInt32 height, UInt32 icon) + : debug(false) { window.title = title; window.width = width; @@ -50,6 +51,7 @@ namespace kiwano } Config::Config(WindowConfig const& wnd_config, RenderConfig const& render_config) + : debug(false) { window = wnd_config; render = render_config; diff --git a/src/kiwano/renderer/Brush.cpp b/src/kiwano/renderer/Brush.cpp new file mode 100644 index 00000000..1515967b --- /dev/null +++ b/src/kiwano/renderer/Brush.cpp @@ -0,0 +1,142 @@ +// 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 "Brush.h" +#include "Renderer.h" +#include "../base/Logger.h" + +namespace kiwano +{ + SolidColorStyle::SolidColorStyle(Color const& color) + : color(color) + { + } + + LinearGradientStyle::LinearGradientStyle(Point const& begin, Point const& end, Vector const& stops, GradientExtendMode extend_mode) + : begin(begin) + , end(end) + , stops(stops) + , extend_mode(extend_mode) + { + } + + RadialGradientStyle::RadialGradientStyle(Point const& center, Vec2 const& offset, Vec2 const& radius, Vector const& stops, GradientExtendMode extend_mode) + : center(center) + , offset(offset) + , radius(radius) + , stops(stops) + , extend_mode(extend_mode) + { + } + + Brush::Brush() + : opacity_(1.f) + , type_(Type::Unknown) + { + } + + Brush::Brush(Color const& color) + : Brush() + { + SetColor(color); + } + + Brush::Brush(SolidColorStyle const& style) + : Brush() + { + SetStyle(style); + } + + Brush::Brush(LinearGradientStyle const& style) + : Brush() + { + SetStyle(style); + } + + Brush::Brush(RadialGradientStyle const& style) + : Brush() + { + SetStyle(style); + } + + bool Brush::IsValid() const + { + return raw_ != nullptr; + } + + Brush::Brush(ComPtr brush) + : Brush() + { + SetBrush(brush); + } + + Float32 Brush::GetOpacity() const + { + return opacity_; + } + + void Brush::SetOpacity(Float32 opacity) + { + opacity_ = opacity; + if (raw_) + { + raw_->SetOpacity(opacity); + } + } + + void Brush::SetStyle(SolidColorStyle const& style) + { + if (type_ == Type::SolidColor && raw_) + { + auto solid_brush = dynamic_cast(raw_.get()); + KGE_ASSERT(solid_brush != nullptr); + solid_brush->SetColor(DX::ConvertToColorF(style.color)); + } + else + { + Renderer::GetInstance()->CreateSolidBrush(*this, style.color); + type_ = Type::SolidColor; + } + } + + void Brush::SetStyle(LinearGradientStyle const& style) + { + Renderer::GetInstance()->CreateLinearGradientBrush(*this, style.begin, style.end, style.stops, style.extend_mode); + type_ = Type::LinearGradient; + } + + void Brush::SetStyle(RadialGradientStyle const& style) + { + Renderer::GetInstance()->CreateRadialGradientBrush(*this, style.center, style.offset, style.radius, style.stops, style.extend_mode); + type_ = Type::RadialGradient; + } + + void Brush::SetBrush(ComPtr const& brush) + { + type_ = Type::Unknown; + raw_ = brush; + + if (raw_) + { + raw_->SetOpacity(opacity_); + } + } + +} diff --git a/src/kiwano/renderer/Brush.h b/src/kiwano/renderer/Brush.h new file mode 100644 index 00000000..9d7ab25f --- /dev/null +++ b/src/kiwano/renderer/Brush.h @@ -0,0 +1,166 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "win32/D2DDeviceResources.h" + +namespace kiwano +{ + // 渐变转换点 + struct GradientStop + { + Float32 offset; + Color color; + + GradientStop() : offset(0.f), color() {} + + GradientStop(Float32 offset, Color color) : offset(offset), color(color) {} + }; + + + // 渐变扩充模式 + // 该模式用于指定画笔如何绘制正常区域外的部分 + // Clamp (夹模式): 重复绘制边界颜色 + // Wrap (夹模式): 重复画笔内容 + // Mirror (镜像模式): 反转画笔内容 + enum class GradientExtendMode + { + Clamp, + Wrap, + Mirror + }; + + + // 纯色样式 + struct SolidColorStyle + { + Color color; + + SolidColorStyle(Color const& color); + }; + + // 线性渐变样式 + struct LinearGradientStyle + { + Point begin; + Point end; + Vector stops; + GradientExtendMode extend_mode; + + LinearGradientStyle( + Point const& begin, + Point const& end, + Vector const& stops, + GradientExtendMode extend_mode = GradientExtendMode::Clamp + ); + }; + + // 径向渐变样式 + struct RadialGradientStyle + { + Point center; + Vec2 offset; + Vec2 radius; + Vector stops; + GradientExtendMode extend_mode; + + RadialGradientStyle( + Point const& center, + Vec2 const& offset, + Vec2 const& radius, + Vector const& stops, + GradientExtendMode extend_mode = GradientExtendMode::Clamp + ); + }; + + // 画笔 + class KGE_API Brush + { + public: + Brush(); + + Brush( + Color const& color + ); + + Brush( + SolidColorStyle const& style + ); + + Brush( + LinearGradientStyle const& style + ); + + Brush( + RadialGradientStyle const& style + ); + + bool IsValid() const; + + inline void SetColor( + Color const& color + ) + { + SetStyle(SolidColorStyle{ color }); + } + + void SetStyle( + SolidColorStyle const& style + ); + + void SetStyle( + LinearGradientStyle const& style + ); + + void SetStyle( + RadialGradientStyle const& style + ); + + Float32 GetOpacity() const; + + void SetOpacity(Float32 opacity); + + public: + enum class Type + { + Unknown, + SolidColor, // 纯色填充 + LinearGradient, // 线性渐变 + RadialGradient // 径向渐变 + }; + + Type GetType() const { return type_; } + + public: + Brush( + ComPtr brush + ); + + void SetBrush(ComPtr const& brush); + + inline ComPtr const& GetBrush() const { return raw_; } + + protected: + Type type_; + Float32 opacity_; + ComPtr raw_; + }; + +} diff --git a/src/kiwano/renderer/RenderTarget.cpp b/src/kiwano/renderer/RenderTarget.cpp index c6441c03..e3bacd95 100644 --- a/src/kiwano/renderer/RenderTarget.cpp +++ b/src/kiwano/renderer/RenderTarget.cpp @@ -67,6 +67,11 @@ namespace kiwano ); } + if (SUCCEEDED(hr)) + { + current_brush_ = default_brush_; + } + return hr; } @@ -86,8 +91,6 @@ namespace kiwano void RenderTarget::BeginDraw() { - HRESULT hr = E_FAIL; - if (collecting_status_) { status_.start = Time::Now(); @@ -97,15 +100,12 @@ namespace kiwano if (render_target_) { render_target_->BeginDraw(); - hr = S_OK; } - - ThrowIfFailed(hr); } void RenderTarget::EndDraw() { - ThrowIfFailed(render_target_->EndDraw()); + ThrowIfFailed( render_target_->EndDraw() ); if (collecting_status_) { @@ -113,26 +113,19 @@ namespace kiwano } } - void RenderTarget::DrawGeometry( - Geometry const& geometry, - Color const& stroke_color, - Float32 stroke_width, - StrokeStyle stroke - ) const + void RenderTarget::DrawGeometry(Geometry const& geometry, Float32 stroke_width, StrokeStyle stroke) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr) && geometry.GetGeometry()) { - default_brush_->SetColor(DX::ConvertToColorF(stroke_color)); - render_target_->DrawGeometry( geometry.GetGeometry().get(), - default_brush_.get(), + current_brush_.get(), stroke_width, GetStrokeStyle(stroke).get() ); @@ -143,42 +136,39 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::FillGeometry(Geometry const& geometry, Color const& fill_color) const + void RenderTarget::FillGeometry(Geometry const& geometry) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr) && geometry.GetGeometry()) { - default_brush_->SetColor(DX::ConvertToColorF(fill_color)); render_target_->FillGeometry( geometry.GetGeometry().get(), - default_brush_.get() + current_brush_.get() ); } ThrowIfFailed(hr); } - void RenderTarget::DrawLine(Point const& point1, Point const& point2, Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke) const + void RenderTarget::DrawLine(Point const& point1, Point const& point2, Float32 stroke_width, StrokeStyle stroke) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(stroke_color)); - render_target_->DrawLine( DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), - default_brush_.get(), + current_brush_.get(), stroke_width, GetStrokeStyle(stroke).get() ); @@ -189,21 +179,20 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::DrawRectangle(Rect const& rect, Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke) const + void RenderTarget::DrawRectangle(Rect const& rect, Float32 stroke_width, StrokeStyle stroke) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(stroke_color)); - render_target_->DrawRectangle( DX::ConvertToRectF(rect), - default_brush_.get(), + current_brush_.get(), stroke_width, GetStrokeStyle(stroke).get() ); @@ -214,45 +203,42 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::FillRectangle(Rect const& rect, Color const& fill_color) const + void RenderTarget::FillRectangle(Rect const& rect) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(fill_color)); render_target_->FillRectangle( DX::ConvertToRectF(rect), - default_brush_.get() + current_brush_.get() ); } ThrowIfFailed(hr); } - void RenderTarget::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke) const + void RenderTarget::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, Float32 stroke_width, StrokeStyle stroke) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(stroke_color)); - render_target_->DrawRoundedRectangle( D2D1::RoundedRect( DX::ConvertToRectF(rect), radius.x, radius.y ), - default_brush_.get(), + current_brush_.get(), stroke_width, GetStrokeStyle(stroke).get() ); @@ -263,49 +249,46 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::FillRoundedRectangle(Rect const& rect, Vec2 const& radius, Color const& fill_color) const + void RenderTarget::FillRoundedRectangle(Rect const& rect, Vec2 const& radius) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(fill_color)); render_target_->FillRoundedRectangle( D2D1::RoundedRect( DX::ConvertToRectF(rect), radius.x, radius.y ), - default_brush_.get() + current_brush_.get() ); } ThrowIfFailed(hr); } - void RenderTarget::DrawEllipse(Point const& center, Vec2 const& radius, Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke) const + void RenderTarget::DrawEllipse(Point const& center, Vec2 const& radius, Float32 stroke_width, StrokeStyle stroke) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(stroke_color)); - render_target_->DrawEllipse( D2D1::Ellipse( DX::ConvertToPoint2F(center), radius.x, radius.y ), - default_brush_.get(), + current_brush_.get(), stroke_width, GetStrokeStyle(stroke).get() ); @@ -316,24 +299,23 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::FillEllipse(Point const& center, Vec2 const& radius, Color const& fill_color) const + void RenderTarget::FillEllipse(Point const& center, Vec2 const& radius) const { HRESULT hr = S_OK; - if (!default_brush_ || !render_target_) + if (!render_target_ || !current_brush_) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { - default_brush_->SetColor(DX::ConvertToColorF(fill_color)); render_target_->FillEllipse( D2D1::Ellipse( DX::ConvertToPoint2F(center), radius.x, radius.y ), - default_brush_.get() + current_brush_.get() ); } @@ -464,7 +446,7 @@ namespace kiwano void RenderTarget::PushLayer(LayerArea& layer) { HRESULT hr = S_OK; - if (!render_target_ || !default_brush_) + if (!render_target_) { hr = E_UNEXPECTED; } @@ -540,6 +522,11 @@ namespace kiwano return opacity_; } + Brush RenderTarget::GetCurrentBrush() const + { + return Brush( current_brush_ ); + } + Matrix3x2 RenderTarget::GetGlobalTransform() const { return global_transform_; @@ -569,7 +556,6 @@ namespace kiwano if (fast_global_transform_) { render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix)); - } else { @@ -602,7 +588,7 @@ namespace kiwano void RenderTarget::SetOpacity(Float32 opacity) { HRESULT hr = S_OK; - if (!default_brush_) + if (!current_brush_) { hr = E_UNEXPECTED; } @@ -612,13 +598,24 @@ namespace kiwano if (opacity_ != opacity) { opacity_ = opacity; - default_brush_->SetOpacity(opacity); + current_brush_->SetOpacity(opacity); } } ThrowIfFailed(hr); } + void RenderTarget::SetCurrentBrush(Brush const& brush) + { + current_brush_ = brush.GetBrush(); + } + + void RenderTarget::SetDefaultBrushColor(Color const& color) + { + KGE_ASSERT(default_brush_); + default_brush_->SetColor(DX::ConvertToColorF(color)); + } + void RenderTarget::SetAntialiasMode(bool enabled) { HRESULT hr = S_OK; diff --git a/src/kiwano/renderer/RenderTarget.h b/src/kiwano/renderer/RenderTarget.h index bc95876a..d4362a02 100644 --- a/src/kiwano/renderer/RenderTarget.h +++ b/src/kiwano/renderer/RenderTarget.h @@ -20,6 +20,7 @@ #pragma once #include "../base/time.h" +#include "Brush.h" #include "Texture.h" #include "Geometry.h" #include "TextLayout.h" @@ -55,62 +56,53 @@ namespace kiwano void DrawGeometry( Geometry const& geometry, - Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke = StrokeStyle::Miter ) const; void FillGeometry( - Geometry const& geometry, - Color const& fill_color + Geometry const& geometry ) const; void DrawLine( Point const& point1, Point const& point2, - Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke = StrokeStyle::Miter ) const; void DrawRectangle( Rect const& rect, - Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke = StrokeStyle::Miter ) const; void FillRectangle( - Rect const& rect, - Color const& fill_color + Rect const& rect ) const; void DrawRoundedRectangle( Rect const& rect, Vec2 const& radius, - Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke = StrokeStyle::Miter ) const; void FillRoundedRectangle( Rect const& rect, - Vec2 const& radius, - Color const& fill_color + Vec2 const& radius ) const; void DrawEllipse( Point const& center, Vec2 const& radius, - Color const& stroke_color, Float32 stroke_width, StrokeStyle stroke = StrokeStyle::Miter ) const; void FillEllipse( Point const& center, - Vec2 const& radius, - Color const& fill_color + Vec2 const& radius ) const; void DrawTexture( @@ -150,12 +142,22 @@ namespace kiwano Float32 GetOpacity() const; + Brush GetCurrentBrush() const; + Matrix3x2 GetGlobalTransform() const; void SetOpacity( Float32 opacity ); + void SetCurrentBrush( + Brush const& brush + ); + + void SetDefaultBrushColor( + Color const& color + ); + void SetTransform( const Matrix3x2& matrix ); diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index cbcfee72..cb36d8d8 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -53,6 +53,7 @@ namespace kiwano KGE_LOG(L"Creating device resources"); hwnd_ = Window::GetInstance()->GetHandle(); + output_size_ = Window::GetInstance()->GetSize(); d2d_res_ = nullptr; d3d_res_ = nullptr; @@ -153,13 +154,13 @@ namespace kiwano if (SUCCEEDED(hr)) { - render_target_->SaveDrawingState(drawing_state_block_.get()); - BeginDraw(); + hr = d3d_res_->ClearRenderTarget(clear_color_); } if (SUCCEEDED(hr)) { - hr = d3d_res_->ClearRenderTarget(clear_color_); + render_target_->SaveDrawingState(drawing_state_block_.get()); + BeginDraw(); } ThrowIfFailed(hr); @@ -174,7 +175,6 @@ namespace kiwano hr = E_UNEXPECTED; } - if (SUCCEEDED(hr)) { EndDraw(); @@ -872,6 +872,113 @@ namespace kiwano ThrowIfFailed(hr); } + void Renderer::CreateSolidBrush(Brush& brush, Color const& color) + { + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + ComPtr output; + if (SUCCEEDED(hr)) + { + hr = d2d_res_->GetDeviceContext()->CreateSolidColorBrush(DX::ConvertToColorF(color), &output); + } + + if (SUCCEEDED(hr)) + { + brush.SetBrush(output); + } + + ThrowIfFailed(hr); + } + + void Renderer::CreateLinearGradientBrush(Brush& brush, Point const& begin, Point const& end, Vector const& stops, GradientExtendMode extend_mode) + { + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + ID2D1GradientStopCollection* collection = nullptr; + hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection( + reinterpret_cast(&stops[0]), + stops.size(), + D2D1_GAMMA_2_2, + D2D1_EXTEND_MODE(extend_mode), + &collection + ); + + if (SUCCEEDED(hr)) + { + ComPtr output; + hr = d2d_res_->GetDeviceContext()->CreateLinearGradientBrush( + D2D1::LinearGradientBrushProperties( + DX::ConvertToPoint2F(begin), + DX::ConvertToPoint2F(end) + ), + collection, + &output + ); + + if (SUCCEEDED(hr)) + { + brush.SetBrush(output); + } + } + } + + ThrowIfFailed(hr); + } + + void Renderer::CreateRadialGradientBrush(Brush& brush, Point const& center, Vec2 const& offset, Vec2 const& radius, + Vector const& stops, GradientExtendMode extend_mode) + { + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + ID2D1GradientStopCollection* collection = nullptr; + hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection( + reinterpret_cast(&stops[0]), + stops.size(), + D2D1_GAMMA_2_2, + D2D1_EXTEND_MODE(extend_mode), + &collection + ); + + if (SUCCEEDED(hr)) + { + ComPtr output; + hr = d2d_res_->GetDeviceContext()->CreateRadialGradientBrush( + D2D1::RadialGradientBrushProperties( + DX::ConvertToPoint2F(center), + DX::ConvertToPoint2F(offset), + radius.x, + radius.y + ), + collection, + &output + ); + + if (SUCCEEDED(hr)) + { + brush.SetBrush(output); + } + } + } + + ThrowIfFailed(hr); + } + void Renderer::SetVSyncEnabled(bool enabled) { vsync_ = enabled; diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index 5cacf976..86861fbb 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -150,6 +150,28 @@ namespace kiwano TextureRenderTarget& render_target ); + void CreateSolidBrush( + Brush& brush, + Color const& color + ); + + void CreateLinearGradientBrush( + Brush& brush, + Point const& begin, + Point const& end, + Vector const& stops, + GradientExtendMode extend_mode + ); + + void CreateRadialGradientBrush( + Brush& brush, + Point const& center, + Vec2 const& offset, + Vec2 const& radius, + Vector const& stops, + GradientExtendMode extend_mode + ); + public: void Init(RenderConfig const& config); diff --git a/src/kiwano/renderer/win32/TextRenderer.cpp b/src/kiwano/renderer/win32/TextRenderer.cpp index 7b0c7502..330f64b7 100644 --- a/src/kiwano/renderer/win32/TextRenderer.cpp +++ b/src/kiwano/renderer/win32/TextRenderer.cpp @@ -35,12 +35,12 @@ namespace kiwano STDMETHOD(CreateDeviceResources)(); STDMETHOD_(void, SetTextStyle)( - _In_ Float32 opacity, - _In_ CONST D2D1_COLOR_F &fillColor, - _In_ BOOL outline, - _In_ CONST D2D1_COLOR_F &outlineColor, - _In_ Float32 outlineWidth, - _In_ ID2D1StrokeStyle* outlineJoin + _In_ Float32 opacity, + _In_ CONST D2D1_COLOR_F &fillColor, + _In_ BOOL outline, + _In_ CONST D2D1_COLOR_F &outlineColor, + _In_ Float32 outlineWidth, + _In_ ID2D1StrokeStyle* outlineJoin ); STDMETHOD(DrawGlyphRun)( diff --git a/src/kiwano/renderer/win32/TextRenderer.h b/src/kiwano/renderer/win32/TextRenderer.h index 519cc577..8b5f95e2 100644 --- a/src/kiwano/renderer/win32/TextRenderer.h +++ b/src/kiwano/renderer/win32/TextRenderer.h @@ -34,10 +34,10 @@ namespace kiwano STDMETHOD_(void, SetTextStyle)( _In_ Float32 opacity, - _In_ CONST D2D1_COLOR_F &fillColor, - _In_ BOOL outline, - _In_ CONST D2D1_COLOR_F &outlineColor, - _In_ Float32 outlineWidth, + _In_ CONST D2D1_COLOR_F &fillColor, + _In_ BOOL outline, + _In_ CONST D2D1_COLOR_F &outlineColor, + _In_ Float32 outlineWidth, _In_ ID2D1StrokeStyle* outlineJoin ) PURE; };