Update RenderTarget & Renderer

This commit is contained in:
Nomango 2019-12-28 22:04:08 +08:00
parent ef77e76c6c
commit c50755bb4b
19 changed files with 699 additions and 921 deletions

View File

@ -75,6 +75,7 @@
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\ui\Button.h" />
<ClInclude Include="..\..\src\kiwano\ui\Menu.h" />

View File

@ -267,6 +267,9 @@
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h">
<Filter>renderer\win32</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp">

View File

@ -38,12 +38,12 @@ namespace kiwano
void Stage::OnEnter()
{
// KGE_SYS_LOG(L"Stage entered");
KGE_SYS_LOG(L"Stage entered");
}
void Stage::OnExit()
{
// KGE_SYS_LOG(L"Stage exited");
KGE_SYS_LOG(L"Stage exited");
}
void Stage::RenderBorder(RenderTarget* rt)

View File

@ -18,18 +18,16 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <stdexcept>
#include <kiwano/macros.h>
#include <3rd-party/StackWalker/StackWalker.h>
namespace kiwano
{
// Display stack trace on exception
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
KGE_ERROR(L"Failed with HRESULT of %08X", hr);
StackWalker{}.ShowCallstack();
static char buffer[1024 + 1];

View File

@ -22,6 +22,7 @@
#include <kiwano/platform/Application.h>
#include <kiwano/platform/modules.h>
#include <kiwano/core/Logger.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/platform/Input.h>
#include <kiwano/platform/Director.h>
@ -148,8 +149,6 @@ namespace kiwano
comps_.clear();
}
Input::instance().Destroy();
Renderer::instance().Destroy();
Window::instance().Destroy();
}
@ -304,14 +303,12 @@ namespace kiwano
{
KeyDownEvent evt;
evt.code = static_cast<int>(wparam);
// evt.count = static_cast<int>(lparam & 0xFF);
app->DispatchEvent(evt);
}
else
{
KeyUpEvent evt;
evt.code = static_cast<int>(wparam);
// evt.count = static_cast<int>(lparam & 0xFF);
app->DispatchEvent(evt);
}
}
@ -321,7 +318,6 @@ namespace kiwano
{
KeyCharEvent evt;
evt.value = static_cast<char>(wparam);
// evt.count = static_cast<int>(lparam & 0xFF);
app->DispatchEvent(evt);
}
break;
@ -383,7 +379,7 @@ namespace kiwano
{
if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
{
// KGE_SYS_LOG(L"Window minimized");
KGE_SYS_LOG(L"Window minimized");
}
else
{
@ -425,7 +421,7 @@ namespace kiwano
case WM_SETTEXT:
{
// KGE_SYS_LOG(L"Window title changed");
KGE_SYS_LOG(L"Window title changed");
WindowTitleChangedEvent evt;
evt.title = reinterpret_cast<const wchar_t*>(lparam);
@ -435,13 +431,13 @@ namespace kiwano
case WM_SETICON:
{
// KGE_SYS_LOG(L"Window icon changed");
KGE_SYS_LOG(L"Window icon changed");
}
break;
case WM_DISPLAYCHANGE:
{
// KGE_SYS_LOG(L"The display resolution has changed");
KGE_SYS_LOG(L"The display resolution has changed");
::InvalidateRect(hwnd, nullptr, FALSE);
}
@ -455,7 +451,7 @@ namespace kiwano
case WM_CLOSE:
{
// KGE_SYS_LOG(L"Window is closing");
KGE_SYS_LOG(L"Window is closing");
if (!app->OnClosing())
{

View File

@ -140,8 +140,4 @@ namespace kiwano
{
return Point{ mouse_pos_x_, mouse_pos_y_ };
}
void Input::Destroy()
{
}
}

View File

@ -100,8 +100,6 @@ namespace kiwano
void UpdateMousePos(float, float);
void Destroy();
private:
Input();

View File

@ -20,6 +20,7 @@
#include <kiwano/platform/Window.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/Application.h>
#define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

View File

@ -20,6 +20,7 @@
#include <kiwano/renderer/RenderTarget.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/core/Logger.h>
namespace kiwano
{
@ -36,32 +37,64 @@ namespace kiwano
status_.primitives = 0;
}
HRESULT RenderTarget::CreateDeviceResources(ComPtr<ID2D1RenderTarget> rt, ComPtr<ID2DDeviceResources> dev_res)
HRESULT RenderTarget::CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> rt)
{
HRESULT hr = E_FAIL;
if (!factory || !rt)
return E_INVALIDARG;
if (rt && dev_res)
{
render_target_ = rt;
device_resources_ = dev_res;
hr = S_OK;
}
render_target_ = rt;
text_renderer_.reset();
current_brush_.reset();
if (SUCCEEDED(hr))
{
text_renderer_.reset();
hr = ITextRenderer::Create(
&text_renderer_,
render_target_.get()
);
}
HRESULT hr = ITextRenderer::Create(
&text_renderer_,
render_target_.get()
);
if (SUCCEEDED(hr))
{
SetAntialiasMode(antialias_);
SetTextAntialiasMode(text_antialias_);
current_brush_.reset();
Resize(reinterpret_cast<const Size&>(GetRenderTarget()->GetSize()));
}
if (SUCCEEDED(hr))
{
ComPtr<ID2D1StrokeStyle> miter_stroke_style;
ComPtr<ID2D1StrokeStyle> bevel_stroke_style;
ComPtr<ID2D1StrokeStyle> round_stroke_style;
D2D1_STROKE_STYLE_PROPERTIES stroke_style = D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_MITER,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f
);
hr = factory->CreateStrokeStyle(stroke_style, nullptr, 0, &miter_stroke_style);
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
hr = factory->CreateStrokeStyle(stroke_style, nullptr, 0, &bevel_stroke_style);
}
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
hr = factory->CreateStrokeStyle(stroke_style, nullptr, 0, &round_stroke_style);
}
if (SUCCEEDED(hr))
{
miter_stroke_style_ = miter_stroke_style;
bevel_stroke_style_ = bevel_stroke_style;
round_stroke_style_ = round_stroke_style;
}
}
return hr;
@ -69,15 +102,18 @@ namespace kiwano
void RenderTarget::DiscardDeviceResources()
{
miter_stroke_style_.reset();
bevel_stroke_style_.reset();
round_stroke_style_.reset();
text_renderer_.reset();
render_target_.reset();
current_brush_.reset();
device_resources_.reset();
}
bool RenderTarget::IsValid() const
{
return render_target_ && device_resources_;
return render_target_ != nullptr;
}
void RenderTarget::BeginDraw()
@ -106,13 +142,10 @@ namespace kiwano
void RenderTarget::DrawGeometry(Geometry const& geometry, float stroke_width, StrokeStyle stroke)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr) && geometry.GetGeometry())
if (geometry.IsValid())
{
render_target_->DrawGeometry(
geometry.GetGeometry().get(),
@ -123,19 +156,14 @@ namespace kiwano
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
}
void RenderTarget::FillGeometry(Geometry const& geometry)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr) && geometry.GetGeometry())
if (geometry.IsValid())
{
render_target_->FillGeometry(
geometry.GetGeometry().get(),
@ -144,181 +172,122 @@ namespace kiwano
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
}
void RenderTarget::DrawLine(Point const& point1, Point const& point2, float stroke_width, StrokeStyle stroke)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr))
{
render_target_->DrawLine(
DX::ConvertToPoint2F(point1),
DX::ConvertToPoint2F(point2),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
render_target_->DrawLine(
DX::ConvertToPoint2F(point1),
DX::ConvertToPoint2F(point2),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::DrawRectangle(Rect const& rect, float stroke_width, StrokeStyle stroke)
{
HRESULT hr = S_OK;
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
render_target_->DrawRectangle(
DX::ConvertToRectF(rect),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
if (SUCCEEDED(hr))
{
render_target_->DrawRectangle(
DX::ConvertToRectF(rect),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::FillRectangle(Rect const& rect)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr))
{
render_target_->FillRectangle(
DX::ConvertToRectF(rect),
current_brush_->GetBrush().get()
);
render_target_->FillRectangle(
DX::ConvertToRectF(rect),
current_brush_->GetBrush().get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, float stroke_width, StrokeStyle stroke)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr))
{
render_target_->DrawRoundedRectangle(
D2D1::RoundedRect(
DX::ConvertToRectF(rect),
radius.x,
radius.y
),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
render_target_->DrawRoundedRectangle(
D2D1::RoundedRect(
DX::ConvertToRectF(rect),
radius.x,
radius.y
),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::FillRoundedRectangle(Rect const& rect, Vec2 const& radius)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr))
{
render_target_->FillRoundedRectangle(
D2D1::RoundedRect(
DX::ConvertToRectF(rect),
radius.x,
radius.y
),
current_brush_->GetBrush().get()
);
render_target_->FillRoundedRectangle(
D2D1::RoundedRect(
DX::ConvertToRectF(rect),
radius.x,
radius.y
),
current_brush_->GetBrush().get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::DrawEllipse(Point const& center, Vec2 const& radius, float stroke_width, StrokeStyle stroke)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr))
{
render_target_->DrawEllipse(
D2D1::Ellipse(
DX::ConvertToPoint2F(center),
radius.x,
radius.y
),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
render_target_->DrawEllipse(
D2D1::Ellipse(
DX::ConvertToPoint2F(center),
radius.x,
radius.y
),
current_brush_->GetBrush().get(),
stroke_width,
GetStrokeStyle(stroke).get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::FillEllipse(Point const& center, Vec2 const& radius)
{
HRESULT hr = S_OK;
if (!render_target_ || !current_brush_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
if (SUCCEEDED(hr))
{
render_target_->FillEllipse(
D2D1::Ellipse(
DX::ConvertToPoint2F(center),
radius.x,
radius.y
),
current_brush_->GetBrush().get()
);
render_target_->FillEllipse(
D2D1::Ellipse(
DX::ConvertToPoint2F(center),
radius.x,
radius.y
),
current_brush_->GetBrush().get()
);
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
IncreasePrimitivesCount();
}
void RenderTarget::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect, float opacity)
@ -328,13 +297,9 @@ namespace kiwano
void RenderTarget::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect, float opacity)
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
if (SUCCEEDED(hr) && texture.IsValid())
if (texture.IsValid())
{
auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
@ -350,134 +315,87 @@ namespace kiwano
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
}
void RenderTarget::DrawTextLayout(TextLayout const& layout, Point const& offset)
{
HRESULT hr = S_OK;
if (!text_renderer_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!");
if (SUCCEEDED(hr))
{
const TextStyle& style = layout.GetStyle();
text_renderer_->SetStyle(
style.fill_brush ? style.fill_brush->GetBrush().get() : nullptr,
style.outline_brush ? style.outline_brush->GetBrush().get() : nullptr,
style.outline_width,
GetStrokeStyle(style.outline_stroke).get()
);
const TextStyle& style = layout.GetStyle();
text_renderer_->SetStyle(
style.fill_brush ? style.fill_brush->GetBrush().get() : nullptr,
style.outline_brush ? style.outline_brush->GetBrush().get() : nullptr,
style.outline_width,
GetStrokeStyle(style.outline_stroke).get()
);
hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), offset.x, offset.y);
}
HRESULT hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), offset.x, offset.y);
if (SUCCEEDED(hr))
{
IncreasePrimitivesCount();
}
ThrowIfFailed(hr);
else
{
KGE_ERROR(L"Failed to draw text layout with HRESULT of %08X", hr);
}
}
void RenderTarget::CreateTexture(Texture& texture, math::Vec2T<uint32_t> size, D2D1_PIXEL_FORMAT format)
{
HRESULT hr = S_OK;
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
if (!render_target_)
{
hr = E_UNEXPECTED;
}
ComPtr<ID2D1Bitmap> saved_bitmap;
HRESULT hr = render_target_->CreateBitmap(
D2D1::SizeU(size.x, size.y),
D2D1::BitmapProperties(format),
&saved_bitmap
);
if (SUCCEEDED(hr))
{
ComPtr<ID2D1Bitmap> saved_bitmap;
hr = render_target_->CreateBitmap(D2D1::SizeU(size.x, size.y), D2D1::BitmapProperties(format), &saved_bitmap);
if (SUCCEEDED(hr))
{
texture.SetBitmap(saved_bitmap);
}
texture.SetBitmap(saved_bitmap);
}
else
{
ThrowIfFailed(hr);
}
ThrowIfFailed(hr);
}
void RenderTarget::CreateLayer(LayerArea& layer)
void RenderTarget::PushClipRect(Rect const& clip_rect)
{
HRESULT hr = S_OK;
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
);
}
if (!render_target_)
{
hr = E_UNEXPECTED;
}
void RenderTarget::PopClipRect()
{
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
render_target_->PopAxisAlignedClip();
}
if (SUCCEEDED(hr))
void RenderTarget::PushLayer(LayerArea& layer)
{
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
if (!layer.IsValid())
{
ComPtr<ID2D1Layer> output;
hr = render_target_->CreateLayer(&output);
HRESULT hr = render_target_->CreateLayer(&output);
if (SUCCEEDED(hr))
{
layer.SetLayer(output);
}
else
{
ThrowIfFailed(hr);
}
}
ThrowIfFailed(hr);
}
void RenderTarget::PushClipRect(Rect const& clip_rect)
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
render_target_->PushAxisAlignedClip(
DX::ConvertToRectF(clip_rect),
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
);
}
ThrowIfFailed(hr);
}
void RenderTarget::PopClipRect()
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
render_target_->PopAxisAlignedClip();
}
ThrowIfFailed(hr);
}
void RenderTarget::PushLayer(LayerArea& layer)
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
if (!layer.IsValid())
{
CreateLayer(layer);
}
if (SUCCEEDED(hr) && layer.IsValid())
if (layer.IsValid())
{
render_target_->PushLayer(
D2D1::LayerParameters(
@ -492,85 +410,50 @@ namespace kiwano
layer.GetLayer().get()
);
}
ThrowIfFailed(hr);
}
void RenderTarget::PopLayer()
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
render_target_->PopLayer();
}
ThrowIfFailed(hr);
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
render_target_->PopLayer();
}
void RenderTarget::Clear()
{
HRESULT hr = E_FAIL;
if (render_target_)
{
render_target_->Clear();
hr = S_OK;
}
ThrowIfFailed(hr);
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
render_target_->Clear();
}
void RenderTarget::Clear(Color const& clear_color)
{
HRESULT hr = E_FAIL;
if (render_target_)
{
render_target_->Clear(DX::ConvertToColorF(clear_color));
hr = S_OK;
}
ThrowIfFailed(hr);
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
render_target_->Clear(DX::ConvertToColorF(clear_color));
}
ComPtr<ID2D1StrokeStyle> RenderTarget::GetStrokeStyle(StrokeStyle style)
{
switch (style)
{
case StrokeStyle::Miter: return device_resources_->GetMiterStrokeStyle(); break;
case StrokeStyle::Bevel: return device_resources_->GetBevelStrokeStyle(); break;
case StrokeStyle::Round: return device_resources_->GetRoundStrokeStyle(); break;
case StrokeStyle::Miter: return miter_stroke_style_;
case StrokeStyle::Bevel: return bevel_stroke_style_;
case StrokeStyle::Round: return round_stroke_style_;
}
return nullptr;
}
void RenderTarget::SetTransform(const Matrix3x2& matrix)
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
if (SUCCEEDED(hr))
if (fast_global_transform_)
{
if (fast_global_transform_)
{
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
}
else
{
Matrix3x2 result = matrix * global_transform_;
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result));
}
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
}
else
{
Matrix3x2 result = matrix * global_transform_;
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result));
}
ThrowIfFailed(hr);
}
void RenderTarget::SetGlobalTransform(const Matrix3x2* matrix)
@ -588,66 +471,53 @@ namespace kiwano
void RenderTarget::SetAntialiasMode(bool enabled)
{
HRESULT hr = S_OK;
if (!render_target_)
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
if (SUCCEEDED(hr))
{
render_target_->SetAntialiasMode(
enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
);
antialias_ = enabled;
}
ThrowIfFailed(hr);
render_target_->SetAntialiasMode(enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
antialias_ = enabled;
}
void RenderTarget::SetTextAntialiasMode(TextAntialiasMode mode)
{
HRESULT hr = S_OK;
if (!render_target_)
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
switch (mode)
{
hr = E_UNEXPECTED;
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;
}
if (SUCCEEDED(hr))
{
text_antialias_ = mode;
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
switch (text_antialias_)
{
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;
}
render_target_->SetTextAntialiasMode(antialias_mode);
}
ThrowIfFailed(hr);
text_antialias_ = mode;
render_target_->SetTextAntialiasMode(antialias_mode);
}
bool RenderTarget::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform)
{
Rect visible_size = { Point{}, reinterpret_cast<const Size&>(render_target_->GetSize()) };
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(transform.Transform(bounds));
}
return visible_size.Intersects(Matrix3x2(transform * global_transform_).Transform(bounds));
return visible_size_.Intersects(Matrix3x2(transform * global_transform_).Transform(bounds));
}
void RenderTarget::Resize(Size const& size)
{
visible_size_ = Rect(Point(), size);
}
void RenderTarget::SetCollectingStatus(bool collecting)

