2019-08-16 00:50:54 +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.
|
|
|
|
|
|
2019-10-11 21:55:29 +08:00
|
|
|
#include <kiwano/renderer/RenderTarget.h>
|
2019-11-13 14:33:15 +08:00
|
|
|
#include <kiwano/core/win32/helper.h>
|
2019-08-16 00:50:54 +08:00
|
|
|
|
|
|
|
|
namespace kiwano
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// RenderTarget
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RenderTarget::RenderTarget()
|
|
|
|
|
: opacity_(1.f)
|
|
|
|
|
, collecting_status_(false)
|
2019-08-21 12:47:19 +08:00
|
|
|
, fast_global_transform_(true)
|
2019-08-21 16:33:41 +08:00
|
|
|
, antialias_(true)
|
|
|
|
|
, text_antialias_(TextAntialiasMode::GrayScale)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
status_.primitives = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 19:32:36 +08:00
|
|
|
HRESULT RenderTarget::CreateDeviceResources(ComPtr<ID2D1RenderTarget> rt, ComPtr<ID2DDeviceResources> dev_res)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
|
|
if (rt && dev_res)
|
|
|
|
|
{
|
|
|
|
|
render_target_ = rt;
|
2019-08-20 19:32:36 +08:00
|
|
|
device_resources_ = dev_res;
|
2019-08-16 00:50:54 +08:00
|
|
|
hr = S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
text_renderer_.reset();
|
|
|
|
|
hr = ITextRenderer::Create(
|
|
|
|
|
&text_renderer_,
|
|
|
|
|
render_target_.get()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2019-08-20 19:32:36 +08:00
|
|
|
default_brush_.reset();
|
2019-08-16 00:50:54 +08:00
|
|
|
hr = render_target_->CreateSolidColorBrush(
|
|
|
|
|
D2D1::ColorF(D2D1::ColorF::White),
|
|
|
|
|
D2D1::BrushProperties(),
|
2019-08-20 19:32:36 +08:00
|
|
|
&default_brush_
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 22:02:53 +08:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2019-12-23 18:05:08 +08:00
|
|
|
SetAntialiasMode(antialias_);
|
|
|
|
|
SetTextAntialiasMode(text_antialias_);
|
|
|
|
|
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_ = default_brush_;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 19:32:36 +08:00
|
|
|
void RenderTarget::DiscardDeviceResources()
|
|
|
|
|
{
|
|
|
|
|
text_renderer_.reset();
|
|
|
|
|
render_target_.reset();
|
|
|
|
|
default_brush_.reset();
|
|
|
|
|
current_brush_.reset();
|
|
|
|
|
device_resources_.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
bool RenderTarget::IsValid() const
|
|
|
|
|
{
|
2019-08-20 19:32:36 +08:00
|
|
|
return render_target_ && device_resources_;
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::BeginDraw()
|
|
|
|
|
{
|
|
|
|
|
if (collecting_status_)
|
|
|
|
|
{
|
|
|
|
|
status_.start = Time::Now();
|
|
|
|
|
status_.primitives = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (render_target_)
|
|
|
|
|
{
|
|
|
|
|
render_target_->BeginDraw();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::EndDraw()
|
|
|
|
|
{
|
2019-09-09 22:02:53 +08:00
|
|
|
ThrowIfFailed( render_target_->EndDraw() );
|
2019-08-16 00:50:54 +08:00
|
|
|
|
|
|
|
|
if (collecting_status_)
|
|
|
|
|
{
|
|
|
|
|
status_.duration = Time::Now() - status_.start;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawGeometry(Geometry const& geometry, float stroke_width, StrokeStyle stroke)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr) && geometry.GetGeometry())
|
|
|
|
|
{
|
|
|
|
|
render_target_->DrawGeometry(
|
|
|
|
|
geometry.GetGeometry().get(),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get(),
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_width,
|
2019-08-21 16:33:41 +08:00
|
|
|
GetStrokeStyle(stroke).get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::FillGeometry(Geometry const& geometry)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr) && geometry.GetGeometry())
|
|
|
|
|
{
|
|
|
|
|
render_target_->FillGeometry(
|
|
|
|
|
geometry.GetGeometry().get(),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
2019-10-14 10:43:11 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawLine(Point const& point1, Point const& point2, float stroke_width, StrokeStyle stroke)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->DrawLine(
|
|
|
|
|
DX::ConvertToPoint2F(point1),
|
|
|
|
|
DX::ConvertToPoint2F(point2),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get(),
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_width,
|
2019-08-21 16:33:41 +08:00
|
|
|
GetStrokeStyle(stroke).get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawRectangle(Rect const& rect, float stroke_width, StrokeStyle stroke)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
|
|
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->DrawRectangle(
|
|
|
|
|
DX::ConvertToRectF(rect),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get(),
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_width,
|
2019-08-21 16:33:41 +08:00
|
|
|
GetStrokeStyle(stroke).get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::FillRectangle(Rect const& rect)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->FillRectangle(
|
|
|
|
|
DX::ConvertToRectF(rect),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
2019-10-14 10:43:11 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, float stroke_width, StrokeStyle stroke)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->DrawRoundedRectangle(
|
|
|
|
|
D2D1::RoundedRect(
|
|
|
|
|
DX::ConvertToRectF(rect),
|
|
|
|
|
radius.x,
|
|
|
|
|
radius.y
|
|
|
|
|
),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get(),
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_width,
|
2019-08-21 16:33:41 +08:00
|
|
|
GetStrokeStyle(stroke).get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::FillRoundedRectangle(Rect const& rect, Vec2 const& radius)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->FillRoundedRectangle(
|
|
|
|
|
D2D1::RoundedRect(
|
|
|
|
|
DX::ConvertToRectF(rect),
|
|
|
|
|
radius.x,
|
|
|
|
|
radius.y
|
|
|
|
|
),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
2019-10-14 10:43:11 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawEllipse(Point const& center, Vec2 const& radius, float stroke_width, StrokeStyle stroke)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->DrawEllipse(
|
|
|
|
|
D2D1::Ellipse(
|
|
|
|
|
DX::ConvertToPoint2F(center),
|
|
|
|
|
radius.x,
|
|
|
|
|
radius.y
|
|
|
|
|
),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get(),
|
2019-08-16 00:50:54 +08:00
|
|
|
stroke_width,
|
2019-08-21 16:33:41 +08:00
|
|
|
GetStrokeStyle(stroke).get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::FillEllipse(Point const& center, Vec2 const& radius)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_ || !current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->FillEllipse(
|
|
|
|
|
D2D1::Ellipse(
|
|
|
|
|
DX::ConvertToPoint2F(center),
|
|
|
|
|
radius.x,
|
|
|
|
|
radius.y
|
|
|
|
|
),
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_.get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
2019-10-14 10:43:11 +08:00
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
2019-08-21 16:33:41 +08:00
|
|
|
DrawTexture(texture, &src_rect, &dest_rect);
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 16:33:41 +08:00
|
|
|
if (SUCCEEDED(hr) && texture.IsValid())
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
2019-08-21 16:33:41 +08:00
|
|
|
auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear)
|
|
|
|
|
? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
|
|
|
|
|
: D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
render_target_->DrawBitmap(
|
2019-08-21 16:33:41 +08:00
|
|
|
texture.GetBitmap().get(),
|
2019-08-16 00:50:54 +08:00
|
|
|
dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
|
|
|
|
|
opacity_,
|
2019-08-21 16:33:41 +08:00
|
|
|
mode,
|
2019-08-16 00:50:54 +08:00
|
|
|
src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::DrawTextLayout(TextLayout const& layout, Point const& offset)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!text_renderer_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
text_renderer_->SetTextStyle(
|
|
|
|
|
opacity_,
|
|
|
|
|
DX::ConvertToColorF(layout.GetTextStyle().color),
|
|
|
|
|
layout.GetTextStyle().outline,
|
|
|
|
|
DX::ConvertToColorF(layout.GetTextStyle().outline_color),
|
|
|
|
|
layout.GetTextStyle().outline_width,
|
2019-08-21 16:33:41 +08:00
|
|
|
GetStrokeStyle(layout.GetTextStyle().outline_stroke).get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
2019-08-27 15:29:32 +08:00
|
|
|
|
|
|
|
|
hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), offset.x, offset.y);
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
IncreasePrimitivesCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
void RenderTarget::CreateLayer(LayerArea& layer)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2019-08-16 10:12:34 +08:00
|
|
|
ComPtr<ID2D1Layer> output;
|
|
|
|
|
hr = render_target_->CreateLayer(&output);
|
2019-08-16 00:50:54 +08:00
|
|
|
|
2019-08-16 10:12:34 +08:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
layer.SetLayer(output);
|
|
|
|
|
}
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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),
|
2019-08-16 10:12:34 +08:00
|
|
|
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::PopClipRect()
|
|
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->PopAxisAlignedClip();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 19:32:36 +08:00
|
|
|
void RenderTarget::PushLayer(LayerArea& layer)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!render_target_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 19:32:36 +08:00
|
|
|
if (!layer.IsValid())
|
|
|
|
|
{
|
|
|
|
|
CreateLayer(layer);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 10:12:34 +08:00
|
|
|
if (SUCCEEDED(hr) && layer.IsValid())
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
render_target_->PushLayer(
|
|
|
|
|
D2D1::LayerParameters(
|
2019-08-16 10:12:34 +08:00
|
|
|
DX::ConvertToRectF(layer.GetAreaRect()),
|
|
|
|
|
layer.GetMaskGeometry().GetGeometry().get(),
|
|
|
|
|
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
|
2019-08-20 19:32:36 +08:00
|
|
|
DX::ConvertToMatrix3x2F(layer.GetMaskTransform()),
|
2019-08-16 10:12:34 +08:00
|
|
|
layer.GetOpacity(),
|
2019-08-16 00:50:54 +08:00
|
|
|
nullptr,
|
|
|
|
|
D2D1_LAYER_OPTIONS_NONE
|
|
|
|
|
),
|
2019-08-16 10:12:34 +08:00
|
|
|
layer.GetLayer().get()
|
2019-08-16 00:50:54 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::PopLayer()
|
|
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->PopLayer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::Clear()
|
|
|
|
|
{
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
|
|
if (render_target_)
|
|
|
|
|
{
|
|
|
|
|
render_target_->Clear();
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-29 22:23:13 +08:00
|
|
|
float RenderTarget::GetOpacity() const
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
return opacity_;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 22:02:53 +08:00
|
|
|
Brush RenderTarget::GetCurrentBrush() const
|
|
|
|
|
{
|
|
|
|
|
return Brush( current_brush_ );
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 23:51:12 +08:00
|
|
|
Matrix3x2 RenderTarget::GetGlobalTransform() const
|
|
|
|
|
{
|
2019-08-21 12:47:19 +08:00
|
|
|
return global_transform_;
|
2019-08-20 23:51:12 +08:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
ComPtr<ID2D1StrokeStyle> RenderTarget::GetStrokeStyle(StrokeStyle style)
|
2019-08-21 16:33:41 +08:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void RenderTarget::SetTransform(const Matrix3x2& matrix)
|
|
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2019-08-21 12:47:19 +08:00
|
|
|
if (fast_global_transform_)
|
|
|
|
|
{
|
|
|
|
|
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Matrix3x2 result = matrix * global_transform_;
|
|
|
|
|
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result));
|
|
|
|
|
}
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 23:51:12 +08:00
|
|
|
void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix)
|
|
|
|
|
{
|
2019-08-21 12:47:19 +08:00
|
|
|
SetGlobalTransform(&matrix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::SetGlobalTransform(const Matrix3x2* matrix)
|
|
|
|
|
{
|
|
|
|
|
if (matrix)
|
|
|
|
|
{
|
|
|
|
|
global_transform_ = *matrix;
|
|
|
|
|
fast_global_transform_ = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fast_global_transform_ = true;
|
|
|
|
|
}
|
2019-08-20 23:51:12 +08:00
|
|
|
}
|
|
|
|
|
|
2019-09-29 22:23:13 +08:00
|
|
|
void RenderTarget::SetOpacity(float opacity)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
2019-09-09 22:02:53 +08:00
|
|
|
if (!current_brush_)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
if (opacity_ != opacity)
|
|
|
|
|
{
|
|
|
|
|
opacity_ = opacity;
|
2019-09-09 22:02:53 +08:00
|
|
|
current_brush_->SetOpacity(opacity);
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 22:02:53 +08:00
|
|
|
void RenderTarget::SetCurrentBrush(Brush const& brush)
|
|
|
|
|
{
|
|
|
|
|
current_brush_ = brush.GetBrush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::SetDefaultBrushColor(Color const& color)
|
|
|
|
|
{
|
|
|
|
|
KGE_ASSERT(default_brush_);
|
|
|
|
|
default_brush_->SetColor(DX::ConvertToColorF(color));
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void RenderTarget::SetAntialiasMode(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
render_target_->SetAntialiasMode(
|
|
|
|
|
enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
|
|
|
|
|
);
|
|
|
|
|
antialias_ = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 16:33:41 +08:00
|
|
|
void RenderTarget::SetTextAntialiasMode(TextAntialiasMode mode)
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (!render_target_)
|
|
|
|
|
{
|
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
text_antialias_ = mode;
|
|
|
|
|
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
|
|
switch (text_antialias_)
|
|
|
|
|
{
|
2019-08-21 16:33:41 +08:00
|
|
|
case TextAntialiasMode::Default:
|
2019-08-16 00:50:54 +08:00
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
|
|
|
break;
|
2019-08-21 16:33:41 +08:00
|
|
|
case TextAntialiasMode::ClearType:
|
2019-08-16 00:50:54 +08:00
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
|
|
break;
|
2019-08-21 16:33:41 +08:00
|
|
|
case TextAntialiasMode::GrayScale:
|
2019-08-16 00:50:54 +08:00
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
|
|
|
break;
|
2019-08-21 16:33:41 +08:00
|
|
|
case TextAntialiasMode::None:
|
2019-08-16 00:50:54 +08:00
|
|
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
render_target_->SetTextAntialiasMode(antialias_mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 21:15:15 +08:00
|
|
|
bool RenderTarget::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform)
|
2019-08-20 19:32:36 +08:00
|
|
|
{
|
2019-08-21 12:47:19 +08:00
|
|
|
Rect visible_size = { Point{}, reinterpret_cast<const Size&>(render_target_->GetSize()) };
|
|
|
|
|
if (fast_global_transform_)
|
|
|
|
|
{
|
|
|
|
|
return visible_size.Intersects(transform.Transform(bounds));
|
|
|
|
|
}
|
|
|
|
|
return visible_size.Intersects(Matrix3x2(transform * global_transform_).Transform(bounds));
|
2019-08-20 19:32:36 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-16 00:50:54 +08:00
|
|
|
void RenderTarget::SetCollectingStatus(bool collecting)
|
|
|
|
|
{
|
|
|
|
|
collecting_status_ = collecting;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderTarget::IncreasePrimitivesCount() const
|
|
|
|
|
{
|
|
|
|
|
if (collecting_status_)
|
|
|
|
|
{
|
|
|
|
|
++status_.primitives;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
2019-08-21 16:33:41 +08:00
|
|
|
// TextureRenderTarget
|
2019-08-16 00:50:54 +08:00
|
|
|
//
|
|
|
|
|
|
2019-08-21 16:33:41 +08:00
|
|
|
TextureRenderTarget::TextureRenderTarget()
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 13:44:40 +08:00
|
|
|
Texture TextureRenderTarget::GetOutput()
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
2019-12-23 18:05:08 +08:00
|
|
|
if (GetRenderTarget())
|
2019-08-16 00:50:54 +08:00
|
|
|
{
|
2019-08-20 19:32:36 +08:00
|
|
|
ComPtr<ID2D1BitmapRenderTarget> bitmap_rt;
|
2019-12-23 18:05:08 +08:00
|
|
|
hr = GetRenderTarget()->QueryInterface<ID2D1BitmapRenderTarget>(&bitmap_rt);
|
2019-08-16 00:50:54 +08:00
|
|
|
|
2019-08-20 19:32:36 +08:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
ComPtr<ID2D1Bitmap> bitmap;
|
|
|
|
|
hr = bitmap_rt->GetBitmap(&bitmap);
|
2019-08-16 00:50:54 +08:00
|
|
|
|
2019-08-20 19:32:36 +08:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2019-08-21 16:33:41 +08:00
|
|
|
return Texture(bitmap);
|
2019-08-20 19:32:36 +08:00
|
|
|
}
|
|
|
|
|
}
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
2019-08-21 16:33:41 +08:00
|
|
|
return Texture();
|
2019-08-16 00:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|