From abaf59379a05f0b90869dcc4610ff630eff3a321 Mon Sep 17 00:00:00 2001 From: Nomango <569629550@qq.com> Date: Tue, 3 Jul 2018 18:16:26 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=81=9AWindow=E7=B1=BB=E5=92=8CRende?= =?UTF-8?q?rer=E7=B1=BB=E5=8D=95=E4=BE=8B=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/Base/GC.cpp | 44 ++- core/Base/Game.cpp | 90 ++---- core/Base/Input.cpp | 12 +- core/Base/Renderer.cpp | 454 +++++++++++++++-------------- core/Base/Window.cpp | 167 ++++++----- core/Collider/CircleCollider.cpp | 2 +- core/Collider/Collider.cpp | 7 +- core/Collider/EllipseCollider.cpp | 2 +- core/Collider/RectCollider.cpp | 2 +- core/Common/Image.cpp | 14 +- core/Common/Object.cpp | 4 +- core/Common/Scene.cpp | 2 +- core/Custom/TextRenderer.cpp | 6 +- core/Node/Button.cpp | 6 +- core/Node/Node.cpp | 12 +- core/Node/Shape/CircleShape.cpp | 10 +- core/Node/Shape/EllipseShape.cpp | 10 +- core/Node/Shape/RectShape.cpp | 10 +- core/Node/Shape/RoundRectShape.cpp | 10 +- core/Node/Shape/Shape.cpp | 8 +- core/Node/Sprite.cpp | 2 +- core/Node/Text.cpp | 13 +- core/Tool/Path.cpp | 6 +- core/Transition/Transition.cpp | 9 +- core/e2dbase.h | 174 +++++++---- core/e2dmacros.h | 14 +- 26 files changed, 578 insertions(+), 512 deletions(-) diff --git a/core/Base/GC.cpp b/core/Base/GC.cpp index 34878da4..044002d1 100644 --- a/core/Base/GC.cpp +++ b/core/Base/GC.cpp @@ -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 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() diff --git a/core/Base/Game.cpp b/core/Base/Game.cpp index f6161881..f99a110f 100644 --- a/core/Base/Game.cpp +++ b/core/Base/Game.cpp @@ -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; - } -} diff --git a/core/Base/Input.cpp b/core/Base/Input.cpp index 5b19a592..829ea9da 100644 --- a/core/Base/Input.cpp +++ b/core/Base/Input.cpp @@ -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) diff --git a/core/Base/Renderer.cpp b/core/Base/Renderer.cpp index 7d8a26c8..6021bde9 100644 --- a/core/Base/Renderer.cpp +++ b/core/Base/Renderer.cpp @@ -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(&s_pIWICFactory) - ); - } - - if (FAILED(hr)) - { - throw SystemException(L"Create IWICImagingFactory failed"); - } - else - { - // 创建 DirectWrite 工厂 - hr = DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast(&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(&_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(&_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; } diff --git a/core/Base/Window.cpp b/core/Base/Window.cpp index 7e885ec8..43f9b0c9 100644 --- a/core/Base/Window.cpp +++ b/core/Base/Window.cpp @@ -3,11 +3,48 @@ #include #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(ceil(640 * dpiX / 96.f)); - int nHeight = static_cast(ceil(480 * dpiY / 96.f)); + int nWidth = static_cast(ceil(width * dpiScaleX / 96.f)); + int nHeight = static_cast(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; diff --git a/core/Collider/CircleCollider.cpp b/core/Collider/CircleCollider.cpp index 98c7a106..53fafe92 100644 --- a/core/Collider/CircleCollider.cpp +++ b/core/Collider/CircleCollider.cpp @@ -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), diff --git a/core/Collider/Collider.cpp b/core/Collider/Collider.cpp index 65e2bc21..38a2d084 100644 --- a/core/Collider/Collider.cpp +++ b/core/Collider/Collider.cpp @@ -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 diff --git a/core/Collider/EllipseCollider.cpp b/core/Collider/EllipseCollider.cpp index ca95893b..934d45ca 100644 --- a/core/Collider/EllipseCollider.cpp +++ b/core/Collider/EllipseCollider.cpp @@ -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), diff --git a/core/Collider/RectCollider.cpp b/core/Collider/RectCollider.cpp index d49541d8..61ca2ab5 100644 --- a/core/Collider/RectCollider.cpp +++ b/core/Collider/RectCollider.cpp @@ -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), diff --git a/core/Common/Image.cpp b/core/Common/Image.cpp index 0b8c50b3..cb1d0c39 100644 --- a/core/Common/Image.cpp +++ b/core/Common/Image.cpp @@ -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 diff --git a/core/Common/Object.cpp b/core/Common/Object.cpp index a3ea7a41..1fd2ddf3 100644 --- a/core/Common/Object.cpp +++ b/core/Common/Object.cpp @@ -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 diff --git a/core/Common/Scene.cpp b/core/Common/Scene.cpp index b4ccd3fd..6045ec2f 100644 --- a/core/Common/Scene.cpp +++ b/core/Common/Scene.cpp @@ -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(); } diff --git a/core/Custom/TextRenderer.cpp b/core/Custom/TextRenderer.cpp index 376ccfb3..352b8a5a 100644 --- a/core/Custom/TextRenderer.cpp +++ b/core/Custom/TextRenderer.cpp @@ -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; diff --git a/core/Node/Button.cpp b/core/Node/Button.cpp index 80c2e825..8588b5b8 100644 --- a/core/Node/Button.cpp +++ b/core/Node/Button.cpp @@ -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); } } diff --git a/core/Node/Node.cpp b/core/Node/Node.cpp index c12e3904..f294fa53 100644 --- a/core/Node/Node.cpp +++ b/core/Node/Node.cpp @@ -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 ); diff --git a/core/Node/Shape/CircleShape.cpp b/core/Node/Shape/CircleShape.cpp index b7b88581..5607bae7 100644 --- a/core/Node/Shape/CircleShape.cpp +++ b/core/Node/Shape/CircleShape.cpp @@ -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() ); } diff --git a/core/Node/Shape/EllipseShape.cpp b/core/Node/Shape/EllipseShape.cpp index a75011a6..a99fb4b4 100644 --- a/core/Node/Shape/EllipseShape.cpp +++ b/core/Node/Shape/EllipseShape.cpp @@ -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() ); } diff --git a/core/Node/Shape/RectShape.cpp b/core/Node/Shape/RectShape.cpp index 2346e0a8..7f85118f 100644 --- a/core/Node/Shape/RectShape.cpp +++ b/core/Node/Shape/RectShape.cpp @@ -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() ); } diff --git a/core/Node/Shape/RoundRectShape.cpp b/core/Node/Shape/RoundRectShape.cpp index 78cc35ff..cc5dfb90 100644 --- a/core/Node/Shape/RoundRectShape.cpp +++ b/core/Node/Shape/RoundRectShape.cpp @@ -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() ); } diff --git a/core/Node/Shape/Shape.cpp b/core/Node/Shape/Shape.cpp index 8f58d672..4f6dd0bc 100644 --- a/core/Node/Shape/Shape.cpp +++ b/core/Node/Shape/Shape.cpp @@ -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; diff --git a/core/Node/Sprite.cpp b/core/Node/Sprite.cpp index 4bc3c8d5..535d68e8 100644 --- a/core/Node/Sprite.cpp +++ b/core/Node/Sprite.cpp @@ -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, diff --git a/core/Node/Text.cpp b/core/Node/Text.cpp index d404807e..ba056e4a 100644 --- a/core/Node/Text.cpp +++ b/core/Node/Text.cpp @@ -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); } } diff --git a/core/Tool/Path.cpp b/core/Tool/Path.cpp index 79983219..681f1aef 100644 --- a/core/Tool/Path.cpp +++ b/core/Tool/Path.cpp @@ -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)) { diff --git a/core/Transition/Transition.cpp b/core/Transition/Transition.cpp index c8e6059d..56f3ecac 100644 --- a/core/Transition/Transition.cpp +++ b/core/Transition/Transition.cpp @@ -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) { diff --git a/core/e2dbase.h b/core/e2dbase.h index 21f9535d..6cbf82cc 100644 --- a/core/e2dbase.h +++ b/core/e2dbase.h @@ -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 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 _pool; + + static GC _instance; }; } \ No newline at end of file diff --git a/core/e2dmacros.h b/core/e2dmacros.h index 6a9d4b02..238044b9 100644 --- a/core/e2dmacros.h +++ b/core/e2dmacros.h @@ -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 \ No newline at end of file +#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