View File

@ -50,6 +50,8 @@ namespace kiwano
class KGE_API RenderTarget
: public ObjectBase
{
friend class Renderer;
public:
bool IsValid() const;
@ -133,27 +135,17 @@ namespace kiwano
D2D1_PIXEL_FORMAT format
);
void CreateLayer(
LayerArea& layer
);
void PushClipRect(
Rect const& clip_rect
);
void PushClipRect(Rect const& clip_rect);
void PopClipRect();
void PushLayer(
LayerArea& layer
);
void PushLayer(LayerArea& layer);
void PopLayer();
void Clear();
void Clear(
Color const& clear_color
);
void Clear(Color const& clear_color);
BrushPtr GetCurrentBrush() const;
@ -191,6 +183,10 @@ namespace kiwano
Matrix3x2 const& transform
);
void Resize(
Size const& size
);
public:
struct Status
{
@ -208,30 +204,34 @@ namespace kiwano
inline Status const& GetStatus() const { return status_; }
protected:
RenderTarget();
inline ComPtr<ID2D1RenderTarget> GetRenderTarget() const { KGE_ASSERT(render_target_); return render_target_; }
inline ComPtr<ITextRenderer> GetTextRenderer() const { KGE_ASSERT(text_renderer_); return text_renderer_; }
ComPtr<ID2D1StrokeStyle> GetStrokeStyle(StrokeStyle style);
protected:
RenderTarget();
HRESULT CreateDeviceResources(ComPtr<ID2D1RenderTarget> rt, ComPtr<ID2DDeviceResources> dev_res);
private:
HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> rt);
void DiscardDeviceResources();
private:
bool antialias_;
bool fast_global_transform_;
mutable bool collecting_status_;
mutable Status status_;
TextAntialiasMode text_antialias_;
ComPtr<ITextRenderer> text_renderer_;
ComPtr<ID2D1RenderTarget> render_target_;
ComPtr<ID2DDeviceResources> device_resources_;
ComPtr<ID2D1StrokeStyle> miter_stroke_style_;
ComPtr<ID2D1StrokeStyle> bevel_stroke_style_;
ComPtr<ID2D1StrokeStyle> round_stroke_style_;
BrushPtr current_brush_;
Rect visible_size_;
Matrix3x2 global_transform_;
mutable bool collecting_status_;
mutable Status status_;
};

