Made Renderer, RenderContext, TextureRenderContext to be interface

This commit is contained in:
Nomango 2020-02-09 18:41:59 +08:00
parent 4633d7b6b9
commit d302ec3a20
30 changed files with 2158 additions and 1828 deletions

View File

@ -62,6 +62,7 @@
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" /> <ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h" /> <ClInclude Include="..\..\src\kiwano\platform\win32\helper.h" />
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" /> <ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" />
<ClInclude Include="..\..\src\kiwano\platform\win32\WindowImpl.h" />
<ClInclude Include="..\..\src\kiwano\platform\Window.h" /> <ClInclude Include="..\..\src\kiwano\platform\Window.h" />
<ClInclude Include="..\..\src\kiwano\render\Brush.h" /> <ClInclude Include="..\..\src\kiwano\render\Brush.h" />
<ClInclude Include="..\..\src\kiwano\render\Color.h" /> <ClInclude Include="..\..\src\kiwano\render\Color.h" />
@ -71,7 +72,10 @@
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\RendererImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" /> <ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.h" />
<ClInclude Include="..\..\src\kiwano\render\Font.h" /> <ClInclude Include="..\..\src\kiwano\render\Font.h" />
<ClInclude Include="..\..\src\kiwano\render\Shape.h" /> <ClInclude Include="..\..\src\kiwano\render\Shape.h" />
<ClInclude Include="..\..\src\kiwano\render\ShapeSink.h" /> <ClInclude Include="..\..\src\kiwano\render\ShapeSink.h" />
@ -140,7 +144,10 @@
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.cpp" /> <ClCompile Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.cpp" /> <ClCompile Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.cpp" /> <ClCompile Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\RendererImpl.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextRenderer.cpp" /> <ClCompile Include="..\..\src\kiwano\render\DirectX\TextRenderer.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Font.cpp" /> <ClCompile Include="..\..\src\kiwano\render\Font.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Shape.cpp" /> <ClCompile Include="..\..\src\kiwano\render\Shape.cpp" />
<ClCompile Include="..\..\src\kiwano\render\ShapeSink.cpp" /> <ClCompile Include="..\..\src\kiwano\render\ShapeSink.cpp" />

View File

@ -288,6 +288,18 @@
<ClInclude Include="..\..\src\kiwano\render\TextureRenderContext.h"> <ClInclude Include="..\..\src\kiwano\render\TextureRenderContext.h">
<Filter>render</Filter> <Filter>render</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.h">
<Filter>render\DirectX</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.h">
<Filter>render\DirectX</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\DirectX\RendererImpl.h">
<Filter>render\DirectX</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\win32\WindowImpl.h">
<Filter>platform\win32</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
@ -488,5 +500,14 @@
<ClCompile Include="..\..\src\kiwano\render\TextureRenderContext.cpp"> <ClCompile Include="..\..\src\kiwano\render\TextureRenderContext.cpp">
<Filter>render</Filter> <Filter>render</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.cpp">
<Filter>render\DirectX</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextureRenderContextImpl.cpp">
<Filter>render\DirectX</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\DirectX\RendererImpl.cpp">
<Filter>render\DirectX</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -58,7 +58,7 @@ void ImGuiModule::SetupComponent()
io.KeyMap[ImGuiKey_Y] = (int)KeyCode::Y; io.KeyMap[ImGuiKey_Y] = (int)KeyCode::Y;
io.KeyMap[ImGuiKey_Z] = (int)KeyCode::Z; io.KeyMap[ImGuiKey_Z] = (int)KeyCode::Z;
ImGui_Impl_Init(Renderer::GetInstance()); ImGui_Impl_Init();
} }
void ImGuiModule::DestroyComponent() void ImGuiModule::DestroyComponent()

View File

@ -7,20 +7,25 @@
#if !defined(KGE_USE_DIRECTX10) #if !defined(KGE_USE_DIRECTX10)
#include <kiwano-imgui/imgui_impl_dx11.h> #include <kiwano-imgui/imgui_impl_dx11.h>
#include <kiwano/render/DirectX/RendererImpl.h>
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(), return ImGui_ImplDX11_Init(renderer.GetD3DDeviceResources()->GetDevice(),
renderer.GetD3DDeviceResources()->GetDeviceContext()); renderer.GetD3DDeviceResources()->GetDeviceContext());
} }
inline void ImGui_Impl_Shutdown() inline void ImGui_Impl_Shutdown()
{ {
ImGui_ImplDX11_Shutdown(); ImGui_ImplDX11_Shutdown();
} }
inline void ImGui_Impl_NewFrame() inline void ImGui_Impl_NewFrame()
{ {
ImGui_ImplDX11_NewFrame(); ImGui_ImplDX11_NewFrame();
} }
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data) inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data)
{ {
ImGui_ImplDX11_RenderDrawData(draw_data); ImGui_ImplDX11_RenderDrawData(draw_data);
@ -30,6 +35,7 @@ inline void ImGui_Impl_InvalidateDeviceObjects()
{ {
ImGui_ImplDX11_InvalidateDeviceObjects(); ImGui_ImplDX11_InvalidateDeviceObjects();
} }
inline bool ImGui_Impl_CreateDeviceObjects() inline bool ImGui_Impl_CreateDeviceObjects()
{ {
return ImGui_ImplDX11_CreateDeviceObjects(); return ImGui_ImplDX11_CreateDeviceObjects();
@ -39,18 +45,22 @@ inline bool ImGui_Impl_CreateDeviceObjects()
#include <kiwano-imgui/imgui_impl_dx10.h> #include <kiwano-imgui/imgui_impl_dx10.h>
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()); return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice());
} }
inline void ImGui_Impl_Shutdown() inline void ImGui_Impl_Shutdown()
{ {
ImGui_ImplDX10_Shutdown(); ImGui_ImplDX10_Shutdown();
} }
inline void ImGui_Impl_NewFrame() inline void ImGui_Impl_NewFrame()
{ {
ImGui_ImplDX10_NewFrame(); ImGui_ImplDX10_NewFrame();
} }
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data) inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data)
{ {
ImGui_ImplDX10_RenderDrawData(draw_data); ImGui_ImplDX10_RenderDrawData(draw_data);
@ -60,6 +70,7 @@ inline void ImGui_Impl_InvalidateDeviceObjects()
{ {
ImGui_ImplDX10_InvalidateDeviceObjects(); ImGui_ImplDX10_InvalidateDeviceObjects();
} }
inline bool ImGui_Impl_CreateDeviceObjects() inline bool ImGui_Impl_CreateDeviceObjects()
{ {
return ImGui_ImplDX10_CreateDeviceObjects(); return ImGui_ImplDX10_CreateDeviceObjects();

View File

@ -35,6 +35,8 @@ CanvasPtr Canvas::Create(Size const& size)
ptr->ctx_ = TextureRenderContext::Create(); ptr->ctx_ = TextureRenderContext::Create();
ptr->stroke_brush_ = Brush::Create(Color::White); ptr->stroke_brush_ = Brush::Create(Color::White);
ptr->fill_brush_ = Brush::Create(Color::White); ptr->fill_brush_ = Brush::Create(Color::White);
ptr->SetSize(ptr->ctx_->GetSize());
} }
catch (std::exception) catch (std::exception)
{ {
@ -71,9 +73,7 @@ void Canvas::OnRender(RenderContext& ctx)
if (texture_cached_ && texture_cached_->IsValid()) if (texture_cached_ && texture_cached_->IsValid())
{ {
PrepareToRender(ctx); PrepareToRender(ctx);
ctx.DrawTexture(*texture_cached_, nullptr, &GetBounds());
Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight());
ctx.DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect);
} }
} }

