重做Window类和Renderer类单例模式

This commit is contained in:
Nomango 2018-07-03 18:16:26 +08:00
parent 1d9f543eb8
commit abaf59379a
26 changed files with 578 additions and 512 deletions

View File

@ -1,28 +1,35 @@
#include "..\e2dbase.h"
// GC 机制,用于自动销毁单例
e2d::GC e2d::GC::_instance;
e2d::GC::~GC()
{
// 删除所有单例
Game::destroyInstance();
Renderer::destroyInstance();
Window::destroyInstance();
}
// GC 释放池的实现机制:
// Object 类中的引用计数_refCount在一定程度上防止了内存泄漏
// 它记录了对象被使用的次数,当计数为 0 时GC 会自动释放这个对象
// 所有的 Object 对象都应在被使用时(例如 Text 添加到了场景中)
// 调用 retain 函数保证该对象不被删除,并在不再使用时调用 release 函数
// 对象管理池
static std::set<e2d::Object*> s_vObjectPool;
// 标志释放池执行状态
static bool s_bNotifyed = false;
void e2d::GC::__update()
{
if (!s_bNotifyed) return;
if (!_notifyed) return;
s_bNotifyed = false;
for (auto iter = s_vObjectPool.begin(); iter != s_vObjectPool.end();)
_notifyed = false;
for (auto iter = _pool.begin(); iter != _pool.end();)
{
if ((*iter)->getRefCount() <= 0)
{
(*iter)->onDestroy();
delete (*iter);
iter = s_vObjectPool.erase(iter);
iter = _pool.erase(iter);
}
else
{
@ -31,26 +38,31 @@ void e2d::GC::__update()
}
}
void e2d::GC::__clear()
void e2d::GC::clear()
{
for (auto pObj : s_vObjectPool)
for (auto pObj : _pool)
{
delete pObj;
}
s_vObjectPool.clear();
_pool.clear();
}
void e2d::GC::__add(e2d::Object * pObject)
void e2d::GC::addObject(e2d::Object * pObject)
{
if (pObject)
{
s_vObjectPool.insert(pObject);
_pool.insert(pObject);
}
}
e2d::GC * e2d::GC::getInstance()
{
return &_instance;
}
void e2d::GC::notify()
{
s_bNotifyed = true;
_notifyed = true;
}
void e2d::GC::flush()

View File

@ -13,6 +13,10 @@ e2d::Game::Game()
{
}
e2d::Game::~Game()
{
}
e2d::Game * e2d::Game::getInstance()
{
if (!_instance)
@ -20,6 +24,15 @@ e2d::Game * e2d::Game::getInstance()
return _instance;
}
void e2d::Game::destroyInstance()
{
if (_instance)
{
delete _instance;
_instance = nullptr;
}
}
bool e2d::Game::init(const String& mutexName)
{
if (_initialized)
@ -41,7 +54,7 @@ bool e2d::Game::init(const String& mutexName)
else if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
// 如果程序已经存在并且正在运行,弹窗提示
Window::info(L"游戏已在其他窗口中打开!", L"提示");
Window::getInstance()->info(L"游戏已在其他窗口中打开!", L"提示");
// 关闭进程互斥体
::CloseHandle(hMutex);
return false;
@ -51,54 +64,15 @@ bool e2d::Game::init(const String& mutexName)
// 初始化 COM 组件
CoInitialize(nullptr);
bool bRendererDevIndResInit = false,
bWindowInit = false,
bRendererDevResInit = false,
bInputInit = false,
bool bInputInit = false,
bMusicInit = false;
auto DestroyResources = [&]()
{
if (bRendererDevIndResInit) Renderer::__discardResources();
if (bWindowInit) Window::__init();
if (bRendererDevResInit) Renderer::__discardDeviceResources();
if (bInputInit) Input::__uninit();
if (bMusicInit) Music::__uninit();
};
// 创建设备无关资源
if (Renderer::__createDeviceIndependentResources())
{
bRendererDevIndResInit = true;
}
else
{
DestroyResources();
throw SystemException(L"渲染器设备无关资源创建失败");
}
// 初始化窗口
if (Window::__init())
{
bWindowInit = true;
}
else
{
DestroyResources();
throw SystemException(L"初始化窗口失败");
}
// 创建设备相关资源
if (Renderer::__createDeviceResources())
{
bRendererDevResInit = true;
}
else
{
DestroyResources();
throw SystemException(L"渲染器设备相关资源创建失败");
}
// 初始化 DirectInput
if (Input::__init())
{
@ -141,14 +115,17 @@ void e2d::Game::start(bool cleanup)
throw Exception(L"开始游戏前未进行初始化");
}
auto window = Window::getInstance();
auto renderer = Renderer::getInstance();
// 初始化场景管理器
SceneManager::__init();
// 显示窗口
::ShowWindow(Window::getHWnd(), SW_SHOWNORMAL);
::ShowWindow(window->getHWnd(), SW_SHOWNORMAL);
// 刷新窗口内容
::UpdateWindow(Window::getHWnd());
::UpdateWindow(window->getHWnd());
// 处理窗口消息
Window::__poll();
window->__poll();
// 初始化计时
Time::__init();
@ -157,7 +134,7 @@ void e2d::Game::start(bool cleanup)
while (!_ended)
{
// 处理窗口消息
Window::__poll();
window->__poll();
// 刷新时间
Time::__updateNow();
@ -168,14 +145,14 @@ void e2d::Game::start(bool cleanup)
Timer::__update(); // 更新定时器
ActionManager::__update(); // 更新动作管理器
SceneManager::__update(); // 更新场景内容
Renderer::__render(); // 渲染游戏画面
renderer->__render(); // 渲染游戏画面
Time::__updateLast(); // 刷新时间信息
}
else
{
Time::__sleep(); // 挂起线程
GC::__update(); // 刷新内存池
Time::__sleep(); // 挂起线程
GC::getInstance()->__update(); // 刷新内存池
}
}
@ -236,8 +213,6 @@ void e2d::Game::cleanup()
ActionManager::__uninit();
// 回收音乐播放器资源
Player::__uninit();
// 删除所有对象
GC::__clear();
// 清空图片缓存
Image::clearCache();
// 回收音乐相关资源
@ -246,21 +221,10 @@ void e2d::Game::cleanup()
Timer::__uninit();
// 关闭输入
Input::__uninit();
// 回收渲染相关资源
Renderer::__discardResources();
// 销毁窗口
Window::__uninit();
// 删除所有对象
GC::getInstance()->clear();
CoUninitialize();
_initialized = false;
}
void e2d::Game::destroy()
{
if (_instance)
{
delete _instance;
_instance = nullptr;
}
}

View File