View File

@ -19,6 +19,7 @@
// THE SOFTWARE.
#include <kiwano/renderer/Renderer.h>
#include <kiwano/core/Logger.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/platform/Window.h>
#include <kiwano/platform/FileSystem.h>
@ -61,20 +62,16 @@ namespace kiwano
HRESULT hr = hwnd_ ? S_OK : E_FAIL;
// Direct2D device resources
if (SUCCEEDED(hr))
{
hr = ID2DDeviceResources::Create(&d2d_res_);
}
// Direct3D device resources
if (SUCCEEDED(hr))
{
hr = ID3DDeviceResources::Create(
&d3d_res_,
d2d_res_.get(),
hwnd_
);
hr = ID3DDeviceResources::Create(&d3d_res_, hwnd_);
}
// Direct2D device resources
if (SUCCEEDED(hr))
{
hr = ID2DDeviceResources::Create(&d2d_res_, d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
}
// DrawingStateBlock
@ -88,7 +85,7 @@ namespace kiwano
// Other device resources
if (SUCCEEDED(hr))
{
hr = CreateDeviceResources();
hr = CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
}
// FontFileLoader and FontCollectionLoader
@ -130,7 +127,7 @@ namespace kiwano
{
KGE_SYS_LOG(L"Destroying device resources");
RenderTarget::DiscardDeviceResources();
DiscardDeviceResources();
d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.get());
res_font_file_loader_.reset();
@ -145,17 +142,9 @@ namespace kiwano
void Renderer::BeforeRender()
{
HRESULT hr = S_OK;
KGE_ASSERT(d3d_res_ && IsValid());
if (!IsValid())
{
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
hr = d3d_res_->ClearRenderTarget(clear_color_);
}
HRESULT hr = d3d_res_->ClearRenderTarget(clear_color_);
if (SUCCEEDED(hr))
{
@ -168,24 +157,12 @@ namespace kiwano
void Renderer::AfterRender()
{
HRESULT hr = S_OK;
if (!IsValid())
{
hr = E_UNEXPECTED;
}
KGE_ASSERT(d3d_res_ && IsValid());
if (SUCCEEDED(hr))
{
EndDraw();
EndDraw();
GetRenderTarget()->RestoreDrawingState(drawing_state_block_.get());
GetRenderTarget()->RestoreDrawingState(drawing_state_block_.get());
}
if (SUCCEEDED(hr))
{
hr = d3d_res_->Present(vsync_);
}
HRESULT hr = d3d_res_->Present(vsync_);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
@ -211,24 +188,20 @@ namespace kiwano
}
}
HRESULT Renderer::CreateDeviceResources()
{
KGE_ASSERT(d2d_res_);
HRESULT hr = RenderTarget::CreateDeviceResources(
d2d_res_->GetDeviceContext(),
d2d_res_
);
return hr;
}
HRESULT Renderer::HandleDeviceLost()
{
KGE_ASSERT(d3d_res_ && d2d_res_ && render_target_);
HRESULT hr = d3d_res_->HandleDeviceLost();
if (SUCCEEDED(hr))
{
hr = CreateDeviceResources();
hr = d2d_res_->HandleDeviceLost(d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
}
if (SUCCEEDED(hr))
{
hr = CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext());
}
return hr;
}
@ -998,6 +971,19 @@ namespace kiwano
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);
}
ThrowIfFailed(hr);
}
void Renderer::SetVSyncEnabled(bool enabled)
{
vsync_ = enabled;
@ -1011,10 +997,9 @@ namespace kiwano
void Renderer::ResizeTarget(uint32_t width, uint32_t height)
{
HRESULT hr = S_OK;
if (!d3d_res_)
{
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
@ -1023,19 +1008,17 @@ namespace kiwano
hr = d3d_res_->SetLogicalSize(output_size_);
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->SetLogicalSize(output_size_);
}
if (SUCCEEDED(hr))
{
Resize(reinterpret_cast<const Size&>(GetRenderTarget()->GetSize()));
}
ThrowIfFailed(hr);
}
void Renderer::Destroy()
{
DiscardDeviceResources();
d2d_res_.reset();
d3d_res_.reset();
drawing_state_block_.reset();
font_collection_loader_.reset();
res_font_file_loader_.reset();
res_font_collection_loader_.reset();
}
}