View File

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/platform/Window.h> #include <kiwano/platform/win32/WindowImpl.h>
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
@ -38,8 +38,19 @@
namespace kiwano namespace kiwano
{ {
namespace win32
Window& Window::GetInstance()
{ {
return WindowImpl::GetInstance();
}
WindowImpl& WindowImpl::GetInstance()
{
static WindowImpl instance;
return instance;
}
namespace namespace
{ {
MONITORINFOEX GetMoniterInfoEx(HWND hwnd) MONITORINFOEX GetMoniterInfoEx(HWND hwnd)
@ -96,51 +107,6 @@ void RestoreResolution(WCHAR* device_name)
} }
} // namespace } // 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<KeyCode, 256> key_map_;
};
WindowImpl::WindowImpl() WindowImpl::WindowImpl()
: handle_(nullptr) : handle_(nullptr)
, device_name_(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); return ::DefWindowProcW(hwnd, msg, wparam, lparam);
} }
} // namespace win32
} // namespace kiwano
namespace kiwano
{
Window& Window::GetInstance()
{
static win32::WindowImpl instance;
return instance;
}
} // namespace kiwano } // namespace kiwano
#endif #endif

View File

@ -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 <kiwano/platform/Window.h>
#include <kiwano/core/Keys.h>
#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<KeyCode, 256> key_map_;
};
} // namespace kiwano
#endif

View File