@ -37,6 +37,8 @@ bool Input::__init()
nullptr
);
auto window = Window::getInstance();
if (SUCCEEDED(hr))
{
// 初始化键盘设备
@ -49,7 +51,7 @@ bool Input::__init()
if (SUCCEEDED(hr))
{
s_KeyboardDevice->SetCooperativeLevel(
Window::getHWnd(),
window->getHWnd(),
DISCL_FOREGROUND | DISCL_NONEXCLUSIVE
);
s_KeyboardDevice->SetDataFormat(
@ -59,7 +61,7 @@ bool Input::__init()
}
else
{
Window::error(L"Keyboard not found!");
window->error(L"Keyboard not found!");
return false;
}
}
@ -71,14 +73,14 @@ bool Input::__init()
if (SUCCEEDED(hr))
{
s_MouseDevice->SetCooperativeLevel(Window::getHWnd(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
s_MouseDevice->SetCooperativeLevel(window->getHWnd(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
s_MouseDevice->SetDataFormat(&c_dfDIMouse);
s_MouseDevice->Acquire();
s_MouseDevice->Poll();
}
else
{
Window::error(L"Mouse not found!");
window->error(L"Mouse not found!");
return false;
}
}
@ -141,7 +143,7 @@ void Input::__updateDeviceState()
}
GetCursorPos(&s_MousePosition);
ScreenToClient(Window::getHWnd(), &s_MousePosition);
ScreenToClient(Window::getInstance()->getHWnd(), &s_MousePosition);
}
bool Input::isDown(Key key)

View File

@ -2,163 +2,66 @@
#include "..\e2dmanager.h"
#include "..\e2dnode.h"
static bool s_bShowFps = false;
static float s_fDpiScaleX = 0;
static float s_fDpiScaleY = 0;
static IDWriteTextFormat * s_pTextFormat = nullptr;
static ID2D1Factory * s_pDirect2dFactory = nullptr;
static ID2D1HwndRenderTarget * s_pRenderTarget = nullptr;
static ID2D1SolidColorBrush * s_pSolidBrush = nullptr;
static IWICImagingFactory * s_pIWICFactory = nullptr;
static IDWriteFactory * s_pDWriteFactory = nullptr;
static e2d::TextRenderer * s_pTextRenderer = nullptr;
static ID2D1StrokeStyle * s_pMiterStrokeStyle = nullptr;
static ID2D1StrokeStyle * s_pBevelStrokeStyle = nullptr;
static ID2D1StrokeStyle * s_pRoundStrokeStyle = nullptr;
static D2D1_COLOR_F s_nClearColor = D2D1::ColorF(D2D1::ColorF::Black);
e2d::Renderer* e2d::Renderer::_instance = nullptr;
ID2D1Factory* e2d::Renderer::_d2dFactory = nullptr;
IWICImagingFactory* e2d::Renderer::_imagingFactory = nullptr;
IDWriteFactory* e2d::Renderer::_writeFactory = nullptr;
IDWriteTextFormat* e2d::Renderer::_textFormat = nullptr;
ID2D1StrokeStyle* e2d::Renderer::_miterStrokeStyle = nullptr;
ID2D1StrokeStyle* e2d::Renderer::_bevelStrokeStyle = nullptr;
ID2D1StrokeStyle* e2d::Renderer::_roundStrokeStyle = nullptr;
bool e2d::Renderer::__createDeviceIndependentResources()
e2d::Renderer * e2d::Renderer::getInstance()
{
// 创建设备无关资源,它们的生命周期和程序的时长相同
HRESULT hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&s_pDirect2dFactory
);
if (!_instance)
{
_instance = new (std::nothrow) Renderer;
}
return _instance;
}
// 工厂将返回当前的系统 DPI这个值也将用来创建窗口
if (SUCCEEDED(hr))
void e2d::Renderer::destroyInstance()
{
if (_instance)
{
s_pDirect2dFactory->GetDesktopDpi(&s_fDpiScaleX, &s_fDpiScaleY);
}
delete _instance;
_instance = nullptr;
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1Factory failed");
}
else
{
hr = s_pDirect2dFactory->CreateStrokeStyle(
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),
nullptr,
0,
&s_pMiterStrokeStyle
);
SafeRelease(_textFormat);
SafeRelease(_d2dFactory);
SafeRelease(_miterStrokeStyle);
SafeRelease(_bevelStrokeStyle);
SafeRelease(_roundStrokeStyle);
SafeRelease(_imagingFactory);
SafeRelease(_writeFactory);
}
}
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
else
{
hr = s_pDirect2dFactory->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_BEVEL,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&s_pBevelStrokeStyle
);
}
e2d::Renderer::Renderer()
: _showFps(false)
, _renderTarget(nullptr)
, _solidBrush(nullptr)
, _textRenderer(nullptr)
, _clearColor(D2D1::ColorF(D2D1::ColorF::Black))
{
this->__createDeviceResources();
}
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
else
{
hr = s_pDirect2dFactory->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_ROUND,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&s_pRoundStrokeStyle
);
}
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
else
{
// 创建 WIC 绘图工厂,用于统一处理各种格式的图片
hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&s_pIWICFactory)
);
}
if (FAILED(hr))
{
throw SystemException(L"Create IWICImagingFactory failed");
}
else
{
// 创建 DirectWrite 工厂
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&s_pDWriteFactory)
);
}
if (FAILED(hr))
{
throw SystemException(L"Create IDWriteFactory failed");
}
else
{
// 创建文本格式化对象
hr = s_pDWriteFactory->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&s_pTextFormat
);
if (SUCCEEDED(hr))
{
s_pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
}
return SUCCEEDED(hr);
e2d::Renderer::~Renderer()
{
SafeRelease(_renderTarget);
SafeRelease(_solidBrush);
SafeRelease(_textRenderer);
}
bool e2d::Renderer::__createDeviceResources()
{
HRESULT hr = S_OK;
if (!s_pRenderTarget)
if (!_renderTarget)
{
HWND hWnd = Window::getHWnd();
HWND hWnd = Window::getInstance()->getHWnd();
// 创建设备相关资源。这些资源应在 Direct3D 设备消失时重建,
// 比如当 isVisiable 被修改,等等
@ -171,12 +74,12 @@ bool e2d::Renderer::__createDeviceResources()
);
// 创建一个 Direct2D 渲染目标
hr = s_pDirect2dFactory->CreateHwndRenderTarget(
hr = Renderer::getFactory()->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,
size),
&s_pRenderTarget
&_renderTarget
);
if (FAILED(hr))
@ -186,9 +89,9 @@ bool e2d::Renderer::__createDeviceResources()
else
{
// 创建画刷
hr = s_pRenderTarget->CreateSolidColorBrush(
hr = _renderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White),
&s_pSolidBrush
&_solidBrush
);
}
@ -196,15 +99,6 @@ bool e2d::Renderer::__createDeviceResources()
{
throw SystemException(L"Create ID2D1SolidColorBrush failed");
}
else
{
// 创建自定义的文字渲染器
s_pTextRenderer = TextRenderer::Create(
s_pDirect2dFactory,
s_pRenderTarget,
s_pSolidBrush
);
}
}
return SUCCEEDED(hr);
@ -212,26 +106,12 @@ bool e2d::Renderer::__createDeviceResources()
void e2d::Renderer::__discardDeviceResources()
{
SafeRelease(s_pRenderTarget);
SafeRelease(s_pSolidBrush);
SafeRelease(s_pTextRenderer);
SafeRelease(s_pMiterStrokeStyle);
SafeRelease(s_pBevelStrokeStyle);
SafeRelease(s_pRoundStrokeStyle);
}
void e2d::Renderer::__discardResources()
{
SafeRelease(s_pTextFormat);
SafeRelease(s_pDirect2dFactory);
SafeRelease(s_pRenderTarget);
SafeRelease(s_pSolidBrush);
SafeRelease(s_pTextRenderer);
SafeRelease(s_pMiterStrokeStyle);
SafeRelease(s_pBevelStrokeStyle);
SafeRelease(s_pRoundStrokeStyle);
SafeRelease(s_pIWICFactory);
SafeRelease(s_pDWriteFactory);
SafeRelease(_renderTarget);
SafeRelease(_solidBrush);
SafeRelease(_textRenderer);
SafeRelease(_miterStrokeStyle);
SafeRelease(_bevelStrokeStyle);
SafeRelease(_roundStrokeStyle);
}
void e2d::Renderer::__render()
@ -242,15 +122,15 @@ void e2d::Renderer::__render()
Renderer::__createDeviceResources();
// 开始渲染
s_pRenderTarget->BeginDraw();
_renderTarget->BeginDraw();
// 使用背景色清空屏幕
s_pRenderTarget->Clear(s_nClearColor);
_renderTarget->Clear(_clearColor);
// 渲染场景
SceneManager::__render();
// 渲染 FPS
if (s_bShowFps && s_pTextFormat)
if (_showFps)
{
static int s_nRenderTimes = 0;
static double s_fLastRenderTime = 0;
@ -267,11 +147,12 @@ void e2d::Renderer::__render()
}
IDWriteTextLayout * pTextLayout = nullptr;
IDWriteTextFormat * pTextFormat = Renderer::getFpsTextFormat();
hr = s_pDWriteFactory->CreateTextLayout(
hr = _writeFactory->CreateTextLayout(
(const WCHAR *)s_sFpsText,
(UINT32)s_sFpsText.getLength(),
s_pTextFormat,
pTextFormat,
0,
0,
&pTextLayout
@ -279,9 +160,9 @@ void e2d::Renderer::__render()
if (SUCCEEDED(hr))
{
s_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
s_pSolidBrush->SetOpacity(1.0f);
s_pTextRenderer->SetTextStyle(
_renderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
_solidBrush->SetOpacity(1.0f);
_textRenderer->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White),
TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
@ -289,21 +170,21 @@ void e2d::Renderer::__render()
D2D1_LINE_JOIN_ROUND
);
pTextLayout->Draw(nullptr, s_pTextRenderer, 10, 0);
pTextLayout->Draw(nullptr, _textRenderer, 10, 0);
SafeRelease(pTextLayout);
}
}
// 终止渲染
hr = s_pRenderTarget->EndDraw();
hr = _renderTarget->EndDraw();
if (hr == D2DERR_RECREATE_TARGET)
{
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
// 并在下一次调用时重建资源
hr = S_OK;
Renderer::__discardDeviceResources();
this->__discardDeviceResources();
}
if (FAILED(hr))
@ -312,73 +193,200 @@ void e2d::Renderer::__render()
}
}
e2d::Color e2d::Renderer::getBackgroundColor()
{
return Color(s_nClearColor.r, s_nClearColor.g, s_nClearColor.b, s_nClearColor.a);
return Color(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);
}
void e2d::Renderer::setBackgroundColor(Color color)
{
s_nClearColor = color.toD2DColorF();
_clearColor = color.toD2DColorF();
}
void e2d::Renderer::showFps(bool show)
{
s_bShowFps = show;
}
float e2d::Renderer::getDpiScaleX()
{
return s_fDpiScaleX;
}
float e2d::Renderer::getDpiScaleY()
{
return s_fDpiScaleY;
}
ID2D1Factory * e2d::Renderer::getID2D1Factory()
{
return s_pDirect2dFactory;
_showFps = show;
}
ID2D1HwndRenderTarget * e2d::Renderer::getRenderTarget()
{
return s_pRenderTarget;
return _renderTarget;
}
ID2D1SolidColorBrush * e2d::Renderer::getSolidColorBrush()
{
return s_pSolidBrush;
}
IWICImagingFactory * e2d::Renderer::getIWICImagingFactory()
{
return s_pIWICFactory;
}
IDWriteFactory * e2d::Renderer::getIDWriteFactory()
{
return s_pDWriteFactory;
return _solidBrush;
}
e2d::TextRenderer * e2d::Renderer::getTextRenderer()
{
return s_pTextRenderer;
if (!_textRenderer)
{
// 创建自定义的文字渲染器
_textRenderer = TextRenderer::Create(
Renderer::getFactory(),
this->getRenderTarget(),
this->getSolidColorBrush()
);
}
return _textRenderer;
}
ID2D1StrokeStyle * e2d::Renderer::getMiterID2D1StrokeStyle()
ID2D1Factory * e2d::Renderer::getFactory()
{
return s_pMiterStrokeStyle;
if (!_d2dFactory)
{
HRESULT hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&_d2dFactory
);
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1Factory failed");
}
}
return _d2dFactory;
}
ID2D1StrokeStyle * e2d::Renderer::getBevelID2D1StrokeStyle()
IWICImagingFactory * e2d::Renderer::getImagingFactory()
{
return s_pBevelStrokeStyle;
if (!_imagingFactory)
{
// 创建 WIC 绘图工厂,用于统一处理各种格式的图片
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&_imagingFactory)
);
if (FAILED(hr))
{
throw SystemException(L"Create IWICImagingFactory failed");
}
}
return _imagingFactory;
}
ID2D1StrokeStyle * e2d::Renderer::getRoundID2D1StrokeStyle()
IDWriteFactory * e2d::Renderer::getWriteFactory()
{
return s_pRoundStrokeStyle;
if (!_writeFactory)
{
// 创建 DirectWrite 工厂
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&_writeFactory)
);
if (FAILED(hr))
{
throw SystemException(L"Create IDWriteFactory failed");
}
}
return _writeFactory;
}
IDWriteTextFormat * e2d::Renderer::getFpsTextFormat()
{
if (!_textFormat)
{
// 创建 FPS 文本格式化对象
HRESULT hr = Renderer::getWriteFactory()->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&_textFormat
);
if (SUCCEEDED(hr))
{
_textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
}
return _textFormat;
}
ID2D1StrokeStyle * e2d::Renderer::getMiterStrokeStyle()
{
if (!_miterStrokeStyle)
{
HRESULT hr = Renderer::getFactory()->CreateStrokeStyle(
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),
nullptr,
0,
&_miterStrokeStyle
);
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
}
return _miterStrokeStyle;
}
ID2D1StrokeStyle * e2d::Renderer::getBevelStrokeStyle()
{
if (!_bevelStrokeStyle)
{
HRESULT hr = Renderer::getFactory()->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_BEVEL,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&_bevelStrokeStyle
);
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
}
return _bevelStrokeStyle;
}
ID2D1StrokeStyle * e2d::Renderer::getRoundStrokeStyle()
{
if (!_roundStrokeStyle)
{
HRESULT hr = Renderer::getFactory()->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_ROUND,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&_roundStrokeStyle
);
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
}
return _roundStrokeStyle;
}