View File

@ -171,6 +171,10 @@ namespace kiwano
GradientExtendMode extend_mode
);
void SetDpi(
float dpi
);
public:
void Init(RenderConfig const& config);
@ -184,8 +188,6 @@ namespace kiwano
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
void Destroy();
public:
inline HWND GetTargetWindow() const { return hwnd_; }
@ -202,8 +204,6 @@ namespace kiwano
~Renderer();
HRESULT CreateDeviceResources();
HRESULT HandleDeviceLost();
void ResizeTarget(uint32_t width, uint32_t height);

View File

@ -36,7 +36,13 @@ namespace kiwano
HRESULT CreateDeviceIndependentResources();
public:
HRESULT CreateDeviceResources(
_In_ ComPtr<IDXGIDevice> dxgi_device,
_In_ ComPtr<IDXGISwapChain> dxgi_swap_chain
);
HRESULT CreateWindowSizeDependentResources();
HRESULT CreateBitmapConverter(
_Out_ ComPtr<IWICFormatConverter>& converter,
_In_opt_ ComPtr<IWICBitmapSource> source,
@ -65,26 +71,31 @@ namespace kiwano
HRESULT CreateTextFormat(
_Out_ ComPtr<IDWriteTextFormat>& text_format,
_In_ String const& family,
String const& family,
_In_ ComPtr<IDWriteFontCollection> collection,
_In_ DWRITE_FONT_WEIGHT weight,
_In_ DWRITE_FONT_STYLE style,
_In_ DWRITE_FONT_STRETCH stretch,
_In_ FLOAT font_size
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch,
FLOAT font_size
) override;
HRESULT CreateTextLayout(
_Out_ ComPtr<IDWriteTextLayout>& text_layout,
_In_ String const& text,
String const& text,
_In_ ComPtr<IDWriteTextFormat> text_format
) override;
HRESULT SetD2DDevice(
_In_ ComPtr<ID2D1Device> device
HRESULT SetDpi(
float dpi
) override;
void SetTargetBitmap(
_In_ ComPtr<ID2D1Bitmap1> target
HRESULT SetLogicalSize(
Size logical_size
) override;
HRESULT HandleDeviceLost(
_In_ ComPtr<IDXGIDevice> dxgi_device,
_In_ ComPtr<IDXGISwapChain> dxgi_swap_chain
) override;
void DiscardResources() override;
@ -102,10 +113,15 @@ namespace kiwano
private:
unsigned long ref_count_;
float dpi_;
ComPtr<IDXGISwapChain> dxgi_swap_chain_;
};
HRESULT ID2DDeviceResources::Create(ID2DDeviceResources** device_resources)
HRESULT ID2DDeviceResources::Create(
_Out_ ID2DDeviceResources** device_resources,
_In_ ComPtr<IDXGIDevice> dxgi_device,
_In_ ComPtr<IDXGISwapChain> dxgi_swap_chain)
{
HRESULT hr = E_FAIL;
if (device_resources)
@ -114,17 +130,22 @@ namespace kiwano
if (res)
{
hr = res->CreateDeviceIndependentResources();
if (SUCCEEDED(hr))
{
hr = res->CreateDeviceResources(dxgi_device, dxgi_swap_chain);
}
if (SUCCEEDED(hr))
{
hr = res->CreateWindowSizeDependentResources();
}
}
if (SUCCEEDED(hr))
{
res->AddRef();
if (*device_resources)
{
(*device_resources)->Release();
}
(*device_resources) = res;
DX::SafeRelease(*device_resources);
(*device_resources) = DX::SafeAcquire(res);
}
else
{
@ -194,10 +215,6 @@ namespace kiwano
imaging_factory_.reset();
dwrite_factory_.reset();
miter_stroke_style_.reset();
bevel_stroke_style_.reset();
round_stroke_style_.reset();
}
HRESULT D2DDeviceResources::CreateDeviceIndependentResources()
@ -224,7 +241,10 @@ namespace kiwano
if (SUCCEEDED(hr))
{
factory_ = factory;
}
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
@ -232,101 +252,114 @@ namespace kiwano
__uuidof(IWICImagingFactory),
reinterpret_cast<void**>(&imaging_factory)
);
if (SUCCEEDED(hr))
{
imaging_factory_ = imaging_factory;
}
}
if (SUCCEEDED(hr))
{
imaging_factory_ = imaging_factory;
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&dwrite_factory)
);
if (SUCCEEDED(hr))
{
dwrite_factory_ = dwrite_factory;
}
}
return hr;
}
HRESULT D2DDeviceResources::CreateDeviceResources(_In_ ComPtr<IDXGIDevice> dxgi_device, _In_ ComPtr<IDXGISwapChain> dxgi_swap_chain)
{
if (!factory_)
return E_UNEXPECTED;
// Create the Direct2D device object and a corresponding context.
ComPtr<ID2D1Device> device;
HRESULT hr = factory_->CreateDevice(dxgi_device.get(), &device);
if (SUCCEEDED(hr))
{
dwrite_factory_ = dwrite_factory;
ComPtr<ID2D1DeviceContext> device_ctx;
ComPtr<ID2D1StrokeStyle> miter_stroke_style;
ComPtr<ID2D1StrokeStyle> bevel_stroke_style;
ComPtr<ID2D1StrokeStyle> round_stroke_style;
D2D1_STROKE_STYLE_PROPERTIES stroke_style = D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_MITER,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f
);
hr = factory_->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&miter_stroke_style
hr = device->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&device_ctx
);
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
hr = factory_->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&bevel_stroke_style
);
}
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
hr = factory_->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&round_stroke_style
);
}
if (SUCCEEDED(hr))
{
miter_stroke_style_ = miter_stroke_style;
bevel_stroke_style_ = bevel_stroke_style;
round_stroke_style_ = round_stroke_style;
device_ = device;
device_context_ = device_ctx;
device_context_->SetDpi(dpi_, dpi_);
dxgi_swap_chain_ = dxgi_swap_chain;
}
}
return hr;
}
HRESULT D2DDeviceResources::SetD2DDevice(_In_ ComPtr<ID2D1Device> device)
HRESULT D2DDeviceResources::CreateWindowSizeDependentResources()
{
ComPtr<ID2D1DeviceContext> device_ctx;
if (!dxgi_swap_chain_ || !device_context_)
return E_UNEXPECTED;
HRESULT hr = device->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&device_ctx
);
// Create a Direct2D target bitmap associated with the
// swap chain back buffer and set it as the current target.
ComPtr<IDXGISurface> dxgi_back_buffer;
HRESULT hr = dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer));
if (SUCCEEDED(hr))
{
device_ = device;
device_context_ = device_ctx;
device_context_->SetDpi(dpi_, dpi_);
}
ComPtr<ID2D1Bitmap1> target;
hr = device_context_->CreateBitmapFromDxgiSurface(
dxgi_back_buffer.get(),
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpi_,
dpi_),
&target);
return hr;
if (SUCCEEDED(hr))
{
target_bitmap_ = target;
device_context_->SetTarget(target_bitmap_.get());
}
}
return E_NOTIMPL;
}
void D2DDeviceResources::SetTargetBitmap(_In_ ComPtr<ID2D1Bitmap1> target)
HRESULT D2DDeviceResources::SetDpi(float dpi)
{
target_bitmap_ = target;
if (device_context_)
device_context_->SetTarget(target_bitmap_.get());
if (!device_context_)
return E_UNEXPECTED;
device_context_->SetDpi(dpi, dpi);
return CreateWindowSizeDependentResources();
}
HRESULT D2DDeviceResources::SetLogicalSize(Size)
{
return CreateWindowSizeDependentResources();
}
HRESULT D2DDeviceResources::HandleDeviceLost(_In_ ComPtr<IDXGIDevice> dxgi_device, _In_ ComPtr<IDXGISwapChain> dxgi_swap_chain)
{
dxgi_swap_chain_ = nullptr;
HRESULT hr = CreateDeviceResources(dxgi_device, dxgi_swap_chain);
if (SUCCEEDED(hr))
{
hr = CreateWindowSizeDependentResources();
}
return hr;
}
HRESULT D2DDeviceResources::CreateBitmapConverter(_Out_ ComPtr<IWICFormatConverter>& converter, _In_opt_ ComPtr<IWICBitmapSource> source,
@ -440,8 +473,8 @@ namespace kiwano
return hr;
}
HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr<IDWriteTextFormat> & text_format, _In_ String const& family, _In_ ComPtr<IDWriteFontCollection> collection,
_In_ DWRITE_FONT_WEIGHT weight, _In_ DWRITE_FONT_STYLE style, _In_ DWRITE_FONT_STRETCH stretch, _In_ FLOAT font_size)
HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr<IDWriteTextFormat> & text_format, String const& family, _In_ ComPtr<IDWriteFontCollection> collection,
DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, FLOAT font_size)
{
if (!dwrite_factory_)
return E_UNEXPECTED;
@ -465,7 +498,7 @@ namespace kiwano
return hr;
}
HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr<IDWriteTextLayout>& text_layout, _In_ String const& text,
HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr<IDWriteTextLayout>& text_layout, String const& text,
_In_ ComPtr<IDWriteTextFormat> text_format)
{
if (!dwrite_factory_)

View File

@ -19,166 +19,12 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/math/math.h>
#include <kiwano/core/Resource.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano/renderer/Color.h>
#include <kiwano/renderer/win32/helper.h>
#include <dwrite.h>
#include <d2d1.h>
#include <d2d1_1.h>
namespace kiwano
{
namespace DX
{
template <typename T>
inline void SafeRelease(T*& ptr)
{
if (ptr != nullptr)
{
ptr->Release();
ptr = nullptr;
}
}
template <typename T>
inline T* SafeAcquire(T* ptr)
{
if (ptr != nullptr)
{
ptr->AddRef();
}
return ptr;
}
//
// Point2F
//
inline D2D1_POINT_2F const& ConvertToPoint2F(Vec2 const& vec2)
{
return reinterpret_cast<D2D1_POINT_2F const&>(vec2);
}
inline D2D1_POINT_2F& ConvertToPoint2F(Vec2& vec2)
{
return reinterpret_cast<D2D1_POINT_2F&>(vec2);
}
inline const D2D1_POINT_2F* ConvertToPoint2F(const Vec2* vec2)
{
return reinterpret_cast<const D2D1_POINT_2F*>(vec2);
}
inline D2D1_POINT_2F* ConvertToPoint2F(Vec2* vec2)
{
return reinterpret_cast<D2D1_POINT_2F*>(vec2);
}
//
// SizeF
//
inline D2D1_SIZE_F const& ConvertToSizeF(Vec2 const& vec2)
{
return reinterpret_cast<D2D1_SIZE_F const&>(vec2);
}
inline D2D1_SIZE_F& ConvertToSizeF(Vec2& vec2)
{
return reinterpret_cast<D2D1_SIZE_F&>(vec2);
}
inline const D2D1_SIZE_F* ConvertToSizeF(const Vec2* vec2)
{
return reinterpret_cast<const D2D1_SIZE_F*>(vec2);
}
inline D2D1_SIZE_F* ConvertToSizeF(Vec2* vec2)
{
return reinterpret_cast<D2D1_SIZE_F*>(vec2);
}
//
// RectF
//
inline D2D1_RECT_F const& ConvertToRectF(Rect const& rect)
{
return reinterpret_cast<D2D1_RECT_F const&>(rect);
}
inline D2D1_RECT_F& ConvertToRectF(Rect& rect)
{
return reinterpret_cast<D2D1_RECT_F&>(rect);
}
inline const D2D1_RECT_F* ConvertToRectF(const Rect* rect)
{
return reinterpret_cast<const D2D1_RECT_F*>(rect);
}
inline D2D1_RECT_F* ConvertToRectF(Rect* rect)
{
return reinterpret_cast<D2D1_RECT_F*>(rect);
}
//
// ColorF
//
inline D2D1_COLOR_F const& ConvertToColorF(Color const& color)
{
return reinterpret_cast<D2D1_COLOR_F const&>(color);
}
inline D2D1_COLOR_F& ConvertToColorF(Color& color)
{
return reinterpret_cast<D2D1_COLOR_F&>(color);
}
inline const D2D1_COLOR_F* ConvertToColorF(const Color* color)
{
return reinterpret_cast<const D2D1_COLOR_F*>(color);
}
inline D2D1_COLOR_F* ConvertToColorF(Color* color)
{
return reinterpret_cast<D2D1_COLOR_F*>(color);
}
//
// MatrixF
//
inline D2D1_MATRIX_3X2_F const& ConvertToMatrix3x2F(Matrix3x2 const& matrix)
{
return reinterpret_cast<D2D1_MATRIX_3X2_F const&>(matrix);
}
inline D2D1_MATRIX_3X2_F& ConvertToMatrix3x2F(Matrix3x2& matrix)
{
return reinterpret_cast<D2D1_MATRIX_3X2_F&>(matrix);
}
inline const D2D1_MATRIX_3X2_F* ConvertToMatrix3x2F(const Matrix3x2* matrix)
{
return reinterpret_cast<const D2D1_MATRIX_3X2_F*>(matrix);
}
inline D2D1_MATRIX_3X2_F* ConvertToMatrix3x2F(Matrix3x2* matrix)
{
return reinterpret_cast<D2D1_MATRIX_3X2_F*>(matrix);
}
// Converts a length in device-independent pixels (DIPs) to a length in physical pixels.
inline float ConvertDipsToPixels(float dips, float dpi)
{
static const float dips_per_inch = 96.0f;
return math::Floor(dips * dpi / dips_per_inch + 0.5f); // Round to nearest integer.
}
}
}
namespace kiwano
{
MIDL_INTERFACE("5706684a-bf6d-4b03-b627-094758a33032")
@ -186,7 +32,11 @@ namespace kiwano
: public IUnknown
{
public:
static HRESULT Create(ID2DDeviceResources** device_resources);
static HRESULT Create(
_Out_ ID2DDeviceResources** device_resources,
_In_ ComPtr<IDXGIDevice> dxgi_device,
_In_ ComPtr<IDXGISwapChain> dxgi_swap_chain
);
virtual HRESULT CreateBitmapConverter(
_Out_ ComPtr<IWICFormatConverter>& converter,
@ -216,26 +66,31 @@ namespace kiwano
virtual HRESULT CreateTextFormat(
_Out_ ComPtr<IDWriteTextFormat>& text_format,
_In_ String const& family,
String const& family,
_In_ ComPtr<IDWriteFontCollection> collection,
_In_ DWRITE_FONT_WEIGHT weight,
_In_ DWRITE_FONT_STYLE style,
_In_ DWRITE_FONT_STRETCH stretch,
_In_ FLOAT font_size
DWRITE_FONT_WEIGHT weight,
DWRITE_FONT_STYLE style,
DWRITE_FONT_STRETCH stretch,
FLOAT font_size
) = 0;
virtual HRESULT CreateTextLayout(
_Out_ ComPtr<IDWriteTextLayout>& text_layout,
_In_ String const& text,
String const& text,
_In_ ComPtr<IDWriteTextFormat> text_format
) = 0;
virtual HRESULT SetD2DDevice(
_In_ ComPtr<ID2D1Device> device
virtual HRESULT SetDpi(
float dpi
) = 0;
virtual void SetTargetBitmap(
_In_ ComPtr<ID2D1Bitmap1> target
virtual HRESULT SetLogicalSize(
Size logical_size
) = 0;
virtual HRESULT HandleDeviceLost(
_In_ ComPtr<IDXGIDevice> dxgi_device,
_In_ ComPtr<IDXGISwapChain> dxgi_swap_chain
) = 0;
virtual void DiscardResources() = 0;
@ -247,10 +102,6 @@ namespace kiwano
inline ID2D1DeviceContext* GetDeviceContext() { KGE_ASSERT(device_context_); return device_context_.get(); }
inline ID2D1Bitmap1* GetTargetBitmap() { KGE_ASSERT(target_bitmap_); return target_bitmap_.get(); }
inline ID2D1StrokeStyle* GetMiterStrokeStyle() { KGE_ASSERT(miter_stroke_style_); return miter_stroke_style_.get(); }
inline ID2D1StrokeStyle* GetBevelStrokeStyle() { KGE_ASSERT(bevel_stroke_style_); return bevel_stroke_style_.get(); }
inline ID2D1StrokeStyle* GetRoundStrokeStyle() { KGE_ASSERT(round_stroke_style_); return round_stroke_style_.get(); }
protected:
ComPtr<ID2D1Factory1> factory_;
ComPtr<ID2D1Device> device_;
@ -259,10 +110,6 @@ namespace kiwano
ComPtr<IWICImagingFactory> imaging_factory_;
ComPtr<IDWriteFactory> dwrite_factory_;
ComPtr<ID2D1StrokeStyle> miter_stroke_style_;
ComPtr<ID2D1StrokeStyle> bevel_stroke_style_;
ComPtr<ID2D1StrokeStyle> round_stroke_style_;
};
}

View File

@ -118,8 +118,6 @@ namespace kiwano
Size logical_size_;
Size output_size_;
unsigned long ref_count_;
ComPtr<ID2DDeviceResources> d2d_res_;
};
@ -135,11 +133,11 @@ namespace kiwano
DiscardResources();
}
HRESULT ID3D10DeviceResources::Create(ID3D10DeviceResources** device_resources, ID2DDeviceResources* d2d_device_res, HWND hwnd)
HRESULT ID3D10DeviceResources::Create(ID3D10DeviceResources** device_resources, HWND hwnd)
{
HRESULT hr = E_FAIL;
if (device_resources && d2d_device_res)
if (device_resources)
{
D3D10DeviceResources* res = new (std::nothrow) D3D10DeviceResources;
if (res)
@ -148,7 +146,6 @@ namespace kiwano
::GetClientRect(hwnd, &rc);
res->hwnd_ = hwnd;
res->d2d_res_ = d2d_device_res;
res->logical_size_.x = float(rc.right - rc.left);
res->logical_size_.y = float(rc.bottom - rc.top);
@ -199,10 +196,10 @@ namespace kiwano
void D3D10DeviceResources::DiscardResources()
{
d2d_res_.reset();
device_.reset();
rt_view_.reset();
ds_view_.reset();
dxgi_device_.reset();
dxgi_swap_chain_.reset();
dxgi_factory_.reset();
@ -236,40 +233,29 @@ namespace kiwano
{
device_ = device;
ComPtr<IDXGIAdapter> dxgi_adapter;
ComPtr<IDXGIDevice> dxgi_device;
ComPtr<IDXGIFactory> dxgi_factory;
ComPtr<ID2D1Device> d2d_device;
if (SUCCEEDED(hr))
{
ComPtr<IDXGIDevice> dxgi_device;
hr = device_->QueryInterface(IID_PPV_ARGS(&dxgi_device));
}
if (SUCCEEDED(hr))
{
hr = dxgi_device->GetAdapter(&dxgi_adapter);
}
if (SUCCEEDED(hr))
{
dxgi_device_ = dxgi_device;
if (SUCCEEDED(hr))
{
hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
}
ComPtr<IDXGIAdapter> dxgi_adapter;
hr = dxgi_device_->GetAdapter(&dxgi_adapter);
if (SUCCEEDED(hr))
{
dxgi_factory_ = dxgi_factory;
}
if (SUCCEEDED(hr))
{
ComPtr<IDXGIFactory> dxgi_factory;
hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
// Create the Direct2D device object and a corresponding context.
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetFactory()->CreateDevice(dxgi_device.get(), &d2d_device);
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->SetD2DDevice(d2d_device);
if (SUCCEEDED(hr))
{
dxgi_factory_ = dxgi_factory;
}
}
}
}
}
@ -292,31 +278,11 @@ namespace kiwano
swap_chain_desc.Windowed = TRUE;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
ComPtr<IDXGIDevice> dxgi_device;
if (SUCCEEDED(hr))
{
hr = device_->QueryInterface(&dxgi_device);
}
ComPtr<IDXGIAdapter> dxgi_adapter;
if (SUCCEEDED(hr))
{
hr = dxgi_device->GetAdapter(&dxgi_adapter);
}
ComPtr<IDXGIFactory> dxgi_factory;
if (SUCCEEDED(hr))
{
hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
}
if (SUCCEEDED(hr))
{
hr = dxgi_factory->CreateSwapChain(
device_.get(),
&swap_chain_desc,
&dxgi_swap_chain_);
}
hr = dxgi_factory_->CreateSwapChain(
device_.get(),
&swap_chain_desc,
&dxgi_swap_chain_
);
}
return hr;
@ -332,7 +298,6 @@ namespace kiwano
// Clear the previous window size specific context.
ID3D10RenderTargetView* null_views[] = { nullptr };
device_->OMSetRenderTargets(ARRAYSIZE(null_views), null_views, nullptr);
d2d_res_->SetTargetBitmap(nullptr);
rt_view_ = nullptr;
ds_view_ = nullptr;
device_->Flush();
@ -424,33 +389,6 @@ namespace kiwano
device_->RSSetViewports(1, &viewport);
}
// Create a Direct2D target bitmap associated with the
// swap chain back buffer and set it as the current target.
if (SUCCEEDED(hr))
{
ComPtr<IDXGISurface> dxgi_back_buffer;
hr = dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer));
ComPtr<ID2D1Bitmap1> target;
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDeviceContext()->CreateBitmapFromDxgiSurface(
dxgi_back_buffer.get(),
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpi_,
dpi_),
&target);
}
if (SUCCEEDED(hr))
{
d2d_res_->SetTargetBitmap(target);
}
}
return hr;
}
@ -490,8 +428,6 @@ namespace kiwano
logical_size_.x = float(rc.right - rc.left);
logical_size_.y = float(rc.bottom - rc.top);
d2d_res_->GetDeviceContext()->SetDpi(dpi_, dpi_);
return CreateWindowSizeDependentResources();
}
return S_OK;