@ -86,8 +86,7 @@ BrushPtr Brush::Create(RadialGradientStyle const& style)
} }
Brush::Brush() Brush::Brush()
: opacity_(1.f) : type_(Type::Unknown)
, type_(Type::Unknown)
{ {
} }
@ -96,20 +95,6 @@ bool Brush::IsValid() const
return raw_ != nullptr; 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) void Brush::SetColor(Color const& color)
{ {
Renderer::GetInstance().CreateBrush(*this, color); Renderer::GetInstance().CreateBrush(*this, color);

View File

@ -24,8 +24,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
class Renderer;
KGE_DECLARE_SMART_PTR(Brush); KGE_DECLARE_SMART_PTR(Brush);
@ -89,9 +87,6 @@ struct RadialGradientStyle
*/ */
class KGE_API Brush : public virtual ObjectBase class KGE_API Brush : public virtual ObjectBase
{ {
friend class RenderContext;
friend class Renderer;
public: public:
/// \~chinese /// \~chinese
/// @brief ´´½¨´¿É«»­Ë¢ /// @brief ´´½¨´¿É«»­Ë¢
@ -141,24 +136,16 @@ public:
/// @brief »ñÈ¡»­Ë¢ÀàÐÍ /// @brief »ñÈ¡»­Ë¢ÀàÐÍ
Type GetType() const; Type GetType() const;
private:
/// \~chinese
/// @brief »ñȡ͸Ã÷¶È
float GetOpacity() const;
/// \~chinese
/// @brief ÉèÖÃ͸Ã÷¶È
void SetOpacity(float opacity);
private: private:
Type type_; Type type_;
float opacity_;
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
public:
void SetBrush(ComPtr<ID2D1Brush> brush, Type type); void SetBrush(ComPtr<ID2D1Brush> brush, Type type);
ComPtr<ID2D1Brush> GetBrush() const; ComPtr<ID2D1Brush> GetBrush() const;
private:
ComPtr<ID2D1Brush> raw_; ComPtr<ID2D1Brush> raw_;
#endif #endif
}; };
@ -175,10 +162,6 @@ inline void Brush::SetBrush(ComPtr<ID2D1Brush> brush, Type type)
{ {
type_ = type; type_ = type;
raw_ = brush; raw_ = brush;
if (raw_)
{
raw_->SetOpacity(opacity_);
}
} }
inline ComPtr<ID2D1Brush> Brush::GetBrush() const inline ComPtr<ID2D1Brush> Brush::GetBrush() const

View File

@ -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 <kiwano/core/Logger.h>
#include <kiwano/render/DirectX/RenderContextImpl.h>
namespace kiwano
{
RenderContextImpl::RenderContextImpl()
{}
RenderContextImpl::~RenderContextImpl()
{
DiscardDeviceResources();
}
HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> 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<const Size&>(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<ID2D1Brush> fill_brush;
ComPtr<ID2D1Brush> 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<uint32_t> size)
{
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
ComPtr<ID2D1Bitmap> 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<ID2D1Layer> output;
HRESULT hr = render_target_->CreateLayer(&output);
if (SUCCEEDED(hr))
{
layer.SetLayer(output);
}
else
{
win32::ThrowIfFailed(hr);
}
}
if (layer.IsValid())
{
ComPtr<ID2D1Geometry> 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<const Size&>(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

View File

@ -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 <kiwano/render/RenderContext.h>
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<uint32_t> 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<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> ctx);
void DiscardDeviceResources();
void SaveDrawingState();
void RestoreDrawingState();
protected:
ComPtr<ITextRenderer> text_renderer_;
ComPtr<ID2D1RenderTarget> render_target_;
ComPtr<ID2D1DrawingStateBlock> drawing_state_;
};
} // namespace kiwano

View File

@ -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 <kiwano/core/Logger.h>
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/platform/FileSystem.h>
#include <kiwano/render/ShapeSink.h>
#include <kiwano/render/DirectX/TextureRenderContextImpl.h>
#include <kiwano/render/DirectX/RendererImpl.h>
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<WindowResizedEvent>())
{
auto window_evt = dynamic_cast<WindowResizedEvent*>(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<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
if (SUCCEEDED(hr))
{
ComPtr<IWICBitmapFrameDecode> source;
hr = decoder->GetFrame(0, &source);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, nullptr, 0.f,
WICBitmapPaletteTypeMedianCut);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> 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<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
if (SUCCEEDED(hr))
{
ComPtr<IWICBitmapFrameDecode> source;
hr = decoder->GetFrame(0, &source);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, nullptr, 0.f,
WICBitmapPaletteTypeMedianCut);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> 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<IWICBitmapDecoder> 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<IWICBitmapDecoder> 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<IWICBitmapFrameDecode> wic_frame;
HRESULT hr = gif.GetDecoder()->GetFrame(UINT(frame_index), &wic_frame);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
d2d_res_->CreateBitmapConverter(converter, wic_frame, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> 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<IWICMetadataQueryReader> 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<float>(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<float>(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<float>(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<float>(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<long>(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<IDWriteFontCollection> 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<Resource>{ res }, &key, &key_size);
if (SUCCEEDED(hr))
{
ComPtr<IDWriteFontCollection> 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<IDWriteTextFormat> 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<IDWriteTextLayout> 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<ID2D1PathGeometry> path_geo;
ComPtr<ID2D1GeometrySink> 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<ID2D1RectangleGeometry> 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<ID2D1RoundedRectangleGeometry> 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<ID2D1EllipseGeometry> 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<ID2D1PathGeometry> 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<ID2D1BitmapRenderTarget> 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<ID2D1SolidColorBrush> 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<ID2D1GradientStopCollection> collection;
hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
reinterpret_cast<const D2D1_GRADIENT_STOP*>(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE(style.extend_mode), &collection);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1LinearGradientBrush> 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<ID2D1GradientStopCollection> collection;
hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
reinterpret_cast<const D2D1_GRADIENT_STOP*>(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE(style.extend_mode), &collection);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1RadialGradientBrush> 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<ID2D1StrokeStyle> 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<float>(width);
output_size_.y = static_cast<float>(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

View File

@ -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 <kiwano/render/Renderer.h>
#include <kiwano/render/DirectX/FontCollectionLoader.h>
#include <kiwano/render/DirectX/RenderContextImpl.h>
#if defined(KGE_USE_DIRECTX10)
#include <kiwano/render/DirectX/D3D10DeviceResources.h>
#else
#include <kiwano/render/DirectX/D3D11DeviceResources.h>
#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<ID2DDeviceResources> d2d_res_;
ComPtr<ID3DDeviceResources> d3d_res_;
ComPtr<IFontCollectionLoader> font_collection_loader_;
ComPtr<IResourceFontFileLoader> res_font_file_loader_;
ComPtr<IResourceFontCollectionLoader> 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

View File

@ -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 <kiwano/core/Logger.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/render/DirectX/TextureRenderContextImpl.h>
namespace kiwano
{
bool TextureRenderContextImpl::GetOutput(Texture& texture)
{
HRESULT hr = E_FAIL;
if (bitmap_rt_)
{
ComPtr<ID2D1Bitmap> bitmap;
hr = bitmap_rt_->GetBitmap(&bitmap);
if (SUCCEEDED(hr))
{
texture.SetBitmap(bitmap);
}
}
return SUCCEEDED(hr);
}
} // namespace kiwano

View File

@ -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 <kiwano/render/TextureRenderContext.h>
#include <kiwano/render/DirectX/RenderContextImpl.h>
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<ID2D1BitmapRenderTarget> bitmap_rt_;
};
KGE_SUPPRESS_WARNING_POP
} // namespace kiwano

View File

@ -63,11 +63,12 @@ public:
bool Load(Resource const& resource); bool Load(Resource const& resource);
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
private: public:
ComPtr<IDWriteFontCollection> GetCollection() const; ComPtr<IDWriteFontCollection> GetCollection() const;
void SetCollection(ComPtr<IDWriteFontCollection> collection); void SetCollection(ComPtr<IDWriteFontCollection> collection);
private:
ComPtr<IDWriteFontCollection> collection_; ComPtr<IDWriteFontCollection> collection_;
#endif #endif
}; };

View File

@ -24,8 +24,6 @@
namespace kiwano namespace kiwano
{ {
class Renderer;
KGE_DECLARE_SMART_PTR(GifImage); KGE_DECLARE_SMART_PTR(GifImage);
/** /**
@ -39,8 +37,6 @@ KGE_DECLARE_SMART_PTR(GifImage);
*/ */
class KGE_API GifImage : public virtual ObjectBase class KGE_API GifImage : public virtual ObjectBase
{ {
friend class Renderer;
public: public:
/// \~chinese /// \~chinese
/// @brief ´´½¨GIFͼƬ /// @brief ´´½¨GIFͼƬ
@ -113,10 +109,12 @@ private:
uint32_t height_in_pixels_; uint32_t height_in_pixels_;
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
public:
ComPtr<IWICBitmapDecoder> GetDecoder() const; ComPtr<IWICBitmapDecoder> GetDecoder() const;
void SetDecoder(ComPtr<IWICBitmapDecoder> decoder); void SetDecoder(ComPtr<IWICBitmapDecoder> decoder);
private:
ComPtr<IWICBitmapDecoder> decoder_; ComPtr<IWICBitmapDecoder> decoder_;
#endif #endif
}; };

View File

@ -23,7 +23,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
/** /**
* \addtogroup Render * \addtogroup Render
@ -36,8 +35,6 @@ class RenderContext;
*/ */
class KGE_API LayerArea class KGE_API LayerArea
{ {
friend class RenderContext;
public: public:
LayerArea(); LayerArea();
@ -84,10 +81,12 @@ private:
Matrix3x2 mask_transform_; Matrix3x2 mask_transform_;
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
public:
ComPtr<ID2D1Layer> GetLayer() const; ComPtr<ID2D1Layer> GetLayer() const;
void SetLayer(ComPtr<ID2D1Layer> layer); void SetLayer(ComPtr<ID2D1Layer> layer);
private:
ComPtr<ID2D1Layer> layer_; ComPtr<ID2D1Layer> layer_;
#endif #endif
}; };

View File

@ -18,7 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <kiwano/render/RenderContext.h> #include <kiwano/render/RenderContext.h>
namespace kiwano namespace kiwano
@ -31,47 +30,6 @@ RenderContext::RenderContext()
, antialias_(true) , antialias_(true)
, text_antialias_(TextAntialiasMode::GrayScale) , text_antialias_(TextAntialiasMode::GrayScale)
{ {
status_.primitives = 0;
}
HRESULT RenderContext::CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> 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<const Size&>(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() void RenderContext::BeginDraw()
@ -81,340 +39,16 @@ void RenderContext::BeginDraw()
status_.start = Time::Now(); status_.start = Time::Now();
status_.primitives = 0; status_.primitives = 0;
} }
if (render_target_)
{
render_target_->BeginDraw();
}
} }
void RenderContext::EndDraw() void RenderContext::EndDraw()
{ {
win32::ThrowIfFailed(render_target_->EndDraw());
if (collecting_status_) if (collecting_status_)
{ {
status_.duration = Time::Now() - status_.start; 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<ID2D1Brush> fill_brush;
ComPtr<ID2D1Brush> 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<uint32_t> size)
{
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
ComPtr<ID2D1Bitmap> 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<ID2D1Layer> output;
HRESULT hr = render_target_->CreateLayer(&output);
if (SUCCEEDED(hr))
{
layer.SetLayer(output);
}
else
{
win32::ThrowIfFailed(hr);
}
}
if (layer.IsValid())
{
ComPtr<ID2D1Geometry> 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<const Size&>(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) void RenderContext::SetGlobalTransform(const Matrix3x2* matrix)
{ {
if (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) void RenderContext::SetCollectingStatus(bool enable)
{ {
collecting_status_ = 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()); return brush_opacity_;
if (drawing_state_)
{
render_target_->SaveDrawingState(drawing_state_.get());
}
} }
void RenderContext::RestoreDrawingState() BrushPtr RenderContext::GetCurrentBrush() const
{ {
KGE_ASSERT(IsValid()); return current_brush_;
}
if (drawing_state_) const Matrix3x2& RenderContext::GetGlobalTransform() const
{ {
render_target_->RestoreDrawingState(drawing_state_.get()); 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 } // namespace kiwano

View File

@ -60,42 +60,36 @@ class KGE_API RenderContext : public virtual ObjectBase
public: public:
/// \~chinese /// \~chinese
/// @brief 是否有效 /// @brief 是否有效
bool IsValid() const; virtual bool IsValid() const = 0;
/// \~chinese /// \~chinese
/// @brief 开始渲染 /// @brief 开始渲染
void BeginDraw(); virtual void BeginDraw();
/// \~chinese /// \~chinese
/// @brief 结束渲染 /// @brief 结束渲染
void EndDraw(); virtual void EndDraw();
/// \~chinese /// \~chinese
/// @brief 绘制纹理 /// @brief 绘制纹理
/// @param texture 纹理 /// @param texture 纹理
/// @param src_rect 源纹理裁剪矩形 /// @param src_rect 源纹理裁剪矩形
/// @param dest_rect 绘制的目标区域 /// @param dest_rect 绘制的目标区域
void DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect); virtual void DrawTexture(Texture const& texture, const Rect* src_rect = nullptr,
const Rect* dest_rect = nullptr) = 0;
/// \~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);
/// \~chinese /// \~chinese
/// @brief 绘制文本布局 /// @brief 绘制文本布局
/// @param layout 文本布局 /// @param layout 文本布局
/// @param offset 偏移量 /// @param offset 偏移量
void DrawTextLayout(TextLayout const& layout, Point const& offset = Point()); virtual void DrawTextLayout(TextLayout const& layout, Point const& offset = Point()) = 0;
/// \~chinese /// \~chinese
/// @brief 绘制形状轮廓 /// @brief 绘制形状轮廓
/// @param shape 形状 /// @param shape 形状
/// @param stroke 线条样式 /// @param stroke 线条样式
/// @param stroke_width 线条宽度 /// @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 /// \~chinese
/// @brief 绘制线段 /// @brief 绘制线段
@ -103,14 +97,15 @@ public:
/// @param point2 线段终点 /// @param point2 线段终点
/// @param stroke 线条样式 /// @param stroke 线条样式
/// @param stroke_width 线条宽度 /// @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 /// \~chinese
/// @brief 绘制矩形边框 /// @brief 绘制矩形边框
/// @param rect 矩形 /// @param rect 矩形
/// @param stroke 线条样式 /// @param stroke 线条样式
/// @param stroke_width 线条宽度 /// @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 /// \~chinese
/// @brief 绘制圆角矩形边框 /// @brief 绘制圆角矩形边框
@ -118,8 +113,8 @@ public:
/// @param radius 圆角半径 /// @param radius 圆角半径
/// @param stroke 线条样式 /// @param stroke 线条样式
/// @param stroke_width 线条宽度 /// @param stroke_width 线条宽度
void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke = nullptr, virtual void DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
float stroke_width = 1.0f); float stroke_width = 1.0f) = 0;
/// \~chinese /// \~chinese
/// @brief 绘制椭圆边框 /// @brief 绘制椭圆边框
@ -127,115 +122,115 @@ public:
/// @param radius 椭圆半径 /// @param radius 椭圆半径
/// @param stroke 线条样式 /// @param stroke 线条样式
/// @param stroke_width 线条宽度 /// @param stroke_width 线条宽度
void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke = nullptr, virtual void DrawEllipse(Point const& center, Vec2 const& radius, StrokeStylePtr stroke = nullptr,
float stroke_width = 1.0f); float stroke_width = 1.0f) = 0;
/// \~chinese /// \~chinese
/// @brief 填充形状 /// @brief 填充形状
/// @param shape 形状 /// @param shape 形状
void FillShape(Shape const& shape); virtual void FillShape(Shape const& shape) = 0;
/// \~chinese /// \~chinese
/// @brief 填充矩形 /// @brief 填充矩形
/// @param rect 矩形 /// @param rect 矩形
void FillRectangle(Rect const& rect); virtual void FillRectangle(Rect const& rect) = 0;
/// \~chinese /// \~chinese
/// @brief 填充圆角矩形 /// @brief 填充圆角矩形
/// @param rect 矩形 /// @param rect 矩形
/// @param radius 圆角半径 /// @param radius 圆角半径
void FillRoundedRectangle(Rect const& rect, Vec2 const& radius); virtual void FillRoundedRectangle(Rect const& rect, Vec2 const& radius) = 0;
/// \~chinese /// \~chinese
/// @brief 填充椭圆 /// @brief 填充椭圆
/// @param center 圆心 /// @param center 圆心
/// @param radius 椭圆半径 /// @param radius 椭圆半径
void FillEllipse(Point const& center, Vec2 const& radius); virtual void FillEllipse(Point const& center, Vec2 const& radius) = 0;
/// \~chinese /// \~chinese
/// @brief 创建纹理 /// @brief 创建纹理
/// @param texture 纹理 /// @param texture 纹理
/// @param size 纹理像素大小 /// @param size 纹理像素大小
void CreateTexture(Texture& texture, math::Vec2T<uint32_t> size); virtual void CreateTexture(Texture& texture, math::Vec2T<uint32_t> size) = 0;
/// \~chinese /// \~chinese
/// @brief 设置绘制的裁剪区域 /// @brief 设置绘制的裁剪区域
/// @param clip_rect 裁剪矩形 /// @param clip_rect 裁剪矩形
void PushClipRect(Rect const& clip_rect); virtual void PushClipRect(Rect const& clip_rect) = 0;
/// \~chinese /// \~chinese
/// @brief 取消上一次设置的绘制裁剪区域 /// @brief 取消上一次设置的绘制裁剪区域
void PopClipRect(); virtual void PopClipRect() = 0;
/// \~chinese /// \~chinese
/// @brief 设置图层区域 /// @brief 设置图层区域
/// @param layer 图层区域 /// @param layer 图层区域
void PushLayer(LayerArea& layer); virtual void PushLayer(LayerArea& layer) = 0;
/// \~chinese /// \~chinese
/// @brief 取消上一次设置的图层区域 /// @brief 取消上一次设置的图层区域
void PopLayer(); virtual void PopLayer() = 0;
/// \~chinese /// \~chinese
/// @brief 清空渲染内容 /// @brief 清空渲染内容
void Clear(); virtual void Clear() = 0;
/// \~chinese /// \~chinese
/// @brief 使用纯色清空渲染内容 /// @brief 使用纯色清空渲染内容
/// @param clear_color 清屏颜色 /// @param clear_color 清屏颜色
void Clear(Color const& clear_color); virtual void Clear(Color const& clear_color) = 0;
/// \~chinese /// \~chinese
/// @brief 获取渲染区域大小 /// @brief 获取渲染区域大小
Size GetSize() const; virtual Size GetSize() const = 0;
/// \~chinese /// \~chinese
/// @brief 获取画刷透明度 /// @brief 获取画刷透明度
float GetBrushOpacity() const; virtual float GetBrushOpacity() const;
/// \~chinese /// \~chinese
/// @brief 获取当前画刷 /// @brief 获取当前画刷
BrushPtr GetCurrentBrush() const; virtual BrushPtr GetCurrentBrush() const;
/// \~chinese /// \~chinese
/// @brief 获取全局二维变换 /// @brief 获取全局二维变换
Matrix3x2 GetGlobalTransform() const; virtual const Matrix3x2& GetGlobalTransform() const;
/// \~chinese /// \~chinese
/// @brief 设置画刷透明度 /// @brief 设置画刷透明度
void SetBrushOpacity(float opacity); virtual void SetBrushOpacity(float opacity);
/// \~chinese /// \~chinese
/// @brief 设置当前画刷 /// @brief 设置当前画刷
void SetCurrentBrush(BrushPtr brush); virtual 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);
/// \~chinese /// \~chinese
/// @brief 设置抗锯齿模式 /// @brief 设置抗锯齿模式
void SetAntialiasMode(bool enabled); virtual void SetAntialiasMode(bool enabled) = 0;
/// \~chinese /// \~chinese
/// @brief 设置文字抗锯齿模式 /// @brief 设置文字抗锯齿模式
void SetTextAntialiasMode(TextAntialiasMode mode); virtual void SetTextAntialiasMode(TextAntialiasMode mode) = 0;
/// \~chinese /// \~chinese
/// @brief 检查边界是否在视区内 /// @brief 检查边界是否在视区内
bool CheckVisibility(Rect const& bounds, Matrix3x2 const& transform); virtual bool CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) = 0;
/// \~chinese /// \~chinese
/// @brief 重设渲染上下文大小 /// @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: public:
/// \~chinese /// \~chinese
@ -260,32 +255,11 @@ public:
protected: protected:
RenderContext(); RenderContext();
ComPtr<ID2D1RenderTarget> GetRenderTarget() const;
ComPtr<ITextRenderer> GetTextRenderer() const;
private:
/// \~chinese
/// @brief 创建设备依赖资源
HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> ctx);
/// \~chinese
/// @brief 销毁设备依赖资源
void DiscardDeviceResources();
/// \~chinese /// \~chinese
/// @brief 增加渲染图元数量 /// @brief 增加渲染图元数量
void IncreasePrimitivesCount(uint32_t increase = 1) const; void IncreasePrimitivesCount(uint32_t increase = 1) const;
/// \~chinese protected:
/// @brief 保存绘制状态
void SaveDrawingState();
/// \~chinese
/// @brief 恢复绘制状态
void RestoreDrawingState();
private:
bool antialias_; bool antialias_;
bool fast_global_transform_; bool fast_global_transform_;
mutable bool collecting_status_; mutable bool collecting_status_;
@ -295,10 +269,6 @@ private:
Rect visible_size_; Rect visible_size_;
Matrix3x2 global_transform_; Matrix3x2 global_transform_;
mutable Status status_; mutable Status status_;
ComPtr<ITextRenderer> text_renderer_;
ComPtr<ID2D1RenderTarget> render_target_;
ComPtr<ID2D1DrawingStateBlock> drawing_state_;
}; };
/** @} */ /** @} */
@ -313,50 +283,4 @@ inline RenderContext::Status const& RenderContext::GetStatus() const
return status_; return status_;
} }
inline ComPtr<ID2D1RenderTarget> RenderContext::GetRenderTarget() const
{
KGE_ASSERT(render_target_);
return render_target_;
}
inline ComPtr<ITextRenderer> 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 } // namespace kiwano

View File

@ -18,10 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/platform/FileSystem.h>
#include <kiwano/render/ShapeSink.h>
#include <kiwano/render/Renderer.h> #include <kiwano/render/Renderer.h>
namespace kiwano 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<WindowResizedEvent>())
{
auto window_evt = dynamic_cast<WindowResizedEvent*>(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<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
if (SUCCEEDED(hr))
{
ComPtr<IWICBitmapFrameDecode> source;
hr = decoder->GetFrame(0, &source);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, nullptr, 0.f,
WICBitmapPaletteTypeMedianCut);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> 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<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource);
if (SUCCEEDED(hr))
{
ComPtr<IWICBitmapFrameDecode> source;
hr = decoder->GetFrame(0, &source);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, nullptr, 0.f,
WICBitmapPaletteTypeMedianCut);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> 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<IWICBitmapDecoder> 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<IWICBitmapDecoder> 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<IWICBitmapFrameDecode> wic_frame;
HRESULT hr = gif.GetDecoder()->GetFrame(UINT(frame_index), &wic_frame);
if (SUCCEEDED(hr))
{
ComPtr<IWICFormatConverter> converter;
d2d_res_->CreateBitmapConverter(converter, wic_frame, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> 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<IWICMetadataQueryReader> 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<float>(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<float>(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<float>(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<float>(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<long>(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<IDWriteFontCollection> 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<Resource>{ res }, &key, &key_size);
if (SUCCEEDED(hr))
{
ComPtr<IDWriteFontCollection> 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<IDWriteTextFormat> 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<IDWriteTextLayout> 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<ID2D1PathGeometry> path_geo;
ComPtr<ID2D1GeometrySink> 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<ID2D1RectangleGeometry> 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<ID2D1RoundedRectangleGeometry> 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<ID2D1EllipseGeometry> 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<ID2D1PathGeometry> 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<ID2D1BitmapRenderTarget> 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<ID2D1SolidColorBrush> 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<ID2D1GradientStopCollection> collection;
hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
reinterpret_cast<const D2D1_GRADIENT_STOP*>(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE(style.extend_mode), &collection);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1LinearGradientBrush> 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<ID2D1GradientStopCollection> collection;
hr = d2d_res_->GetDeviceContext()->CreateGradientStopCollection(
reinterpret_cast<const D2D1_GRADIENT_STOP*>(&style.stops[0]), UINT32(style.stops.size()), D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE(style.extend_mode), &collection);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1RadialGradientBrush> 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<ID2D1StrokeStyle> 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<float>(width);
output_size_.y = static_cast<float>(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 } // namespace kiwano

View File

@ -26,23 +26,10 @@
#include <kiwano/render/TextStyle.hpp> #include <kiwano/render/TextStyle.hpp>
#include <kiwano/render/RenderContext.h> #include <kiwano/render/RenderContext.h>
#include <kiwano/render/TextureRenderContext.h> #include <kiwano/render/TextureRenderContext.h>
#include <kiwano/render/DirectX/FontCollectionLoader.h>
#if defined(KGE_USE_DIRECTX10)
#include <kiwano/render/DirectX/D3D10DeviceResources.h>
#else
#include <kiwano/render/DirectX/D3D11DeviceResources.h>
#endif
namespace kiwano namespace kiwano
{ {
#if defined(KGE_USE_DIRECTX10)
typedef ID3D10DeviceResources ID3DDeviceResources;
#else
typedef ID3D11DeviceResources ID3DDeviceResources;
#endif
/** /**
* \~chinese * \~chinese
* \defgroup Render * \defgroup Render
@ -57,137 +44,127 @@ typedef ID3D11DeviceResources ID3DDeviceResources;
* \~chinese * \~chinese
* @brief * @brief
*/ */
class KGE_API Renderer class KGE_API Renderer : public EventComponent
: public Singleton<Renderer>
, public EventComponent
{ {
friend Singleton<Renderer>;
public: public:
/// \~chinese
/// @brief 获取实例
static Renderer& GetInstance();
/// \~chinese /// \~chinese
/// @brief 获取清屏颜色 /// @brief 获取清屏颜色
Color const& GetClearColor() const; virtual Color GetClearColor() const;
/// \~chinese /// \~chinese
/// @brief 设置清屏颜色 /// @brief 设置清屏颜色
void SetClearColor(Color const& clear_color); virtual void SetClearColor(Color const& clear_color);
/// \~chinese /// \~chinese
/// @brief 开启或关闭垂直同步 /// @brief 开启或关闭垂直同步
void SetVSyncEnabled(bool enabled); virtual void SetVSyncEnabled(bool enabled);
/// \~chinese
/// @brief 设置DPI
void SetDpi(float dpi);
/// \~chinese /// \~chinese
/// @brief 创建纹理 /// @brief 创建纹理
/// @param[out] texture 纹理 /// @param[out] texture 纹理
/// @param[in] file_path 图片路径 /// @param[in] file_path 图片路径
void CreateTexture(Texture& texture, String const& file_path); virtual void CreateTexture(Texture& texture, String const& file_path) = 0;
/// \~chinese /// \~chinese
/// @brief 创建纹理 /// @brief 创建纹理
/// @param[out] texture 纹理 /// @param[out] texture 纹理
/// @param[in] resource 图片资源 /// @param[in] resource 图片资源
void CreateTexture(Texture& texture, Resource const& resource); virtual void CreateTexture(Texture& texture, Resource const& resource) = 0;
/// \~chinese /// \~chinese
/// @brief 创建GIF图像 /// @brief 创建GIF图像
/// @param[out] gif GIF图像 /// @param[out] gif GIF图像
/// @param[in] file_path 图片路径 /// @param[in] file_path 图片路径
void CreateGifImage(GifImage& gif, String const& file_path); virtual void CreateGifImage(GifImage& gif, String const& file_path) = 0;
/// \~chinese /// \~chinese
/// @brief 创建GIF图像 /// @brief 创建GIF图像
/// @param[out] gif GIF图像 /// @param[out] gif GIF图像
/// @param[in] resource 图片资源 /// @param[in] resource 图片资源
void CreateGifImage(GifImage& gif, Resource const& resource); virtual void CreateGifImage(GifImage& gif, Resource const& resource) = 0;
/// \~chinese /// \~chinese
/// @brief 创建GIF图像帧 /// @brief 创建GIF图像帧
/// @param[out] frame GIF图像帧 /// @param[out] frame GIF图像帧
/// @param[in] gif GIF图像 /// @param[in] gif GIF图像
/// @param[in] frame_index 帧下标 /// @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 /// \~chinese
/// @brief 创建字体集 /// @brief 创建字体集
/// @param[out] font 字体 /// @param[out] font 字体
/// @param[in] file_paths 字体文件路径 /// @param[in] file_paths 字体文件路径
void CreateFontCollection(Font& font, String const& file_path); virtual void CreateFontCollection(Font& font, String const& file_path) = 0;
/// \~chinese /// \~chinese
/// @brief 创建字体集 /// @brief 创建字体集
/// @param[out] font 字体 /// @param[out] font 字体
/// @param[in] res_arr 字体资源 /// @param[in] res_arr 字体资源
void CreateFontCollection(Font& font, Resource const& res); virtual void CreateFontCollection(Font& font, Resource const& res) = 0;
/// \~chinese /// \~chinese
/// @brief 创建文字格式 /// @brief 创建文字格式
/// @param[out] layout 字体布局 /// @param[out] layout 字体布局
void CreateTextFormat(TextLayout& layout); virtual void CreateTextFormat(TextLayout& layout) = 0;
/// \~chinese /// \~chinese
/// @brief 创建文字布局 /// @brief 创建文字布局
/// @param[out] layout 字体布局 /// @param[out] layout 字体布局
void CreateTextLayout(TextLayout& layout); virtual void CreateTextLayout(TextLayout& layout) = 0;
/// \~chinese /// \~chinese
/// @brief 创建线段形状 /// @brief 创建线段形状
/// @param[out] geo 形状 /// @param[out] geo 形状
/// @param[in] begin_pos 线段起点 /// @param[in] begin_pos 线段起点
/// @param[in] end_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 /// \~chinese
/// @brief 创建矩形形状 /// @brief 创建矩形形状
/// @param[out] geo 形状 /// @param[out] geo 形状
/// @param[in] rect 矩形大小 /// @param[in] rect 矩形大小
void CreateRectShape(Shape& shape, Rect const& rect); virtual void CreateRectShape(Shape& shape, Rect const& rect) = 0;
/// \~chinese /// \~chinese
/// @brief 创建圆角矩形形状 /// @brief 创建圆角矩形形状
/// @param[out] geo 形状 /// @param[out] geo 形状
/// @param[in] rect 矩形大小 /// @param[in] rect 矩形大小
/// @param[in] radius 圆角半径 /// @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 /// \~chinese
/// @brief 创建椭圆形状 /// @brief 创建椭圆形状
/// @param[out] geo 形状 /// @param[out] geo 形状
/// @param[in] center 椭圆圆心 /// @param[in] center 椭圆圆心
/// @param[in] radius 椭圆半径 /// @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 /// \~chinese
/// @brief 创建几何图形生成器 /// @brief 创建几何图形生成器
/// @param[out] sink 形状生成器 /// @param[out] sink 形状生成器
void CreateShapeSink(ShapeSink& sink); virtual void CreateShapeSink(ShapeSink& sink) = 0;
/// \~chinese
/// @brief 创建纹理渲染上下文
/// @param[out] render_context 渲染上下文
/// @param[in] desired_size 期望的输出大小
void CreateTextureRenderContext(TextureRenderContext& render_context, const Size* desired_size = nullptr);
/// \~chinese /// \~chinese
/// @brief 创建纯色画刷 /// @brief 创建纯色画刷
/// @param[out] brush 画刷 /// @param[out] brush 画刷
/// @param[in] color 颜色 /// @param[in] color 颜色
void CreateBrush(Brush& brush, Color const& color); virtual void CreateBrush(Brush& brush, Color const& color) = 0;
/// \~chinese /// \~chinese
/// @brief 创建线性渐变画刷 /// @brief 创建线性渐变画刷
/// @param[out] brush 画刷 /// @param[out] brush 画刷
/// @param[in] style 线性渐变样式 /// @param[in] style 线性渐变样式
void CreateBrush(Brush& brush, LinearGradientStyle const& style); virtual void CreateBrush(Brush& brush, LinearGradientStyle const& style) = 0;
/// \~chinese /// \~chinese
/// @brief 创建径向渐变画刷 /// @brief 创建径向渐变画刷
/// @param[out] brush 画刷 /// @param[out] brush 画刷
/// @param[in] style 径向渐变样式 /// @param[in] style 径向渐变样式
void CreateBrush(Brush& brush, RadialGradientStyle const& style); virtual void CreateBrush(Brush& brush, RadialGradientStyle const& style) = 0;
/// \~chinese /// \~chinese
/// @brief 创建线条样式 /// @brief 创建线条样式
@ -197,74 +174,52 @@ public:
/// @param[in] dash_array 虚线长度与间隙数组 /// @param[in] dash_array 虚线长度与间隙数组
/// @param[in] dash_size 虚线数组大小 /// @param[in] dash_size 虚线数组大小
/// @param[in] dash_offset 虚线偏移量 /// @param[in] dash_offset 虚线偏移量
void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join, const float* dash_array, virtual void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
size_t dash_size, float dash_offset); 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: public:
/// \~chinese /// \~chinese
/// @brief 开始渲染 /// @brief 开始渲染
void BeginDraw(); virtual void BeginDraw() = 0;
/// \~chinese /// \~chinese
/// @brief 结束渲染 /// @brief 结束渲染
void EndDraw(); virtual void EndDraw() = 0;
/// \~chinese /// \~chinese
/// @brief 清除绘制内容 /// @brief 清除绘制内容
void Clear(); virtual void Clear() = 0;
/// \~chinese /// \~chinese
/// @brief 将绘制内容呈现至窗口 /// @brief 将绘制内容呈现至窗口
void Present(); virtual void Present() = 0;
/// \~chinese /// \~chinese
/// @brief 获取渲染上下文 /// @brief 获取渲染上下文
RenderContext& GetContext(); virtual RenderContext& GetContext() = 0;
/// \~chinese /// \~chinese
/// @brief 获取目标窗口 /// @brief 获取目标窗口
WindowHandle GetTargetWindow() const; virtual WindowHandle GetTargetWindow() const;
/// \~chinese /// \~chinese
/// @brief 获取渲染输出大小 /// @brief 获取渲染输出大小
Size const& GetOutputSize() const; virtual Size GetOutputSize() const;
/// \~chinese protected:
/// @brief 获取Direct2D设备资源
ID2DDeviceResources* GetD2DDeviceResources();
/// \~chinese
/// @brief 获取Direct3D设备资源
ID3DDeviceResources* GetD3DDeviceResources();
public:
void SetupComponent() override;
void DestroyComponent() override;
void HandleEvent(Event* evt) override;
private:
Renderer(); Renderer();
~Renderer(); protected:
HRESULT HandleDeviceLost();
void ResizeTarget(uint32_t width, uint32_t height);
private:
bool vsync_; bool vsync_;
WindowHandle target_window_; WindowHandle target_window_;
Color clear_color_; Color clear_color_;
Size output_size_; Size output_size_;
RenderContext render_ctx_;
ComPtr<ID2DDeviceResources> d2d_res_;
ComPtr<ID3DDeviceResources> d3d_res_;
ComPtr<IFontCollectionLoader> font_collection_loader_;
ComPtr<IResourceFontFileLoader> res_font_file_loader_;
ComPtr<IResourceFontCollectionLoader> res_font_collection_loader_;
}; };
/** @} */ /** @} */
@ -274,30 +229,24 @@ inline WindowHandle Renderer::GetTargetWindow() const
return target_window_; return target_window_;
} }
inline Size const& Renderer::GetOutputSize() const inline Size Renderer::GetOutputSize() const
{ {
return output_size_; return output_size_;
} }
inline Color const& Renderer::GetClearColor() const inline Color Renderer::GetClearColor() const
{ {
return clear_color_; 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_); clear_color_ = color;
return d2d_res_.get();
} }
inline ID3DDeviceResources* Renderer::GetD3DDeviceResources()
{
KGE_ASSERT(d3d_res_);
return d3d_res_.get();
}
} // namespace kiwano } // namespace kiwano

View File

@ -24,8 +24,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
class Renderer;
class ShapeSink; class ShapeSink;
KGE_DECLARE_SMART_PTR(Shape); KGE_DECLARE_SMART_PTR(Shape);
@ -41,8 +39,6 @@ KGE_DECLARE_SMART_PTR(Shape);
*/ */
class KGE_API Shape : public virtual ObjectBase class KGE_API Shape : public virtual ObjectBase
{ {
friend class RenderContext;
friend class Renderer;
friend class ShapeSink; friend class ShapeSink;
public: public:
@ -116,7 +112,7 @@ public:
void Clear(); void Clear();
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
private: public:
ComPtr<ID2D1Geometry> GetGeometry() const; ComPtr<ID2D1Geometry> GetGeometry() const;
void SetGeometry(ComPtr<ID2D1Geometry> shape); void SetGeometry(ComPtr<ID2D1Geometry> shape);

View File

@ -23,8 +23,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
class Renderer;
/** /**
* \addtogroup Render * \addtogroup Render
@ -45,8 +43,6 @@ enum class CombineMode
/// @brief ÐÎ×´Éú³ÉÆ÷ /// @brief ÐÎ×´Éú³ÉÆ÷
class KGE_API ShapeSink : protected Noncopyable class KGE_API ShapeSink : protected Noncopyable
{ {
friend class Renderer;
public: public:
ShapeSink(); ShapeSink();
@ -137,7 +133,7 @@ private:
ShapePtr shape_; ShapePtr shape_;
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
private: public:
ComPtr<ID2D1PathGeometry> GetPathGeometry() const; ComPtr<ID2D1PathGeometry> GetPathGeometry() const;
void SetPathGeometry(ComPtr<ID2D1PathGeometry> path); void SetPathGeometry(ComPtr<ID2D1PathGeometry> path);
@ -146,6 +142,7 @@ private:
void SetGeometrySink(ComPtr<ID2D1GeometrySink> sink); void SetGeometrySink(ComPtr<ID2D1GeometrySink> sink);
private:
ComPtr<ID2D1GeometrySink> sink_; ComPtr<ID2D1GeometrySink> sink_;
ComPtr<ID2D1PathGeometry> path_geo_; ComPtr<ID2D1PathGeometry> path_geo_;
#endif #endif

View File

@ -24,8 +24,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
class Renderer;
KGE_DECLARE_SMART_PTR(StrokeStyle); KGE_DECLARE_SMART_PTR(StrokeStyle);
@ -71,9 +69,6 @@ enum class DashStyle
/// @brief ĎßĚőŃůĘ˝ /// @brief ĎßĚőŃůĘ˝
class StrokeStyle : public virtual ObjectBase class StrokeStyle : public virtual ObjectBase
{ {
friend class RenderContext;
friend class Renderer;
public: public:
/// \~chinese /// \~chinese
/// @brief ´´˝¨ĎßĚőŃůĘ˝ /// @brief ´´˝¨ĎßĚőŃůĘ˝
@ -115,7 +110,7 @@ public:
bool IsValid() const; bool IsValid() const;
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
private: public:
ComPtr<ID2D1StrokeStyle> GetStrokeStyle() const; ComPtr<ID2D1StrokeStyle> GetStrokeStyle() const;
void SetStrokeStyle(ComPtr<ID2D1StrokeStyle> style); void SetStrokeStyle(ComPtr<ID2D1StrokeStyle> style);

View File

@ -24,8 +24,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
class Renderer;
/** /**
* \addtogroup Render * \addtogroup Render
@ -36,9 +34,6 @@ class Renderer;
/// @brief 文本布局 /// @brief 文本布局
class KGE_API TextLayout class KGE_API TextLayout
{ {
friend class RenderContext;
friend class Renderer;
public: public:
/// \~chinese /// \~chinese
/// @brief 构造空的文本布局 /// @brief 构造空的文本布局
@ -165,8 +160,13 @@ public:
void SetDirtyFlag(uint8_t flag); void SetDirtyFlag(uint8_t flag);
#if defined(KGE_WIN32)
private: private:
uint8_t dirty_flag_;
String text_;
TextStyle style_;
#if defined(KGE_WIN32)
public:
ComPtr<IDWriteTextFormat> GetTextFormat() const; ComPtr<IDWriteTextFormat> GetTextFormat() const;
void SetTextFormat(ComPtr<IDWriteTextFormat> format); void SetTextFormat(ComPtr<IDWriteTextFormat> format);
@ -175,15 +175,10 @@ private:
void SetTextLayout(ComPtr<IDWriteTextLayout> layout); void SetTextLayout(ComPtr<IDWriteTextLayout> layout);
private:
ComPtr<IDWriteTextFormat> text_format_; ComPtr<IDWriteTextFormat> text_format_;
ComPtr<IDWriteTextLayout> text_layout_; ComPtr<IDWriteTextLayout> text_layout_;
#endif #endif
private:
uint8_t dirty_flag_;
String text_;
TextStyle style_;
}; };
/** @} */ /** @} */

View File

@ -181,15 +181,6 @@ InterpolationMode Texture::GetDefaultInterpolationMode()
} }
#if defined(KGE_WIN32) #if defined(KGE_WIN32)
D2D1_PIXEL_FORMAT Texture::GetPixelFormat() const
{
if (bitmap_)
{
return bitmap_->GetPixelFormat();
}
return D2D1_PIXEL_FORMAT();
}
ComPtr<ID2D1Bitmap> Texture::GetBitmap() const ComPtr<ID2D1Bitmap> Texture::GetBitmap() const
{ {
return bitmap_; return bitmap_;

View File

@ -24,9 +24,6 @@
namespace kiwano namespace kiwano
{ {
class RenderContext;
class TextureRenderContext;
class Renderer;
KGE_DECLARE_SMART_PTR(Texture); KGE_DECLARE_SMART_PTR(Texture);
@ -52,10 +49,6 @@ enum class InterpolationMode
*/ */
class KGE_API Texture : public virtual ObjectBase class KGE_API Texture : public virtual ObjectBase
{ {
friend class RenderContext;
friend class TextureRenderContext;
friend class Renderer;
public: public:
/// \~chinese /// \~chinese
/// @brief 从本地文件创建纹理 /// @brief 从本地文件创建纹理
@ -133,8 +126,13 @@ public:
/// @brief 获取默认的像素插值方式 /// @brief 获取默认的像素插值方式
static InterpolationMode GetDefaultInterpolationMode(); static InterpolationMode GetDefaultInterpolationMode();
#if defined(KGE_WIN32)
private: private:
InterpolationMode interpolation_mode_;
static InterpolationMode default_interpolation_mode_;
#if defined(KGE_WIN32)
public:
/// \~chinese /// \~chinese
/// @brief 获取源位图 /// @brief 获取源位图
ComPtr<ID2D1Bitmap> GetBitmap() const; ComPtr<ID2D1Bitmap> GetBitmap() const;
@ -143,17 +141,9 @@ private:
/// @brief 设置源位图 /// @brief 设置源位图
void SetBitmap(ComPtr<ID2D1Bitmap> bitmap); void SetBitmap(ComPtr<ID2D1Bitmap> bitmap);
/// \~chinese private:
/// @brief »ñÈ¡ÏñËØ¸ñʽ
D2D1_PIXEL_FORMAT GetPixelFormat() const;
ComPtr<ID2D1Bitmap> bitmap_; ComPtr<ID2D1Bitmap> bitmap_;
#endif #endif
private:
InterpolationMode interpolation_mode_;
static InterpolationMode default_interpolation_mode_;
}; };
/** @} */ /** @} */

View File

@ -27,56 +27,30 @@ namespace kiwano
TextureRenderContextPtr TextureRenderContext::Create() TextureRenderContextPtr TextureRenderContext::Create()
{ {
TextureRenderContextPtr ptr = new TextureRenderContext; TextureRenderContextPtr ptr;
if (ptr)
{
try try
{ {
Renderer::GetInstance().CreateTextureRenderContext(*ptr); ptr = Renderer::GetInstance().CreateTextureRenderContext(nullptr);
} }
catch (std::exception) catch (std::exception&)
{ {
return nullptr; return nullptr;
} }
}
return ptr; return ptr;
} }
TextureRenderContextPtr TextureRenderContext::Create(Size const& desired_size) TextureRenderContextPtr TextureRenderContext::Create(Size const& desired_size)
{ {
TextureRenderContextPtr ptr = new TextureRenderContext; TextureRenderContextPtr ptr;
if (ptr)
{
try try
{ {
Renderer::GetInstance().CreateTextureRenderContext(*ptr, &desired_size); ptr = Renderer::GetInstance().CreateTextureRenderContext(&desired_size);
} }
catch (std::exception) catch (std::exception&)
{ {
return nullptr; return nullptr;
} }
}
return ptr; return ptr;
} }
TextureRenderContext::TextureRenderContext() {}
bool TextureRenderContext::GetOutput(Texture& texture)
{
HRESULT hr = E_FAIL;
if (bitmap_rt_)
{
ComPtr<ID2D1Bitmap> bitmap;
hr = bitmap_rt_->GetBitmap(&bitmap);
if (SUCCEEDED(hr))
{
texture.SetBitmap(bitmap);
}
}
return SUCCEEDED(hr);
}
} // namespace kiwano } // namespace kiwano

View File

@ -23,8 +23,6 @@
namespace kiwano namespace kiwano
{ {
class Renderer;
KGE_DECLARE_SMART_PTR(TextureRenderContext); KGE_DECLARE_SMART_PTR(TextureRenderContext);
/** /**
@ -35,10 +33,8 @@ KGE_DECLARE_SMART_PTR(TextureRenderContext);
/// \~chinese /// \~chinese
/// @brief 纹理渲染上下文 /// @brief 纹理渲染上下文
/// @details 纹理渲染上下文将渲染输出到一个纹理对象中 /// @details 纹理渲染上下文将渲染输出到一个纹理对象中
class KGE_API TextureRenderContext : public RenderContext class KGE_API TextureRenderContext : public virtual RenderContext
{ {
friend class Renderer;
public: public:
/// \~chinese /// \~chinese
/// @brief 创建纹理渲染上下文 /// @brief 创建纹理渲染上下文
@ -49,41 +45,13 @@ public:
/// @param size 期望的输出大小 /// @param size 期望的输出大小
static TextureRenderContextPtr Create(Size const& desired_size); static TextureRenderContextPtr Create(Size const& desired_size);
/// \~chinese
/// @brief ÊÇ·ñÓÐЧ
bool IsValid() const;
/// \~chinese /// \~chinese
/// @brief 获取渲染输出 /// @brief 获取渲染输出
/// @param[out] texture 纹理输出 /// @param[out] texture 纹理输出
/// @return 操作是否成功 /// @return 操作是否成功
bool GetOutput(Texture& texture); virtual bool GetOutput(Texture& texture) = 0;
private:
TextureRenderContext();
ComPtr<ID2D1BitmapRenderTarget> GetBitmapRenderTarget() const;
void SetBitmapRenderTarget(ComPtr<ID2D1BitmapRenderTarget> ctx);
private:
ComPtr<ID2D1BitmapRenderTarget> bitmap_rt_;
}; };
/** @} */ /** @} */
inline bool TextureRenderContext::IsValid() const
{
return bitmap_rt_ != nullptr;
}
inline ComPtr<ID2D1BitmapRenderTarget> TextureRenderContext::GetBitmapRenderTarget() const
{
return bitmap_rt_;
}
inline void TextureRenderContext::SetBitmapRenderTarget(ComPtr<ID2D1BitmapRenderTarget> ctx)
{
bitmap_rt_ = ctx;
}
} // namespace kiwano } // namespace kiwano