diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj
index f544ab77..d4eadbbe 100644
--- a/projects/kiwano/kiwano.vcxproj
+++ b/projects/kiwano/kiwano.vcxproj
@@ -62,6 +62,7 @@
+
@@ -71,7 +72,10 @@
+
+
+
@@ -140,7 +144,10 @@
+
+
+
diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters
index 007fb85b..06a3e54e 100644
--- a/projects/kiwano/kiwano.vcxproj.filters
+++ b/projects/kiwano/kiwano.vcxproj.filters
@@ -288,6 +288,18 @@
render
+
+ render\DirectX
+
+
+ render\DirectX
+
+
+ render\DirectX
+
+
+ platform\win32
+
@@ -488,5 +500,14 @@
render
+
+ render\DirectX
+
+
+ render\DirectX
+
+
+ render\DirectX
+
\ No newline at end of file
diff --git a/src/kiwano-imgui/ImGuiModule.cpp b/src/kiwano-imgui/ImGuiModule.cpp
index 360e0320..a3129855 100644
--- a/src/kiwano-imgui/ImGuiModule.cpp
+++ b/src/kiwano-imgui/ImGuiModule.cpp
@@ -58,7 +58,7 @@ void ImGuiModule::SetupComponent()
io.KeyMap[ImGuiKey_Y] = (int)KeyCode::Y;
io.KeyMap[ImGuiKey_Z] = (int)KeyCode::Z;
- ImGui_Impl_Init(Renderer::GetInstance());
+ ImGui_Impl_Init();
}
void ImGuiModule::DestroyComponent()
diff --git a/src/kiwano-imgui/imgui_impl.h b/src/kiwano-imgui/imgui_impl.h
index 0402bcd5..31275492 100644
--- a/src/kiwano-imgui/imgui_impl.h
+++ b/src/kiwano-imgui/imgui_impl.h
@@ -7,20 +7,25 @@
#if !defined(KGE_USE_DIRECTX10)
#include
+#include
-inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer)
+inline bool ImGui_Impl_Init()
{
+ ::kiwano::RendererImpl& renderer = ::kiwano::RendererImpl::GetInstance();
return ImGui_ImplDX11_Init(renderer.GetD3DDeviceResources()->GetDevice(),
renderer.GetD3DDeviceResources()->GetDeviceContext());
}
+
inline void ImGui_Impl_Shutdown()
{
ImGui_ImplDX11_Shutdown();
}
+
inline void ImGui_Impl_NewFrame()
{
ImGui_ImplDX11_NewFrame();
}
+
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data)
{
ImGui_ImplDX11_RenderDrawData(draw_data);
@@ -30,6 +35,7 @@ inline void ImGui_Impl_InvalidateDeviceObjects()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
}
+
inline bool ImGui_Impl_CreateDeviceObjects()
{
return ImGui_ImplDX11_CreateDeviceObjects();
@@ -39,18 +45,22 @@ inline bool ImGui_Impl_CreateDeviceObjects()
#include
-inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer)
+inline bool ImGui_Impl_Init()
{
+ ::kiwano::RendererImpl& renderer = ::kiwano::RendererImpl::GetInstance();
return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice());
}
+
inline void ImGui_Impl_Shutdown()
{
ImGui_ImplDX10_Shutdown();
}
+
inline void ImGui_Impl_NewFrame()
{
ImGui_ImplDX10_NewFrame();
}
+
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data)
{
ImGui_ImplDX10_RenderDrawData(draw_data);
@@ -60,6 +70,7 @@ inline void ImGui_Impl_InvalidateDeviceObjects()
{
ImGui_ImplDX10_InvalidateDeviceObjects();
}
+
inline bool ImGui_Impl_CreateDeviceObjects()
{
return ImGui_ImplDX10_CreateDeviceObjects();
diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp
index eb7715a6..305c2e4d 100644
--- a/src/kiwano/2d/Canvas.cpp
+++ b/src/kiwano/2d/Canvas.cpp
@@ -35,6 +35,8 @@ CanvasPtr Canvas::Create(Size const& size)
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)
{
@@ -71,9 +73,7 @@ void Canvas::OnRender(RenderContext& ctx)
if (texture_cached_ && texture_cached_->IsValid())
{
PrepareToRender(ctx);
-
- Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight());
- ctx.DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect);
+ ctx.DrawTexture(*texture_cached_, nullptr, &GetBounds());
}
}
diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp
index 1f8c1fd7..104bfe9c 100644
--- a/src/kiwano/platform/win32/WindowImpl.cpp
+++ b/src/kiwano/platform/win32/WindowImpl.cpp
@@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-#include
+#include
#if defined(KGE_WIN32)
@@ -38,8 +38,19 @@
namespace kiwano
{
-namespace win32
+
+
+Window& Window::GetInstance()
{
+ return WindowImpl::GetInstance();
+}
+
+WindowImpl& WindowImpl::GetInstance()
+{
+ static WindowImpl instance;
+ return instance;
+}
+
namespace
{
MONITORINFOEX GetMoniterInfoEx(HWND hwnd)
@@ -96,51 +107,6 @@ void RestoreResolution(WCHAR* device_name)
}
} // namespace
-class KGE_API WindowImpl : public kiwano::Window
-{
-public:
- WindowImpl();
-
- ~WindowImpl();
-
- void Create(String const& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable,
- bool fullscreen) override;
-
- WindowHandle GetHandle() const override;
-
- void SetTitle(String const& title) override;
-
- void SetIcon(uint32_t icon_resource) override;
-
- void Resize(uint32_t width, uint32_t height) override;
-
- void SetFullscreen(bool fullscreen) override;
-
- void SetCursor(CursorType cursor) override;
-
- void Destroy() override;
-
-private:
- void PumpEvents() override;
-
- DWORD GetStyle() const;
-
- void UpdateCursor();
-
- void SetActive(bool actived);
-
- static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM);
-
-private:
- bool resizable_;
- bool is_fullscreen_;
- wchar_t* device_name_;
- WindowHandle handle_;
- CursorType mouse_cursor_;
-
- std::array key_map_;
-};
-
WindowImpl::WindowImpl()
: handle_(nullptr)
, device_name_(nullptr)
@@ -678,18 +644,6 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
-} // namespace win32
-} // namespace kiwano
-
-namespace kiwano
-{
-
-Window& Window::GetInstance()
-{
- static win32::WindowImpl instance;
- return instance;
-}
-
} // namespace kiwano
#endif
diff --git a/src/kiwano/platform/win32/WindowImpl.h b/src/kiwano/platform/win32/WindowImpl.h
new file mode 100644
index 00000000..fc46a1dd
--- /dev/null
+++ b/src/kiwano/platform/win32/WindowImpl.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2016-2020 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
+#include
+
+#if defined(KGE_WIN32)
+
+namespace kiwano
+{
+
+class KGE_API WindowImpl : public Window
+{
+public:
+ static WindowImpl& GetInstance();
+
+ void Create(String const& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable,
+ bool fullscreen) override;
+
+ WindowHandle GetHandle() const override;
+
+ void SetTitle(String const& title) override;
+
+ void SetIcon(uint32_t icon_resource) override;
+
+ void Resize(uint32_t width, uint32_t height) override;
+
+ void SetFullscreen(bool fullscreen) override;
+
+ void SetCursor(CursorType cursor) override;
+
+ void Destroy() override;
+
+private:
+ WindowImpl();
+
+ ~WindowImpl();
+
+ void PumpEvents() override;
+
+ DWORD GetStyle() const;
+
+ void UpdateCursor();
+
+ void SetActive(bool actived);
+
+ static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM);
+
+private:
+ bool resizable_;
+ bool is_fullscreen_;
+ wchar_t* device_name_;
+ WindowHandle handle_;
+ CursorType mouse_cursor_;
+
+ std::array key_map_;
+};
+
+} // namespace kiwano
+
+#endif
diff --git a/src/kiwano/render/Brush.cpp b/src/kiwano/render/Brush.cpp
index f02d53d5..f5e6250f 100644
--- a/src/kiwano/render/Brush.cpp
+++ b/src/kiwano/render/Brush.cpp
@@ -86,8 +86,7 @@ BrushPtr Brush::Create(RadialGradientStyle const& style)
}
Brush::Brush()
- : opacity_(1.f)
- , type_(Type::Unknown)
+ : type_(Type::Unknown)
{
}
@@ -96,20 +95,6 @@ bool Brush::IsValid() const
return raw_ != nullptr;
}
-float Brush::GetOpacity() const
-{
- return opacity_;
-}
-
-void Brush::SetOpacity(float opacity)
-{
- opacity_ = opacity;
- if (raw_)
- {
- raw_->SetOpacity(opacity);
- }
-}
-
void Brush::SetColor(Color const& color)
{
Renderer::GetInstance().CreateBrush(*this, color);
diff --git a/src/kiwano/render/Brush.h b/src/kiwano/render/Brush.h
index 01268952..2d9c977e 100644
--- a/src/kiwano/render/Brush.h
+++ b/src/kiwano/render/Brush.h
@@ -24,8 +24,6 @@
namespace kiwano
{
-class RenderContext;
-class Renderer;
KGE_DECLARE_SMART_PTR(Brush);
@@ -89,9 +87,6 @@ struct RadialGradientStyle
*/
class KGE_API Brush : public virtual ObjectBase
{
- friend class RenderContext;
- friend class Renderer;
-
public:
/// \~chinese
/// @brief 创建纯色画刷
@@ -142,23 +137,15 @@ public:
Type GetType() const;
private:
- /// \~chinese
- /// @brief 获取透明度
- float GetOpacity() const;
-
- /// \~chinese
- /// @brief 设置透明度
- void SetOpacity(float opacity);
-
-private:
- Type type_;
- float opacity_;
+ Type type_;
#if defined(KGE_WIN32)
+public:
void SetBrush(ComPtr brush, Type type);
ComPtr GetBrush() const;
+private:
ComPtr raw_;
#endif
};
@@ -175,10 +162,6 @@ inline void Brush::SetBrush(ComPtr brush, Type type)
{
type_ = type;
raw_ = brush;
- if (raw_)
- {
- raw_->SetOpacity(opacity_);
- }
}
inline ComPtr Brush::GetBrush() const
diff --git a/src/kiwano/render/DirectX/RenderContextImpl.cpp b/src/kiwano/render/DirectX/RenderContextImpl.cpp
new file mode 100644
index 00000000..b3d4ffe3
--- /dev/null
+++ b/src/kiwano/render/DirectX/RenderContextImpl.cpp
@@ -0,0 +1,489 @@
+// 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
+
+namespace kiwano
+{
+
+RenderContextImpl::RenderContextImpl()
+{}
+
+RenderContextImpl::~RenderContextImpl()
+{
+ DiscardDeviceResources();
+}
+
+HRESULT RenderContextImpl::CreateDeviceResources(ComPtr factory, ComPtr ctx)
+{
+ if (!factory || !ctx)
+ return E_INVALIDARG;
+
+ render_target_ = ctx;
+ text_renderer_.reset();
+ current_brush_.reset();
+
+ HRESULT hr = ITextRenderer::Create(&text_renderer_, render_target_.get());
+
+ if (SUCCEEDED(hr))
+ {
+ SetAntialiasMode(antialias_);
+ SetTextAntialiasMode(text_antialias_);
+
+ Resize(reinterpret_cast(ctx->GetSize()));
+ }
+
+ // DrawingStateBlock
+ if (SUCCEEDED(hr))
+ {
+ hr = factory->CreateDrawingStateBlock(&drawing_state_);
+ }
+
+ return hr;
+}
+
+void RenderContextImpl::DiscardDeviceResources()
+{
+ text_renderer_.reset();
+ render_target_.reset();
+ current_brush_.reset();
+}
+
+bool RenderContextImpl::IsValid() const
+{
+ return render_target_ != nullptr;
+}
+
+void RenderContextImpl::BeginDraw()
+{
+ SaveDrawingState();
+
+ RenderContext::BeginDraw();
+
+ if (render_target_)
+ {
+ render_target_->BeginDraw();
+ }
+}
+
+void RenderContextImpl::EndDraw()
+{
+ win32::ThrowIfFailed(render_target_->EndDraw());
+
+ RenderContext::EndDraw();
+
+ RestoreDrawingState();
+}
+
+void RenderContextImpl::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+
+ if (texture.IsValid())
+ {
+ auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
+ ? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
+ : D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
+
+ render_target_->DrawBitmap(texture.GetBitmap().get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
+ brush_opacity_, mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
+
+ IncreasePrimitivesCount();
+ }
+}
+
+void RenderContextImpl::DrawTextLayout(TextLayout const& layout, Point const& offset)
+{
+ KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!");
+
+ if (layout.IsValid())
+ {
+ ComPtr fill_brush;
+ ComPtr outline_brush;
+ const TextStyle& style = layout.GetStyle();
+
+ if (style.fill_brush)
+ {
+ fill_brush = style.fill_brush->GetBrush();
+ fill_brush->SetOpacity(brush_opacity_);
+ }
+
+ if (style.outline_brush)
+ {
+ outline_brush = style.outline_brush->GetBrush();
+ outline_brush->SetOpacity(brush_opacity_);
+ }
+
+ HRESULT hr = S_OK;
+
+ if (style.outline_stroke)
+ {
+ hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().get(), offset.x, offset.y, fill_brush.get(),
+ outline_brush.get(), style.outline_width,
+ style.outline_stroke->GetStrokeStyle().get());
+ }
+ else
+ {
+ hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().get(), offset.x, offset.y, fill_brush.get(),
+ outline_brush.get(), style.outline_width, nullptr);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IncreasePrimitivesCount(text_renderer_->GetLastPrimitivesCount());
+ }
+ else
+ {
+ KGE_ERROR(L"Failed to draw text layout with HRESULT of %08X", hr);
+ }
+ }
+}
+
+void RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::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 RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T size)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+
+ ComPtr saved_bitmap;
+
+ HRESULT hr = render_target_->CreateBitmap(D2D1::SizeU(size.x, size.y), D2D1::BitmapProperties(), &saved_bitmap);
+
+ if (SUCCEEDED(hr))
+ {
+ texture.SetBitmap(saved_bitmap);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RenderContextImpl::PushClipRect(Rect const& clip_rect)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+ render_target_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect),
+ antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
+}
+
+void RenderContextImpl::PopClipRect()
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+ render_target_->PopAxisAlignedClip();
+}
+
+void RenderContextImpl::PushLayer(LayerArea& layer)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+ if (!layer.IsValid())
+ {
+ ComPtr output;
+ HRESULT hr = render_target_->CreateLayer(&output);
+
+ if (SUCCEEDED(hr))
+ {
+ layer.SetLayer(output);
+ }
+ else
+ {
+ win32::ThrowIfFailed(hr);
+ }
+ }
+
+ if (layer.IsValid())
+ {
+ ComPtr mask;
+ if (layer.GetMaskShape())
+ mask = layer.GetMaskShape()->GetGeometry();
+
+ render_target_->PushLayer(
+ D2D1::LayerParameters(DX::ConvertToRectF(layer.GetAreaRect()), mask.get(),
+ antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
+ DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
+ D2D1_LAYER_OPTIONS_NONE),
+ layer.GetLayer().get());
+ }
+}
+
+void RenderContextImpl::PopLayer()
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+ render_target_->PopLayer();
+}
+
+void RenderContextImpl::Clear()
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+ render_target_->Clear();
+}
+
+void RenderContextImpl::Clear(Color const& clear_color)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+ render_target_->Clear(DX::ConvertToColorF(clear_color));
+}
+
+Size RenderContextImpl::GetSize() const
+{
+ if (render_target_)
+ {
+ return reinterpret_cast(render_target_->GetSize());
+ }
+ return Size();
+}
+
+void RenderContextImpl::SetCurrentBrush(BrushPtr brush)
+{
+ RenderContext::SetCurrentBrush(brush);
+
+ if (current_brush_ && current_brush_->IsValid())
+ {
+ current_brush_->GetBrush()->SetOpacity(brush_opacity_);
+ }
+}
+
+void RenderContextImpl::SetTransform(const Matrix3x2& matrix)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+
+ if (fast_global_transform_)
+ {
+ render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
+ }
+ else
+ {
+ Matrix3x2 result = matrix * global_transform_;
+ render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result));
+ }
+}
+
+void RenderContextImpl::SetAntialiasMode(bool enabled)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+
+ render_target_->SetAntialiasMode(enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
+ antialias_ = enabled;
+}
+
+void RenderContextImpl::SetTextAntialiasMode(TextAntialiasMode mode)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+
+ D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
+ switch (mode)
+ {
+ case TextAntialiasMode::Default:
+ antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
+ break;
+ case TextAntialiasMode::ClearType:
+ antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
+ break;
+ case TextAntialiasMode::GrayScale:
+ antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+ break;
+ case TextAntialiasMode::None:
+ antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
+ break;
+ default:
+ break;
+ }
+
+ text_antialias_ = mode;
+ render_target_->SetTextAntialiasMode(antialias_mode);
+}
+
+bool RenderContextImpl::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform)
+{
+ KGE_ASSERT(render_target_ && "Render target has not been initialized!");
+
+ if (fast_global_transform_)
+ {
+ return visible_size_.Intersects(transform.Transform(bounds));
+ }
+ return visible_size_.Intersects(Matrix3x2(transform * global_transform_).Transform(bounds));
+}
+
+void RenderContextImpl::Resize(Size const& size)
+{
+ visible_size_ = Rect(Point(), size);
+}
+
+void RenderContextImpl::SaveDrawingState()
+{
+ KGE_ASSERT(IsValid());
+
+ if (drawing_state_)
+ {
+ render_target_->SaveDrawingState(drawing_state_.get());
+ }
+}
+
+void RenderContextImpl::RestoreDrawingState()
+{
+ KGE_ASSERT(IsValid());
+
+ if (drawing_state_)
+ {
+ render_target_->RestoreDrawingState(drawing_state_.get());
+ }
+}
+
+} // namespace kiwano
diff --git a/src/kiwano/render/DirectX/RenderContextImpl.h b/src/kiwano/render/DirectX/RenderContextImpl.h
new file mode 100644
index 00000000..92d6a95d
--- /dev/null
+++ b/src/kiwano/render/DirectX/RenderContextImpl.h
@@ -0,0 +1,114 @@
+// 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 RendererImpl;
+
+KGE_DECLARE_SMART_PTR(RenderContextImpl);
+
+class KGE_API RenderContextImpl : public virtual RenderContext
+{
+ friend class RendererImpl;
+
+public:
+ bool IsValid() const override;
+
+ void BeginDraw() override;
+
+ void EndDraw() override;
+
+ void DrawTexture(Texture const& texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr) override;
+
+ void DrawTextLayout(TextLayout const& layout, Point const& offset = Point()) override;
+
+ void DrawShape(Shape const& shape, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f) override;
+
+ void DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke = nullptr,
+ float stroke_width = 1.0f) override;
+
+ void DrawRectangle(Rect const& rect, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f) override;
+
+ void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
+ float stroke_width = 1.0f) override;
+
+ void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
+ float stroke_width = 1.0f) override;
+
+ void FillShape(Shape const& shape) override;
+
+ void FillRectangle(Rect const& rect) override;
+
+ void FillRoundedRectangle(Rect const& rect, Vec2 const& radius) override;
+
+ void FillEllipse(Point const& center, Vec2 const& radius) override;
+
+ void CreateTexture(Texture& texture, math::Vec2T size) override;
+
+ void PushClipRect(Rect const& clip_rect) override;
+
+ void PopClipRect() override;
+
+ void PushLayer(LayerArea& layer) override;
+
+ void PopLayer() override;
+
+ void Clear() override;
+
+ void Clear(Color const& clear_color) override;
+
+ Size GetSize() const override;
+
+ void SetCurrentBrush(BrushPtr brush) override;
+
+ void SetTransform(const Matrix3x2& matrix) override;
+
+ void SetAntialiasMode(bool enabled) override;
+
+ void SetTextAntialiasMode(TextAntialiasMode mode) override;
+
+ bool CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) override;
+
+ void Resize(Size const& size) override;
+
+protected:
+ RenderContextImpl();
+
+ virtual ~RenderContextImpl();
+
+ HRESULT CreateDeviceResources(ComPtr factory, ComPtr ctx);
+
+ void DiscardDeviceResources();
+
+ void SaveDrawingState();
+
+ void RestoreDrawingState();
+
+protected:
+ ComPtr text_renderer_;
+ ComPtr render_target_;
+ ComPtr drawing_state_;
+};
+
+} // namespace kiwano
diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp
new file mode 100644
index 00000000..0f9ff4d2
--- /dev/null
+++ b/src/kiwano/render/DirectX/RendererImpl.cpp
@@ -0,0 +1,954 @@
+// 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
+#include
+#include
+#include
+
+namespace kiwano
+{
+
+Renderer& Renderer::GetInstance()
+{
+ return RendererImpl::GetInstance();
+}
+
+RendererImpl& RendererImpl::GetInstance()
+{
+ static RendererImpl instance;
+ return instance;
+}
+
+RendererImpl::RendererImpl()
+{
+ render_ctx_ = new RenderContextImpl;
+}
+
+void RendererImpl::SetupComponent()
+{
+ KGE_SYS_LOG(L"Creating device resources");
+
+ win32::ThrowIfFailed(::CoInitialize(nullptr));
+
+ target_window_ = Window::GetInstance().GetHandle();
+ output_size_ = Window::GetInstance().GetSize();
+
+ d2d_res_ = nullptr;
+ d3d_res_ = nullptr;
+
+ HRESULT hr = target_window_ ? S_OK : E_FAIL;
+
+ // Direct3D device resources
+ if (SUCCEEDED(hr))
+ {
+ hr = ID3DDeviceResources::Create(&d3d_res_, target_window_);
+
+ // Direct2D device resources
+ if (SUCCEEDED(hr))
+ {
+ hr = ID2DDeviceResources::Create(&d2d_res_, d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
+
+ // Other device resources
+ if (SUCCEEDED(hr))
+ {
+ hr = render_ctx_->CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
+ }
+
+ // FontFileLoader and FontCollectionLoader
+ if (SUCCEEDED(hr))
+ {
+ hr = IFontCollectionLoader::Create(&font_collection_loader_);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(font_collection_loader_.get());
+ }
+ }
+
+ // ResourceFontFileLoader and ResourceFontCollectionLoader
+ if (SUCCEEDED(hr))
+ {
+ hr = IResourceFontFileLoader::Create(&res_font_file_loader_);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetDWriteFactory()->RegisterFontFileLoader(res_font_file_loader_.get());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IResourceFontCollectionLoader::Create(&res_font_collection_loader_,
+ res_font_file_loader_.get());
+
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(
+ res_font_collection_loader_.get());
+ }
+ }
+ }
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::DestroyComponent()
+{
+ KGE_SYS_LOG(L"Destroying device resources");
+
+ d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.get());
+ res_font_file_loader_.reset();
+
+ d2d_res_->GetDWriteFactory()->UnregisterFontCollectionLoader(res_font_collection_loader_.get());
+ res_font_collection_loader_.reset();
+
+ render_ctx_.reset();
+ d2d_res_.reset();
+ d3d_res_.reset();
+
+ ::CoUninitialize();
+}
+
+void RendererImpl::BeginDraw()
+{
+ KGE_ASSERT(render_ctx_);
+
+ render_ctx_->BeginDraw();
+}
+
+void RendererImpl::EndDraw()
+{
+ KGE_ASSERT(render_ctx_);
+
+ render_ctx_->EndDraw();
+}
+
+void RendererImpl::Clear()
+{
+ KGE_ASSERT(d3d_res_);
+
+ HRESULT hr = d3d_res_->ClearRenderTarget(clear_color_);
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::Present()
+{
+ KGE_ASSERT(d3d_res_);
+
+ HRESULT hr = d3d_res_->Present(vsync_);
+
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
+ {
+ // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
+ hr = HandleDeviceLost();
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::HandleEvent(Event* evt)
+{
+ if (evt->IsType())
+ {
+ auto window_evt = dynamic_cast(evt);
+ Resize(window_evt->width, window_evt->height);
+ }
+}
+
+HRESULT RendererImpl::HandleDeviceLost()
+{
+ KGE_ASSERT(d3d_res_ && d2d_res_ && render_ctx_);
+
+ HRESULT hr = d3d_res_->HandleDeviceLost();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->HandleDeviceLost(d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = render_ctx_->CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
+ }
+ return hr;
+}
+
+void RendererImpl::CreateTexture(Texture& texture, String const& file_path)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (!FileSystem::GetInstance().IsFileExists(file_path))
+ {
+ KGE_WARN(L"Texture file '%s' not found!", file_path.c_str());
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
+
+ ComPtr decoder;
+ hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr source;
+ hr = decoder->GetFrame(0, &source);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr converter;
+ hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
+ WICBitmapDitherTypeNone, nullptr, 0.f,
+ WICBitmapPaletteTypeMedianCut);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr bitmap;
+ hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
+
+ if (SUCCEEDED(hr))
+ {
+ texture.SetBitmap(bitmap);
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ KGE_WARN(L"Load texture failed with HRESULT of %08X!", hr);
+ }
+}
+
+void RendererImpl::CreateTexture(Texture& texture, Resource const& resource)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr decoder;
+ hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr source;
+ hr = decoder->GetFrame(0, &source);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr converter;
+ hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
+ WICBitmapDitherTypeNone, nullptr, 0.f,
+ WICBitmapPaletteTypeMedianCut);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr bitmap;
+ hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
+
+ if (SUCCEEDED(hr))
+ {
+ texture.SetBitmap(bitmap);
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ KGE_WARN(L"Load texture failed with HRESULT of %08X!", hr);
+ }
+}
+
+void RendererImpl::CreateGifImage(GifImage& gif, String const& file_path)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (!FileSystem::GetInstance().IsFileExists(file_path))
+ {
+ KGE_WARN(L"Gif texture file '%s' not found!", file_path.c_str());
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
+
+ ComPtr decoder;
+ hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
+
+ if (SUCCEEDED(hr))
+ {
+ gif.SetDecoder(decoder);
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ KGE_WARN(L"Load GIF texture failed with HRESULT of %08X!", hr);
+ }
+}
+
+void RendererImpl::CreateGifImage(GifImage& gif, Resource const& resource)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr decoder;
+ hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
+
+ if (SUCCEEDED(hr))
+ {
+ gif.SetDecoder(decoder);
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ KGE_WARN(L"Load GIF texture failed with HRESULT of %08X!", hr);
+ }
+}
+
+void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (gif.GetDecoder() == nullptr)
+ {
+ hr = E_INVALIDARG;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr wic_frame;
+
+ HRESULT hr = gif.GetDecoder()->GetFrame(UINT(frame_index), &wic_frame);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr converter;
+ d2d_res_->CreateBitmapConverter(converter, wic_frame, GUID_WICPixelFormat32bppPBGRA,
+ WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr raw_bitmap;
+ hr = d2d_res_->CreateBitmapFromConverter(raw_bitmap, nullptr, converter);
+
+ if (SUCCEEDED(hr))
+ {
+ frame.texture = new Texture;
+ frame.texture->SetBitmap(raw_bitmap);
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ PROPVARIANT prop_val;
+ PropVariantInit(&prop_val);
+
+ // Get Metadata Query Reader from the frame
+ ComPtr metadata_reader;
+ hr = wic_frame->GetMetadataQueryReader(&metadata_reader);
+
+ // Get the Metadata for the current frame
+ if (SUCCEEDED(hr))
+ {
+ hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val);
+ if (SUCCEEDED(hr))
+ {
+ hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
+ if (SUCCEEDED(hr))
+ {
+ frame.rect.left_top.x = static_cast(prop_val.uiVal);
+ }
+ PropVariantClear(&prop_val);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val);
+ if (SUCCEEDED(hr))
+ {
+ hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
+ if (SUCCEEDED(hr))
+ {
+ frame.rect.left_top.y = static_cast(prop_val.uiVal);
+ }
+ PropVariantClear(&prop_val);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val);
+ if (SUCCEEDED(hr))
+ {
+ hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
+ if (SUCCEEDED(hr))
+ {
+ frame.rect.right_bottom.x = frame.rect.left_top.x + static_cast(prop_val.uiVal);
+ }
+ PropVariantClear(&prop_val);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val);
+ if (SUCCEEDED(hr))
+ {
+ hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
+ if (SUCCEEDED(hr))
+ {
+ frame.rect.right_bottom.y = frame.rect.left_top.y + static_cast(prop_val.uiVal);
+ }
+ PropVariantClear(&prop_val);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
+
+ if (SUCCEEDED(hr))
+ {
+ uint32_t udelay = 0;
+
+ hr = UIntMult(prop_val.uiVal, 10, &udelay);
+ if (SUCCEEDED(hr))
+ {
+ frame.delay.SetMilliseconds(static_cast(udelay));
+ }
+ }
+ PropVariantClear(&prop_val);
+ }
+ else
+ {
+ frame.delay = 0;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL;
+ if (SUCCEEDED(hr))
+ {
+ frame.disposal_type = GifImage::DisposalType(prop_val.bVal);
+ }
+ ::PropVariantClear(&prop_val);
+ }
+ else
+ {
+ frame.disposal_type = GifImage::DisposalType::Unknown;
+ }
+ }
+
+ ::PropVariantClear(&prop_val);
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ KGE_WARN(L"Load GIF frame failed with HRESULT of %08X!", hr);
+ }
+}
+
+void RendererImpl::CreateFontCollection(Font& font, String const& file_path)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (!FileSystem::GetInstance().IsFileExists(file_path))
+ {
+ KGE_WARN(L"Font file '%s' not found!", file_path.c_str());
+ hr = E_FAIL;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ LPVOID key = nullptr;
+ uint32_t key_size = 0;
+ String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
+
+ hr = font_collection_loader_->AddFilePaths({ full_path }, &key, &key_size);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr font_collection;
+ hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(font_collection_loader_.get(), key, key_size,
+ &font_collection);
+
+ if (SUCCEEDED(hr))
+ {
+ font.SetCollection(font_collection);
+ }
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateFontCollection(Font& font, Resource const& res)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ LPVOID key = nullptr;
+ uint32_t key_size = 0;
+
+ hr = res_font_collection_loader_->AddResources(Vector{ res }, &key, &key_size);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr font_collection;
+ hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(res_font_collection_loader_.get(), key,
+ key_size, &font_collection);
+
+ if (SUCCEEDED(hr))
+ {
+ font.SetCollection(font_collection);
+ }
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateTextFormat(TextLayout& layout)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr output;
+ if (SUCCEEDED(hr))
+ {
+ const TextStyle& style = layout.GetStyle();
+
+ hr = d2d_res_->CreateTextFormat(output, style.font_family, style.font ? style.font->GetCollection() : nullptr,
+ DWRITE_FONT_WEIGHT(style.font_weight),
+ style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
+ DWRITE_FONT_STRETCH_NORMAL, style.font_size);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ layout.SetTextFormat(output);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateTextLayout(TextLayout& layout)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr output;
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->CreateTextLayout(output, layout.GetText(), layout.GetTextFormat());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ layout.SetTextLayout(output);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr path_geo;
+ ComPtr path_sink;
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetFactory()->CreatePathGeometry(&path_geo);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = path_geo->Open(&path_sink);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
+ path_sink->AddLine(DX::ConvertToPoint2F(end_pos));
+ path_sink->EndFigure(D2D1_FIGURE_END_OPEN);
+ hr = path_sink->Close();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ shape.SetGeometry(path_geo);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr output;
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetFactory()->CreateRectangleGeometry(DX::ConvertToRectF(rect), &output);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ shape.SetGeometry(output);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr output;
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetFactory()->CreateRoundedRectangleGeometry(
+ D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), &output);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ shape.SetGeometry(output);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr output;
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetFactory()->CreateEllipseGeometry(
+ D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), &output);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ shape.SetGeometry(output);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateShapeSink(ShapeSink& sink)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ ComPtr output;
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->GetFactory()->CreatePathGeometry(&output);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ sink.SetPathGeometry(output);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+TextureRenderContextPtr RendererImpl::CreateTextureRenderContext(const Size* desired_size)
+{
+ TextureRenderContextImplPtr ptr = new TextureRenderContextImpl;
+
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr bitmap_rt;
+
+ if (desired_size)
+ {
+ hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(DX::ConvertToSizeF(*desired_size),
+ &bitmap_rt);
+ }
+ else
+ {
+ hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(&bitmap_rt);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = ptr->CreateDeviceResources(d2d_res_->GetFactory(), bitmap_rt);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ptr->bitmap_rt_ = bitmap_rt;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ return ptr;
+
+ return nullptr;
+}
+
+void RendererImpl::CreateBrush(Brush& brush, Color const& color)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr solid_brush;
+
+ if (brush.GetType() == Brush::Type::SolidColor && brush.GetBrush())
+ {
+ hr = brush.GetBrush()->QueryInterface(&solid_brush);
+ if (SUCCEEDED(hr))
+ {
+ solid_brush->SetColor(DX::ConvertToColorF(color));
+ }
+ }
+ else
+ {
+ hr = d2d_res_->GetDeviceContext()->CreateSolidColorBrush(DX::ConvertToColorF(color), &solid_brush);
+
+ if (SUCCEEDED(hr))
+ {
+ brush.SetBrush(solid_brush, Brush::Type::SolidColor);
+ }
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr collection;
+ hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
+ reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
+ D2D1_EXTEND_MODE(style.extend_mode), &collection);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr output;
+ hr = d2d_res_->GetDeviceContext()->CreateLinearGradientBrush(
+ D2D1::LinearGradientBrushProperties(DX::ConvertToPoint2F(style.begin), DX::ConvertToPoint2F(style.end)),
+ collection.get(), &output);
+
+ if (SUCCEEDED(hr))
+ {
+ brush.SetBrush(output, Brush::Type::LinearGradient);
+ }
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr collection;
+ hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
+ reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
+ D2D1_EXTEND_MODE(style.extend_mode), &collection);
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr output;
+ hr = d2d_res_->GetDeviceContext()->CreateRadialGradientBrush(
+ D2D1::RadialGradientBrushProperties(DX::ConvertToPoint2F(style.center),
+ DX::ConvertToPoint2F(style.offset), style.radius.x, style.radius.y),
+ collection.get(), &output);
+
+ if (SUCCEEDED(hr))
+ {
+ brush.SetBrush(output, Brush::Type::RadialGradient);
+ }
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
+ const float* dash_array, size_t dash_size, float dash_offset)
+{
+ HRESULT hr = S_OK;
+ if (!d2d_res_)
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ D2D1_STROKE_STYLE_PROPERTIES style =
+ D2D1::StrokeStyleProperties(D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap),
+ D2D1_LINE_JOIN(line_join), 10.0f, D2D1_DASH_STYLE_CUSTOM, dash_offset);
+
+ ComPtr output;
+ hr = d2d_res_->GetFactory()->CreateStrokeStyle(style, dash_array, dash_size, &output);
+
+ if (SUCCEEDED(hr))
+ {
+ stroke_style.SetStrokeStyle(output);
+ }
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+void RendererImpl::Resize(uint32_t width, uint32_t height)
+{
+ HRESULT hr = S_OK;
+
+ if (!d3d_res_)
+ hr = E_UNEXPECTED;
+
+ if (SUCCEEDED(hr))
+ {
+ output_size_.x = static_cast(width);
+ output_size_.y = static_cast(height);
+
+ hr = d3d_res_->SetLogicalSize(output_size_);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = d2d_res_->SetLogicalSize(output_size_);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ render_ctx_->Resize(output_size_);
+ }
+
+ win32::ThrowIfFailed(hr);
+}
+
+} // namespace kiwano
diff --git a/src/kiwano/render/DirectX/RendererImpl.h b/src/kiwano/render/DirectX/RendererImpl.h
new file mode 100644
index 00000000..0b8ecccd
--- /dev/null
+++ b/src/kiwano/render/DirectX/RendererImpl.h
@@ -0,0 +1,147 @@
+// 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
+#include
+#include
+
+#if defined(KGE_USE_DIRECTX10)
+#include
+#else
+#include
+#endif
+
+namespace kiwano
+{
+
+#if defined(KGE_USE_DIRECTX10)
+typedef ID3D10DeviceResources ID3DDeviceResources;
+#else
+typedef ID3D11DeviceResources ID3DDeviceResources;
+#endif
+
+class KGE_API RendererImpl
+ : public Renderer
+{
+public:
+ static RendererImpl& GetInstance();
+
+ void CreateTexture(Texture& texture, String const& file_path);
+
+ void CreateTexture(Texture& texture, Resource const& resource);
+
+ void CreateGifImage(GifImage& gif, String const& file_path);
+
+ void CreateGifImage(GifImage& gif, Resource const& resource);
+
+ void CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index);
+
+ void CreateFontCollection(Font& font, String const& file_path);
+
+ void CreateFontCollection(Font& font, Resource const& res);
+
+ void CreateTextFormat(TextLayout& layout);
+
+ void CreateTextLayout(TextLayout& layout);
+
+ void CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos);
+
+ void CreateRectShape(Shape& shape, Rect const& rect);
+
+ void CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius);
+
+ void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius);
+
+ void CreateShapeSink(ShapeSink& sink);
+
+ void CreateBrush(Brush& brush, Color const& color);
+
+ void CreateBrush(Brush& brush, LinearGradientStyle const& style);
+
+ void CreateBrush(Brush& brush, RadialGradientStyle const& style);
+
+ void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, const float* dash_array,
+ size_t dash_size, float dash_offset);
+
+ TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr);
+
+public:
+ void BeginDraw();
+
+ void EndDraw();
+
+ void Clear();
+
+ void Present();
+
+ RenderContext& GetContext();
+
+ /// \~chinese
+ /// @brief 获取Direct2D设备资源
+ ID2DDeviceResources* GetD2DDeviceResources();
+
+ /// \~chinese
+ /// @brief 获取Direct3D设备资源
+ ID3DDeviceResources* GetD3DDeviceResources();
+
+public:
+ void SetupComponent() override;
+
+ void DestroyComponent() override;
+
+ void HandleEvent(Event* evt) override;
+
+private:
+ RendererImpl();
+
+ HRESULT HandleDeviceLost();
+
+ void Resize(uint32_t width, uint32_t height);
+
+private:
+ RenderContextImplPtr render_ctx_;
+ ComPtr d2d_res_;
+ ComPtr d3d_res_;
+ ComPtr font_collection_loader_;
+ ComPtr res_font_file_loader_;
+ ComPtr res_font_collection_loader_;
+};
+
+/** @} */
+
+inline RenderContext& RendererImpl::GetContext()
+{
+ return *render_ctx_;
+}
+
+inline ID2DDeviceResources* RendererImpl::GetD2DDeviceResources()
+{
+ KGE_ASSERT(d2d_res_);
+ return d2d_res_.get();
+}
+
+inline ID3DDeviceResources* RendererImpl::GetD3DDeviceResources()
+{
+ KGE_ASSERT(d3d_res_);
+ return d3d_res_.get();
+}
+
+} // namespace kiwano
diff --git a/src/kiwano/render/DirectX/TextureRenderContextImpl.cpp b/src/kiwano/render/DirectX/TextureRenderContextImpl.cpp
new file mode 100644
index 00000000..de2c24e1
--- /dev/null
+++ b/src/kiwano/render/DirectX/TextureRenderContextImpl.cpp
@@ -0,0 +1,46 @@
+// 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
+{
+
+bool TextureRenderContextImpl::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/DirectX/TextureRenderContextImpl.h b/src/kiwano/render/DirectX/TextureRenderContextImpl.h
new file mode 100644
index 00000000..b8274f13
--- /dev/null
+++ b/src/kiwano/render/DirectX/TextureRenderContextImpl.h
@@ -0,0 +1,104 @@
+// 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
+#include
+
+namespace kiwano
+{
+
+class RendererImpl;
+
+KGE_DECLARE_SMART_PTR(TextureRenderContextImpl);
+
+KGE_SUPPRESS_WARNING_PUSH
+KGE_SUPPRESS_WARNING(4250) // inherits via domainance
+
+class KGE_API TextureRenderContextImpl
+ : public RenderContextImpl
+ , public TextureRenderContext
+{
+ friend class RendererImpl;
+
+public:
+ bool GetOutput(Texture& texture) override;
+
+ using RenderContextImpl::IsValid;
+
+ using RenderContextImpl::BeginDraw;
+
+ using RenderContextImpl::EndDraw;
+
+ using RenderContextImpl::DrawTexture;
+
+ using RenderContextImpl::DrawTextLayout;
+
+ using RenderContextImpl::DrawShape;
+
+ using RenderContextImpl::DrawLine;
+
+ using RenderContextImpl::DrawRectangle;
+
+ using RenderContextImpl::DrawRoundedRectangle;
+
+ using RenderContextImpl::DrawEllipse;
+
+ using RenderContextImpl::FillShape;
+
+ using RenderContextImpl::FillRectangle;
+
+ using RenderContextImpl::FillRoundedRectangle;
+
+ using RenderContextImpl::FillEllipse;
+
+ using RenderContextImpl::CreateTexture;
+
+ using RenderContextImpl::PushClipRect;
+
+ using RenderContextImpl::PopClipRect;
+
+ using RenderContextImpl::PushLayer;
+
+ using RenderContextImpl::PopLayer;
+
+ using RenderContextImpl::Clear;
+
+ using RenderContextImpl::GetSize;
+
+ using RenderContextImpl::SetCurrentBrush;
+
+ using RenderContextImpl::SetTransform;
+
+ using RenderContextImpl::SetAntialiasMode;
+
+ using RenderContextImpl::SetTextAntialiasMode;
+
+ using RenderContextImpl::CheckVisibility;
+
+ using RenderContextImpl::Resize;
+
+private:
+ ComPtr bitmap_rt_;
+};
+
+KGE_SUPPRESS_WARNING_POP
+
+} // namespace kiwano
diff --git a/src/kiwano/render/Font.h b/src/kiwano/render/Font.h
index 9ba98b91..e4d2e5b5 100644
--- a/src/kiwano/render/Font.h
+++ b/src/kiwano/render/Font.h
@@ -63,11 +63,12 @@ public:
bool Load(Resource const& resource);
#if defined(KGE_WIN32)
-private:
+public:
ComPtr GetCollection() const;
void SetCollection(ComPtr collection);
+private:
ComPtr collection_;
#endif
};
diff --git a/src/kiwano/render/GifImage.h b/src/kiwano/render/GifImage.h
index c791eb1e..bd8e082c 100644
--- a/src/kiwano/render/GifImage.h
+++ b/src/kiwano/render/GifImage.h
@@ -24,8 +24,6 @@
namespace kiwano
{
-class Renderer;
-
KGE_DECLARE_SMART_PTR(GifImage);
/**
@@ -39,8 +37,6 @@ KGE_DECLARE_SMART_PTR(GifImage);
*/
class KGE_API GifImage : public virtual ObjectBase
{
- friend class Renderer;
-
public:
/// \~chinese
/// @brief 创建GIF图片
@@ -113,10 +109,12 @@ private:
uint32_t height_in_pixels_;
#if defined(KGE_WIN32)
+public:
ComPtr GetDecoder() const;
void SetDecoder(ComPtr decoder);
+private:
ComPtr decoder_;
#endif
};
diff --git a/src/kiwano/render/LayerArea.h b/src/kiwano/render/LayerArea.h
index ad10ed0a..e88db1f3 100644
--- a/src/kiwano/render/LayerArea.h
+++ b/src/kiwano/render/LayerArea.h
@@ -23,7 +23,6 @@
namespace kiwano
{
-class RenderContext;
/**
* \addtogroup Render
@@ -36,8 +35,6 @@ class RenderContext;
*/
class KGE_API LayerArea
{
- friend class RenderContext;
-
public:
LayerArea();
@@ -84,10 +81,12 @@ private:
Matrix3x2 mask_transform_;
#if defined(KGE_WIN32)
+public:
ComPtr GetLayer() const;
void SetLayer(ComPtr layer);
+private:
ComPtr layer_;
#endif
};
diff --git a/src/kiwano/render/RenderContext.cpp b/src/kiwano/render/RenderContext.cpp
index e2376083..3cdc98f6 100644
--- a/src/kiwano/render/RenderContext.cpp
+++ b/src/kiwano/render/RenderContext.cpp
@@ -18,7 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-#include
#include
namespace kiwano
@@ -31,47 +30,6 @@ RenderContext::RenderContext()
, antialias_(true)
, text_antialias_(TextAntialiasMode::GrayScale)
{
- status_.primitives = 0;
-}
-
-HRESULT RenderContext::CreateDeviceResources(ComPtr factory, ComPtr ctx)
-{
- if (!factory || !ctx)
- return E_INVALIDARG;
-
- render_target_ = ctx;
- text_renderer_.reset();
- current_brush_.reset();
-
- HRESULT hr = ITextRenderer::Create(&text_renderer_, render_target_.get());
-
- if (SUCCEEDED(hr))
- {
- SetAntialiasMode(antialias_);
- SetTextAntialiasMode(text_antialias_);
-
- Resize(reinterpret_cast(GetRenderTarget()->GetSize()));
- }
-
- // DrawingStateBlock
- if (SUCCEEDED(hr))
- {
- hr = factory->CreateDrawingStateBlock(&drawing_state_);
- }
-
- return hr;
-}
-
-void RenderContext::DiscardDeviceResources()
-{
- text_renderer_.reset();
- render_target_.reset();
- current_brush_.reset();
-}
-
-bool RenderContext::IsValid() const
-{
- return render_target_ != nullptr;
}
void RenderContext::BeginDraw()
@@ -81,340 +39,16 @@ void RenderContext::BeginDraw()
status_.start = Time::Now();
status_.primitives = 0;
}
-
- if (render_target_)
- {
- render_target_->BeginDraw();
- }
}
void RenderContext::EndDraw()
{
- win32::ThrowIfFailed(render_target_->EndDraw());
-
if (collecting_status_)
{
status_.duration = Time::Now() - status_.start;
}
}
-void RenderContext::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect)
-{
- DrawTexture(texture, &src_rect, &dest_rect);
-}
-
-void RenderContext::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
-
- if (texture.IsValid())
- {
- auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
- ? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
- : D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
-
- render_target_->DrawBitmap(texture.GetBitmap().get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
- brush_opacity_, mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
-
- IncreasePrimitivesCount();
- }
-}
-
-void RenderContext::DrawTextLayout(TextLayout const& layout, Point const& offset)
-{
- KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!");
-
- if (layout.IsValid())
- {
- ComPtr fill_brush;
- ComPtr outline_brush;
- const TextStyle& style = layout.GetStyle();
-
- if (style.fill_brush)
- {
- fill_brush = style.fill_brush->GetBrush();
- fill_brush->SetOpacity(brush_opacity_);
- }
-
- if (style.outline_brush)
- {
- outline_brush = style.outline_brush->GetBrush();
- outline_brush->SetOpacity(brush_opacity_);
- }
-
- HRESULT hr = S_OK;
-
- if (style.outline_stroke)
- {
- hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().get(), offset.x, offset.y, fill_brush.get(),
- outline_brush.get(), style.outline_width,
- style.outline_stroke->GetStrokeStyle().get());
- }
- else
- {
- hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().get(), offset.x, offset.y, fill_brush.get(),
- outline_brush.get(), style.outline_width, nullptr);
- }
-
- if (SUCCEEDED(hr))
- {
- IncreasePrimitivesCount(text_renderer_->GetLastPrimitivesCount());
- }
- else
- {
- KGE_ERROR(L"Failed to draw text layout with HRESULT of %08X", hr);
- }
- }
-}
-
-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!");
-
- ComPtr saved_bitmap;
-
- HRESULT hr = render_target_->CreateBitmap(D2D1::SizeU(size.x, size.y), D2D1::BitmapProperties(), &saved_bitmap);
-
- if (SUCCEEDED(hr))
- {
- texture.SetBitmap(saved_bitmap);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void RenderContext::PushClipRect(Rect const& clip_rect)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
- render_target_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect),
- antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
-}
-
-void RenderContext::PopClipRect()
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
- render_target_->PopAxisAlignedClip();
-}
-
-void RenderContext::PushLayer(LayerArea& layer)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
- if (!layer.IsValid())
- {
- ComPtr output;
- HRESULT hr = render_target_->CreateLayer(&output);
-
- if (SUCCEEDED(hr))
- {
- layer.SetLayer(output);
- }
- else
- {
- win32::ThrowIfFailed(hr);
- }
- }
-
- if (layer.IsValid())
- {
- ComPtr mask;
- if (layer.GetMaskShape())
- mask = layer.GetMaskShape()->GetGeometry();
-
- render_target_->PushLayer(
- D2D1::LayerParameters(DX::ConvertToRectF(layer.GetAreaRect()), mask.get(),
- antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
- DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
- D2D1_LAYER_OPTIONS_NONE),
- layer.GetLayer().get());
- }
-}
-
-void RenderContext::PopLayer()
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
- render_target_->PopLayer();
-}
-
-void RenderContext::Clear()
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
- render_target_->Clear();
-}
-
-void RenderContext::Clear(Color const& clear_color)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
- 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!");
-
- if (fast_global_transform_)
- {
- render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
- }
- else
- {
- Matrix3x2 result = matrix * global_transform_;
- render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result));
- }
-}
-
void RenderContext::SetGlobalTransform(const Matrix3x2* matrix)
{
if (matrix)
@@ -428,57 +62,6 @@ void RenderContext::SetGlobalTransform(const Matrix3x2* matrix)
}
}
-void RenderContext::SetAntialiasMode(bool enabled)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
-
- render_target_->SetAntialiasMode(enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
- antialias_ = enabled;
-}
-
-void RenderContext::SetTextAntialiasMode(TextAntialiasMode mode)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
-
- D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
- switch (mode)
- {
- case TextAntialiasMode::Default:
- antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
- break;
- case TextAntialiasMode::ClearType:
- antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
- break;
- case TextAntialiasMode::GrayScale:
- antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
- break;
- case TextAntialiasMode::None:
- antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
- break;
- default:
- break;
- }
-
- text_antialias_ = mode;
- render_target_->SetTextAntialiasMode(antialias_mode);
-}
-
-bool RenderContext::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform)
-{
- KGE_ASSERT(render_target_ && "Render target has not been initialized!");
-
- if (fast_global_transform_)
- {
- return visible_size_.Intersects(transform.Transform(bounds));
- }
- return visible_size_.Intersects(Matrix3x2(transform * global_transform_).Transform(bounds));
-}
-
-void RenderContext::Resize(Size const& size)
-{
- visible_size_ = Rect(Point(), size);
-}
-
void RenderContext::SetCollectingStatus(bool enable)
{
collecting_status_ = enable;
@@ -492,24 +75,34 @@ void RenderContext::IncreasePrimitivesCount(uint32_t increase) const
}
}
-void RenderContext::SaveDrawingState()
+float RenderContext::GetBrushOpacity() const
{
- KGE_ASSERT(IsValid());
-
- if (drawing_state_)
- {
- render_target_->SaveDrawingState(drawing_state_.get());
- }
+ return brush_opacity_;
}
-void RenderContext::RestoreDrawingState()
+BrushPtr RenderContext::GetCurrentBrush() const
{
- KGE_ASSERT(IsValid());
+ return current_brush_;
+}
- if (drawing_state_)
- {
- render_target_->RestoreDrawingState(drawing_state_.get());
- }
+const Matrix3x2& RenderContext::GetGlobalTransform() const
+{
+ return global_transform_;
+}
+
+void RenderContext::SetBrushOpacity(float opacity)
+{
+ brush_opacity_ = opacity;
+}
+
+void RenderContext::SetGlobalTransform(const Matrix3x2& matrix)
+{
+ SetGlobalTransform(&matrix);
+}
+
+void RenderContext::SetCurrentBrush(BrushPtr brush)
+{
+ current_brush_ = brush;
}
} // namespace kiwano
diff --git a/src/kiwano/render/RenderContext.h b/src/kiwano/render/RenderContext.h
index 6f45f207..0c8a853e 100644
--- a/src/kiwano/render/RenderContext.h
+++ b/src/kiwano/render/RenderContext.h
@@ -60,42 +60,36 @@ class KGE_API RenderContext : public virtual ObjectBase
public:
/// \~chinese
/// @brief 是否有效
- bool IsValid() const;
+ virtual bool IsValid() const = 0;
/// \~chinese
/// @brief 开始渲染
- void BeginDraw();
+ virtual void BeginDraw();
/// \~chinese
/// @brief 结束渲染
- void EndDraw();
+ virtual void EndDraw();
/// \~chinese
/// @brief 绘制纹理
/// @param texture 纹理
/// @param src_rect 源纹理裁剪矩形
/// @param dest_rect 绘制的目标区域
- void DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect);
-
- /// \~chinese
- /// @brief 绘制纹理
- /// @param texture 纹理
- /// @param src_rect 源纹理裁剪矩形
- /// @param dest_rect 绘制的目标区域
- void DrawTexture(Texture const& texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
+ virtual void DrawTexture(Texture const& texture, const Rect* src_rect = nullptr,
+ const Rect* dest_rect = nullptr) = 0;
/// \~chinese
/// @brief 绘制文本布局
/// @param layout 文本布局
/// @param offset 偏移量
- void DrawTextLayout(TextLayout const& layout, Point const& offset = Point());
+ virtual void DrawTextLayout(TextLayout const& layout, Point const& offset = Point()) = 0;
/// \~chinese
/// @brief 绘制形状轮廓
/// @param shape 形状
/// @param stroke 线条样式
/// @param stroke_width 线条宽度
- void DrawShape(Shape const& shape, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f);
+ virtual void DrawShape(Shape const& shape, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f) = 0;
/// \~chinese
/// @brief 绘制线段
@@ -103,14 +97,15 @@ public:
/// @param point2 线段终点
/// @param stroke 线条样式
/// @param stroke_width 线条宽度
- void DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f);
+ virtual void DrawLine(Point const& point1, Point const& point2, StrokeStylePtr stroke = nullptr,
+ float stroke_width = 1.0f) = 0;
/// \~chinese
/// @brief 绘制矩形边框
/// @param rect 矩形
/// @param stroke 线条样式
/// @param stroke_width 线条宽度
- void DrawRectangle(Rect const& rect, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f);
+ virtual void DrawRectangle(Rect const& rect, StrokeStylePtr stroke = nullptr, float stroke_width = 1.0f) = 0;
/// \~chinese
/// @brief 绘制圆角矩形边框
@@ -118,8 +113,8 @@ public:
/// @param radius 圆角半径
/// @param stroke 线条样式
/// @param stroke_width 线条宽度
- void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
- float stroke_width = 1.0f);
+ virtual void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
+ float stroke_width = 1.0f) = 0;
/// \~chinese
/// @brief 绘制椭圆边框
@@ -127,115 +122,115 @@ public:
/// @param radius 椭圆半径
/// @param stroke 线条样式
/// @param stroke_width 线条宽度
- void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
- float stroke_width = 1.0f);
+ virtual void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
+ float stroke_width = 1.0f) = 0;
/// \~chinese
/// @brief 填充形状
/// @param shape 形状
- void FillShape(Shape const& shape);
+ virtual void FillShape(Shape const& shape) = 0;
/// \~chinese
/// @brief 填充矩形
/// @param rect 矩形
- void FillRectangle(Rect const& rect);
+ virtual void FillRectangle(Rect const& rect) = 0;
/// \~chinese
/// @brief 填充圆角矩形
/// @param rect 矩形
/// @param radius 圆角半径
- void FillRoundedRectangle(Rect const& rect, Vec2 const& radius);
+ virtual void FillRoundedRectangle(Rect const& rect, Vec2 const& radius) = 0;
/// \~chinese
/// @brief 填充椭圆
/// @param center 圆心
/// @param radius 椭圆半径
- void FillEllipse(Point const& center, Vec2 const& radius);
+ virtual void FillEllipse(Point const& center, Vec2 const& radius) = 0;
/// \~chinese
/// @brief 创建纹理
/// @param texture 纹理
/// @param size 纹理像素大小
- void CreateTexture(Texture& texture, math::Vec2T size);
+ virtual void CreateTexture(Texture& texture, math::Vec2T size) = 0;
/// \~chinese
/// @brief 设置绘制的裁剪区域
/// @param clip_rect 裁剪矩形
- void PushClipRect(Rect const& clip_rect);
+ virtual void PushClipRect(Rect const& clip_rect) = 0;
/// \~chinese
/// @brief 取消上一次设置的绘制裁剪区域
- void PopClipRect();
+ virtual void PopClipRect() = 0;
/// \~chinese
/// @brief 设置图层区域
/// @param layer 图层区域
- void PushLayer(LayerArea& layer);
+ virtual void PushLayer(LayerArea& layer) = 0;
/// \~chinese
/// @brief 取消上一次设置的图层区域
- void PopLayer();
+ virtual void PopLayer() = 0;
/// \~chinese
/// @brief 清空渲染内容
- void Clear();
+ virtual void Clear() = 0;
/// \~chinese
/// @brief 使用纯色清空渲染内容
/// @param clear_color 清屏颜色
- void Clear(Color const& clear_color);
+ virtual void Clear(Color const& clear_color) = 0;
/// \~chinese
/// @brief 获取渲染区域大小
- Size GetSize() const;
+ virtual Size GetSize() const = 0;
/// \~chinese
/// @brief 获取画刷透明度
- float GetBrushOpacity() const;
+ virtual float GetBrushOpacity() const;
/// \~chinese
/// @brief 获取当前画刷
- BrushPtr GetCurrentBrush() const;
+ virtual BrushPtr GetCurrentBrush() const;
/// \~chinese
/// @brief 获取全局二维变换
- Matrix3x2 GetGlobalTransform() const;
+ virtual const Matrix3x2& GetGlobalTransform() const;
/// \~chinese
/// @brief 设置画刷透明度
- void SetBrushOpacity(float opacity);
+ virtual void SetBrushOpacity(float opacity);
/// \~chinese
/// @brief 设置当前画刷
- void SetCurrentBrush(BrushPtr brush);
-
- /// \~chinese
- /// @brief 设置上下文的二维变换
- void SetTransform(const Matrix3x2& matrix);
-
- /// \~chinese
- /// @brief 设置全局二维变换
- void SetGlobalTransform(const Matrix3x2& matrix);
-
- /// \~chinese
- /// @brief 设置全局二维变换
- void SetGlobalTransform(const Matrix3x2* matrix);
+ virtual void SetCurrentBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置抗锯齿模式
- void SetAntialiasMode(bool enabled);
+ virtual void SetAntialiasMode(bool enabled) = 0;
/// \~chinese
/// @brief 设置文字抗锯齿模式
- void SetTextAntialiasMode(TextAntialiasMode mode);
+ virtual void SetTextAntialiasMode(TextAntialiasMode mode) = 0;
/// \~chinese
/// @brief 检查边界是否在视区内
- bool CheckVisibility(Rect const& bounds, Matrix3x2 const& transform);
+ virtual bool CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) = 0;
/// \~chinese
/// @brief 重设渲染上下文大小
- void Resize(Size const& size);
+ virtual void Resize(Size const& size) = 0;
+
+ /// \~chinese
+ /// @brief 设置上下文的二维变换
+ virtual void SetTransform(const Matrix3x2& matrix) = 0;
+
+ /// \~chinese
+ /// @brief 设置全局二维变换
+ virtual void SetGlobalTransform(const Matrix3x2& matrix);
+
+ /// \~chinese
+ /// @brief 设置全局二维变换
+ virtual void SetGlobalTransform(const Matrix3x2* matrix);
public:
/// \~chinese
@@ -260,32 +255,11 @@ public:
protected:
RenderContext();
- ComPtr GetRenderTarget() const;
-
- ComPtr GetTextRenderer() const;
-
-private:
- /// \~chinese
- /// @brief 创建设备依赖资源
- HRESULT CreateDeviceResources(ComPtr factory, ComPtr ctx);
-
- /// \~chinese
- /// @brief 销毁设备依赖资源
- void DiscardDeviceResources();
-
/// \~chinese
/// @brief 增加渲染图元数量
void IncreasePrimitivesCount(uint32_t increase = 1) const;
- /// \~chinese
- /// @brief 保存绘制状态
- void SaveDrawingState();
-
- /// \~chinese
- /// @brief 恢复绘制状态
- void RestoreDrawingState();
-
-private:
+protected:
bool antialias_;
bool fast_global_transform_;
mutable bool collecting_status_;
@@ -295,10 +269,6 @@ private:
Rect visible_size_;
Matrix3x2 global_transform_;
mutable Status status_;
-
- ComPtr text_renderer_;
- ComPtr render_target_;
- ComPtr drawing_state_;
};
/** @} */
@@ -313,50 +283,4 @@ inline RenderContext::Status const& RenderContext::GetStatus() const
return status_;
}
-inline ComPtr RenderContext::GetRenderTarget() const
-{
- KGE_ASSERT(render_target_);
- return render_target_;
-}
-
-inline ComPtr RenderContext::GetTextRenderer() const
-{
- KGE_ASSERT(text_renderer_);
- return text_renderer_;
-}
-
-inline float RenderContext::GetBrushOpacity() const
-{
- return brush_opacity_;
-}
-
-inline BrushPtr RenderContext::GetCurrentBrush() const
-{
- return current_brush_;
-}
-
-inline Matrix3x2 RenderContext::GetGlobalTransform() const
-{
- return global_transform_;
-}
-
-inline void RenderContext::SetBrushOpacity(float opacity)
-{
- brush_opacity_ = opacity;
-}
-
-inline void RenderContext::SetGlobalTransform(const Matrix3x2& matrix)
-{
- SetGlobalTransform(&matrix);
-}
-
-inline void RenderContext::SetCurrentBrush(BrushPtr brush)
-{
- current_brush_ = brush;
- if (current_brush_)
- {
- current_brush_->SetOpacity(brush_opacity_);
- }
-}
-
} // namespace kiwano
diff --git a/src/kiwano/render/Renderer.cpp b/src/kiwano/render/Renderer.cpp
index 6850dbb5..36956eac 100644
--- a/src/kiwano/render/Renderer.cpp
+++ b/src/kiwano/render/Renderer.cpp
@@ -18,10 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-#include
-#include
-#include
-#include
#include
namespace kiwano
@@ -34,934 +30,4 @@ Renderer::Renderer()
{
}
-Renderer::~Renderer() {}
-
-void Renderer::SetupComponent()
-{
- KGE_SYS_LOG(L"Creating device resources");
-
- win32::ThrowIfFailed(::CoInitialize(nullptr));
-
- target_window_ = Window::GetInstance().GetHandle();
- output_size_ = Window::GetInstance().GetSize();
-
- d2d_res_ = nullptr;
- d3d_res_ = nullptr;
-
- HRESULT hr = target_window_ ? S_OK : E_FAIL;
-
- // Direct3D device resources
- if (SUCCEEDED(hr))
- {
- hr = ID3DDeviceResources::Create(&d3d_res_, target_window_);
-
- // Direct2D device resources
- if (SUCCEEDED(hr))
- {
- hr = ID2DDeviceResources::Create(&d2d_res_, d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
-
- // Other device resources
- if (SUCCEEDED(hr))
- {
- hr = render_ctx_.CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
- }
-
- // FontFileLoader and FontCollectionLoader
- if (SUCCEEDED(hr))
- {
- hr = IFontCollectionLoader::Create(&font_collection_loader_);
-
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(font_collection_loader_.get());
- }
- }
-
- // ResourceFontFileLoader and ResourceFontCollectionLoader
- if (SUCCEEDED(hr))
- {
- hr = IResourceFontFileLoader::Create(&res_font_file_loader_);
-
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetDWriteFactory()->RegisterFontFileLoader(res_font_file_loader_.get());
- }
-
- if (SUCCEEDED(hr))
- {
- hr = IResourceFontCollectionLoader::Create(&res_font_collection_loader_,
- res_font_file_loader_.get());
-
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(
- res_font_collection_loader_.get());
- }
- }
- }
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::DestroyComponent()
-{
- KGE_SYS_LOG(L"Destroying device resources");
-
- render_ctx_.DiscardDeviceResources();
-
- d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.get());
- res_font_file_loader_.reset();
-
- d2d_res_->GetDWriteFactory()->UnregisterFontCollectionLoader(res_font_collection_loader_.get());
- res_font_collection_loader_.reset();
-
- d2d_res_.reset();
- d3d_res_.reset();
-
- ::CoUninitialize();
-}
-
-void Renderer::BeginDraw()
-{
- KGE_ASSERT(render_ctx_.IsValid());
-
- render_ctx_.SaveDrawingState();
- render_ctx_.BeginDraw();
-}
-
-void Renderer::EndDraw()
-{
- KGE_ASSERT(render_ctx_.IsValid());
-
- render_ctx_.EndDraw();
- render_ctx_.RestoreDrawingState();
-}
-
-void Renderer::Clear()
-{
- KGE_ASSERT(d3d_res_);
-
- HRESULT hr = d3d_res_->ClearRenderTarget(clear_color_);
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::Present()
-{
- KGE_ASSERT(d3d_res_);
-
- HRESULT hr = d3d_res_->Present(vsync_);
-
- if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
- {
- // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
- hr = HandleDeviceLost();
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::HandleEvent(Event* evt)
-{
- if (evt->IsType())
- {
- auto window_evt = dynamic_cast(evt);
- ResizeTarget(window_evt->width, window_evt->height);
- }
-}
-
-HRESULT Renderer::HandleDeviceLost()
-{
- KGE_ASSERT(d3d_res_ && d2d_res_ && render_ctx_.IsValid());
-
- HRESULT hr = d3d_res_->HandleDeviceLost();
-
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->HandleDeviceLost(d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
- }
-
- if (SUCCEEDED(hr))
- {
- hr = render_ctx_.CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
- }
- return hr;
-}
-
-void Renderer::CreateTexture(Texture& texture, String const& file_path)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (!FileSystem::GetInstance().IsFileExists(file_path))
- {
- KGE_WARN(L"Texture file '%s' not found!", file_path.c_str());
- hr = E_FAIL;
- }
-
- if (SUCCEEDED(hr))
- {
- String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
-
- ComPtr decoder;
- hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
-
- if (SUCCEEDED(hr))
- {
- ComPtr source;
- hr = decoder->GetFrame(0, &source);
-
- if (SUCCEEDED(hr))
- {
- ComPtr converter;
- hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
- WICBitmapDitherTypeNone, nullptr, 0.f,
- WICBitmapPaletteTypeMedianCut);
-
- if (SUCCEEDED(hr))
- {
- ComPtr bitmap;
- hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
-
- if (SUCCEEDED(hr))
- {
- texture.SetBitmap(bitmap);
- }
- }
- }
- }
- }
-
- if (FAILED(hr))
- {
- KGE_WARN(L"Load texture failed with HRESULT of %08X!", hr);
- }
-}
-
-void Renderer::CreateTexture(Texture& texture, Resource const& resource)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr decoder;
- hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
-
- if (SUCCEEDED(hr))
- {
- ComPtr source;
- hr = decoder->GetFrame(0, &source);
-
- if (SUCCEEDED(hr))
- {
- ComPtr converter;
- hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
- WICBitmapDitherTypeNone, nullptr, 0.f,
- WICBitmapPaletteTypeMedianCut);
-
- if (SUCCEEDED(hr))
- {
- ComPtr bitmap;
- hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
-
- if (SUCCEEDED(hr))
- {
- texture.SetBitmap(bitmap);
- }
- }
- }
- }
- }
-
- if (FAILED(hr))
- {
- KGE_WARN(L"Load texture failed with HRESULT of %08X!", hr);
- }
-}
-
-void Renderer::CreateGifImage(GifImage& gif, String const& file_path)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (!FileSystem::GetInstance().IsFileExists(file_path))
- {
- KGE_WARN(L"Gif texture file '%s' not found!", file_path.c_str());
- hr = E_FAIL;
- }
-
- if (SUCCEEDED(hr))
- {
- String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
-
- ComPtr decoder;
- hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
-
- if (SUCCEEDED(hr))
- {
- gif.SetDecoder(decoder);
- }
- }
-
- if (FAILED(hr))
- {
- KGE_WARN(L"Load GIF texture failed with HRESULT of %08X!", hr);
- }
-}
-
-void Renderer::CreateGifImage(GifImage& gif, Resource const& resource)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr decoder;
- hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
-
- if (SUCCEEDED(hr))
- {
- gif.SetDecoder(decoder);
- }
- }
-
- if (FAILED(hr))
- {
- KGE_WARN(L"Load GIF texture failed with HRESULT of %08X!", hr);
- }
-}
-
-void Renderer::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (gif.GetDecoder() == nullptr)
- {
- hr = E_INVALIDARG;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr wic_frame;
-
- HRESULT hr = gif.GetDecoder()->GetFrame(UINT(frame_index), &wic_frame);
-
- if (SUCCEEDED(hr))
- {
- ComPtr converter;
- d2d_res_->CreateBitmapConverter(converter, wic_frame, GUID_WICPixelFormat32bppPBGRA,
- WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom);
-
- if (SUCCEEDED(hr))
- {
- ComPtr raw_bitmap;
- hr = d2d_res_->CreateBitmapFromConverter(raw_bitmap, nullptr, converter);
-
- if (SUCCEEDED(hr))
- {
- frame.texture = new Texture;
- frame.texture->SetBitmap(raw_bitmap);
- }
- }
- }
-
- if (SUCCEEDED(hr))
- {
- PROPVARIANT prop_val;
- PropVariantInit(&prop_val);
-
- // Get Metadata Query Reader from the frame
- ComPtr metadata_reader;
- hr = wic_frame->GetMetadataQueryReader(&metadata_reader);
-
- // Get the Metadata for the current frame
- if (SUCCEEDED(hr))
- {
- hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val);
- if (SUCCEEDED(hr))
- {
- hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
- if (SUCCEEDED(hr))
- {
- frame.rect.left_top.x = static_cast(prop_val.uiVal);
- }
- PropVariantClear(&prop_val);
- }
- }
-
- if (SUCCEEDED(hr))
- {
- hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val);
- if (SUCCEEDED(hr))
- {
- hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
- if (SUCCEEDED(hr))
- {
- frame.rect.left_top.y = static_cast(prop_val.uiVal);
- }
- PropVariantClear(&prop_val);
- }
- }
-
- if (SUCCEEDED(hr))
- {
- hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val);
- if (SUCCEEDED(hr))
- {
- hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
- if (SUCCEEDED(hr))
- {
- frame.rect.right_bottom.x = frame.rect.left_top.x + static_cast(prop_val.uiVal);
- }
- PropVariantClear(&prop_val);
- }
- }
-
- if (SUCCEEDED(hr))
- {
- hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val);
- if (SUCCEEDED(hr))
- {
- hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
- if (SUCCEEDED(hr))
- {
- frame.rect.right_bottom.y = frame.rect.left_top.y + static_cast(prop_val.uiVal);
- }
- PropVariantClear(&prop_val);
- }
- }
-
- if (SUCCEEDED(hr))
- {
- hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val);
-
- if (SUCCEEDED(hr))
- {
- hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
-
- if (SUCCEEDED(hr))
- {
- uint32_t udelay = 0;
-
- hr = UIntMult(prop_val.uiVal, 10, &udelay);
- if (SUCCEEDED(hr))
- {
- frame.delay.SetMilliseconds(static_cast(udelay));
- }
- }
- PropVariantClear(&prop_val);
- }
- else
- {
- frame.delay = 0;
- }
- }
-
- if (SUCCEEDED(hr))
- {
- hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val);
-
- if (SUCCEEDED(hr))
- {
- hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL;
- if (SUCCEEDED(hr))
- {
- frame.disposal_type = GifImage::DisposalType(prop_val.bVal);
- }
- ::PropVariantClear(&prop_val);
- }
- else
- {
- frame.disposal_type = GifImage::DisposalType::Unknown;
- }
- }
-
- ::PropVariantClear(&prop_val);
- }
- }
-
- if (FAILED(hr))
- {
- KGE_WARN(L"Load GIF frame failed with HRESULT of %08X!", hr);
- }
-}
-
-void Renderer::CreateFontCollection(Font& font, String const& file_path)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- if (!FileSystem::GetInstance().IsFileExists(file_path))
- {
- KGE_WARN(L"Font file '%s' not found!", file_path.c_str());
- hr = E_FAIL;
- }
- }
-
- if (SUCCEEDED(hr))
- {
- LPVOID key = nullptr;
- uint32_t key_size = 0;
- String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
-
- hr = font_collection_loader_->AddFilePaths({ full_path }, &key, &key_size);
-
- if (SUCCEEDED(hr))
- {
- ComPtr font_collection;
- hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(font_collection_loader_.get(), key, key_size,
- &font_collection);
-
- if (SUCCEEDED(hr))
- {
- font.SetCollection(font_collection);
- }
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateFontCollection(Font& font, Resource const& res)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- LPVOID key = nullptr;
- uint32_t key_size = 0;
-
- hr = res_font_collection_loader_->AddResources(Vector{ res }, &key, &key_size);
-
- if (SUCCEEDED(hr))
- {
- ComPtr font_collection;
- hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(res_font_collection_loader_.get(), key,
- key_size, &font_collection);
-
- if (SUCCEEDED(hr))
- {
- font.SetCollection(font_collection);
- }
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateTextFormat(TextLayout& layout)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr output;
- if (SUCCEEDED(hr))
- {
- const TextStyle& style = layout.GetStyle();
-
- hr = d2d_res_->CreateTextFormat(output, style.font_family, style.font ? style.font->GetCollection() : nullptr,
- DWRITE_FONT_WEIGHT(style.font_weight),
- style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
- DWRITE_FONT_STRETCH_NORMAL, style.font_size);
- }
-
- if (SUCCEEDED(hr))
- {
- layout.SetTextFormat(output);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateTextLayout(TextLayout& layout)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr output;
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->CreateTextLayout(output, layout.GetText(), layout.GetTextFormat());
- }
-
- if (SUCCEEDED(hr))
- {
- layout.SetTextLayout(output);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr path_geo;
- ComPtr path_sink;
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetFactory()->CreatePathGeometry(&path_geo);
- }
-
- if (SUCCEEDED(hr))
- {
- hr = path_geo->Open(&path_sink);
- }
-
- if (SUCCEEDED(hr))
- {
- path_sink->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
- path_sink->AddLine(DX::ConvertToPoint2F(end_pos));
- path_sink->EndFigure(D2D1_FIGURE_END_OPEN);
- hr = path_sink->Close();
- }
-
- if (SUCCEEDED(hr))
- {
- shape.SetGeometry(path_geo);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateRectShape(Shape& shape, Rect const& rect)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr output;
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetFactory()->CreateRectangleGeometry(DX::ConvertToRectF(rect), &output);
- }
-
- if (SUCCEEDED(hr))
- {
- shape.SetGeometry(output);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr output;
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetFactory()->CreateRoundedRectangleGeometry(
- D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), &output);
- }
-
- if (SUCCEEDED(hr))
- {
- shape.SetGeometry(output);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr output;
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetFactory()->CreateEllipseGeometry(
- D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), &output);
- }
-
- if (SUCCEEDED(hr))
- {
- shape.SetGeometry(output);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateShapeSink(ShapeSink& sink)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- ComPtr output;
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->GetFactory()->CreatePathGeometry(&output);
- }
-
- if (SUCCEEDED(hr))
- {
- sink.SetPathGeometry(output);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateTextureRenderContext(TextureRenderContext& render_context, const Size* desired_size)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr bitmap_rt;
-
- if (desired_size)
- {
- hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(DX::ConvertToSizeF(*desired_size),
- &bitmap_rt);
- }
- else
- {
- hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(&bitmap_rt);
- }
-
- if (SUCCEEDED(hr))
- {
- hr = render_context.CreateDeviceResources(d2d_res_->GetFactory(), bitmap_rt);
- }
-
- if (SUCCEEDED(hr))
- {
- render_context.SetBitmapRenderTarget(bitmap_rt);
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateBrush(Brush& brush, Color const& color)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr solid_brush;
-
- if (brush.GetType() == Brush::Type::SolidColor && brush.GetBrush())
- {
- hr = brush.GetBrush()->QueryInterface(&solid_brush);
- if (SUCCEEDED(hr))
- {
- solid_brush->SetColor(DX::ConvertToColorF(color));
- }
- }
- else
- {
- hr = d2d_res_->GetDeviceContext()->CreateSolidColorBrush(DX::ConvertToColorF(color), &solid_brush);
-
- if (SUCCEEDED(hr))
- {
- brush.SetBrush(solid_brush, Brush::Type::SolidColor);
- }
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateBrush(Brush& brush, LinearGradientStyle const& style)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr collection;
- hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
- reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
- D2D1_EXTEND_MODE(style.extend_mode), &collection);
-
- if (SUCCEEDED(hr))
- {
- ComPtr output;
- hr = d2d_res_->GetDeviceContext()->CreateLinearGradientBrush(
- D2D1::LinearGradientBrushProperties(DX::ConvertToPoint2F(style.begin), DX::ConvertToPoint2F(style.end)),
- collection.get(), &output);
-
- if (SUCCEEDED(hr))
- {
- brush.SetBrush(output, Brush::Type::LinearGradient);
- }
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateBrush(Brush& brush, RadialGradientStyle const& style)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- ComPtr collection;
- hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
- reinterpret_cast(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
- D2D1_EXTEND_MODE(style.extend_mode), &collection);
-
- if (SUCCEEDED(hr))
- {
- ComPtr output;
- hr = d2d_res_->GetDeviceContext()->CreateRadialGradientBrush(
- D2D1::RadialGradientBrushProperties(DX::ConvertToPoint2F(style.center),
- DX::ConvertToPoint2F(style.offset), style.radius.x, style.radius.y),
- collection.get(), &output);
-
- if (SUCCEEDED(hr))
- {
- brush.SetBrush(output, Brush::Type::RadialGradient);
- }
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
- const float* dash_array, size_t dash_size, float dash_offset)
-{
- HRESULT hr = S_OK;
- if (!d2d_res_)
- {
- hr = E_UNEXPECTED;
- }
-
- if (SUCCEEDED(hr))
- {
- D2D1_STROKE_STYLE_PROPERTIES style =
- D2D1::StrokeStyleProperties(D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap), D2D1_CAP_STYLE(cap),
- D2D1_LINE_JOIN(line_join), 10.0f, D2D1_DASH_STYLE_CUSTOM, dash_offset);
-
- ComPtr output;
- hr = d2d_res_->GetFactory()->CreateStrokeStyle(style, dash_array, dash_size, &output);
-
- if (SUCCEEDED(hr))
- {
- stroke_style.SetStrokeStyle(output);
- }
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::SetDpi(float dpi)
-{
- KGE_ASSERT(d3d_res_ && d2d_res_);
-
- HRESULT hr = d3d_res_->SetDpi(dpi);
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->SetDpi(dpi);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
-void Renderer::SetVSyncEnabled(bool enabled)
-{
- vsync_ = enabled;
-}
-
-void Renderer::SetClearColor(const Color& color)
-{
- clear_color_ = color;
-}
-
-void Renderer::ResizeTarget(uint32_t width, uint32_t height)
-{
- HRESULT hr = S_OK;
-
- if (!d3d_res_)
- hr = E_UNEXPECTED;
-
- if (SUCCEEDED(hr))
- {
- output_size_.x = static_cast(width);
- output_size_.y = static_cast(height);
-
- hr = d3d_res_->SetLogicalSize(output_size_);
- }
-
- if (SUCCEEDED(hr))
- {
- hr = d2d_res_->SetLogicalSize(output_size_);
- }
-
- if (SUCCEEDED(hr))
- {
- render_ctx_.Resize(output_size_);
- }
-
- win32::ThrowIfFailed(hr);
-}
-
} // namespace kiwano
diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h
index f5e9e756..c820aa7d 100644
--- a/src/kiwano/render/Renderer.h
+++ b/src/kiwano/render/Renderer.h
@@ -26,23 +26,10 @@
#include
#include
#include
-#include
-
-#if defined(KGE_USE_DIRECTX10)
-#include
-#else
-#include
-#endif
namespace kiwano
{
-#if defined(KGE_USE_DIRECTX10)
-typedef ID3D10DeviceResources ID3DDeviceResources;
-#else
-typedef ID3D11DeviceResources ID3DDeviceResources;
-#endif
-
/**
* \~chinese
* \defgroup Render 渲染引擎
@@ -57,137 +44,127 @@ typedef ID3D11DeviceResources ID3DDeviceResources;
* \~chinese
* @brief 渲染器
*/
-class KGE_API Renderer
- : public Singleton
- , public EventComponent
+class KGE_API Renderer : public EventComponent
{
- friend Singleton;
-
public:
+ /// \~chinese
+ /// @brief 获取实例
+ static Renderer& GetInstance();
+
/// \~chinese
/// @brief 获取清屏颜色
- Color const& GetClearColor() const;
+ virtual Color GetClearColor() const;
/// \~chinese
/// @brief 设置清屏颜色
- void SetClearColor(Color const& clear_color);
+ virtual void SetClearColor(Color const& clear_color);
/// \~chinese
/// @brief 开启或关闭垂直同步
- void SetVSyncEnabled(bool enabled);
-
- /// \~chinese
- /// @brief 设置DPI
- void SetDpi(float dpi);
+ virtual void SetVSyncEnabled(bool enabled);
/// \~chinese
/// @brief 创建纹理
/// @param[out] texture 纹理
/// @param[in] file_path 图片路径
- void CreateTexture(Texture& texture, String const& file_path);
+ virtual void CreateTexture(Texture& texture, String const& file_path) = 0;
/// \~chinese
/// @brief 创建纹理
/// @param[out] texture 纹理
/// @param[in] resource 图片资源
- void CreateTexture(Texture& texture, Resource const& resource);
+ virtual void CreateTexture(Texture& texture, Resource const& resource) = 0;
/// \~chinese
/// @brief 创建GIF图像
/// @param[out] gif GIF图像
/// @param[in] file_path 图片路径
- void CreateGifImage(GifImage& gif, String const& file_path);
+ virtual void CreateGifImage(GifImage& gif, String const& file_path) = 0;
/// \~chinese
/// @brief 创建GIF图像
/// @param[out] gif GIF图像
/// @param[in] resource 图片资源
- void CreateGifImage(GifImage& gif, Resource const& resource);
+ virtual void CreateGifImage(GifImage& gif, Resource const& resource) = 0;
/// \~chinese
/// @brief 创建GIF图像帧
/// @param[out] frame GIF图像帧
/// @param[in] gif GIF图像
/// @param[in] frame_index 帧下标
- void CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index);
+ virtual void CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index) = 0;
/// \~chinese
/// @brief 创建字体集
/// @param[out] font 字体
/// @param[in] file_paths 字体文件路径
- void CreateFontCollection(Font& font, String const& file_path);
+ virtual void CreateFontCollection(Font& font, String const& file_path) = 0;
/// \~chinese
/// @brief 创建字体集
/// @param[out] font 字体
/// @param[in] res_arr 字体资源
- void CreateFontCollection(Font& font, Resource const& res);
+ virtual void CreateFontCollection(Font& font, Resource const& res) = 0;
/// \~chinese
/// @brief 创建文字格式
/// @param[out] layout 字体布局
- void CreateTextFormat(TextLayout& layout);
+ virtual void CreateTextFormat(TextLayout& layout) = 0;
/// \~chinese
/// @brief 创建文字布局
/// @param[out] layout 字体布局
- void CreateTextLayout(TextLayout& layout);
+ virtual void CreateTextLayout(TextLayout& layout) = 0;
/// \~chinese
/// @brief 创建线段形状
/// @param[out] geo 形状
/// @param[in] begin_pos 线段起点
/// @param[in] end_pos 线段终点
- void CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos);
+ virtual void CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos) = 0;
/// \~chinese
/// @brief 创建矩形形状
/// @param[out] geo 形状
/// @param[in] rect 矩形大小
- void CreateRectShape(Shape& shape, Rect const& rect);
+ virtual void CreateRectShape(Shape& shape, Rect const& rect) = 0;
/// \~chinese
/// @brief 创建圆角矩形形状
/// @param[out] geo 形状
/// @param[in] rect 矩形大小
/// @param[in] radius 圆角半径
- void CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius);
+ virtual void CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius) = 0;
/// \~chinese
/// @brief 创建椭圆形状
/// @param[out] geo 形状
/// @param[in] center 椭圆圆心
/// @param[in] radius 椭圆半径
- void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius);
+ virtual void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius) = 0;
/// \~chinese
/// @brief 创建几何图形生成器
/// @param[out] sink 形状生成器
- void CreateShapeSink(ShapeSink& sink);
-
- /// \~chinese
- /// @brief 创建纹理渲染上下文
- /// @param[out] render_context 渲染上下文
- /// @param[in] desired_size 期望的输出大小
- void CreateTextureRenderContext(TextureRenderContext& render_context, const Size* desired_size = nullptr);
+ virtual void CreateShapeSink(ShapeSink& sink) = 0;
/// \~chinese
/// @brief 创建纯色画刷
/// @param[out] brush 画刷
/// @param[in] color 颜色
- void CreateBrush(Brush& brush, Color const& color);
+ virtual void CreateBrush(Brush& brush, Color const& color) = 0;
/// \~chinese
/// @brief 创建线性渐变画刷
/// @param[out] brush 画刷
/// @param[in] style 线性渐变样式
- void CreateBrush(Brush& brush, LinearGradientStyle const& style);
+ virtual void CreateBrush(Brush& brush, LinearGradientStyle const& style) = 0;
/// \~chinese
/// @brief 创建径向渐变画刷
/// @param[out] brush 画刷
/// @param[in] style 径向渐变样式
- void CreateBrush(Brush& brush, RadialGradientStyle const& style);
+ virtual void CreateBrush(Brush& brush, RadialGradientStyle const& style) = 0;
/// \~chinese
/// @brief 创建线条样式
@@ -197,74 +174,52 @@ public:
/// @param[in] dash_array 虚线长度与间隙数组
/// @param[in] dash_size 虚线数组大小
/// @param[in] dash_offset 虚线偏移量
- void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, const float* dash_array,
- size_t dash_size, float dash_offset);
+ virtual void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
+ const float* dash_array, size_t dash_size, float dash_offset) = 0;
+
+ /// \~chinese
+ /// @brief 创建纹理渲染上下文
+ /// @param[in] desired_size 期望的输出大小
+ /// @return 纹理渲染上下文
+ virtual TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr) = 0;
public:
/// \~chinese
/// @brief 开始渲染
- void BeginDraw();
+ virtual void BeginDraw() = 0;
/// \~chinese
/// @brief 结束渲染
- void EndDraw();
+ virtual void EndDraw() = 0;
/// \~chinese
/// @brief 清除绘制内容
- void Clear();
+ virtual void Clear() = 0;
/// \~chinese
/// @brief 将绘制内容呈现至窗口
- void Present();
+ virtual void Present() = 0;
/// \~chinese
/// @brief 获取渲染上下文
- RenderContext& GetContext();
+ virtual RenderContext& GetContext() = 0;
/// \~chinese
/// @brief 获取目标窗口
- WindowHandle GetTargetWindow() const;
+ virtual WindowHandle GetTargetWindow() const;
/// \~chinese
/// @brief 获取渲染输出大小
- Size const& GetOutputSize() const;
+ virtual Size GetOutputSize() const;
- /// \~chinese
- /// @brief 获取Direct2D设备资源
- ID2DDeviceResources* GetD2DDeviceResources();
-
- /// \~chinese
- /// @brief 获取Direct3D设备资源
- ID3DDeviceResources* GetD3DDeviceResources();
-
-public:
- void SetupComponent() override;
-
- void DestroyComponent() override;
-
- void HandleEvent(Event* evt) override;
-
-private:
+protected:
Renderer();
- ~Renderer();
-
- HRESULT HandleDeviceLost();
-
- void ResizeTarget(uint32_t width, uint32_t height);
-
-private:
- bool vsync_;
- WindowHandle target_window_;
- Color clear_color_;
- Size output_size_;
- RenderContext render_ctx_;
-
- ComPtr d2d_res_;
- ComPtr d3d_res_;
- ComPtr font_collection_loader_;
- ComPtr res_font_file_loader_;
- ComPtr res_font_collection_loader_;
+protected:
+ bool vsync_;
+ WindowHandle target_window_;
+ Color clear_color_;
+ Size output_size_;
};
/** @} */
@@ -274,30 +229,24 @@ inline WindowHandle Renderer::GetTargetWindow() const
return target_window_;
}
-inline Size const& Renderer::GetOutputSize() const
+inline Size Renderer::GetOutputSize() const
{
return output_size_;
}
-inline Color const& Renderer::GetClearColor() const
+inline Color Renderer::GetClearColor() const
{
return clear_color_;
}
-inline RenderContext& Renderer::GetContext()
+inline void Renderer::SetVSyncEnabled(bool enabled)
{
- return render_ctx_;
+ vsync_ = enabled;
}
-inline ID2DDeviceResources* Renderer::GetD2DDeviceResources()
+inline void Renderer::SetClearColor(const Color& color)
{
- KGE_ASSERT(d2d_res_);
- return d2d_res_.get();
+ clear_color_ = color;
}
-inline ID3DDeviceResources* Renderer::GetD3DDeviceResources()
-{
- KGE_ASSERT(d3d_res_);
- return d3d_res_.get();
-}
} // namespace kiwano
diff --git a/src/kiwano/render/Shape.h b/src/kiwano/render/Shape.h
index 85930f9a..768bfba8 100644
--- a/src/kiwano/render/Shape.h
+++ b/src/kiwano/render/Shape.h
@@ -24,8 +24,6 @@
namespace kiwano
{
-class RenderContext;
-class Renderer;
class ShapeSink;
KGE_DECLARE_SMART_PTR(Shape);
@@ -41,8 +39,6 @@ KGE_DECLARE_SMART_PTR(Shape);
*/
class KGE_API Shape : public virtual ObjectBase
{
- friend class RenderContext;
- friend class Renderer;
friend class ShapeSink;
public:
@@ -116,7 +112,7 @@ public:
void Clear();
#if defined(KGE_WIN32)
-private:
+public:
ComPtr GetGeometry() const;
void SetGeometry(ComPtr shape);
diff --git a/src/kiwano/render/ShapeSink.h b/src/kiwano/render/ShapeSink.h
index 1cccf39c..280b09cc 100644
--- a/src/kiwano/render/ShapeSink.h
+++ b/src/kiwano/render/ShapeSink.h
@@ -23,8 +23,6 @@
namespace kiwano
{
-class RenderContext;
-class Renderer;
/**
* \addtogroup Render
@@ -45,8 +43,6 @@ enum class CombineMode
/// @brief 形状生成器
class KGE_API ShapeSink : protected Noncopyable
{
- friend class Renderer;
-
public:
ShapeSink();
@@ -137,7 +133,7 @@ private:
ShapePtr shape_;
#if defined(KGE_WIN32)
-private:
+public:
ComPtr GetPathGeometry() const;
void SetPathGeometry(ComPtr path);
@@ -146,6 +142,7 @@ private:
void SetGeometrySink(ComPtr sink);
+private:
ComPtr sink_;
ComPtr path_geo_;
#endif
diff --git a/src/kiwano/render/StrokeStyle.h b/src/kiwano/render/StrokeStyle.h
index ec104f95..f4da804c 100644
--- a/src/kiwano/render/StrokeStyle.h
+++ b/src/kiwano/render/StrokeStyle.h
@@ -24,8 +24,6 @@
namespace kiwano
{
-class RenderContext;
-class Renderer;
KGE_DECLARE_SMART_PTR(StrokeStyle);
@@ -71,9 +69,6 @@ enum class DashStyle
/// @brief 线条样式
class StrokeStyle : public virtual ObjectBase
{
- friend class RenderContext;
- friend class Renderer;
-
public:
/// \~chinese
/// @brief 创建线条样式
@@ -115,7 +110,7 @@ public:
bool IsValid() const;
#if defined(KGE_WIN32)
-private:
+public:
ComPtr GetStrokeStyle() const;
void SetStrokeStyle(ComPtr style);
diff --git a/src/kiwano/render/TextLayout.h b/src/kiwano/render/TextLayout.h
index 1f01f241..0652b98d 100644
--- a/src/kiwano/render/TextLayout.h
+++ b/src/kiwano/render/TextLayout.h
@@ -24,8 +24,6 @@
namespace kiwano
{
-class RenderContext;
-class Renderer;
/**
* \addtogroup Render
@@ -36,9 +34,6 @@ class Renderer;
/// @brief 文本布局
class KGE_API TextLayout
{
- friend class RenderContext;
- friend class Renderer;
-
public:
/// \~chinese
/// @brief 构造空的文本布局
@@ -165,8 +160,13 @@ public:
void SetDirtyFlag(uint8_t flag);
-#if defined(KGE_WIN32)
private:
+ uint8_t dirty_flag_;
+ String text_;
+ TextStyle style_;
+
+#if defined(KGE_WIN32)
+public:
ComPtr GetTextFormat() const;
void SetTextFormat(ComPtr format);
@@ -175,15 +175,10 @@ private:
void SetTextLayout(ComPtr layout);
+private:
ComPtr text_format_;
ComPtr text_layout_;
#endif
-
-private:
- uint8_t dirty_flag_;
-
- String text_;
- TextStyle style_;
};
/** @} */
diff --git a/src/kiwano/render/Texture.cpp b/src/kiwano/render/Texture.cpp
index 4c9248fa..219f7dc6 100644
--- a/src/kiwano/render/Texture.cpp
+++ b/src/kiwano/render/Texture.cpp
@@ -181,15 +181,6 @@ InterpolationMode Texture::GetDefaultInterpolationMode()
}
#if defined(KGE_WIN32)
-D2D1_PIXEL_FORMAT Texture::GetPixelFormat() const
-{
- if (bitmap_)
- {
- return bitmap_->GetPixelFormat();
- }
- return D2D1_PIXEL_FORMAT();
-}
-
ComPtr Texture::GetBitmap() const
{
return bitmap_;
diff --git a/src/kiwano/render/Texture.h b/src/kiwano/render/Texture.h
index 715a32df..fada3dce 100644
--- a/src/kiwano/render/Texture.h
+++ b/src/kiwano/render/Texture.h
@@ -24,9 +24,6 @@
namespace kiwano
{
-class RenderContext;
-class TextureRenderContext;
-class Renderer;
KGE_DECLARE_SMART_PTR(Texture);
@@ -52,10 +49,6 @@ enum class InterpolationMode
*/
class KGE_API Texture : public virtual ObjectBase
{
- friend class RenderContext;
- friend class TextureRenderContext;
- friend class Renderer;
-
public:
/// \~chinese
/// @brief 从本地文件创建纹理
@@ -133,8 +126,13 @@ public:
/// @brief 获取默认的像素插值方式
static InterpolationMode GetDefaultInterpolationMode();
-#if defined(KGE_WIN32)
private:
+ InterpolationMode interpolation_mode_;
+
+ static InterpolationMode default_interpolation_mode_;
+
+#if defined(KGE_WIN32)
+public:
/// \~chinese
/// @brief 获取源位图
ComPtr GetBitmap() const;
@@ -143,17 +141,9 @@ private:
/// @brief 设置源位图
void SetBitmap(ComPtr bitmap);
- /// \~chinese
- /// @brief 获取像素格式
- D2D1_PIXEL_FORMAT GetPixelFormat() const;
-
+private:
ComPtr bitmap_;
#endif
-
-private:
- InterpolationMode interpolation_mode_;
-
- static InterpolationMode default_interpolation_mode_;
};
/** @} */
diff --git a/src/kiwano/render/TextureRenderContext.cpp b/src/kiwano/render/TextureRenderContext.cpp
index f2995b8c..19e6bc62 100644
--- a/src/kiwano/render/TextureRenderContext.cpp
+++ b/src/kiwano/render/TextureRenderContext.cpp
@@ -27,56 +27,30 @@ namespace kiwano
TextureRenderContextPtr TextureRenderContext::Create()
{
- TextureRenderContextPtr ptr = new TextureRenderContext;
- if (ptr)
+ TextureRenderContextPtr ptr;
+ try
{
- try
- {
- Renderer::GetInstance().CreateTextureRenderContext(*ptr);
- }
- catch (std::exception)
- {
- return nullptr;
- }
+ ptr = Renderer::GetInstance().CreateTextureRenderContext(nullptr);
+ }
+ catch (std::exception&)
+ {
+ return nullptr;
}
return ptr;
}
TextureRenderContextPtr TextureRenderContext::Create(Size const& desired_size)
{
- TextureRenderContextPtr ptr = new TextureRenderContext;
- if (ptr)
+ TextureRenderContextPtr ptr;
+ try
{
- try
- {
- Renderer::GetInstance().CreateTextureRenderContext(*ptr, &desired_size);
- }
- catch (std::exception)
- {
- return nullptr;
- }
+ ptr = Renderer::GetInstance().CreateTextureRenderContext(&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
index ed412152..27746a06 100644
--- a/src/kiwano/render/TextureRenderContext.h
+++ b/src/kiwano/render/TextureRenderContext.h
@@ -23,8 +23,6 @@
namespace kiwano
{
-class Renderer;
-
KGE_DECLARE_SMART_PTR(TextureRenderContext);
/**
@@ -35,10 +33,8 @@ KGE_DECLARE_SMART_PTR(TextureRenderContext);
/// \~chinese
/// @brief 纹理渲染上下文
/// @details 纹理渲染上下文将渲染输出到一个纹理对象中
-class KGE_API TextureRenderContext : public RenderContext
+class KGE_API TextureRenderContext : public virtual RenderContext
{
- friend class Renderer;
-
public:
/// \~chinese
/// @brief 创建纹理渲染上下文
@@ -49,41 +45,13 @@ public:
/// @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_;
+ virtual bool GetOutput(Texture& texture) = 0;
};
/** @} */
-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