View File

@ -21,8 +21,7 @@
#pragma once
#include <kiwano/macros.h>
#include <kiwano/renderer/win32/D2DDeviceResources.h>
#include <kiwano/renderer/win32/helper.h>
#include <kiwano/renderer/win32/D3DDeviceResourcesBase.h>
#include <d3d10_1.h>
@ -33,20 +32,22 @@ namespace kiwano
: public ID3DDeviceResourcesBase
{
public:
static HRESULT Create(ID3D10DeviceResources** device_resources, ID2DDeviceResources* d2d_device_res, HWND hwnd);
static HRESULT Create(ID3D10DeviceResources** device_resources, HWND hwnd);
inline ID3D10Device* GetDevice() { KGE_ASSERT(device_); return device_.get(); }
inline ID3D10RenderTargetView* GetRenderTargetView() { KGE_ASSERT(rt_view_); return rt_view_.get(); }
inline ID3D10DepthStencilView* GetDepthStencilView() { KGE_ASSERT(ds_view_); return ds_view_.get(); }
inline IDXGIFactory* GetDXGIFactory() { KGE_ASSERT(dxgi_factory_); return dxgi_factory_.get(); }
inline IDXGIDevice* GetDXGIDevice() { KGE_ASSERT(dxgi_device_); return dxgi_device_.get(); }
inline IDXGISwapChain* GetDXGISwapChain() { KGE_ASSERT(dxgi_swap_chain_); return dxgi_swap_chain_.get(); }
protected:
ComPtr<ID3D10Device> device_;
ComPtr<ID3D10RenderTargetView> rt_view_;
ComPtr<ID3D10DepthStencilView> ds_view_;
ComPtr<IDXGISwapChain> dxgi_swap_chain_;
ComPtr<IDXGIFactory> dxgi_factory_;
ComPtr<IDXGIDevice> dxgi_device_;
ComPtr<IDXGISwapChain> dxgi_swap_chain_;
};
}

