2019-04-11 14:40:54 +08:00
|
|
|
|
// Copyright (c) 2016-2018 Kiwano - Nomango
|
2019-03-31 01:37:06 +08:00
|
|
|
|
//
|
|
|
|
|
|
// 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 "render.h"
|
|
|
|
|
|
#include "../2d/Image.h"
|
|
|
|
|
|
#include "../base/logs.h"
|
|
|
|
|
|
#include "../platform/Application.h"
|
|
|
|
|
|
|
2019-04-11 14:40:54 +08:00
|
|
|
|
namespace kiwano
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
|
|
|
|
|
Renderer::Renderer()
|
|
|
|
|
|
: hwnd_(nullptr)
|
|
|
|
|
|
, antialias_(true)
|
|
|
|
|
|
, vsync_(true)
|
|
|
|
|
|
, text_antialias_(TextAntialias::ClearType)
|
|
|
|
|
|
, clear_color_(Color::Black)
|
|
|
|
|
|
, opacity_(1.f)
|
2019-07-29 09:40:39 +08:00
|
|
|
|
, collecting_status_(false)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
|
|
|
|
|
status_.primitives = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Renderer::~Renderer()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::SetupComponent(Application* app)
|
|
|
|
|
|
{
|
2019-04-11 14:40:54 +08:00
|
|
|
|
KGE_LOG(L"Creating device resources");
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
|
|
|
|
|
hwnd_ = app->GetWindow()->GetHandle();
|
2019-04-22 13:21:12 +08:00
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hwnd_ ? S_OK : E_FAIL);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
2019-07-30 00:41:06 +08:00
|
|
|
|
d2d_res_ = nullptr;
|
|
|
|
|
|
d3d_res_ = nullptr;
|
2019-04-22 13:21:12 +08:00
|
|
|
|
drawing_state_block_ = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
2019-07-30 00:41:06 +08:00
|
|
|
|
ID2DDeviceResources::Create(
|
|
|
|
|
|
&d2d_res_
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
#if defined(KGE_USE_DIRECTX10)
|
|
|
|
|
|
ID3D10DeviceResources::Create(
|
|
|
|
|
|
&d3d_res_,
|
|
|
|
|
|
d2d_res_.Get(),
|
|
|
|
|
|
hwnd_
|
|
|
|
|
|
)
|
|
|
|
|
|
#else
|
|
|
|
|
|
ID3D11DeviceResources::Create(
|
|
|
|
|
|
&d3d_res_,
|
|
|
|
|
|
d2d_res_.Get(),
|
2019-03-31 01:37:06 +08:00
|
|
|
|
hwnd_
|
2019-04-22 13:21:12 +08:00
|
|
|
|
)
|
2019-07-30 00:41:06 +08:00
|
|
|
|
#endif
|
2019-04-22 13:21:12 +08:00
|
|
|
|
);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
2019-07-30 00:41:06 +08:00
|
|
|
|
device_context_ = d2d_res_->GetDeviceContext();
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
2019-04-22 13:21:12 +08:00
|
|
|
|
ThrowIfFailed(
|
2019-07-30 00:41:06 +08:00
|
|
|
|
d2d_res_->GetFactory()->CreateDrawingStateBlock(
|
2019-03-31 01:37:06 +08:00
|
|
|
|
&drawing_state_block_
|
2019-04-22 13:21:12 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
2019-04-22 13:21:12 +08:00
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
CreateDeviceResources()
|
|
|
|
|
|
);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
2019-04-22 13:21:12 +08:00
|
|
|
|
output_size_ = app->GetWindow()->GetSize();
|
2019-03-31 01:37:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::DestroyComponent()
|
|
|
|
|
|
{
|
2019-04-11 14:40:54 +08:00
|
|
|
|
KGE_LOG(L"Destroying device resources");
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
|
|
|
|
|
drawing_state_block_.Reset();
|
|
|
|
|
|
solid_color_brush_.Reset();
|
2019-07-30 00:41:06 +08:00
|
|
|
|
d2d_res_.Reset();
|
|
|
|
|
|
d3d_res_.Reset();
|
2019-03-31 01:37:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-30 13:32:10 +08:00
|
|
|
|
void Renderer::BeforeRender()
|
|
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
BeginDraw()
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::AfterRender()
|
|
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
EndDraw()
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
case WM_SIZE:
|
|
|
|
|
|
{
|
|
|
|
|
|
UINT width = LOWORD(lparam);
|
|
|
|
|
|
UINT height = HIWORD(lparam);
|
|
|
|
|
|
|
|
|
|
|
|
Resize(width, height);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-31 01:37:06 +08:00
|
|
|
|
HRESULT Renderer::CreateDeviceResources()
|
|
|
|
|
|
{
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
|
|
|
|
|
|
hr = device_context_->CreateSolidColorBrush(
|
|
|
|
|
|
D2D1::ColorF(D2D1::ColorF::White),
|
|
|
|
|
|
&solid_color_brush_
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
hr = ITextRenderer::Create(
|
|
|
|
|
|
&text_renderer_,
|
|
|
|
|
|
device_context_.Get()
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
SetAntialiasMode(antialias_);
|
|
|
|
|
|
SetTextAntialiasMode(text_antialias_);
|
|
|
|
|
|
}
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::HandleDeviceLost()
|
|
|
|
|
|
{
|
2019-07-30 00:41:06 +08:00
|
|
|
|
HRESULT hr = d3d_res_->HandleDeviceLost();
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
hr = CreateDeviceResources();
|
|
|
|
|
|
}
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::BeginDraw()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (collecting_status_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
2019-04-09 02:25:17 +08:00
|
|
|
|
status_.start = Time::Now();
|
2019-03-31 01:37:06 +08:00
|
|
|
|
status_.primitives = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->SaveDrawingState(drawing_state_block_.Get());
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->BeginDraw();
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::EndDraw()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT hr = device_context_->EndDraw();
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->RestoreDrawingState(drawing_state_block_.Get());
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
2019-07-30 00:41:06 +08:00
|
|
|
|
hr = d3d_res_->Present(vsync_);
|
2019-07-29 09:40:39 +08:00
|
|
|
|
}
|
2019-03-31 01:37:06 +08:00
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
2019-07-30 00:41:06 +08:00
|
|
|
|
hr = d3d_res_->ClearRenderTarget(clear_color_);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> Direct3D <20>豸<EFBFBD><E8B1B8>ִ<EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
|
|
|
|
|
|
hr = HandleDeviceLost();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (collecting_status_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
2019-04-09 02:25:17 +08:00
|
|
|
|
status_.duration = Time::Now() - status_.start;
|
2019-03-31 01:37:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::CreateLayer(ComPtr<ID2D1Layer>& layer)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
layer = nullptr;
|
|
|
|
|
|
return device_context_->CreateLayer(&layer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::DrawGeometry(
|
|
|
|
|
|
ComPtr<ID2D1Geometry> const& geometry,
|
|
|
|
|
|
Color const& stroke_color,
|
|
|
|
|
|
float stroke_width,
|
|
|
|
|
|
StrokeStyle stroke
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!solid_color_brush_ || !device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->DrawGeometry(
|
|
|
|
|
|
geometry.Get(),
|
|
|
|
|
|
solid_color_brush_.Get(),
|
|
|
|
|
|
stroke_width,
|
2019-07-30 00:41:06 +08:00
|
|
|
|
d2d_res_->GetStrokeStyle(stroke)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (collecting_status_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
++status_.primitives;
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::FillGeometry(ComPtr<ID2D1Geometry> const & geometry, Color const& fill_color)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!solid_color_brush_ || !device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
|
|
|
|
|
device_context_->FillGeometry(
|
|
|
|
|
|
geometry.Get(),
|
|
|
|
|
|
solid_color_brush_.Get()
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-03 15:27:18 +08:00
|
|
|
|
HRESULT Renderer::DrawImage(ImagePtr image, Rect const& dest_rect)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
if (!image->GetBitmap())
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->DrawBitmap(
|
|
|
|
|
|
image->GetBitmap().Get(),
|
|
|
|
|
|
DX::ConvertToRectF(dest_rect),
|
|
|
|
|
|
opacity_,
|
|
|
|
|
|
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
|
|
|
|
|
DX::ConvertToRectF(image->GetCropRect())
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (collecting_status_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
++status_.primitives;
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-04-14 22:37:05 +08:00
|
|
|
|
HRESULT Renderer::DrawBitmap(ComPtr<ID2D1Bitmap> const & bitmap, Rect const& src_rect, Rect const& dest_rect)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
if (!bitmap)
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
|
|
|
|
// Do not crop bitmap
|
|
|
|
|
|
device_context_->DrawBitmap(
|
|
|
|
|
|
bitmap.Get(),
|
2019-04-14 22:37:05 +08:00
|
|
|
|
DX::ConvertToRectF(dest_rect),
|
2019-03-31 01:37:06 +08:00
|
|
|
|
opacity_,
|
|
|
|
|
|
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
2019-04-14 22:37:05 +08:00
|
|
|
|
DX::ConvertToRectF(src_rect)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (collecting_status_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
++status_.primitives;
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::DrawTextLayout(ComPtr<IDWriteTextLayout> const& text_layout)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!text_renderer_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
if (collecting_status_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
++status_.primitives;
|
|
|
|
|
|
return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::SetVSyncEnabled(bool enabled)
|
|
|
|
|
|
{
|
|
|
|
|
|
vsync_ = enabled;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::PushClip(const Matrix & clip_matrix, const Size & clip_size)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->SetTransform(DX::ConvertToMatrix3x2F(clip_matrix));
|
|
|
|
|
|
device_context_->PushAxisAlignedClip(
|
|
|
|
|
|
D2D1::RectF(0, 0, clip_size.x, clip_size.y),
|
|
|
|
|
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
|
|
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::PopClip()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->PopAxisAlignedClip();
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::PushLayer(ComPtr<ID2D1Layer> const& layer, LayerProperties const& properties)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_ || !solid_color_brush_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->PushLayer(
|
|
|
|
|
|
D2D1::LayerParameters(
|
|
|
|
|
|
DX::ConvertToRectF(properties.area),
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
|
|
|
|
D2D1::Matrix3x2F::Identity(),
|
|
|
|
|
|
properties.opacity,
|
|
|
|
|
|
solid_color_brush_.Get(),
|
|
|
|
|
|
D2D1_LAYER_OPTIONS_NONE
|
|
|
|
|
|
),
|
|
|
|
|
|
layer.Get()
|
|
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::PopLayer()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->PopLayer();
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::Resize(UINT width, UINT height)
|
|
|
|
|
|
{
|
|
|
|
|
|
output_size_.x = static_cast<float>(width);
|
|
|
|
|
|
output_size_.y = static_cast<float>(height);
|
2019-07-30 00:41:06 +08:00
|
|
|
|
if (d3d_res_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
2019-07-30 00:41:06 +08:00
|
|
|
|
return d3d_res_->SetLogicalSize(output_size_);
|
2019-03-31 01:37:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-29 09:40:39 +08:00
|
|
|
|
void Renderer::SetCollectingStatus(bool collecting)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
{
|
2019-07-29 09:40:39 +08:00
|
|
|
|
collecting_status_ = collecting;
|
2019-03-31 01:37:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::SetClearColor(const Color & color)
|
|
|
|
|
|
{
|
|
|
|
|
|
clear_color_ = color;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::SetTransform(const Matrix & matrix)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2019-07-29 14:48:17 +08:00
|
|
|
|
device_context_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
|
2019-03-31 01:37:06 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Renderer::SetOpacity(float opacity)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (opacity_ != opacity)
|
|
|
|
|
|
{
|
|
|
|
|
|
opacity_ = opacity;
|
|
|
|
|
|
solid_color_brush_->SetOpacity(opacity);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::SetTextStyle(
|
|
|
|
|
|
Color const& color,
|
|
|
|
|
|
bool has_outline,
|
|
|
|
|
|
Color const& outline_color,
|
|
|
|
|
|
float outline_width,
|
|
|
|
|
|
StrokeStyle outline_stroke
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
2019-07-30 00:41:06 +08:00
|
|
|
|
if (!text_renderer_ || !d3d_res_)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
text_renderer_->SetTextStyle(
|
|
|
|
|
|
DX::ConvertToColorF(color),
|
|
|
|
|
|
has_outline,
|
|
|
|
|
|
DX::ConvertToColorF(outline_color),
|
|
|
|
|
|
outline_width,
|
2019-07-30 00:41:06 +08:00
|
|
|
|
d2d_res_->GetStrokeStyle(outline_stroke)
|
2019-03-31 01:37:06 +08:00
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::SetAntialiasMode(bool enabled)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
device_context_->SetAntialiasMode(
|
|
|
|
|
|
enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
|
|
|
|
|
|
);
|
|
|
|
|
|
antialias_ = enabled;
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT Renderer::SetTextAntialiasMode(TextAntialias mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!device_context_)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
text_antialias_ = mode;
|
|
|
|
|
|
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
|
|
|
switch (text_antialias_)
|
|
|
|
|
|
{
|
|
|
|
|
|
case TextAntialias::Default:
|
|
|
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TextAntialias::ClearType:
|
|
|
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TextAntialias::GrayScale:
|
|
|
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TextAntialias::None:
|
|
|
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
device_context_->SetTextAntialiasMode(antialias_mode);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|