2018-11-08 21:39:26 +08:00
|
|
|
|
// Copyright (c) 2016-2018 Easy2D - 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 "render.h"
|
|
|
|
|
|
#include "time.h"
|
2018-11-16 15:53:39 +08:00
|
|
|
|
#include "base.hpp"
|
2018-11-15 17:59:18 +08:00
|
|
|
|
#include "logs.h"
|
2018-11-12 20:46:54 +08:00
|
|
|
|
#include "modules.h"
|
2018-11-14 01:34:41 +08:00
|
|
|
|
#include "Image.h"
|
2018-11-18 20:26:41 +08:00
|
|
|
|
#include "Transform.hpp"
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
|
|
|
|
|
namespace easy2d
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
namespace devices
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 02:10:35 +08:00
|
|
|
|
GraphicsDevice::GraphicsDevice()
|
|
|
|
|
|
: fps_text_format_(nullptr)
|
|
|
|
|
|
, fps_text_layout_(nullptr)
|
|
|
|
|
|
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
|
2018-11-18 20:26:41 +08:00
|
|
|
|
, opacity_(1.f)
|
2018-11-21 16:26:52 +08:00
|
|
|
|
, window_occluded_(false)
|
|
|
|
|
|
, initialized_(false)
|
|
|
|
|
|
, options_()
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 02:10:35 +08:00
|
|
|
|
ZeroMemory(&d2d, sizeof(D2DResources));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GraphicsDevice::~GraphicsDevice()
|
|
|
|
|
|
{
|
2018-11-15 17:59:18 +08:00
|
|
|
|
E2D_LOG("Destroying graphics device");
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
ClearImageCache();
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
void GraphicsDevice::Init(HWND hwnd, GraphicsOptions options, bool debug)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (initialized_)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
2018-11-15 17:59:18 +08:00
|
|
|
|
E2D_LOG("Initing graphics device");
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
options_ = options;
|
|
|
|
|
|
|
|
|
|
|
|
D2D1_FACTORY_OPTIONS fact_options;
|
|
|
|
|
|
fact_options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
ThrowIfFailed(
|
2018-11-17 17:15:32 +08:00
|
|
|
|
modules::DirectX().D2D1CreateFactory(
|
2018-11-08 21:39:26 +08:00
|
|
|
|
D2D1_FACTORY_TYPE_SINGLE_THREADED,
|
2018-11-12 22:36:50 +08:00
|
|
|
|
__uuidof(ID2D1Factory),
|
2018-11-21 16:26:52 +08:00
|
|
|
|
&fact_options,
|
2018-11-12 22:36:50 +08:00
|
|
|
|
reinterpret_cast<void**>(&d2d.factory)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
CoCreateInstance(
|
|
|
|
|
|
CLSID_WICImagingFactory,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
CLSCTX_INPROC_SERVER,
|
2018-11-12 22:36:50 +08:00
|
|
|
|
__uuidof(IWICImagingFactory),
|
2018-11-12 20:46:54 +08:00
|
|
|
|
reinterpret_cast<void**>(&d2d.imaging_factory)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
2018-11-17 17:15:32 +08:00
|
|
|
|
modules::DirectX().DWriteCreateFactory(
|
2018-11-08 21:39:26 +08:00
|
|
|
|
DWRITE_FACTORY_TYPE_SHARED,
|
|
|
|
|
|
__uuidof(IDWriteFactory),
|
2018-11-12 20:46:54 +08:00
|
|
|
|
reinterpret_cast<IUnknown**>(&d2d.write_factory)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
auto 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
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.factory->CreateStrokeStyle(
|
2018-11-08 21:39:26 +08:00
|
|
|
|
stroke_style,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0,
|
2018-11-12 20:46:54 +08:00
|
|
|
|
&d2d.miter_stroke_style
|
2018-11-08 21:39:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
|
|
|
|
|
|
ThrowIfFailed(
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.factory->CreateStrokeStyle(
|
2018-11-08 21:39:26 +08:00
|
|
|
|
stroke_style,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0,
|
2018-11-12 20:46:54 +08:00
|
|
|
|
&d2d.bevel_stroke_style
|
2018-11-08 21:39:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
|
|
|
|
|
|
ThrowIfFailed(
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.factory->CreateStrokeStyle(
|
2018-11-08 21:39:26 +08:00
|
|
|
|
stroke_style,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0,
|
2018-11-12 20:46:54 +08:00
|
|
|
|
&d2d.round_stroke_style
|
2018-11-08 21:39:26 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CreateDeviceResources(hwnd);
|
2018-11-12 22:36:50 +08:00
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
initialized_ = true;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
void GraphicsDevice::BeginDraw(HWND hwnd)
|
|
|
|
|
|
{
|
|
|
|
|
|
CreateDeviceResources(hwnd);
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
window_occluded_ = !!(d2d.render_target->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED);
|
2018-11-19 17:56:17 +08:00
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (!window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
{
|
|
|
|
|
|
d2d.render_target->BeginDraw();
|
|
|
|
|
|
d2d.render_target->Clear(clear_color_);
|
|
|
|
|
|
}
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDevice::EndDraw()
|
|
|
|
|
|
{
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (!window_occluded_)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-19 17:56:17 +08:00
|
|
|
|
HRESULT hr = d2d.render_target->EndDraw();
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-19 17:56:17 +08:00
|
|
|
|
if (hr == D2DERR_RECREATE_TARGET)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <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>Դ
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ε<EFBFBD><CEB5><EFBFBD>ʱ<EFBFBD>ؽ<EFBFBD><D8BD><EFBFBD>Դ
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
|
|
|
|
|
|
fps_text_format_ = nullptr;
|
|
|
|
|
|
fps_text_layout_ = nullptr;
|
|
|
|
|
|
d2d.text_renderer = nullptr;
|
|
|
|
|
|
d2d.solid_brush = nullptr;
|
|
|
|
|
|
d2d.render_target = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
|
}
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
void GraphicsDevice::ClearImageCache()
|
|
|
|
|
|
{
|
|
|
|
|
|
bitmap_cache_.clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-20 01:20:06 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateRectangleGeometry(cpRectangleGeometry & geo, Rect const& rect) const
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.factory)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-20 01:20:06 +08:00
|
|
|
|
cpRectangleGeometry rectangle;
|
|
|
|
|
|
HRESULT hr = d2d.factory->CreateRectangleGeometry(
|
|
|
|
|
|
rect,
|
|
|
|
|
|
&rectangle
|
|
|
|
|
|
);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
|
2018-11-20 01:20:06 +08:00
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
geo = rectangle;
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
2018-11-12 20:46:54 +08:00
|
|
|
|
|
2018-11-20 14:30:39 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateRoundedRectangleGeometry(cpRoundedRectangleGeometry & geo, Rect const & rect, float radius_x, float radius_y) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.factory)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
cpRoundedRectangleGeometry rounded_rect;
|
|
|
|
|
|
HRESULT hr = d2d.factory->CreateRoundedRectangleGeometry(
|
|
|
|
|
|
D2D1::RoundedRect(
|
|
|
|
|
|
rect,
|
|
|
|
|
|
radius_x,
|
|
|
|
|
|
radius_y
|
|
|
|
|
|
),
|
|
|
|
|
|
&rounded_rect
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
geo = rounded_rect;
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-20 01:20:06 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateEllipseGeometry(cpEllipseGeometry & geo, Point const & center, float radius_x, float radius_y) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.factory)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
cpEllipseGeometry ellipse;
|
|
|
|
|
|
HRESULT hr = d2d.factory->CreateEllipseGeometry(
|
|
|
|
|
|
D2D1::Ellipse(
|
|
|
|
|
|
center,
|
|
|
|
|
|
radius_x,
|
|
|
|
|
|
radius_y
|
|
|
|
|
|
),
|
|
|
|
|
|
&ellipse
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
2018-11-20 01:20:06 +08:00
|
|
|
|
geo = ellipse;
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::CreateTransformedGeometry(
|
|
|
|
|
|
cpTransformedGeometry& transformed,
|
|
|
|
|
|
math::Matrix const& matrix,
|
|
|
|
|
|
cpGeometry const& geo
|
|
|
|
|
|
) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.factory)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
cpTransformedGeometry transformed_tmp;
|
|
|
|
|
|
HRESULT hr = d2d.factory->CreateTransformedGeometry(
|
|
|
|
|
|
geo.Get(),
|
|
|
|
|
|
ConvertToD2DMatrix(matrix),
|
|
|
|
|
|
&transformed_tmp
|
|
|
|
|
|
);
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
if (SUCCEEDED(hr))
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-20 01:20:06 +08:00
|
|
|
|
transformed = transformed_tmp;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreatePathGeometry(cpPathGeometry & geometry) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.factory)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
return d2d.factory->CreatePathGeometry(&geometry);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::CreateTextFormat(cpTextFormat & text_format, Font const & font, TextStyle const & text_style) const
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.write_factory)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
cpTextFormat text_format_tmp;
|
|
|
|
|
|
HRESULT hr = d2d.write_factory->CreateTextFormat(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
font.family.c_str(),
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
DWRITE_FONT_WEIGHT(font.weight),
|
|
|
|
|
|
font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
|
|
|
|
|
|
DWRITE_FONT_STRETCH_NORMAL,
|
|
|
|
|
|
font.size,
|
|
|
|
|
|
L"",
|
2018-11-18 20:26:41 +08:00
|
|
|
|
&text_format_tmp
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (text_style.line_spacing == 0.f)
|
|
|
|
|
|
{
|
|
|
|
|
|
text_format_tmp->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
text_format_tmp->SetLineSpacing(
|
|
|
|
|
|
DWRITE_LINE_SPACING_METHOD_UNIFORM,
|
|
|
|
|
|
text_style.line_spacing,
|
|
|
|
|
|
text_style.line_spacing * 0.8f
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
text_format_tmp->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(text_style.alignment));
|
|
|
|
|
|
text_format_tmp->SetWordWrapping(text_style.wrap ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP);
|
|
|
|
|
|
text_format = text_format_tmp;
|
|
|
|
|
|
}
|
|
|
|
|
|
return hr;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateTextLayout(cpTextLayout & text_layout, Size& layout_size, String const & text, cpTextFormat const& text_format, TextStyle const & text_style) const
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.write_factory)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
text_layout = nullptr;
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
cpTextLayout text_layout_tmp;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
UINT32 length = static_cast<UINT32>(text.length());
|
2018-11-18 20:26:41 +08:00
|
|
|
|
|
|
|
|
|
|
if (text_style.wrap)
|
|
|
|
|
|
{
|
|
|
|
|
|
hr = d2d.write_factory->CreateTextLayout(
|
|
|
|
|
|
text.c_str(),
|
|
|
|
|
|
length,
|
|
|
|
|
|
text_format.Get(),
|
|
|
|
|
|
text_style.wrap_width,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&text_layout_tmp
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
hr = d2d.write_factory->CreateTextLayout(
|
|
|
|
|
|
text.c_str(),
|
|
|
|
|
|
length,
|
|
|
|
|
|
text_format.Get(),
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&text_layout_tmp
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
DWRITE_TEXT_METRICS metrics;
|
|
|
|
|
|
text_layout_tmp->GetMetrics(&metrics);
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
text_layout_tmp = nullptr;
|
|
|
|
|
|
hr = d2d.write_factory->CreateTextLayout(
|
|
|
|
|
|
text.c_str(),
|
|
|
|
|
|
length,
|
|
|
|
|
|
text_format.Get(),
|
|
|
|
|
|
metrics.width,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&text_layout_tmp
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
DWRITE_TEXT_METRICS metrics;
|
|
|
|
|
|
text_layout_tmp->GetMetrics(&metrics);
|
|
|
|
|
|
|
|
|
|
|
|
if (text_style.wrap)
|
|
|
|
|
|
{
|
|
|
|
|
|
layout_size = Size(metrics.layoutWidth, metrics.height);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
layout_size = Size(metrics.width, metrics.height);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DWRITE_TEXT_RANGE range = { 0, length };
|
|
|
|
|
|
if (text_style.underline)
|
|
|
|
|
|
{
|
|
|
|
|
|
text_layout_tmp->SetUnderline(true, range);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (text_style.strikethrough)
|
|
|
|
|
|
{
|
|
|
|
|
|
text_layout_tmp->SetStrikethrough(true, range);
|
|
|
|
|
|
}
|
|
|
|
|
|
text_layout = text_layout_tmp;
|
|
|
|
|
|
}
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::CreateTextRenderer(
|
|
|
|
|
|
cpTextRenderer& text_renderer,
|
|
|
|
|
|
cpRenderTarget const& render_target,
|
|
|
|
|
|
cpSolidColorBrush const& brush
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.factory)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
cpTextRenderer text_renderer_tmp;
|
|
|
|
|
|
HRESULT hr = ITextRenderer::Create(
|
|
|
|
|
|
&text_renderer_tmp,
|
|
|
|
|
|
d2d.factory.Get(),
|
|
|
|
|
|
render_target.Get(),
|
|
|
|
|
|
brush.Get()
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
2018-11-18 20:26:41 +08:00
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
text_renderer = text_renderer_tmp;
|
|
|
|
|
|
return hr;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateLayer(cpLayer& layer)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
layer = nullptr;
|
|
|
|
|
|
return d2d.render_target->CreateLayer(&layer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::CreateSolidColorBrush(cpSolidColorBrush & brush) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.render_target)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
brush = nullptr;
|
|
|
|
|
|
return d2d.render_target->CreateSolidColorBrush(
|
|
|
|
|
|
D2D1::ColorF(D2D1::ColorF::White),
|
|
|
|
|
|
&brush
|
|
|
|
|
|
);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::DrawGeometry(
|
2018-11-17 17:15:32 +08:00
|
|
|
|
cpGeometry const& geometry,
|
2018-11-20 01:20:06 +08:00
|
|
|
|
Color const& stroke_color,
|
2018-11-12 02:10:35 +08:00
|
|
|
|
float stroke_width,
|
|
|
|
|
|
StrokeStyle stroke
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.solid_brush ||
|
|
|
|
|
|
!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-20 01:20:06 +08:00
|
|
|
|
d2d.solid_brush->SetColor(stroke_color);
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->DrawGeometry(
|
2018-11-17 17:15:32 +08:00
|
|
|
|
geometry.Get(),
|
|
|
|
|
|
d2d.solid_brush.Get(),
|
2018-11-12 02:10:35 +08:00
|
|
|
|
stroke_width,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
GetStrokeStyle(stroke).Get()
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-20 01:20:06 +08:00
|
|
|
|
HRESULT GraphicsDevice::FillGeometry(cpGeometry const & geometry, const Color & fill_color)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.solid_brush ||
|
|
|
|
|
|
!d2d.render_target)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-20 01:20:06 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
|
|
|
|
d2d.solid_brush->SetColor(fill_color);
|
|
|
|
|
|
d2d.render_target->FillGeometry(
|
|
|
|
|
|
geometry.Get(),
|
|
|
|
|
|
d2d.solid_brush.Get()
|
|
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::DrawImage(spImage const & image)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.render_target)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
if (!image->GetBitmap())
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
d2d.render_target->DrawBitmap(
|
|
|
|
|
|
image->GetBitmap().Get(),
|
|
|
|
|
|
D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()),
|
|
|
|
|
|
opacity_,
|
|
|
|
|
|
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
|
|
|
|
|
image->GetCropRect()
|
|
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
cpStrokeStyle const& GraphicsDevice::GetStrokeStyle(StrokeStyle stroke) const
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
switch (stroke)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 02:10:35 +08:00
|
|
|
|
case StrokeStyle::Miter:
|
2018-11-17 17:15:32 +08:00
|
|
|
|
return d2d.miter_stroke_style;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case StrokeStyle::Bevel:
|
2018-11-17 17:15:32 +08:00
|
|
|
|
return d2d.bevel_stroke_style;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case StrokeStyle::Round:
|
2018-11-17 17:15:32 +08:00
|
|
|
|
return d2d.round_stroke_style;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
break;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
2018-11-17 17:15:32 +08:00
|
|
|
|
return d2d.miter_stroke_style;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::DrawBitmap(
|
|
|
|
|
|
cpBitmap const& bitmap
|
2018-11-12 02:10:35 +08:00
|
|
|
|
)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
// Do not crop bitmap
|
|
|
|
|
|
auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height);
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->DrawBitmap(
|
2018-11-18 20:26:41 +08:00
|
|
|
|
bitmap.Get(),
|
|
|
|
|
|
rect,
|
|
|
|
|
|
opacity_,
|
2018-11-12 02:10:35 +08:00
|
|
|
|
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
2018-11-18 20:26:41 +08:00
|
|
|
|
rect
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
HRESULT GraphicsDevice::DrawTextLayout(cpTextLayout const& text_layout)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.text_renderer)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
return text_layout->Draw(nullptr, d2d.text_renderer.Get(), 0, 0);
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size)
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-16 17:19:03 +08:00
|
|
|
|
d2d.render_target->SetTransform(ConvertToD2DMatrix(clip_matrix));
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->PushAxisAlignedClip(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
D2D1::RectF(0, 0, clip_size.width, clip_size.height),
|
|
|
|
|
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
|
|
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
HRESULT GraphicsDevice::PopClip()
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->PopAxisAlignedClip();
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return S_OK;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
HRESULT GraphicsDevice::PushLayer(cpLayer const& layer, LayerProperties const& properties)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target ||
|
|
|
|
|
|
!d2d.solid_brush)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->PushLayer(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
D2D1::LayerParameters(
|
|
|
|
|
|
properties.area,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
|
|
|
|
D2D1::Matrix3x2F::Identity(),
|
|
|
|
|
|
properties.opacity,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
d2d.solid_brush.Get(),
|
2018-11-12 02:10:35 +08:00
|
|
|
|
D2D1_LAYER_OPTIONS_NONE
|
|
|
|
|
|
),
|
2018-11-17 17:15:32 +08:00
|
|
|
|
layer.Get()
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
HRESULT GraphicsDevice::PopLayer()
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-21 16:26:52 +08:00
|
|
|
|
if (window_occluded_)
|
2018-11-19 17:56:17 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->PopLayer();
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return S_OK;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::GetSize(Size & size)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.render_target)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
auto rtsize = d2d.render_target->GetSize();
|
|
|
|
|
|
size.width = rtsize.width;
|
|
|
|
|
|
size.height = rtsize.height;
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (d2d.imaging_factory == nullptr ||
|
|
|
|
|
|
d2d.render_target == nullptr)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
}
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
size_t hash_code = std::hash<String>{}(file_path);
|
|
|
|
|
|
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
|
|
|
|
|
|
{
|
2018-11-17 17:15:32 +08:00
|
|
|
|
bitmap = bitmap_cache_[hash_code];
|
2018-11-12 20:46:54 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
IWICBitmapDecoder* decoder = nullptr;
|
|
|
|
|
|
IWICBitmapFrameDecode* source = nullptr;
|
|
|
|
|
|
IWICStream* stream = nullptr;
|
|
|
|
|
|
IWICFormatConverter* converter = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
2018-11-12 20:46:54 +08:00
|
|
|
|
HRESULT hr = d2d.imaging_factory->CreateDecoderFromFilename(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
file_path.c_str(),
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
GENERIC_READ,
|
|
|
|
|
|
WICDecodeMetadataCacheOnLoad,
|
|
|
|
|
|
&decoder
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
hr = decoder->GetFrame(0, &source);
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ͼƬ<CDBC><C6AC>ʽת<CABD><D7AA><EFBFBD><EFBFBD>
|
2018-11-12 20:46:54 +08:00
|
|
|
|
hr = d2d.imaging_factory->CreateFormatConverter(&converter);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// ͼƬ<CDBC><C6AC>ʽת<CABD><D7AA><EFBFBD><EFBFBD> 32bppPBGRA
|
|
|
|
|
|
hr = converter->Initialize(
|
|
|
|
|
|
source,
|
|
|
|
|
|
GUID_WICPixelFormat32bppPBGRA,
|
|
|
|
|
|
WICBitmapDitherTypeNone,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0.f,
|
|
|
|
|
|
WICBitmapPaletteTypeMedianCut
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><> WIC λͼ<CEBB><CDBC><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> Direct2D λͼ
|
2018-11-17 17:15:32 +08:00
|
|
|
|
bitmap = nullptr;
|
2018-11-12 20:46:54 +08:00
|
|
|
|
hr = d2d.render_target->CreateBitmapFromWicBitmap(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
converter,
|
|
|
|
|
|
nullptr,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
&bitmap
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
2018-11-17 17:15:32 +08:00
|
|
|
|
bitmap_cache_.insert(std::make_pair(hash_code, bitmap));
|
2018-11-12 20:46:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
SafeRelease(decoder);
|
|
|
|
|
|
SafeRelease(source);
|
|
|
|
|
|
SafeRelease(stream);
|
|
|
|
|
|
SafeRelease(converter);
|
|
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-17 17:15:32 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateBitmapFromResource(cpBitmap& bitmap, Resource const& res)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (d2d.imaging_factory == nullptr ||
|
|
|
|
|
|
d2d.render_target == nullptr)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
size_t hash_code = res.GetHashCode();
|
|
|
|
|
|
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
|
|
|
|
|
|
{
|
2018-11-17 17:15:32 +08:00
|
|
|
|
bitmap = bitmap_cache_[hash_code];
|
2018-11-12 20:46:54 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
|
|
|
|
HINSTANCE hinstance = GetModuleHandle(nullptr);
|
|
|
|
|
|
IWICBitmapDecoder* decoder = nullptr;
|
|
|
|
|
|
IWICBitmapFrameDecode* source = nullptr;
|
|
|
|
|
|
IWICStream* stream = nullptr;
|
|
|
|
|
|
IWICFormatConverter* converter = nullptr;
|
2018-11-12 23:32:50 +08:00
|
|
|
|
ResourceData buffer;
|
2018-11-12 20:46:54 +08:00
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
|
2018-11-12 23:32:50 +08:00
|
|
|
|
hr = res.Load(&buffer) ? S_OK : E_FAIL;
|
2018-11-12 02:10:35 +08:00
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> WIC <20><>
|
2018-11-12 20:46:54 +08:00
|
|
|
|
hr = d2d.imaging_factory->CreateStream(&stream);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
|
|
|
|
|
hr = stream->InitializeFromMemory(
|
2018-11-12 23:32:50 +08:00
|
|
|
|
static_cast<WICInProcPointer>(buffer.buffer),
|
|
|
|
|
|
buffer.buffer_size
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD><EFBFBD><EFBFBD>
|
2018-11-12 20:46:54 +08:00
|
|
|
|
hr = d2d.imaging_factory->CreateDecoderFromStream(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
stream,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
WICDecodeMetadataCacheOnLoad,
|
|
|
|
|
|
&decoder
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
hr = decoder->GetFrame(0, &source);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ͼƬ<CDBC><C6AC>ʽת<CABD><D7AA><EFBFBD><EFBFBD>
|
2018-11-12 20:46:54 +08:00
|
|
|
|
hr = d2d.imaging_factory->CreateFormatConverter(&converter);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// ͼƬ<CDBC><C6AC>ʽת<CABD><D7AA><EFBFBD><EFBFBD> 32bppPBGRA
|
|
|
|
|
|
hr = converter->Initialize(
|
|
|
|
|
|
source,
|
|
|
|
|
|
GUID_WICPixelFormat32bppPBGRA,
|
|
|
|
|
|
WICBitmapDitherTypeNone,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0.f,
|
|
|
|
|
|
WICBitmapPaletteTypeMedianCut
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><> WIC λͼ<CEBB><CDBC><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> Direct2D λͼ
|
2018-11-12 20:46:54 +08:00
|
|
|
|
hr = d2d.render_target->CreateBitmapFromWicBitmap(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
converter,
|
|
|
|
|
|
nullptr,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
&bitmap
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
|
{
|
2018-11-17 17:15:32 +08:00
|
|
|
|
bitmap_cache_.insert(std::make_pair(hash_code, bitmap));
|
2018-11-12 20:46:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
SafeRelease(decoder);
|
|
|
|
|
|
SafeRelease(source);
|
|
|
|
|
|
SafeRelease(stream);
|
|
|
|
|
|
SafeRelease(converter);
|
|
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!d2d.render_target)
|
|
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
|
|
|
|
|
brt = nullptr;
|
|
|
|
|
|
return d2d.render_target->CreateCompatibleRenderTarget(&brt);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height)
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->Resize(D2D1::SizeU(width, height));
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix)
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-16 17:19:03 +08:00
|
|
|
|
d2d.render_target->SetTransform(ConvertToD2DMatrix(matrix));
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
HRESULT GraphicsDevice::SetOpacity(float opacity)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-18 20:26:41 +08:00
|
|
|
|
opacity_ = opacity;
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.solid_brush->SetOpacity(opacity);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT GraphicsDevice::SetTextStyle(
|
2018-11-17 17:15:32 +08:00
|
|
|
|
Color const& color,
|
2018-11-12 02:10:35 +08:00
|
|
|
|
bool has_outline,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
Color const& outline_color,
|
2018-11-12 02:10:35 +08:00
|
|
|
|
float outline_width,
|
|
|
|
|
|
StrokeStyle outline_stroke
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.text_renderer)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.text_renderer->SetTextStyle(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
color,
|
|
|
|
|
|
has_outline,
|
|
|
|
|
|
outline_color,
|
|
|
|
|
|
outline_width,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
GetStrokeStyle(outline_stroke).Get()
|
2018-11-12 02:10:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
return S_OK;
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDevice::SetBackgroundColor(const Color& color)
|
|
|
|
|
|
{
|
|
|
|
|
|
clear_color_ = color;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 02:10:35 +08:00
|
|
|
|
void GraphicsDevice::CreateDeviceResources(HWND hwnd)
|
|
|
|
|
|
{
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.render_target)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
RECT rc;
|
|
|
|
|
|
::GetClientRect(hwnd, &rc);
|
|
|
|
|
|
|
|
|
|
|
|
D2D1_SIZE_U size = D2D1::SizeU(
|
|
|
|
|
|
rc.right - rc.left,
|
|
|
|
|
|
rc.bottom - rc.top
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>Щ<EFBFBD><D0A9>ԴӦ<D4B4><D3A6> Direct2D <20>豸<EFBFBD><E8B1B8>ʧʱ<CAA7>ؽ<EFBFBD>
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> Direct2D <20><>ȾĿ<C8BE><C4BF>
|
|
|
|
|
|
ThrowIfFailed(
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.factory->CreateHwndRenderTarget(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
D2D1::RenderTargetProperties(),
|
|
|
|
|
|
D2D1::HwndRenderTargetProperties(
|
|
|
|
|
|
hwnd,
|
|
|
|
|
|
size,
|
2018-11-21 16:26:52 +08:00
|
|
|
|
options_.vsync ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY
|
|
|
|
|
|
),
|
2018-11-12 20:46:54 +08:00
|
|
|
|
&d2d.render_target
|
2018-11-12 02:10:35 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
2018-11-21 16:26:52 +08:00
|
|
|
|
|
|
|
|
|
|
d2d.render_target->SetAntialiasMode(
|
|
|
|
|
|
options_.antialias ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
D2D1_TEXT_ANTIALIAS_MODE mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
|
|
|
switch (options_.text_antialias)
|
|
|
|
|
|
{
|
|
|
|
|
|
case TextAntialias::Default:
|
|
|
|
|
|
mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TextAntialias::ClearType:
|
|
|
|
|
|
mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TextAntialias::GrayScale:
|
|
|
|
|
|
mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TextAntialias::None:
|
|
|
|
|
|
mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
d2d.render_target->SetTextAntialiasMode(mode);
|
2018-11-12 02:10:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.solid_brush)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
2018-11-12 20:46:54 +08:00
|
|
|
|
d2d.render_target->CreateSolidColorBrush(
|
2018-11-12 02:10:35 +08:00
|
|
|
|
D2D1::ColorF(D2D1::ColorF::White),
|
2018-11-12 20:46:54 +08:00
|
|
|
|
&d2d.solid_brush
|
2018-11-12 02:10:35 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-12 20:46:54 +08:00
|
|
|
|
if (!d2d.text_renderer)
|
2018-11-12 02:10:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
ITextRenderer::Create(
|
2018-11-12 20:46:54 +08:00
|
|
|
|
&d2d.text_renderer,
|
2018-11-17 17:15:32 +08:00
|
|
|
|
d2d.factory.Get(),
|
|
|
|
|
|
d2d.render_target.Get(),
|
|
|
|
|
|
d2d.solid_brush.Get()
|
2018-11-12 02:10:35 +08:00
|
|
|
|
)
|
|
|
|
|
|
);
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-11-20 01:20:06 +08:00
|
|
|
|
|
2018-11-08 21:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|