View File

@ -19,8 +19,8 @@
// THE SOFTWARE.
#include <kiwano/renderer/win32/D3D11DeviceResources.h>
#include <kiwano/core/Logger.h>
#include <versionhelpers.h> // IsWindows10OrGreater
#pragma comment(lib, "d3d11.lib")
@ -95,7 +95,6 @@ namespace kiwano
unsigned long ref_count_;
D3D_FEATURE_LEVEL d3d_feature_level_;
ComPtr<ID2DDeviceResources> d2d_res_;
};
@ -112,11 +111,11 @@ namespace kiwano
DiscardResources();
}
HRESULT ID3D11DeviceResources::Create(ID3D11DeviceResources** device_resources, ID2DDeviceResources* d2d_device_res, HWND hwnd)
HRESULT ID3D11DeviceResources::Create(ID3D11DeviceResources** device_resources, HWND hwnd)
{
HRESULT hr = E_FAIL;
if (device_resources && d2d_device_res)
if (device_resources)
{
D3D11DeviceResources* res = new (std::nothrow) D3D11DeviceResources;
if (res)
@ -125,7 +124,6 @@ namespace kiwano
::GetClientRect(hwnd, &rc);
res->hwnd_ = hwnd;
res->d2d_res_ = d2d_device_res;
res->logical_size_.x = float(rc.right - rc.left);
res->logical_size_.y = float(rc.bottom - rc.top);
@ -176,11 +174,11 @@ namespace kiwano
void D3D11DeviceResources::DiscardResources()
{
d2d_res_.reset();
device_.reset();
device_context_.reset();
rt_view_.reset();
ds_view_.reset();
dxgi_device_.reset();
dxgi_swap_chain_.reset();
dxgi_factory_.reset();
@ -253,40 +251,29 @@ namespace kiwano
device_ = device;
device_context_ = context;
ComPtr<IDXGIAdapter> dxgi_adapter;
ComPtr<IDXGIDevice> dxgi_device;
ComPtr<IDXGIFactory> dxgi_factory;
ComPtr<ID2D1Device> d2d_device;
if (SUCCEEDED(hr))
{
ComPtr<IDXGIDevice> dxgi_device;
hr = device_->QueryInterface(IID_PPV_ARGS(&dxgi_device));
}
if (SUCCEEDED(hr))
{
hr = dxgi_device->GetAdapter(&dxgi_adapter);
}
if (SUCCEEDED(hr))
{
dxgi_device_ = dxgi_device;
if (SUCCEEDED(hr))
{
hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
}
ComPtr<IDXGIAdapter> dxgi_adapter;
hr = dxgi_device_->GetAdapter(&dxgi_adapter);
if (SUCCEEDED(hr))
{
dxgi_factory_ = dxgi_factory;
}
if (SUCCEEDED(hr))
{
ComPtr<IDXGIFactory> dxgi_factory;
hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
// Create the Direct2D device object and a corresponding context.
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetFactory()->CreateDevice(dxgi_device.get(), &d2d_device);
}
if (SUCCEEDED(hr))
{
hr = d2d_res_->SetD2DDevice(d2d_device);
if (SUCCEEDED(hr))
{
dxgi_factory_ = dxgi_factory;
}
}
}
}
}
@ -328,33 +315,12 @@ namespace kiwano
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
}
ComPtr<IDXGIDevice> dxgi_device;
if (SUCCEEDED(hr))
{
hr = device_->QueryInterface(&dxgi_device);
}
ComPtr<IDXGIAdapter> dxgi_adapter;
if (SUCCEEDED(hr))
{
hr = dxgi_device->GetAdapter(&dxgi_adapter);
}
ComPtr<IDXGIFactory> dxgi_factory;
if (SUCCEEDED(hr))
{
hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
}
if (SUCCEEDED(hr))
{
hr = dxgi_factory->CreateSwapChain(
device_.get(),
&swap_chain_desc,
&dxgi_swap_chain_);
}
hr = dxgi_factory_->CreateSwapChain(
device_.get(),
&swap_chain_desc,
&dxgi_swap_chain_
);
}
return hr;
}
@ -368,7 +334,6 @@ namespace kiwano
// Clear the previous window size specific context.
ID3D11RenderTargetView* null_views[] = { nullptr };
device_context_->OMSetRenderTargets(ARRAYSIZE(null_views), null_views, nullptr);
d2d_res_->SetTargetBitmap(nullptr);
rt_view_ = nullptr;
ds_view_ = nullptr;
device_context_->Flush();
@ -444,32 +409,6 @@ namespace kiwano
device_context_->RSSetViewports(1, &screen_viewport);
}
// Create a Direct2D target bitmap associated with the
// swap chain back buffer and set it as the current target.
if (SUCCEEDED(hr))
{
ComPtr<IDXGISurface> dxgi_back_buffer;
hr = dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer));
ComPtr<ID2D1Bitmap1> target;
if (SUCCEEDED(hr))
{
hr = d2d_res_->GetDeviceContext()->CreateBitmapFromDxgiSurface(
dxgi_back_buffer.get(),
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpi_,
dpi_),
&target);
}
if (SUCCEEDED(hr))
{
d2d_res_->SetTargetBitmap(target);
}
}
return hr;
}
@ -509,8 +448,6 @@ namespace kiwano
logical_size_.x = float(rc.right - rc.left);
logical_size_.y = float(rc.bottom - rc.top);
d2d_res_->GetDeviceContext()->SetDpi(dpi_, dpi_);
return CreateWindowSizeDependentResources();
}
return S_OK;

