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"
|
|
|
|
|
|
#include "base.h"
|
|
|
|
|
|
|
|
|
|
|
|
#pragma comment(lib, "d2d1.lib")
|
|
|
|
|
|
#pragma comment(lib, "dwrite.lib")
|
|
|
|
|
|
#pragma comment(lib, "windowscodecs.lib")
|
|
|
|
|
|
|
|
|
|
|
|
namespace easy2d
|
|
|
|
|
|
{
|
|
|
|
|
|
namespace render
|
|
|
|
|
|
{
|
|
|
|
|
|
_D2D_Resource D2D = { 0 };
|
|
|
|
|
|
|
2018-11-11 16:32:12 +08:00
|
|
|
|
void easy2d::render::Initialize(HWND hwnd)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (D2D.Factory)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
D2D1CreateFactory(
|
|
|
|
|
|
D2D1_FACTORY_TYPE_SINGLE_THREADED,
|
|
|
|
|
|
&D2D.Factory
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
CoCreateInstance(
|
|
|
|
|
|
CLSID_WICImagingFactory,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
|
|
IID_IWICImagingFactory,
|
|
|
|
|
|
reinterpret_cast<void**>(&D2D.WICImagingFactory)
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
DWriteCreateFactory(
|
|
|
|
|
|
DWRITE_FACTORY_TYPE_SHARED,
|
|
|
|
|
|
__uuidof(IDWriteFactory),
|
|
|
|
|
|
reinterpret_cast<IUnknown**>(&D2D.DWriteFactory)
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
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(
|
|
|
|
|
|
D2D.Factory->CreateStrokeStyle(
|
|
|
|
|
|
stroke_style,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&D2D.MiterStrokeStyle
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
D2D.Factory->CreateStrokeStyle(
|
|
|
|
|
|
stroke_style,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&D2D.BevelStrokeStyle
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
D2D.Factory->CreateStrokeStyle(
|
|
|
|
|
|
stroke_style,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&D2D.RoundStrokeStyle
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CreateDeviceResources(hwnd);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-11 16:32:12 +08:00
|
|
|
|
void easy2d::render::CreateDeviceResources(HWND hwnd)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!D2D.HwndRenderTarget)
|
|
|
|
|
|
{
|
|
|
|
|
|
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(
|
|
|
|
|
|
D2D.Factory->CreateHwndRenderTarget(
|
|
|
|
|
|
D2D1::RenderTargetProperties(),
|
|
|
|
|
|
D2D1::HwndRenderTargetProperties(
|
|
|
|
|
|
hwnd,
|
|
|
|
|
|
size,
|
|
|
|
|
|
D2D1_PRESENT_OPTIONS_NONE),
|
|
|
|
|
|
&D2D.HwndRenderTarget
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!D2D.SolidColorBrush)
|
|
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
D2D.HwndRenderTarget->CreateSolidColorBrush(
|
|
|
|
|
|
D2D1::ColorF(D2D1::ColorF::White),
|
|
|
|
|
|
&D2D.SolidColorBrush
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!D2D.TextRenderer)
|
|
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
ITextRenderer::Create(
|
|
|
|
|
|
&D2D.TextRenderer,
|
|
|
|
|
|
D2D.Factory,
|
|
|
|
|
|
D2D.HwndRenderTarget,
|
|
|
|
|
|
D2D.SolidColorBrush
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-11 16:32:12 +08:00
|
|
|
|
void easy2d::render::Uninitialize()
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
SafeRelease(D2D.TextRenderer);
|
|
|
|
|
|
SafeRelease(D2D.SolidColorBrush);
|
|
|
|
|
|
SafeRelease(D2D.HwndRenderTarget);
|
|
|
|
|
|
|
|
|
|
|
|
SafeRelease(D2D.MiterStrokeStyle);
|
|
|
|
|
|
SafeRelease(D2D.BevelStrokeStyle);
|
|
|
|
|
|
SafeRelease(D2D.RoundStrokeStyle);
|
|
|
|
|
|
|
|
|
|
|
|
SafeRelease(D2D.WICImagingFactory);
|
|
|
|
|
|
SafeRelease(D2D.DWriteFactory);
|
|
|
|
|
|
SafeRelease(D2D.Factory);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
|
|
|
|
// GraphicsDevice
|
|
|
|
|
|
//-------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
GraphicsDevice instance;
|
|
|
|
|
|
|
|
|
|
|
|
GraphicsDevice::GraphicsDevice()
|
|
|
|
|
|
: fps_text_format_(nullptr)
|
|
|
|
|
|
, fps_text_layout_(nullptr)
|
|
|
|
|
|
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GraphicsDevice::~GraphicsDevice()
|
|
|
|
|
|
{
|
|
|
|
|
|
SafeRelease(fps_text_format_);
|
|
|
|
|
|
SafeRelease(fps_text_layout_);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDevice::BeginDraw(HWND hwnd)
|
|
|
|
|
|
{
|
|
|
|
|
|
render::CreateDeviceResources(hwnd);
|
|
|
|
|
|
render::D2D.HwndRenderTarget->BeginDraw();
|
|
|
|
|
|
render::D2D.HwndRenderTarget->Clear(clear_color_);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDevice::EndDraw()
|
|
|
|
|
|
{
|
|
|
|
|
|
HRESULT hr = render::D2D.HwndRenderTarget->EndDraw();
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
SafeRelease(fps_text_format_);
|
|
|
|
|
|
SafeRelease(fps_text_layout_);
|
|
|
|
|
|
SafeRelease(render::D2D.TextRenderer);
|
|
|
|
|
|
SafeRelease(render::D2D.SolidColorBrush);
|
|
|
|
|
|
SafeRelease(render::D2D.HwndRenderTarget);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(hr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDevice::SetBackgroundColor(const Color& color)
|
|
|
|
|
|
{
|
|
|
|
|
|
clear_color_ = color;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDevice::DrawDebugInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
static int render_times_ = 0;
|
2018-11-11 16:32:12 +08:00
|
|
|
|
static auto last_render_time_ = time::Now();
|
|
|
|
|
|
|
|
|
|
|
|
int64_t duration = (time::Now() - last_render_time_).Milliseconds();
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (!fps_text_format_)
|
|
|
|
|
|
{
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
render::D2D.DWriteFactory->CreateTextFormat(
|
|
|
|
|
|
L"",
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
DWRITE_FONT_WEIGHT_NORMAL,
|
|
|
|
|
|
DWRITE_FONT_STYLE_NORMAL,
|
|
|
|
|
|
DWRITE_FONT_STRETCH_NORMAL,
|
|
|
|
|
|
20,
|
|
|
|
|
|
L"",
|
|
|
|
|
|
&fps_text_format_
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
fps_text_format_->SetWordWrapping(
|
|
|
|
|
|
DWRITE_WORD_WRAPPING_NO_WRAP
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
++render_times_;
|
2018-11-11 16:32:12 +08:00
|
|
|
|
if (duration >= 100LL)
|
2018-11-08 21:39:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
wchar_t fps_text[12] = {};
|
2018-11-11 16:32:12 +08:00
|
|
|
|
int len = swprintf_s(fps_text, L"FPS: %.1f", 1000.f / static_cast<float>(duration) * render_times_);
|
2018-11-08 21:39:26 +08:00
|
|
|
|
|
|
|
|
|
|
last_render_time_ = time::Now();
|
|
|
|
|
|
render_times_ = 0;
|
|
|
|
|
|
|
|
|
|
|
|
SafeRelease(fps_text_layout_);
|
|
|
|
|
|
|
|
|
|
|
|
ThrowIfFailed(
|
|
|
|
|
|
render::D2D.DWriteFactory->CreateTextLayout(
|
|
|
|
|
|
fps_text,
|
|
|
|
|
|
static_cast<UINT32>(len),
|
|
|
|
|
|
fps_text_format_,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
&fps_text_layout_
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (fps_text_layout_)
|
|
|
|
|
|
{
|
|
|
|
|
|
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
|
|
|
|
|
|
render::D2D.SolidColorBrush->SetOpacity(1.0f);
|
|
|
|
|
|
render::D2D.TextRenderer->SetTextStyle(
|
|
|
|
|
|
D2D1::ColorF(D2D1::ColorF::White),
|
|
|
|
|
|
TRUE,
|
|
|
|
|
|
D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
|
|
|
|
|
|
1.5f,
|
|
|
|
|
|
D2D1_LINE_JOIN_ROUND
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
fps_text_layout_->Draw(nullptr, render::D2D.TextRenderer, 10, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|