2020-02-09 18:41:59 +08:00
|
|
|
// 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/render/DirectX/RenderContextImpl.h>
|
2020-02-16 20:14:01 +08:00
|
|
|
#include <kiwano/render/DirectX/NativePtr.h>
|
2020-02-16 20:32:08 +08:00
|
|
|
#include <kiwano/render/Renderer.h>
|
2020-05-24 11:26:21 +08:00
|
|
|
#include <kiwano/utils/Logger.h>
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
namespace kiwano
|
|
|
|
|
{
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
RenderContextImpl::RenderContextImpl() {}
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
RenderContextImpl::~RenderContextImpl()
|
|
|
|
|
{
|
|
|
|
|
DiscardDeviceResources();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 18:22:52 +08:00
|
|
|
HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> render_target)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
2020-02-20 18:22:52 +08:00
|
|
|
if (!factory || !render_target)
|
2020-02-09 18:41:59 +08:00
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
2020-02-20 18:22:52 +08:00
|
|
|
render_target_ = render_target;
|
2020-02-15 17:32:32 +08:00
|
|
|
text_renderer_.Reset();
|
|
|
|
|
current_brush_.Reset();
|
2020-02-09 18:41:59 +08:00
|
|
|
|
2020-02-15 17:32:32 +08:00
|
|
|
HRESULT hr = ITextRenderer::Create(&text_renderer_, render_target_.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
SetAntialiasMode(antialias_);
|
|
|
|
|
SetTextAntialiasMode(text_antialias_);
|
|
|
|
|
|
2020-02-20 18:22:52 +08:00
|
|
|
Resize(reinterpret_cast<const Size&>(render_target->GetSize()));
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DrawingStateBlock
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
hr = factory->CreateDrawingStateBlock(&drawing_state_);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 18:22:52 +08:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
NativePtr::Set(this, render_target);
|
|
|
|
|
}
|
2020-02-09 18:41:59 +08:00
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderContextImpl::DiscardDeviceResources()
|
|
|
|
|
{
|
2020-02-15 17:32:32 +08:00
|
|
|
text_renderer_.Reset();
|
|
|
|
|
render_target_.Reset();
|
|
|
|
|
current_brush_.Reset();
|
2020-02-09 18:41:59 +08:00
|
|
|
|
2020-02-20 18:22:52 +08:00
|
|
|
ResetNativePointer();
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderContextImpl::BeginDraw()
|
|
|
|
|
{
|
2020-10-04 04:39:22 +08:00
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
|
2020-02-09 18:41:59 +08:00
|
|
|
SaveDrawingState();
|
|
|
|
|
|
|
|
|
|
RenderContext::BeginDraw();
|
|
|
|
|
|
2020-10-04 04:39:22 +08:00
|
|
|
render_target_->BeginDraw();
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderContextImpl::EndDraw()
|
|
|
|
|
{
|
2020-10-04 04:39:22 +08:00
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
|
|
|
|
|
HRESULT hr = render_target_->EndDraw();
|
|
|
|
|
KGE_THROW_IF_FAILED(hr, "ID2D1RenderTarget EndDraw failed");
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
RenderContext::EndDraw();
|
|
|
|
|
|
|
|
|
|
RestoreDrawingState();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawTexture(const Texture& texture, const Rect* src_rect, const Rect* dest_rect)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
|
|
|
|
|
if (texture.IsValid())
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
D2D1_BITMAP_INTERPOLATION_MODE mode;
|
|
|
|
|
if (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
|
|
|
|
|
{
|
|
|
|
|
mode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mode = D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
|
|
|
|
|
}
|
2020-02-09 18:41:59 +08:00
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto bitmap = NativePtr::Get<ID2D1Bitmap>(texture);
|
|
|
|
|
render_target_->DrawBitmap(bitmap.Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, brush_opacity_,
|
|
|
|
|
mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawTextLayout(const TextLayout& layout, const Point& offset)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(text_renderer_ && "Text renderer has not been initialized!");
|
|
|
|
|
|
|
|
|
|
if (layout.IsValid())
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
auto native = NativePtr::Get<IDWriteTextLayout>(layout);
|
2020-08-04 16:31:20 +08:00
|
|
|
auto fill_brush = NativePtr::Get<ID2D1Brush>(layout.GetFillBrush());
|
|
|
|
|
auto outline_brush = NativePtr::Get<ID2D1Brush>(layout.GetOutlineBrush());
|
|
|
|
|
auto outline_stroke = NativePtr::Get<ID2D1StrokeStyle>(layout.GetOutlineStrokeStyle());
|
2020-02-16 20:14:01 +08:00
|
|
|
float outline_width = 1.0f;
|
2020-02-09 18:41:59 +08:00
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
if (fill_brush)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
fill_brush->SetOpacity(brush_opacity_);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
if (outline_brush)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
outline_brush->SetOpacity(brush_opacity_);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-04 16:31:20 +08:00
|
|
|
if (layout.GetOutlineStrokeStyle())
|
2020-02-16 12:53:18 +08:00
|
|
|
{
|
2020-08-05 01:55:42 +08:00
|
|
|
outline_width = layout.GetOutlineStrokeStyle()->GetWidth();
|
2020-02-16 12:53:18 +08:00
|
|
|
}
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
HRESULT hr = text_renderer_->DrawTextLayout(native.Get(), offset.x, offset.y, fill_brush.Get(),
|
2020-02-16 12:53:18 +08:00
|
|
|
outline_brush.Get(), outline_width, outline_stroke.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
IncreasePrimitivesCount(text_renderer_->GetLastPrimitivesCount());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-07-17 12:23:18 +08:00
|
|
|
KGE_ERRORF("Failed to draw text layout with HRESULT of %08X", hr);
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawShape(const Shape& shape)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
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())
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
|
|
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
2020-08-05 01:55:42 +08:00
|
|
|
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
2020-02-16 20:14:01 +08:00
|
|
|
|
|
|
|
|
render_target_->DrawGeometry(geometry.Get(), brush.Get(), stroke_width, stroke_style.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawLine(const Point& point1, const Point& point2)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
2020-08-05 01:55:42 +08:00
|
|
|
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
2020-02-16 20:14:01 +08:00
|
|
|
|
|
|
|
|
render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), brush.Get(), stroke_width,
|
|
|
|
|
stroke_style.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawRectangle(const Rect& rect)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
2020-08-05 01:55:42 +08:00
|
|
|
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
2020-02-16 20:14:01 +08:00
|
|
|
|
|
|
|
|
render_target_->DrawRectangle(DX::ConvertToRectF(rect), brush.Get(), stroke_width, stroke_style.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawRoundedRectangle(const Rect& rect, const Vec2& radius)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
2020-08-05 01:55:42 +08:00
|
|
|
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
2020-02-16 20:14:01 +08:00
|
|
|
|
|
|
|
|
render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get(),
|
|
|
|
|
stroke_width, stroke_style.Get());
|
2020-02-11 12:09:59 +08:00
|
|
|
|
2020-02-09 18:41:59 +08:00
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::DrawEllipse(const Point& center, const Vec2& radius)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
2020-08-05 01:55:42 +08:00
|
|
|
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
2020-02-16 20:14:01 +08:00
|
|
|
|
|
|
|
|
render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get(),
|
|
|
|
|
stroke_width, stroke_style.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::FillShape(const Shape& shape)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
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())
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
|
|
|
|
|
render_target_->FillGeometry(geometry.Get(), brush.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::FillRectangle(const Rect& rect)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
render_target_->FillRectangle(DX::ConvertToRectF(rect), brush.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::FillRoundedRectangle(const Rect& rect, const Vec2& radius)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::FillEllipse(const Point& center, const Vec2& radius)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
|
|
|
|
render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
NativePtr::Set(texture, saved_bitmap);
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
2020-02-15 17:32:32 +08:00
|
|
|
KGE_THROW_IF_FAILED(hr, "Create texture failed");
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::PushClipRect(const Rect& clip_rect)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
2020-02-16 20:14:01 +08:00
|
|
|
|
|
|
|
|
D2D1_ANTIALIAS_MODE mode;
|
|
|
|
|
if (antialias_)
|
|
|
|
|
{
|
|
|
|
|
mode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mode = D2D1_ANTIALIAS_MODE_ALIASED;
|
|
|
|
|
}
|
|
|
|
|
render_target_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect), mode);
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderContextImpl::PopClipRect()
|
|
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
|
|
|
|
render_target_->PopAxisAlignedClip();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-10 18:03:35 +08:00
|
|
|
void RenderContextImpl::PushLayer(Layer& layer)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
2020-02-10 14:41:19 +08:00
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto native = NativePtr::Get<ID2D1Layer>(layer);
|
|
|
|
|
auto mask = NativePtr::Get<ID2D1Geometry>(layer.GetMaskShape());
|
|
|
|
|
|
|
|
|
|
if (!native)
|
|
|
|
|
{
|
|
|
|
|
HRESULT hr = render_target_->CreateLayer(&native);
|
2020-02-09 18:41:59 +08:00
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
NativePtr::Set(layer, native);
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
2020-02-16 20:14:01 +08:00
|
|
|
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
2020-02-16 20:14:01 +08:00
|
|
|
auto params = D2D1::LayerParameters(DX::ConvertToRectF(layer.GetClipRect()), mask.Get(),
|
|
|
|
|
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
|
|
|
|
|
DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
|
|
|
|
|
D2D1_LAYER_OPTIONS_NONE);
|
|
|
|
|
|
|
|
|
|
render_target_->PushLayer(params, native.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::Clear(const Color& clear_color)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
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())
|
|
|
|
|
{
|
2020-02-16 20:14:01 +08:00
|
|
|
NativePtr::Get<ID2D1Brush>(current_brush_)->SetOpacity(brush_opacity_);
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-16 20:32:08 +08:00
|
|
|
void RenderContextImpl::SetCurrentStrokeStyle(StrokeStylePtr stroke_style)
|
|
|
|
|
{
|
|
|
|
|
RenderContext::SetCurrentStrokeStyle(stroke_style);
|
|
|
|
|
|
|
|
|
|
if (current_stroke_ && !current_stroke_->IsValid())
|
|
|
|
|
{
|
|
|
|
|
Renderer::GetInstance().CreateStrokeStyle(*current_stroke_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-09 18:41:59 +08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
bool RenderContextImpl::CheckVisibility(const Rect& bounds, const Matrix3x2& transform)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 12:09:50 +08:00
|
|
|
void RenderContextImpl::Resize(const Size& size)
|
2020-02-09 18:41:59 +08:00
|
|
|
{
|
|
|
|
|
visible_size_ = Rect(Point(), size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderContextImpl::SaveDrawingState()
|
|
|
|
|
{
|
|
|
|
|
KGE_ASSERT(IsValid());
|
|
|
|
|
|
|
|
|
|
if (drawing_state_)
|
|
|
|
|
{
|
2020-02-15 17:32:32 +08:00
|
|
|
render_target_->SaveDrawingState(drawing_state_.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderContextImpl::RestoreDrawingState()
|
|
|
|
|
{
|
|
|
|
|
KGE_ASSERT(IsValid());
|
|
|
|
|
|
|
|
|
|
if (drawing_state_)
|
|
|
|
|
{
|
2020-02-15 17:32:32 +08:00
|
|
|
render_target_->RestoreDrawingState(drawing_state_.Get());
|
2020-02-09 18:41:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace kiwano
|