View File

@ -21,8 +21,7 @@
#pragma once
#include <kiwano/macros.h>
#include <kiwano/renderer/win32/D2DDeviceResources.h>
#include <kiwano/renderer/win32/helper.h>
#include <kiwano/renderer/win32/D3DDeviceResourcesBase.h>
#include <d3d11.h>
@ -33,13 +32,14 @@ namespace kiwano
: public ID3DDeviceResourcesBase
{
public:
static HRESULT Create(ID3D11DeviceResources** device_resources, ID2DDeviceResources* d2d_device_res, HWND hwnd);
static HRESULT Create(ID3D11DeviceResources** device_resources, HWND hwnd);
inline ID3D11Device* GetDevice() { KGE_ASSERT(device_); return device_.get(); }
inline ID3D11DeviceContext* GetDeviceContext() { KGE_ASSERT(device_context_); return device_context_.get(); }
inline ID3D11RenderTargetView* GetRenderTargetView() { KGE_ASSERT(rt_view_); return rt_view_.get(); }
inline ID3D11DepthStencilView* GetDepthStencilView() { KGE_ASSERT(ds_view_); return ds_view_.get(); }
inline IDXGIFactory* GetDXGIFactory() { KGE_ASSERT(dxgi_factory_); return dxgi_factory_.get(); }
inline IDXGIDevice* GetDXGIDevice() { KGE_ASSERT(dxgi_device_); return dxgi_device_.get(); }
inline IDXGISwapChain* GetDXGISwapChain() { KGE_ASSERT(dxgi_swap_chain_); return dxgi_swap_chain_.get(); }
protected:
@ -47,8 +47,9 @@ namespace kiwano
ComPtr<ID3D11DeviceContext> device_context_;
ComPtr<ID3D11RenderTargetView> rt_view_;
ComPtr<ID3D11DepthStencilView> ds_view_;
ComPtr<IDXGISwapChain> dxgi_swap_chain_;
ComPtr<IDXGIFactory> dxgi_factory_;
ComPtr<IDXGIDevice> dxgi_device_;
ComPtr<IDXGISwapChain> dxgi_swap_chain_;
};
}

