Magic_Game/src/core/Factory.cpp

518 lines
11 KiB
C++
Raw Normal View History

2018-11-21 17:18:59 +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 "Factory.h"
#include "logs.h"
#include "modules.h"
#include "Transform.hpp"
namespace easy2d
{
FactoryImpl::FactoryImpl()
{
}
FactoryImpl::~FactoryImpl()
{
E2D_LOG("Destroying device independent resources");
}
2018-11-21 19:24:18 +08:00
HRESULT FactoryImpl::Init(bool debug)
2018-11-21 17:18:59 +08:00
{
E2D_LOG("Creating device independent resources");
D2D1_FACTORY_OPTIONS fact_options;
fact_options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE;
2018-11-21 19:24:18 +08:00
HRESULT hr = modules::DirectX().D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory),
&fact_options,
reinterpret_cast<void**>(&factory_)
2018-11-21 17:18:59 +08:00
);
2018-11-21 19:24:18 +08:00
if (SUCCEEDED(hr))
{
2018-11-21 17:18:59 +08:00
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
2018-11-21 19:24:18 +08:00
reinterpret_cast<void**>(&imaging_factory_)
);
}
2018-11-21 17:18:59 +08:00
2018-11-21 19:24:18 +08:00
if (SUCCEEDED(hr))
{
2018-11-21 17:18:59 +08:00
modules::DirectX().DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
2018-11-21 19:24:18 +08:00
reinterpret_cast<IUnknown**>(&write_factory_)
);
}
2018-11-21 17:18:59 +08:00
2018-11-21 19:24:18 +08:00
if (SUCCEEDED(hr))
{
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
);
2018-11-21 17:18:59 +08:00
2018-11-21 19:24:18 +08:00
hr = factory_->CreateStrokeStyle(
2018-11-21 17:18:59 +08:00
stroke_style,
nullptr,
0,
2018-11-21 19:24:18 +08:00
&miter_stroke_style_
);
2018-11-21 17:18:59 +08:00
2018-11-21 19:24:18 +08:00
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
hr = factory_->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&bevel_stroke_style_
);
}
2018-11-21 17:18:59 +08:00
2018-11-21 19:24:18 +08:00
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
hr = factory_->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&round_stroke_style_
);
}
}
return hr;
2018-11-21 17:18:59 +08:00
}
HRESULT FactoryImpl::CreateHwndRenderTarget(CpHwndRenderTarget & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpHwndRenderTarget hwnd_render_target_tmp;
2018-11-21 19:24:18 +08:00
HRESULT hr = factory_->CreateHwndRenderTarget(
2018-11-21 17:18:59 +08:00
properties,
hwnd_rt_properties,
&hwnd_render_target_tmp
);
if (SUCCEEDED(hr))
hwnd_render_target = hwnd_render_target_tmp;
return hr;
}
HRESULT FactoryImpl::CreateTextRenderer(
CpTextRenderer& text_renderer,
CpRenderTarget const& render_target,
CpSolidColorBrush const& brush
2018-11-21 17:18:59 +08:00
)
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpTextRenderer text_renderer_tmp;
2018-11-21 17:18:59 +08:00
HRESULT hr = ITextRenderer::Create(
&text_renderer_tmp,
2018-11-21 19:24:18 +08:00
factory_.Get(),
2018-11-21 17:18:59 +08:00
render_target.Get(),
brush.Get()
);
if (SUCCEEDED(hr))
text_renderer = text_renderer_tmp;
return hr;
}
2019-01-21 21:24:45 +08:00
HRESULT FactoryImpl::CreateBitmapFromFile(CpBitmap & bitmap, CpRenderTarget const & rt, String const & file_path)
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (imaging_factory_ == nullptr)
2018-11-21 17:18:59 +08:00
{
return E_UNEXPECTED;
}
using namespace intrusive;
SmartPointer<IWICBitmapDecoder> decoder;
SmartPointer<IWICBitmapFrameDecode> source;
SmartPointer<IWICStream> stream;
SmartPointer<IWICFormatConverter> converter;
SmartPointer<ID2D1Bitmap> bitmap_tmp;
2018-11-21 19:24:18 +08:00
HRESULT hr = imaging_factory_->CreateDecoderFromFilename(
2018-11-21 17:18:59 +08:00
file_path.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&decoder
);
if (SUCCEEDED(hr))
{
hr = decoder->GetFrame(0, &source);
}
if (SUCCEEDED(hr))
{
2018-11-21 19:24:18 +08:00
hr = imaging_factory_->CreateFormatConverter(&converter);
2018-11-21 17:18:59 +08:00
}
if (SUCCEEDED(hr))
{
// ͼƬ<CDBC><C6AC>ʽת<CABD><D7AA><EFBFBD><EFBFBD> 32bppPBGRA
hr = converter->Initialize(
source.Get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
hr = rt->CreateBitmapFromWicBitmap(
converter.Get(),
nullptr,
&bitmap_tmp
);
}
if (SUCCEEDED(hr))
bitmap = bitmap_tmp;
return hr;
}
HRESULT FactoryImpl::CreateBitmapFromResource(CpBitmap & bitmap, CpRenderTarget const & rt, Resource const & res)
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (imaging_factory_ == nullptr)
2018-11-21 17:18:59 +08:00
{
return E_UNEXPECTED;
}
using namespace intrusive;
SmartPointer<IWICBitmapDecoder> decoder;
SmartPointer<IWICBitmapFrameDecode> source;
SmartPointer<IWICStream> stream;
SmartPointer<IWICFormatConverter> converter;
SmartPointer<ID2D1Bitmap> bitmap_tmp;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
2019-01-21 21:24:45 +08:00
LPVOID buffer;
DWORD buffer_size;
HRESULT hr = res.Load(buffer, buffer_size) ? S_OK : E_FAIL;
2018-11-21 17:18:59 +08:00
if (SUCCEEDED(hr))
{
2018-11-21 19:24:18 +08:00
hr = imaging_factory_->CreateStream(&stream);
2018-11-21 17:18:59 +08:00
}
if (SUCCEEDED(hr))
{
hr = stream->InitializeFromMemory(
2019-01-21 21:24:45 +08:00
static_cast<WICInProcPointer>(buffer),
buffer_size
2018-11-21 17:18:59 +08:00
);
}
if (SUCCEEDED(hr))
{
2018-11-21 19:24:18 +08:00
hr = imaging_factory_->CreateDecoderFromStream(
2018-11-21 17:18:59 +08:00
stream.Get(),
nullptr,
WICDecodeMetadataCacheOnLoad,
&decoder
);
}
if (SUCCEEDED(hr))
{
hr = decoder->GetFrame(0, &source);
}
if (SUCCEEDED(hr))
{
2018-11-21 19:24:18 +08:00
hr = imaging_factory_->CreateFormatConverter(&converter);
2018-11-21 17:18:59 +08:00
}
if (SUCCEEDED(hr))
{
// ͼƬ<CDBC><C6AC>ʽת<CABD><D7AA><EFBFBD><EFBFBD> 32bppPBGRA
hr = converter->Initialize(
source.Get(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
hr = rt->CreateBitmapFromWicBitmap(
converter.Get(),
nullptr,
&bitmap_tmp
);
}
if (SUCCEEDED(hr))
{
bitmap = bitmap_tmp;
}
return hr;
}
HRESULT FactoryImpl::CreateRectangleGeometry(CpRectangleGeometry & geo, Rect const& rect) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpRectangleGeometry rectangle;
2018-11-21 19:24:18 +08:00
HRESULT hr = factory_->CreateRectangleGeometry(
2018-11-21 17:18:59 +08:00
rect,
&rectangle
);
if (SUCCEEDED(hr))
geo = rectangle;
return hr;
}
HRESULT FactoryImpl::CreateRoundedRectangleGeometry(CpRoundedRectangleGeometry & geo, Rect const & rect, float radius_x, float radius_y) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpRoundedRectangleGeometry rounded_rect;
2018-11-21 19:24:18 +08:00
HRESULT hr = factory_->CreateRoundedRectangleGeometry(
2018-11-21 17:18:59 +08:00
D2D1::RoundedRect(
rect,
radius_x,
radius_y
),
&rounded_rect
);
if (SUCCEEDED(hr))
geo = rounded_rect;
return hr;
}
HRESULT FactoryImpl::CreateEllipseGeometry(CpEllipseGeometry & geo, Point const & center, float radius_x, float radius_y) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpEllipseGeometry ellipse;
2018-11-21 19:24:18 +08:00
HRESULT hr = factory_->CreateEllipseGeometry(
2018-11-21 17:18:59 +08:00
D2D1::Ellipse(
center,
radius_x,
radius_y
),
&ellipse
);
if (SUCCEEDED(hr))
geo = ellipse;
return hr;
}
HRESULT FactoryImpl::CreateTransformedGeometry(
CpTransformedGeometry& transformed,
2018-11-25 15:00:15 +08:00
Matrix const& matrix,
CpGeometry const& geo
2018-11-21 17:18:59 +08:00
) const
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpTransformedGeometry transformed_tmp;
2018-11-21 19:24:18 +08:00
HRESULT hr = factory_->CreateTransformedGeometry(
2018-11-21 17:18:59 +08:00
geo.Get(),
matrix,
2018-11-21 17:18:59 +08:00
&transformed_tmp
);
if (SUCCEEDED(hr))
{
transformed = transformed_tmp;
}
return hr;
}
HRESULT FactoryImpl::CreatePathGeometry(CpPathGeometry & geometry) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
2018-11-21 19:24:18 +08:00
return factory_->CreatePathGeometry(&geometry);
2018-11-21 17:18:59 +08:00
}
HRESULT FactoryImpl::CreateTextFormat(CpTextFormat & text_format, Font const & font, TextStyle const & text_style) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!write_factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
CpTextFormat text_format_tmp;
2018-11-21 19:24:18 +08:00
HRESULT hr = write_factory_->CreateTextFormat(
2018-11-21 17:18:59 +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"",
&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;
}
2019-01-21 21:24:45 +08:00
HRESULT FactoryImpl::CreateTextLayout(CpTextLayout & text_layout, Size& layout_size, String const & text, CpTextFormat const& text_format, TextStyle const & text_style) const
2018-11-21 17:18:59 +08:00
{
2018-11-21 19:24:18 +08:00
if (!write_factory_)
2018-11-21 17:18:59 +08:00
return E_UNEXPECTED;
text_layout = nullptr;
HRESULT hr;
CpTextLayout text_layout_tmp;
2018-11-21 17:18:59 +08:00
UINT32 length = static_cast<UINT32>(text.length());
if (text_style.wrap)
{
2018-11-21 19:24:18 +08:00
hr = write_factory_->CreateTextLayout(
2018-11-21 17:18:59 +08:00
text.c_str(),
length,
text_format.Get(),
text_style.wrap_width,
0,
&text_layout_tmp
);
}
else
{
2018-11-21 19:24:18 +08:00
hr = write_factory_->CreateTextLayout(
2018-11-21 17:18:59 +08:00
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;
2018-11-21 19:24:18 +08:00
hr = write_factory_->CreateTextLayout(
2018-11-21 17:18:59 +08:00
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;
}
CpStrokeStyle const& FactoryImpl::GetStrokeStyle(StrokeStyle stroke) const
2018-11-21 17:18:59 +08:00
{
switch (stroke)
{
case StrokeStyle::Miter:
2018-11-21 19:24:18 +08:00
return miter_stroke_style_;
2018-11-21 17:18:59 +08:00
break;
case StrokeStyle::Bevel:
2018-11-21 19:24:18 +08:00
return bevel_stroke_style_;
2018-11-21 17:18:59 +08:00
break;
case StrokeStyle::Round:
2018-11-21 19:24:18 +08:00
return round_stroke_style_;
2018-11-21 17:18:59 +08:00
break;
}
2018-11-21 19:24:18 +08:00
return miter_stroke_style_;
2018-11-21 17:18:59 +08:00
}
}