View File

@ -3,11 +3,48 @@
#include <imm.h>
#pragma comment (lib ,"imm32.lib")
// 窗口句柄
static HWND s_HWnd = nullptr;
e2d::Window * e2d::Window::_instance = nullptr;
bool e2d::Window::__init()
e2d::Window::Window()
: _hWnd(nullptr)
, _size()
, _title()
{
}
e2d::Window::~Window()
{
// 关闭控制台
if (::GetConsoleWindow())
{
::FreeConsole();
}
// 关闭窗口
if (_hWnd)
{
::DestroyWindow(_hWnd);
_hWnd = nullptr;
}
}
e2d::Window * e2d::Window::getInstance()
{
if (!_instance)
_instance = new (std::nothrow) Window;
return _instance;
}
void e2d::Window::destroyInstance()
{
if (_instance)
{
delete _instance;
_instance = nullptr;
}
}
bool e2d::Window::create(const String& title, int width, int height)
{
// 注册窗口类
WNDCLASSEX wcex = { 0 };
@ -27,11 +64,11 @@ bool e2d::Window::__init()
// 因为 CreateWindow 函数使用的是像素大小,获取系统的 DPI 以使它
// 适应窗口缩放
float dpiX = Renderer::getDpiScaleX();
float dpiY = Renderer::getDpiScaleY();
float dpiScaleX = 0.f, dpiScaleY = 0.f;
Renderer::getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY);
int nWidth = static_cast<int>(ceil(640 * dpiX / 96.f));
int nHeight = static_cast<int>(ceil(480 * dpiY / 96.f));
int nWidth = static_cast<int>(ceil(width * dpiScaleX / 96.f));
int nHeight = static_cast<int>(ceil(height * dpiScaleY / 96.f));
// 计算窗口大小
DWORD dwStyle = WS_OVERLAPPEDWINDOW &~ WS_MAXIMIZEBOX &~ WS_THICKFRAME;
@ -46,10 +83,10 @@ bool e2d::Window::__init()
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
// 创建窗口
s_HWnd = ::CreateWindowEx(
_hWnd = ::CreateWindowEx(
NULL,
L"Easy2DApp",
L"Easy2D Game",
(LPCTSTR)title,
dwStyle,
(screenWidth - nWidth) / 2, (screenHeight - nHeight) / 2,
nWidth, nHeight,
@ -59,12 +96,12 @@ bool e2d::Window::__init()
nullptr
);
HRESULT hr = s_HWnd ? S_OK : E_FAIL;
HRESULT hr = _hWnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// 禁用输入法
Window::setTypewritingEnable(false);
this->setTypewritingEnable(false);
// 禁用控制台关闭按钮
HWND consoleHWnd = ::GetConsoleWindow();
if (consoleHWnd)
@ -72,32 +109,15 @@ bool e2d::Window::__init()
HMENU hmenu = ::GetSystemMenu(consoleHWnd, FALSE);
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
}
this->_size = Size(width, height);
this->_title = title;
return true;
}
else
{
::UnregisterClass(L"Easy2DApp", HINST_THISCOMPONENT);
}
if (FAILED(hr))
{
Window::error(L"Create Window Failed!");
}
return SUCCEEDED(hr);
}
void e2d::Window::__uninit()
{
// 关闭控制台
if (::GetConsoleWindow())
{
::FreeConsole();
}
// 关闭窗口
if (s_HWnd)
{
::DestroyWindow(s_HWnd);
s_HWnd = nullptr;
this->error(L"Create Window Failed!");
return false;
}
}
@ -114,43 +134,27 @@ void e2d::Window::__poll()
double e2d::Window::getWidth()
{
if (s_HWnd)
{
// 获取客户区大小
tagRECT rcClient;
::GetClientRect(s_HWnd, &rcClient);
return rcClient.right - rcClient.left;
}
return 0;
return _size.width;
}
double e2d::Window::getHeight()
{
if (s_HWnd)
{
// 获取客户区大小
tagRECT rcClient;
::GetClientRect(s_HWnd, &rcClient);
return rcClient.bottom - rcClient.top;
}
return 0;
return _size.height;
}
e2d::Size e2d::Window::getSize()
{
if (s_HWnd)
{
// 获取客户区大小
tagRECT rcClient;
::GetClientRect(s_HWnd, &rcClient);
return Size(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
}
return Size();
return _size;
}
e2d::String e2d::Window::getTitle()
{
return _title;
}
HWND e2d::Window::getHWnd()
{
return s_HWnd;
return _hWnd;
}
void e2d::Window::setSize(int width, int height)
@ -171,13 +175,13 @@ void e2d::Window::setSize(int width, int height)
width = min(width, screenWidth);
height = min(height, screenHeight);
// 修改窗口大小,并设置窗口在屏幕居中
::MoveWindow(s_HWnd, (screenWidth - width) / 2, (screenHeight - height) / 2, width, height, TRUE);
::MoveWindow(_hWnd, (screenWidth - width) / 2, (screenHeight - height) / 2, width, height, TRUE);
}
void e2d::Window::setTitle(const String& title)
{
// 设置窗口标题
::SetWindowText(s_HWnd, (LPCWSTR)title);
::SetWindowText(_hWnd, (LPCWSTR)title);
}
void e2d::Window::setIcon(int iconID)
@ -185,8 +189,8 @@ void e2d::Window::setIcon(int iconID)
HINSTANCE hInstance = ::GetModuleHandle(nullptr);
HICON hIcon = (HICON)::LoadImage(hInstance, MAKEINTRESOURCE(iconID), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
// 设置窗口的图标
::SendMessage(s_HWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
::SendMessage(s_HWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
::SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
::SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
}
void e2d::Window::setCursor(Cursor cursor)
@ -222,13 +226,6 @@ void e2d::Window::setCursor(Cursor cursor)
::SetCursor(hCursor);
}
e2d::String e2d::Window::getTitle()
{
wchar_t wszTitle[MAX_PATH] = { 0 };
::GetWindowText(s_HWnd, wszTitle, MAX_PATH);
return wszTitle;
}
void e2d::Window::showConsole(bool show)
{
// 查找已存在的控制台句柄
@ -257,7 +254,7 @@ void e2d::Window::showConsole(bool show)
}
else
{
Window::error(L"Alloc Console Failed!");
this->error(L"Alloc Console Failed!");
}
}
}
@ -278,7 +275,7 @@ void e2d::Window::setTypewritingEnable(bool enable)
{
if (hImc != nullptr)
{
::ImmAssociateContext(Window::getHWnd(), hImc);
::ImmAssociateContext(_hWnd, hImc);
hImc = nullptr;
}
}
@ -286,26 +283,26 @@ void e2d::Window::setTypewritingEnable(bool enable)
{
if (hImc == nullptr)
{
hImc = ::ImmAssociateContext(Window::getHWnd(), nullptr);
hImc = ::ImmAssociateContext(_hWnd, nullptr);
}
}
}
void e2d::Window::info(const String & text, const String & title)
{
::MessageBox(s_HWnd, (LPCWSTR)text, (LPCWSTR)title, MB_ICONINFORMATION | MB_OK);
::MessageBox(_hWnd, (LPCWSTR)text, (LPCWSTR)title, MB_ICONINFORMATION | MB_OK);
Game::getInstance()->reset();
}
void e2d::Window::warning(const String& title, const String& text)
{
::MessageBox(s_HWnd, (LPCWSTR)text, (LPCWSTR)title, MB_ICONWARNING | MB_OK);
::MessageBox(_hWnd, (LPCWSTR)text, (LPCWSTR)title, MB_ICONWARNING | MB_OK);
Game::getInstance()->reset();
}
void e2d::Window::error(const String & text, const String & title)
{
::MessageBox(s_HWnd, (LPCWSTR)text, (LPCWSTR)title, MB_ICONERROR | MB_OK);
::MessageBox(_hWnd, (LPCWSTR)text, (LPCWSTR)title, MB_ICONERROR | MB_OK);
Game::getInstance()->reset();
}
@ -323,11 +320,25 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
auto instance = Window::getInstance();
if (instance)
instance->_size = Size(width, height);
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标适当。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生
auto pRT = Renderer::getRenderTarget();
if (pRT) pRT->Resize(D2D1::SizeU(width, height));
auto pRT = Renderer::getInstance()->getRenderTarget();
if (pRT)
pRT->Resize(D2D1::SizeU(width, height));
}
break;
// 处理窗口标题变化消息
case WM_SETTEXT:
{
auto instance = Window::getInstance();
instance->_title = (const wchar_t*)lParam;
}
break;
@ -344,7 +355,7 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
// 重绘窗口
case WM_PAINT:
{
e2d::Renderer::__render();
e2d::Renderer::getInstance()->__render();
ValidateRect(hWnd, nullptr);
}
result = 0;