View File

@ -0,0 +1,177 @@
// 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/math/math.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano/renderer/Color.h>
#include <d2d1.h>
namespace kiwano
{
namespace DX
{
template <typename T>
inline void SafeRelease(T*& ptr)
{
if (ptr != nullptr)
{
ptr->Release();
ptr = nullptr;
}
}
template <typename T>
inline T* SafeAcquire(T* ptr)
{
if (ptr != nullptr)
{
ptr->AddRef();
}
return ptr;
}
//
// Point2F
//
inline D2D1_POINT_2F const& ConvertToPoint2F(Vec2 const& vec2)
{
return reinterpret_cast<D2D1_POINT_2F const&>(vec2);
}
inline D2D1_POINT_2F& ConvertToPoint2F(Vec2& vec2)
{
return reinterpret_cast<D2D1_POINT_2F&>(vec2);
}
inline const D2D1_POINT_2F* ConvertToPoint2F(const Vec2* vec2)
{
return reinterpret_cast<const D2D1_POINT_2F*>(vec2);
}
inline D2D1_POINT_2F* ConvertToPoint2F(Vec2* vec2)
{
return reinterpret_cast<D2D1_POINT_2F*>(vec2);
}
//
// SizeF
//
inline D2D1_SIZE_F const& ConvertToSizeF(Vec2 const& vec2)
{
return reinterpret_cast<D2D1_SIZE_F const&>(vec2);
}
inline D2D1_SIZE_F& ConvertToSizeF(Vec2& vec2)
{
return reinterpret_cast<D2D1_SIZE_F&>(vec2);
}
inline const D2D1_SIZE_F* ConvertToSizeF(const Vec2* vec2)
{
return reinterpret_cast<const D2D1_SIZE_F*>(vec2);
}
inline D2D1_SIZE_F* ConvertToSizeF(Vec2* vec2)
{
return reinterpret_cast<D2D1_SIZE_F*>(vec2);
}
//
// RectF
//
inline D2D1_RECT_F const& ConvertToRectF(Rect const& rect)
{
return reinterpret_cast<D2D1_RECT_F const&>(rect);
}
inline D2D1_RECT_F& ConvertToRectF(Rect& rect)
{
return reinterpret_cast<D2D1_RECT_F&>(rect);
}
inline const D2D1_RECT_F* ConvertToRectF(const Rect* rect)
{
return reinterpret_cast<const D2D1_RECT_F*>(rect);
}
inline D2D1_RECT_F* ConvertToRectF(Rect* rect)
{
return reinterpret_cast<D2D1_RECT_F*>(rect);
}
//
// ColorF
//
inline D2D1_COLOR_F const& ConvertToColorF(Color const& color)
{
return reinterpret_cast<D2D1_COLOR_F const&>(color);
}
inline D2D1_COLOR_F& ConvertToColorF(Color& color)
{
return reinterpret_cast<D2D1_COLOR_F&>(color);
}
inline const D2D1_COLOR_F* ConvertToColorF(const Color* color)
{
return reinterpret_cast<const D2D1_COLOR_F*>(color);
}
inline D2D1_COLOR_F* ConvertToColorF(Color* color)
{
return reinterpret_cast<D2D1_COLOR_F*>(color);
}
//
// MatrixF
//
inline D2D1_MATRIX_3X2_F const& ConvertToMatrix3x2F(Matrix3x2 const& matrix)
{
return reinterpret_cast<D2D1_MATRIX_3X2_F const&>(matrix);
}
inline D2D1_MATRIX_3X2_F& ConvertToMatrix3x2F(Matrix3x2& matrix)
{
return reinterpret_cast<D2D1_MATRIX_3X2_F&>(matrix);
}
inline const D2D1_MATRIX_3X2_F* ConvertToMatrix3x2F(const Matrix3x2* matrix)
{
return reinterpret_cast<const D2D1_MATRIX_3X2_F*>(matrix);
}
inline D2D1_MATRIX_3X2_F* ConvertToMatrix3x2F(Matrix3x2* matrix)
{
return reinterpret_cast<D2D1_MATRIX_3X2_F*>(matrix);
}
// Converts a length in device-independent pixels (DIPs) to a length in physical pixels.
inline float ConvertDipsToPixels(float dips, float dpi)
{
static const float dips_per_inch = 96.0f;
return math::Floor(dips * dpi / dips_per_inch + 0.5f); // Round to nearest integer.
}
}
}