View File

@ -35,7 +35,7 @@ void e2d::CircleCollider::setCircle(Point center, double radius)
{
SafeRelease(_d2dCircle);
Renderer::getID2D1Factory()->CreateEllipseGeometry(
Renderer::getFactory()->CreateEllipseGeometry(
D2D1::Ellipse(
D2D1::Point2F(
float(center.x),

View File

@ -51,12 +51,13 @@ void e2d::Collider::_render()
{
if (_transformed && _enable)
{
auto renderer = Renderer::getInstance();
// 获取纯色画刷
ID2D1SolidColorBrush * pBrush = Renderer::getSolidColorBrush();
ID2D1SolidColorBrush * pBrush = renderer->getSolidColorBrush();
// 设置画刷颜色和透明度
pBrush->SetColor(_color.toD2DColorF());
// 绘制几何碰撞体
Renderer::getRenderTarget()->DrawGeometry(_transformed, pBrush);
renderer->getRenderTarget()->DrawGeometry(_transformed, pBrush);
}
}
@ -93,7 +94,7 @@ void e2d::Collider::_transform()
SafeRelease(_transformed);
// 根据父节点转换几何图形
Renderer::getID2D1Factory()->CreateTransformedGeometry(
Renderer::getFactory()->CreateTransformedGeometry(
getD2dGeometry(),
_parentNode->_finalMatri,
&_transformed

View File

@ -35,7 +35,7 @@ void e2d::EllipseCollider::setEllipse(Point center, double radiusX, double radiu
{
SafeRelease(_d2dEllipse);
Renderer::getID2D1Factory()->CreateEllipseGeometry(
Renderer::getFactory()->CreateEllipseGeometry(
D2D1::Ellipse(
D2D1::Point2F(
float(center.x),

View File

@ -28,7 +28,7 @@ void e2d::RectCollider::setRect(double left, double top, double right, double bo
{
SafeRelease(_d2dRectangle);
Renderer::getID2D1Factory()->CreateRectangleGeometry(
Renderer::getFactory()->CreateRectangleGeometry(
D2D1::RectF(
float(left),
float(top),

View File

@ -176,7 +176,7 @@ bool e2d::Image::preload(const String& filePath)
ID2D1Bitmap *pBitmap = nullptr;
// 创建解码器
hr = Renderer::getIWICImagingFactory()->CreateDecoderFromFilename(
hr = Renderer::getImagingFactory()->CreateDecoderFromFilename(
(LPCWSTR)actualFilePath,
nullptr,
GENERIC_READ,
@ -194,7 +194,7 @@ bool e2d::Image::preload(const String& filePath)
{
// 创建图片格式转换器
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = Renderer::getIWICImagingFactory()->CreateFormatConverter(&pConverter);
hr = Renderer::getImagingFactory()->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
@ -213,7 +213,7 @@ bool e2d::Image::preload(const String& filePath)
if (SUCCEEDED(hr))
{
// 从 WIC 位图创建一个 Direct2D 位图
hr = Renderer::getRenderTarget()->CreateBitmapFromWicBitmap(
hr = Renderer::getInstance()->getRenderTarget()->CreateBitmapFromWicBitmap(
pConverter,
nullptr,
&pBitmap
@ -291,7 +291,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
// 创建 WIC 流
hr = Renderer::getIWICImagingFactory()->CreateStream(&pStream);
hr = Renderer::getImagingFactory()->CreateStream(&pStream);
}
if (SUCCEEDED(hr))
@ -306,7 +306,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
// 创建流的解码器
hr = Renderer::getIWICImagingFactory()->CreateDecoderFromStream(
hr = Renderer::getImagingFactory()->CreateDecoderFromStream(
pStream,
nullptr,
WICDecodeMetadataCacheOnLoad,
@ -324,7 +324,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
{
// 创建图片格式转换器
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = Renderer::getIWICImagingFactory()->CreateFormatConverter(&pConverter);
hr = Renderer::getImagingFactory()->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
@ -343,7 +343,7 @@ bool e2d::Image::preload(int resNameId, const String& resType)
if (SUCCEEDED(hr))
{
// 从 WIC 位图创建一个 Direct2D 位图
hr = Renderer::getRenderTarget()->CreateBitmapFromWicBitmap(
hr = Renderer::getInstance()->getRenderTarget()->CreateBitmapFromWicBitmap(
pConverter,
nullptr,
&pBitmap

View File

@ -13,7 +13,7 @@ e2d::Object::~Object()
void e2d::Object::autorelease()
{
GC::__add(this);
GC::getInstance()->addObject(this);
}
void e2d::Object::retain()
@ -24,7 +24,7 @@ void e2d::Object::retain()
void e2d::Object::release()
{
_refCount--;
GC::notify();
GC::getInstance()->notify();
}
int e2d::Object::getRefCount() const

View File

@ -30,7 +30,7 @@ void e2d::Scene::_render()
if (_colliderVisiable)
{
// 恢复矩阵转换
Renderer::getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
Renderer::getInstance()->getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
// 绘制所有几何图形
_root->_drawCollider();
}

View File

@ -59,13 +59,13 @@ STDMETHODIMP_(void) TextRenderer::SetTextStyle(
switch (outlineJoin)
{
case D2D1_LINE_JOIN_MITER:
pCurrStrokeStyle_ = Renderer::getMiterID2D1StrokeStyle();
pCurrStrokeStyle_ = Renderer::getMiterStrokeStyle();
break;
case D2D1_LINE_JOIN_BEVEL:
pCurrStrokeStyle_ = Renderer::getBevelID2D1StrokeStyle();
pCurrStrokeStyle_ = Renderer::getBevelStrokeStyle();
break;
case D2D1_LINE_JOIN_ROUND:
pCurrStrokeStyle_ = Renderer::getRoundID2D1StrokeStyle();
pCurrStrokeStyle_ = Renderer::getRoundStrokeStyle();
break;
default:
pCurrStrokeStyle_ = nullptr;

View File

@ -209,14 +209,14 @@ void e2d::Button::_fixedUpdate()
if (_normal->containsPoint(Input::getMousePos()))
{
_setState(ButtonState::Selected);
Window::setCursor(Window::Cursor::Hand);
Window::getInstance()->setCursor(Window::Cursor::Hand);
return;
}
}
else if (_normal->containsPoint(Input::getMousePos()))
{
_setState(ButtonState::Mouseover);
Window::setCursor(Window::Cursor::Hand);
Window::getInstance()->setCursor(Window::Cursor::Hand);
return;
}
@ -225,7 +225,7 @@ void e2d::Button::_fixedUpdate()
if (_visiable && !_enable && _normal && _normal->containsPoint(Input::getMousePos()))
{
Window::setCursor(Window::Cursor::No);
Window::getInstance()->setCursor(Window::Cursor::No);
}
}

View File

@ -105,7 +105,7 @@ void e2d::Node::_render()
if (_children.empty())
{
// 转换渲染器的二维矩阵
Renderer::getRenderTarget()->SetTransform(_finalMatri);
Renderer::getInstance()->getRenderTarget()->SetTransform(_finalMatri);
// 渲染自身
this->onRender();
}
@ -131,7 +131,7 @@ void e2d::Node::_render()
}
// 转换渲染器的二维矩阵
Renderer::getRenderTarget()->SetTransform(_finalMatri);
Renderer::getInstance()->getRenderTarget()->SetTransform(_finalMatri);
// 渲染自身
this->onRender();
@ -826,7 +826,7 @@ bool e2d::Node::containsPoint(const Point& point) const
{
// 为节点创建一个临时碰撞体
ID2D1RectangleGeometry * rect;
Renderer::getID2D1Factory()->CreateRectangleGeometry(
Renderer::getFactory()->CreateRectangleGeometry(
D2D1::RectF(0, 0, _width, _height),
&rect
);
@ -871,18 +871,18 @@ bool e2d::Node::intersects(Node * node) const
D2D1_GEOMETRY_RELATION relation;
// 根据自身大小位置创建矩形
Renderer::getID2D1Factory()->CreateRectangleGeometry(
Renderer::getFactory()->CreateRectangleGeometry(
D2D1::RectF(0, 0, _width, _height),
&pRect1
);
// 根据二维矩阵进行转换
Renderer::getID2D1Factory()->CreateTransformedGeometry(
Renderer::getFactory()->CreateTransformedGeometry(
pRect1,
_finalMatri,
&pCollider
);
// 根据相比较节点的大小位置创建矩形
Renderer::getID2D1Factory()->CreateRectangleGeometry(
Renderer::getFactory()->CreateRectangleGeometry(
D2D1::RectF(0, 0, node->_width, node->_height),
&pRect2
);

View File

@ -36,9 +36,10 @@ void e2d::CircleShape::setRadius(double radius)
void e2d::CircleShape::_renderLine()
{
Renderer::getRenderTarget()->DrawEllipse(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->DrawEllipse(
D2D1::Ellipse(D2D1::Point2F(_radius, _radius), _radius, _radius),
Renderer::getSolidColorBrush(),
renderer->getSolidColorBrush(),
_strokeWidth,
_strokeStyle
);
@ -46,8 +47,9 @@ void e2d::CircleShape::_renderLine()
void e2d::CircleShape::_renderFill()
{
Renderer::getRenderTarget()->FillEllipse(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->FillEllipse(
D2D1::Ellipse(D2D1::Point2F(_radius, _radius), _radius, _radius),
Renderer::getSolidColorBrush()
renderer->getSolidColorBrush()
);
}

View File

@ -50,9 +50,10 @@ void e2d::EllipseShape::setRadiusY(double radiusY)
void e2d::EllipseShape::_renderLine()
{
Renderer::getRenderTarget()->DrawEllipse(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->DrawEllipse(
D2D1::Ellipse(D2D1::Point2F(_radiusX, _radiusY), _radiusX, _radiusY),
Renderer::getSolidColorBrush(),
renderer->getSolidColorBrush(),
_strokeWidth,
_strokeStyle
);
@ -60,8 +61,9 @@ void e2d::EllipseShape::_renderLine()
void e2d::EllipseShape::_renderFill()
{
Renderer::getRenderTarget()->FillEllipse(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->FillEllipse(
D2D1::Ellipse(D2D1::Point2F(_radiusX, _radiusY), _radiusX, _radiusY),
Renderer::getSolidColorBrush()
renderer->getSolidColorBrush()
);
}

View File

@ -22,9 +22,10 @@ e2d::RectShape::~RectShape()
void e2d::RectShape::_renderLine()
{
Renderer::getRenderTarget()->DrawRectangle(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->DrawRectangle(
D2D1::RectF(0, 0, _width, _height),
Renderer::getSolidColorBrush(),
renderer->getSolidColorBrush(),
_strokeWidth,
_strokeStyle
);
@ -32,8 +33,9 @@ void e2d::RectShape::_renderLine()
void e2d::RectShape::_renderFill()
{
Renderer::getRenderTarget()->FillRectangle(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->FillRectangle(
D2D1::RectF(0, 0, _width, _height),
Renderer::getSolidColorBrush()
renderer->getSolidColorBrush()
);
}

View File

@ -48,9 +48,10 @@ void e2d::RoundRectShape::setRadiusY(double radiusY)
void e2d::RoundRectShape::_renderLine()
{
Renderer::getRenderTarget()->DrawRoundedRectangle(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->DrawRoundedRectangle(
D2D1::RoundedRect(D2D1::RectF(0, 0, _width, _height), _radiusX, _radiusY),
Renderer::getSolidColorBrush(),
renderer->getSolidColorBrush(),
_strokeWidth,
_strokeStyle
);
@ -58,8 +59,9 @@ void e2d::RoundRectShape::_renderLine()
void e2d::RoundRectShape::_renderFill()
{
Renderer::getRenderTarget()->FillRoundedRectangle(
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->FillRoundedRectangle(
D2D1::RoundedRect(D2D1::RectF(0, 0, _width, _height), _radiusX, _radiusY),
Renderer::getSolidColorBrush()
renderer->getSolidColorBrush()
);
}

View File

@ -15,7 +15,7 @@ e2d::Shape::~Shape()
void e2d::Shape::onRender()
{
auto pBrush = Renderer::getSolidColorBrush();
auto pBrush = Renderer::getInstance()->getSolidColorBrush();
pBrush->SetOpacity(_displayOpacity);
switch (_style)
@ -94,13 +94,13 @@ void e2d::Shape::setLineJoin(LineJoin lineJoin)
switch (lineJoin)
{
case LineJoin::Miter:
_strokeStyle = Renderer::getMiterID2D1StrokeStyle();
_strokeStyle = Renderer::getMiterStrokeStyle();
break;
case LineJoin::Bevel:
_strokeStyle = Renderer::getBevelID2D1StrokeStyle();
_strokeStyle = Renderer::getBevelStrokeStyle();
break;
case LineJoin::Round:
_strokeStyle = Renderer::getRoundID2D1StrokeStyle();
_strokeStyle = Renderer::getRoundStrokeStyle();
break;
default:
_strokeStyle = nullptr;

View File

@ -110,7 +110,7 @@ void e2d::Sprite::onRender()
float fCropX = float(_image->getCropX());
float fCropY = float(_image->getCropY());
// äÖȾͼƬ
Renderer::getRenderTarget()->DrawBitmap(
Renderer::getInstance()->getRenderTarget()->DrawBitmap(
_image->getBitmap(),
D2D1::RectF(0, 0, _width, _height),
_displayOpacity,

View File

@ -291,12 +291,13 @@ void e2d::Text::onRender()
{
if (_textLayout)
{
auto renderer = Renderer::getInstance();
// 创建文本区域
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, _width, _height);
// 设置画刷颜色和透明度
Renderer::getSolidColorBrush()->SetOpacity(_displayOpacity);
renderer->getSolidColorBrush()->SetOpacity(_displayOpacity);
// 获取文本渲染器
auto pTextRenderer = Renderer::getTextRenderer();
auto pTextRenderer = renderer->getTextRenderer();
pTextRenderer->SetTextStyle(
_style.color.toD2DColorF(),
_style.hasOutline,
@ -320,7 +321,7 @@ void e2d::Text::_createFormat()
{
SafeRelease(_textFormat);
HRESULT hr = Renderer::getIDWriteFactory()->CreateTextFormat(
HRESULT hr = Renderer::getWriteFactory()->CreateTextFormat(
(const WCHAR *)_font.family,
nullptr,
DWRITE_FONT_WEIGHT(_font.weight),
@ -390,7 +391,7 @@ void e2d::Text::_createLayout()
// 对文本自动换行情况下进行处理
if (_style.wrapping)
{
hr = Renderer::getIDWriteFactory()->CreateTextLayout(
hr = Renderer::getWriteFactory()->CreateTextLayout(
(const WCHAR *)_text,
length,
_textFormat,
@ -409,7 +410,7 @@ void e2d::Text::_createLayout()
}
else
{
hr = Renderer::getIDWriteFactory()->CreateTextLayout((const WCHAR *)_text, length, _textFormat, 0, 0, &_textLayout);
hr = Renderer::getWriteFactory()->CreateTextLayout((const WCHAR *)_text, length, _textFormat, 0, 0, &_textLayout);
// 为防止文本对齐问题,根据刚才创建的 layout 宽度重新创建它
if (_textLayout)
{
@ -420,7 +421,7 @@ void e2d::Text::_createLayout()
this->setSize(metrics.width, metrics.height);
// 重新创建 layout
SafeRelease(_textLayout);
hr = Renderer::getIDWriteFactory()->CreateTextLayout((const WCHAR *)_text, length, _textFormat, _width, 0, &_textLayout);
hr = Renderer::getWriteFactory()->CreateTextLayout((const WCHAR *)_text, length, _textFormat, _width, 0, &_textLayout);
}
}

View File

@ -174,15 +174,15 @@ e2d::String e2d::Path::getSaveFilePath(const String& title, const String& defExt
OPENFILENAME ofn = { 0 };
wchar_t strFilename[MAX_PATH] = { 0 }; // 用于接收文件名
ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小
ofn.hwndOwner = Window::getHWnd(); // 窗口句柄
ofn.hwndOwner = Window::getInstance()->getHWnd(); // 窗口句柄
ofn.lpstrFilter = L"所有文件\0*.*\0\0"; // 设置过滤
ofn.nFilterIndex = 1; // 过滤器索引
ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名
ofn.nMaxFile = sizeof(strFilename); // 缓冲区长度
ofn.lpstrInitialDir = nullptr; // 初始目录为默认
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
ofn.lpstrTitle = (LPCWSTR)title; // 标题
ofn.lpstrDefExt = (LPCWSTR)defExt; // 默认追加的扩展名
ofn.lpstrTitle = (LPCWSTR)title; // 标题
ofn.lpstrDefExt = (LPCWSTR)defExt; // 默认追加的扩展名
if (GetSaveFileName(&ofn))
{

View File

@ -35,12 +35,13 @@ void e2d::Transition::onDestroy()
void e2d::Transition::_init(Scene * prev, Scene * next)
{
auto renderer = Renderer::getInstance();
// ´´½¨Í¼²ã
HRESULT hr = Renderer::getRenderTarget()->CreateLayer(&_inLayer);
HRESULT hr = renderer->getRenderTarget()->CreateLayer(&_inLayer);
if (SUCCEEDED(hr))
{
hr = Renderer::getRenderTarget()->CreateLayer(&_outLayer);
hr = renderer->getRenderTarget()->CreateLayer(&_outLayer);
}
if (FAILED(hr))
@ -54,7 +55,7 @@ void e2d::Transition::_init(Scene * prev, Scene * next)
if (_outScene) _outScene->retain();
if (_inScene) _inScene->retain();
_windowSize = Window::getSize();
_windowSize = Window::getInstance()->getSize();
_outLayerParam = _inLayerParam = D2D1::LayerParameters();
}
@ -85,7 +86,7 @@ void e2d::Transition::_update()
void e2d::Transition::_render()
{
auto pRT = Renderer::getRenderTarget();
auto pRT = Renderer::getInstance()->getRenderTarget();
if (_outScene)
{

View File

@ -14,9 +14,12 @@ namespace e2d
class Game
{
public:
// 获取游戏
// 获取游戏
static Game * getInstance();
// 销毁实例
static void destroyInstance();
// 初始化游戏
bool init(
const String& mutexName = L"" /* 进程互斥体名称 */
@ -39,9 +42,6 @@ public:
// 清理资源
void cleanup();
// 销毁实例
void destroy();
// 重置游戏内部计时
void reset();
@ -51,6 +51,8 @@ public:
private:
Game();
~Game();
E2D_DISABLE_COPY(Game);
private:
@ -78,82 +80,101 @@ public:
};
public:
// 获取窗口实例
static Window * getInstance();
// 销毁窗口实例
static void destroyInstance();
// 创建新窗口
bool create(
const String& title,
int width,
int height
);
// 修改窗口大小
static void setSize(
void setSize(
int width, /* 窗口宽度 */
int height /* 窗口高度 */
);
// 设置窗口标题
static void setTitle(
void setTitle(
const String& title /* 窗口标题 */
);
// 设置窗口图标
static void setIcon(
void setIcon(
int iconID
);
// 设置鼠标指针样式
static void setCursor(
void setCursor(
Cursor cursor
);
// 获取窗口标题
static String getTitle();
String getTitle();
// 获取窗口宽度
static double getWidth();
double getWidth();
// 获取窗口高度
static double getHeight();
double getHeight();
// 获取窗口大小
static Size getSize();
Size getSize();
// 获取窗口句柄
static HWND getHWnd();
HWND getHWnd();
// 打开/隐藏控制台
static void showConsole(
void showConsole(
bool show = true
);
// 是否允许响应输入法
static void setTypewritingEnable(
void setTypewritingEnable(
bool enable
);
// 弹出提示窗口
static void info(
void info(
const String& text, /* 内容 */
const String& title = L"Infomation" /* 窗口标题 */
);
// 弹出警告窗口
static void warning(
void warning(
const String& text, /* 内容 */
const String& title = L"Warning" /* 窗口标题 */
);
// 弹出错误窗口
static void error(
void error(
const String& text, /* 内容 */
const String& title = L"Error" /* 窗口标题 */
);
private:
// 初始化窗口
static bool __init();
Window();
// 重置窗口属性
static void __uninit();
~Window();
E2D_DISABLE_COPY(Window);
// 处理窗口消息
static void __poll();
void __poll();
// Win32 窗口消息回调程序
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
private:
HWND _hWnd;
Size _size;
String _title;
static Window * _instance;
};
@ -389,67 +410,86 @@ class Renderer
friend class Window;
public:
// 获取渲染器实例
static Renderer * getInstance();
// 销毁实例
static void destroyInstance();
// 获取背景色
static Color getBackgroundColor();
Color getBackgroundColor();
// 修改背景色
static void setBackgroundColor(
void setBackgroundColor(
Color color
);
// 显示 FPS
static void showFps(
void showFps(
bool show = true
);
// 获取系统 DPI 缩放
static float getDpiScaleX();
// 获取系统 DPI 缩放
static float getDpiScaleY();
// 获取 ID2D1Factory 对象
static ID2D1Factory * getID2D1Factory();
// 获取文字渲染器
TextRenderer * getTextRenderer();
// 获取 ID2D1HwndRenderTarget 对象
static ID2D1HwndRenderTarget * getRenderTarget();
ID2D1HwndRenderTarget * getRenderTarget();
// 获取 ID2D1SolidColorBrush 对象
static ID2D1SolidColorBrush * getSolidColorBrush();
ID2D1SolidColorBrush * getSolidColorBrush();
// 获取 ID2D1Factory 对象
static ID2D1Factory * getFactory();
// 获取 IWICImagingFactory 对象
static IWICImagingFactory * getIWICImagingFactory();
static IWICImagingFactory * getImagingFactory();
// 获取 IDWriteFactory 对象
static IDWriteFactory * getIDWriteFactory();
static IDWriteFactory * getWriteFactory();
// 获取文字渲染器
static TextRenderer * getTextRenderer();
// 获取 FPS 文本格式化对象
static IDWriteTextFormat * getFpsTextFormat();
// 获取 Miter 样式的 ID2D1StrokeStyle
static ID2D1StrokeStyle * getMiterID2D1StrokeStyle();
static ID2D1StrokeStyle * getMiterStrokeStyle();
// 获取 Bevel 样式的 ID2D1StrokeStyle
static ID2D1StrokeStyle * getBevelID2D1StrokeStyle();
static ID2D1StrokeStyle * getBevelStrokeStyle();
// 获取 Round 样式的 ID2D1StrokeStyle
static ID2D1StrokeStyle * getRoundID2D1StrokeStyle();
static ID2D1StrokeStyle * getRoundStrokeStyle();
private:
// 渲染游戏画面
static void __render();
Renderer();
// 创建设备无关资源
static bool __createDeviceIndependentResources();
~Renderer();
E2D_DISABLE_COPY(Renderer);
// 渲染游戏画面
void __render();
// 创建设备相关资源
static bool __createDeviceResources();
bool __createDeviceResources();
// 删除设备相关资源
static void __discardDeviceResources();
void __discardDeviceResources();
// 删除所有渲染相关资源
static void __discardResources();
private:
bool _showFps;
D2D1_COLOR_F _clearColor;
ID2D1HwndRenderTarget* _renderTarget;
ID2D1SolidColorBrush* _solidBrush;
TextRenderer* _textRenderer;
static ID2D1Factory* _d2dFactory;
static IWICImagingFactory* _imagingFactory;
static IDWriteFactory* _writeFactory;
static IDWriteTextFormat* _textFormat;
static ID2D1StrokeStyle* _miterStrokeStyle;
static ID2D1StrokeStyle* _bevelStrokeStyle;
static ID2D1StrokeStyle* _roundStrokeStyle;
static Renderer * _instance;
};
@ -457,9 +497,11 @@ private:
class GC
{
friend class Game;
friend class Object;
public:
// 获取 GC 实例
static GC* getInstance();
// 保留对象
template <typename Type>
static inline void retain(Type*& p)
@ -482,22 +524,34 @@ public:
}
// 通知 GC 回收垃圾内存
static void notify();
void notify();
// 手动回收垃圾内存
static void flush();
void flush();
private:
// 将对象放入 GC
static void __add(
void addObject(
Object * pObject
);
// 更新 GC
static void __update();
// 清空所有对象
static void __clear();
void clear();
private:
GC() {}
~GC();
E2D_DISABLE_COPY(GC);
// 更新 GC
void __update();
private:
bool _notifyed;
std::set<Object*> _pool;
static GC _instance;
};
}

View File

@ -81,13 +81,17 @@
#if _MSC_VER >= 1800
# define E2D_OP_EXPLICIT explicit
# define E2D_DELETE = delete
#else
# define E2D_OP_EXPLICIT
# define E2D_DELETE
#endif
#define E2D_DISABLE_COPY(ClassName)\
ClassName(const ClassName &); \
ClassName & operator= (const ClassName &) E2D_DELETE
#if _MSC_VER >= 1800
# define E2D_DISABLE_COPY(Class) \
Class(const Class &) = delete; \
Class & operator= (const Class &) = delete
#else
# define E2D_DISABLE_COPY(Class) \
Class(const Class &); \
Class & operator= (const Class &)
#endif