diff --git a/core/Base/GC.cpp b/core/Base/GC.cpp index 158b95db..e79ee259 100644 --- a/core/Base/GC.cpp +++ b/core/Base/GC.cpp @@ -41,10 +41,6 @@ e2d::GC::~GC() Image::clearCache(); // 删除所有单例 - Game::destroyInstance(); - Renderer::destroyInstance(); - Input::destroyInstance(); - Window::destroyInstance(); Timer::destroyInstance(); SceneManager::destroyInstance(); ActionManager::destroyInstance(); diff --git a/core/Base/Game.cpp b/core/Base/Game.cpp index 59ccea5a..f86f030d 100644 --- a/core/Base/Game.cpp +++ b/core/Base/Game.cpp @@ -4,35 +4,38 @@ #include -e2d::Game * e2d::Game::_instance = nullptr; - e2d::Game::Game() : _quit(true) , _paused(false) , _config() + , _window(nullptr) + , _input(nullptr) + , _renderer(nullptr) { CoInitialize(nullptr); + + _input = new (std::nothrow) Input; + _renderer = new (std::nothrow) Renderer; } e2d::Game::~Game() { + if (_renderer) + delete _renderer; + + if (_input) + delete _input; + + if (_window) + delete _window; + CoUninitialize(); } e2d::Game * e2d::Game::getInstance() { - if (!_instance) - _instance = new (std::nothrow) Game; - return _instance; -} - -void e2d::Game::destroyInstance() -{ - if (_instance) - { - delete _instance; - _instance = nullptr; - } + static Game instance; + return &instance; } void e2d::Game::start() @@ -41,11 +44,11 @@ void e2d::Game::start() const int minInterval = 5; Time last = Time::now(); - HWND hWnd = Window::getInstance()->getHWnd(); + HWND hWnd = _window->getHWnd(); ::ShowWindow(hWnd, SW_SHOWNORMAL); ::UpdateWindow(hWnd); - Window::getInstance()->poll(); + _window->poll(); SceneManager::getInstance()->update(); while (!_quit) @@ -56,12 +59,12 @@ void e2d::Game::start() if (dur.milliseconds() > minInterval) { last = now; - Input::getInstance()->update(); + _input->update(); Timer::getInstance()->update(); ActionManager::getInstance()->update(); SceneManager::getInstance()->update(); - Renderer::getInstance()->render(); - Window::getInstance()->poll(); + _renderer->render(); + _window->poll(); GC::getInstance()->flush(); } else @@ -103,11 +106,18 @@ void e2d::Game::setConfig(const Config& config) _config = config; } -const e2d::Config& e2d::Game::getConfig() +const e2d::Config& e2d::Game::getConfig() const { return _config; } +void e2d::Game::setWindow(Window * window) +{ + _window = window; + _renderer->init(_window); + _input->init(_window); +} + void e2d::Game::quit() { _quit = true; diff --git a/core/Base/Input.cpp b/core/Base/Input.cpp index 71a1fccb..e2c2ca26 100644 --- a/core/Base/Input.cpp +++ b/core/Base/Input.cpp @@ -3,7 +3,6 @@ #include "..\e2dmanager.h" #pragma comment(lib, "dinput8.lib") -e2d::Input * e2d::Input::_instance = nullptr; e2d::Input::Input() : _directInput(false) @@ -23,52 +22,6 @@ e2d::Input::Input() (void**)&_directInput, nullptr ); - - auto window = Window::getInstance(); - - if (SUCCEEDED(hr)) - { - // 初始化键盘设备 - hr = _directInput->CreateDevice( - GUID_SysKeyboard, - &_keyboardDevice, - nullptr - ); - - if (SUCCEEDED(hr)) - { - _keyboardDevice->SetCooperativeLevel( - window->getHWnd(), - DISCL_FOREGROUND | DISCL_NONEXCLUSIVE - ); - _keyboardDevice->SetDataFormat( - &c_dfDIKeyboard); - _keyboardDevice->Acquire(); - _keyboardDevice->Poll(); - } - else - { - throw SystemException(L"Keyboard not found!"); - } - } - - if (SUCCEEDED(hr)) - { - // 初始化鼠标设备 - hr = _directInput->CreateDevice(GUID_SysMouse, &_mouseDevice, nullptr); - - if (SUCCEEDED(hr)) - { - _mouseDevice->SetCooperativeLevel(window->getHWnd(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); - _mouseDevice->SetDataFormat(&c_dfDIMouse); - _mouseDevice->Acquire(); - _mouseDevice->Poll(); - } - else - { - throw SystemException(L"Mouse not found!"); - } - } } e2d::Input::~Input() @@ -85,20 +38,37 @@ e2d::Input::~Input() CoUninitialize(); } -e2d::Input * e2d::Input::getInstance() +void e2d::Input::init(Window * window) { - if (!_instance) - _instance = new (std::nothrow) Input; - return _instance; -} + HWND hwnd = window->getHWnd(); -void e2d::Input::destroyInstance() -{ - if (_instance) - { - delete _instance; - _instance = nullptr; - } + // 初始化键盘设备 + ThrowIfFailed( + _directInput->CreateDevice( + GUID_SysKeyboard, + &_keyboardDevice, + nullptr + ) + ); + + _keyboardDevice->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); + _keyboardDevice->SetDataFormat(&c_dfDIKeyboard); + _keyboardDevice->Acquire(); + _keyboardDevice->Poll(); + + // 初始化鼠标设备 + ThrowIfFailed( + _directInput->CreateDevice( + GUID_SysMouse, + &_mouseDevice, + nullptr + ) + ); + + _mouseDevice->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); + _mouseDevice->SetDataFormat(&c_dfDIMouse); + _mouseDevice->Acquire(); + _mouseDevice->Poll(); } void e2d::Input::update() @@ -160,7 +130,7 @@ float e2d::Input::getMouseY() e2d::Point e2d::Input::getMousePos() { - auto window = Window::getInstance(); + auto window = Game::getInstance()->getWindow(); POINT mousePos; ::GetCursorPos(&mousePos); diff --git a/core/Base/Renderer.cpp b/core/Base/Renderer.cpp index 6d7e7369..d608a74c 100644 --- a/core/Base/Renderer.cpp +++ b/core/Base/Renderer.cpp @@ -3,39 +3,6 @@ #include "..\e2dnode.h" -e2d::Renderer* e2d::Renderer::_instance = nullptr; -ID2D1Factory* e2d::Renderer::_d2dFactory = nullptr; -IWICImagingFactory* e2d::Renderer::_imagingFactory = nullptr; -IDWriteFactory* e2d::Renderer::_writeFactory = nullptr; -ID2D1StrokeStyle* e2d::Renderer::_miterStrokeStyle = nullptr; -ID2D1StrokeStyle* e2d::Renderer::_bevelStrokeStyle = nullptr; -ID2D1StrokeStyle* e2d::Renderer::_roundStrokeStyle = nullptr; - -e2d::Renderer * e2d::Renderer::getInstance() -{ - if (!_instance) - { - _instance = new (std::nothrow) Renderer; - } - return _instance; -} - -void e2d::Renderer::destroyInstance() -{ - if (_instance) - { - delete _instance; - _instance = nullptr; - - SafeRelease(_miterStrokeStyle); - SafeRelease(_bevelStrokeStyle); - SafeRelease(_roundStrokeStyle); - SafeRelease(_d2dFactory); - SafeRelease(_imagingFactory); - SafeRelease(_writeFactory); - } -} - e2d::Renderer::Renderer() : _lastRenderTime(Time::now()) , _renderTimes(0) @@ -44,9 +11,40 @@ e2d::Renderer::Renderer() , _renderTarget(nullptr) , _solidBrush(nullptr) , _textRenderer(nullptr) + , _factory(nullptr) + , _imagingFactory(nullptr) + , _writeFactory(nullptr) + , _miterStrokeStyle(nullptr) + , _bevelStrokeStyle(nullptr) + , _roundStrokeStyle(nullptr) , _clearColor(D2D1::ColorF(D2D1::ColorF::Black)) { CoInitialize(nullptr); + + ThrowIfFailed( + D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + &_factory + ) + ); + + ThrowIfFailed( + CoCreateInstance( + CLSID_WICImagingFactory, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IWICImagingFactory, + reinterpret_cast(&_imagingFactory) + ) + ); + + ThrowIfFailed( + DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&_writeFactory) + ) + ); } e2d::Renderer::~Renderer() @@ -57,27 +55,69 @@ e2d::Renderer::~Renderer() SafeRelease(_solidBrush); SafeRelease(_renderTarget); + SafeRelease(_miterStrokeStyle); + SafeRelease(_bevelStrokeStyle); + SafeRelease(_roundStrokeStyle); + SafeRelease(_factory); + SafeRelease(_imagingFactory); + SafeRelease(_writeFactory); + CoUninitialize(); } -void e2d::Renderer::discardDeviceResources() +void e2d::Renderer::init(Window * window) { - SafeRelease(_renderTarget); - SafeRelease(_solidBrush); - SafeRelease(_textRenderer); + if (!window) + return; + + HWND hWnd = window->getHWnd(); + + RECT rc; + GetClientRect(hWnd, &rc); + + D2D1_SIZE_U size = D2D1::SizeU( + rc.right - rc.left, + rc.bottom - rc.top + ); + + // 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 + // 创建一个 Direct2D 渲染目标 + ThrowIfFailed( + _factory->CreateHwndRenderTarget( + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties( + hWnd, + size, + D2D1_PRESENT_OPTIONS_NONE), + &_renderTarget + ) + ); + + // 创建画刷 + ThrowIfFailed( + _renderTarget->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &_solidBrush + ) + ); + + // 创建自定义的文字渲染器 + ThrowIfFailed( + TextRenderer::Create( + &_textRenderer, + _factory, + _renderTarget, + _solidBrush + ) + ); } void e2d::Renderer::render() { - auto renderTarget = this->getRenderTarget(); - // 仅当窗口没有被遮挡时进行渲染 - if (renderTarget->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED) - return; - // 开始渲染 - renderTarget->BeginDraw(); + _renderTarget->BeginDraw(); // 使用背景色清空屏幕 - renderTarget->Clear(_clearColor); + _renderTarget->Clear(_clearColor); // 渲染场景 SceneManager::getInstance()->render(); @@ -89,19 +129,24 @@ void e2d::Renderer::render() } // 终止渲染 - HRESULT hr = renderTarget->EndDraw(); + HRESULT hr = _renderTarget->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 // 并在下一次调用时重建资源 hr = S_OK; - this->discardDeviceResources(); + + SafeRelease(_fpsFormat); + SafeRelease(_fpsLayout); + SafeRelease(_textRenderer); + SafeRelease(_solidBrush); + SafeRelease(_renderTarget); } if (FAILED(hr)) { - throw SystemException(L"Device loss recovery failed"); + throw SystemException("Device loss recovery failed"); } } @@ -116,48 +161,45 @@ void e2d::Renderer::_renderFps() _lastRenderTime = Time::now(); _renderTimes = 0; - auto writeFactory = Renderer::getWriteFactory(); if (!_fpsFormat) { - HRESULT hr = writeFactory->CreateTextFormat( - L"", - nullptr, - DWRITE_FONT_WEIGHT_NORMAL, - DWRITE_FONT_STYLE_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, - 20, - L"", - &_fpsFormat + ThrowIfFailed( + _writeFactory->CreateTextFormat( + L"", + nullptr, + DWRITE_FONT_WEIGHT_NORMAL, + DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + 20, + L"", + &_fpsFormat + ) ); - if (SUCCEEDED(hr)) - { - _fpsFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); - } + ThrowIfFailed( + _fpsFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP) + ); } SafeRelease(_fpsLayout); - if (_fpsFormat) - { - writeFactory->CreateTextLayout( + ThrowIfFailed( + _writeFactory->CreateTextLayout( (const WCHAR *)fpsText, (UINT32)fpsText.getLength(), _fpsFormat, 0, 0, &_fpsLayout - ); - } + ) + ); } if (_fpsLayout) { - this->getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); - this->getSolidColorBrush()->SetOpacity(1.0f); - - auto textRenderer = this->getTextRenderer(); - textRenderer->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), @@ -165,7 +207,9 @@ void e2d::Renderer::_renderFps() D2D1_LINE_JOIN_ROUND ); - _fpsLayout->Draw(nullptr, textRenderer, 10, 0); + ThrowIfFailed( + _fpsLayout->Draw(nullptr, _textRenderer, 10, 0) + ); } } @@ -179,156 +223,25 @@ void e2d::Renderer::setBackgroundColor(Color color) _clearColor = (D2D1_COLOR_F)color; } -ID2D1HwndRenderTarget * e2d::Renderer::getRenderTarget() -{ - if (!_renderTarget) - { - HWND hWnd = Window::getInstance()->getHWnd(); - - // 创建设备相关资源。这些资源应在 Direct3D 设备消失时重建 - RECT rc; - GetClientRect(hWnd, &rc); - - D2D1_SIZE_U size = D2D1::SizeU( - rc.right - rc.left, - rc.bottom - rc.top - ); - - // 创建一个 Direct2D 渲染目标 - HRESULT hr = Renderer::getFactory()->CreateHwndRenderTarget( - D2D1::RenderTargetProperties(), - D2D1::HwndRenderTargetProperties( - hWnd, - size, - D2D1_PRESENT_OPTIONS_NONE), - &_renderTarget - ); - - if (FAILED(hr)) - { - throw SystemException(L"Create ID2D1HwndRenderTarget failed"); - } - } - return _renderTarget; -} - -ID2D1SolidColorBrush * e2d::Renderer::getSolidColorBrush() -{ - if (!_solidBrush) - { - // 创建画刷 - HRESULT hr = this->getRenderTarget()->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::White), - &_solidBrush - ); - - if (FAILED(hr)) - { - throw SystemException(L"Create ID2D1SolidColorBrush failed"); - } - } - return _solidBrush; -} - -e2d::TextRenderer * e2d::Renderer::getTextRenderer() -{ - if (!_textRenderer) - { - // 创建自定义的文字渲染器 - HRESULT hr = TextRenderer::Create( - &_textRenderer, - Renderer::getFactory(), - this->getRenderTarget(), - this->getSolidColorBrush() - ); - - if (FAILED(hr)) - { - throw SystemException(L"Create TextRenderer failed"); - } - } - return _textRenderer; -} - -ID2D1Factory * e2d::Renderer::getFactory() -{ - if (!_d2dFactory) - { - HRESULT hr = D2D1CreateFactory( - D2D1_FACTORY_TYPE_SINGLE_THREADED, - &_d2dFactory - ); - - if (FAILED(hr)) - { - throw SystemException(L"Create ID2D1Factory failed"); - } - } - return _d2dFactory; -} - -IWICImagingFactory * e2d::Renderer::getImagingFactory() -{ - 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; -} - -IDWriteFactory * e2d::Renderer::getWriteFactory() -{ - 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; -} - 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 + ThrowIfFailed( + _factory->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; } @@ -337,24 +250,21 @@ 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 + ThrowIfFailed( + _factory->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; } @@ -363,24 +273,21 @@ 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 + ThrowIfFailed( + _factory->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 b9c11575..e3867ac8 100644 --- a/core/Base/Window.cpp +++ b/core/Base/Window.cpp @@ -8,46 +8,95 @@ #define REGISTER_CLASS L"Easy2DApp" -e2d::Window * e2d::Window::_instance = nullptr; - -e2d::Window::Window() +e2d::Window::Window(const String & title, int width, int height, int iconID) : _hWnd(nullptr) - , _size(640, 480) - , _title(L"Easy2D Game") - , _iconID(0) + , _width(width) + , _height(height) + , _title(title) + , _iconID(iconID) , _dpi(0.f) { + CoInitialize(nullptr); + + WNDCLASSEX wcex = { 0 }; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.lpszClassName = REGISTER_CLASS; + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wcex.lpfnWndProc = Window::WndProc; + wcex.hIcon = nullptr; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = sizeof(LONG_PTR); + wcex.hInstance = HINST_THISCOMPONENT; + wcex.hbrBackground = nullptr; + wcex.lpszMenuName = nullptr; + wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW); + + if (_iconID != 0) + { + wcex.hIcon = (HICON)::LoadImage( + HINST_THISCOMPONENT, + MAKEINTRESOURCE(_iconID), + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE + ); + } + + // 注册窗口类 + RegisterClassEx(&wcex); + + // 计算窗口大小 + Rect clientRect = __adjustWindow(_width, _height); + + // 创建窗口 + HWND hWnd = ::CreateWindowEx( + NULL, + REGISTER_CLASS, + (LPCTSTR)_title, + WINDOW_STYLE, + int(clientRect.origin.x), + int(clientRect.origin.y), + int(clientRect.size.width), + int(clientRect.size.height), + nullptr, + nullptr, + HINST_THISCOMPONENT, + this + ); + + if (hWnd) + { + // 禁用输入法 + setTypewritingEnabled(false); + // 禁用控制台关闭按钮 + HWND consoleHWnd = ::GetConsoleWindow(); + if (consoleHWnd) + { + HMENU hmenu = ::GetSystemMenu(consoleHWnd, FALSE); + ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); + } + // 获取 DPI + _dpi = static_cast(::GetDpiForWindow(hWnd)); + } + else + { + ::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT); + throw SystemException("Create window failed"); + } } 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; - } + CoUninitialize(); } bool e2d::Window::createMutex(const String & mutex) @@ -87,80 +136,11 @@ bool e2d::Window::createMutex(const String & mutex) return true; } -HWND e2d::Window::__registerWindow() -{ - WNDCLASSEX wcex = { 0 }; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.lpszClassName = REGISTER_CLASS; - wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; - wcex.lpfnWndProc = Window::WndProc; - wcex.hIcon = nullptr; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = sizeof(LONG_PTR); - wcex.hInstance = HINST_THISCOMPONENT; - wcex.hbrBackground = nullptr; - wcex.lpszMenuName = nullptr; - wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW); - - if (_iconID != 0) - { - wcex.hIcon = (HICON)::LoadImage( - HINST_THISCOMPONENT, - MAKEINTRESOURCE(_iconID), - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE - ); - } - - // 注册窗口类 - RegisterClassEx(&wcex); - - // 计算窗口大小 - Rect wRect = __adjustWindow(int(_size.width), int(_size.height)); - - // 创建窗口 - HWND hWnd = ::CreateWindowEx( - NULL, - REGISTER_CLASS, - (LPCTSTR)_title, - WINDOW_STYLE, - int(wRect.origin.x), - int(wRect.origin.y), - int(wRect.size.width), - int(wRect.size.height), - nullptr, - nullptr, - HINST_THISCOMPONENT, - nullptr - ); - - if (hWnd) - { - // 禁用输入法 - setTypewritingEnabled(false); - // 禁用控制台关闭按钮 - HWND consoleHWnd = ::GetConsoleWindow(); - if (consoleHWnd) - { - HMENU hmenu = ::GetSystemMenu(consoleHWnd, FALSE); - ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); - } - // 获取 DPI - _dpi = static_cast(::GetDpiForWindow(hWnd)); - } - else - { - ::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT); - } - return hWnd; -} - e2d::Rect e2d::Window::__adjustWindow(int width, int height) { float dpiScaleX = 0.f, dpiScaleY = 0.f; - Renderer::getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY); + auto renderer = Game::getInstance()->getRenderer(); + renderer->getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY); Rect result; RECT wRECT = { 0, 0, LONG(ceil(width * dpiScaleX / 96.f)), LONG(ceil(height * dpiScaleY / 96.f)) }; @@ -190,47 +170,44 @@ void e2d::Window::poll() } } -float e2d::Window::getWidth() +int e2d::Window::getWidth() const { - return _size.width; + return _width; } -float e2d::Window::getHeight() +int e2d::Window::getHeight() const { - return _size.height; + return _height; } -e2d::Size e2d::Window::getSize() +e2d::Size e2d::Window::getSize() const { - return _size; + return Size(float(_width), float(_height)); } -float e2d::Window::getDpi() +float e2d::Window::getDpi() const { return _dpi; } -e2d::String e2d::Window::getTitle() +e2d::String e2d::Window::getTitle() const { return _title; } -HWND e2d::Window::getHWnd() +HWND e2d::Window::getHWnd() const { - if (!_hWnd) - { - _hWnd = __registerWindow(); - if (_hWnd == nullptr) - { - throw SystemException(L"注册窗口失败"); - } - } return _hWnd; } void e2d::Window::setSize(int width, int height) { - _size = Size(static_cast(width), static_cast(height)); + if (_width == width && _height == height) + return; + + _width = width; + _height = height; + if (_hWnd) { Rect wRect = __adjustWindow(width, height); @@ -390,121 +367,144 @@ bool e2d::Window::popup(const String & text, const String & title, Popup style, } -LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +LRESULT e2d::Window::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT result = 0; - bool hasHandled = false; - switch (message) + if (uMsg == WM_CREATE) { + LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam; + Window *window = (Window *)pcs->lpCreateParams; - // 处理鼠标消息 - case WM_LBUTTONUP: - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_RBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - case WM_MOUSEMOVE: - case WM_MOUSEWHEEL: - { - SceneManager::getInstance()->dispatch(MouseEvent(hWnd, message, wParam, lParam)); + ::SetWindowLongPtrW( + hWnd, + GWLP_USERDATA, + PtrToUlong(window) + ); + + result = 1; } - result = 0; - hasHandled = true; - break; - - // 处理按键消息 - case WM_KEYDOWN: - case WM_KEYUP: + else { - SceneManager::getInstance()->dispatch(KeyEvent(hWnd, message, wParam, lParam)); - } - result = 0; - hasHandled = true; - break; + bool hasHandled = false; + Window *window = reinterpret_cast( + static_cast( + ::GetWindowLongPtrW(hWnd, GWLP_USERDATA) + ) + ); - // 处理窗口大小变化消息 - case WM_SIZE: - { - UINT width = LOWORD(lParam); - UINT height = HIWORD(lParam); - - if (wParam == SIZE_RESTORED) + switch (uMsg) { - _instance->_size.width = width * 96.f / _instance->_dpi; - _instance->_size.height = height * 96.f / _instance->_dpi; + + // 处理鼠标消息 + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + { + SceneManager::getInstance()->dispatch(MouseEvent(hWnd, uMsg, wParam, lParam, window->_dpi)); + } + result = 0; + hasHandled = true; + break; + + // 处理按键消息 + case WM_KEYDOWN: + case WM_KEYUP: + { + SceneManager::getInstance()->dispatch(KeyEvent(hWnd, uMsg, wParam, lParam)); + } + result = 0; + hasHandled = true; + break; + + // 处理窗口大小变化消息 + case WM_SIZE: + { + UINT width = LOWORD(lParam); + UINT height = HIWORD(lParam); + + if (wParam == SIZE_RESTORED) + { + window->_width = static_cast(width * 96.f / window->_dpi); + window->_height = static_cast(height * 96.f / window->_dpi); + } + + // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 + // 目标适当。它可能会调用失败,但是这里可以忽略有可能的 + // 错误,因为这个错误将在下一次调用 EndDraw 时产生 + auto renderer = Game::getInstance()->getRenderer(); + auto pRT = renderer->getRenderTarget(); + if (pRT) + { + pRT->Resize(D2D1::SizeU(width, height)); + } + } + break; + + // 处理窗口标题变化消息 + case WM_SETTEXT: + { + window->_title = (const wchar_t*)lParam; + } + break; + + // 处理分辨率变化消息 + case WM_DISPLAYCHANGE: + { + // 重绘客户区 + InvalidateRect(hWnd, nullptr, FALSE); + } + result = 0; + hasHandled = true; + break; + + // 重绘窗口 + case WM_PAINT: + { + auto renderer = Game::getInstance()->getRenderer(); + renderer->render(); + ValidateRect(hWnd, nullptr); + } + result = 0; + hasHandled = true; + break; + + // 窗口关闭消息 + case WM_CLOSE: + { + e2d::Scene * pCurrentScene = e2d::SceneManager::getInstance()->getCurrentScene(); + if (!pCurrentScene || pCurrentScene->onCloseWindow()) + { + e2d::Game::getInstance()->quit(); + } + } + result = 0; + hasHandled = true; + break; + + // 窗口销毁消息 + case WM_DESTROY: + { + PostQuitMessage(0); + } + result = 1; + hasHandled = true; + break; + } - // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 - // 目标适当。它可能会调用失败,但是这里可以忽略有可能的 - // 错误,因为这个错误将在下一次调用 EndDraw 时产生 - auto pRT = Renderer::getInstance()->getRenderTarget(); - if (pRT) + if (!hasHandled) { - pRT->Resize(D2D1::SizeU(width, height)); + result = DefWindowProc(hWnd, uMsg, wParam, lParam); } } - break; - - // 处理窗口标题变化消息 - case WM_SETTEXT: - { - _instance->_title = (const wchar_t*)lParam; - } - break; - - // 处理分辨率变化消息 - case WM_DISPLAYCHANGE: - { - // 重绘客户区 - InvalidateRect(hWnd, nullptr, FALSE); - } - result = 0; - hasHandled = true; - break; - - // 重绘窗口 - case WM_PAINT: - { - e2d::Renderer::getInstance()->render(); - ValidateRect(hWnd, nullptr); - } - result = 0; - hasHandled = true; - break; - - // 窗口关闭消息 - case WM_CLOSE: - { - e2d::Scene * pCurrentScene = e2d::SceneManager::getInstance()->getCurrentScene(); - if (!pCurrentScene || pCurrentScene->onCloseWindow()) - { - e2d::Game::getInstance()->quit(); - } - } - result = 0; - hasHandled = true; - break; - - // 窗口销毁消息 - case WM_DESTROY: - { - PostQuitMessage(0); - } - result = 1; - hasHandled = true; - break; - - } - - if (!hasHandled) - { - result = DefWindowProc(hWnd, message, wParam, lParam); - } - return result; } \ No newline at end of file diff --git a/core/Common/Collider.cpp b/core/Common/Collider.cpp index d4205c68..f9253b52 100644 --- a/core/Common/Collider.cpp +++ b/core/Common/Collider.cpp @@ -80,7 +80,7 @@ void e2d::Collider::render() { if (_geometry && _enabled && _visible) { - auto renderer = Renderer::getInstance(); + auto renderer = Game::getInstance()->getRenderer(); // 获取纯色画刷 ID2D1SolidColorBrush * brush = renderer->getSolidColorBrush(); // 设置画刷颜色和透明度 @@ -131,13 +131,14 @@ void e2d::Collider::recreate() return; SafeRelease(_geometry); + auto factory = Game::getInstance()->getRenderer()->getFactory(); switch (_shape) { case Shape::Rect: { ID2D1RectangleGeometry* rectangle = nullptr; - Renderer::getFactory()->CreateRectangleGeometry( + factory->CreateRectangleGeometry( D2D1::RectF(0, 0, _parentNode->getRealWidth(), _parentNode->getRealHeight()), &rectangle ); @@ -150,7 +151,7 @@ void e2d::Collider::recreate() float minSide = std::min(_parentNode->getRealWidth(), _parentNode->getRealHeight()); ID2D1EllipseGeometry* circle = nullptr; - Renderer::getFactory()->CreateEllipseGeometry( + factory->CreateEllipseGeometry( D2D1::Ellipse( D2D1::Point2F( _parentNode->getRealWidth() / 2, @@ -171,7 +172,7 @@ void e2d::Collider::recreate() halfHeight = _parentNode->getHeight() / 2; ID2D1EllipseGeometry* ellipse = nullptr; - Renderer::getFactory()->CreateEllipseGeometry( + factory->CreateEllipseGeometry( D2D1::Ellipse( D2D1::Point2F( halfWidth, @@ -186,7 +187,7 @@ void e2d::Collider::recreate() } ID2D1TransformedGeometry * _transformed; - Renderer::getFactory()->CreateTransformedGeometry( + factory->CreateTransformedGeometry( _geometry, _parentNode->_finalMatri, &_transformed diff --git a/core/Common/Image.cpp b/core/Common/Image.cpp index a039c3a1..a4ca3260 100644 --- a/core/Common/Image.cpp +++ b/core/Common/Image.cpp @@ -160,7 +160,7 @@ bool e2d::Image::preload(const Resource& res) IWICStream *pStream = nullptr; IWICFormatConverter *pConverter = nullptr; ID2D1Bitmap *pBitmap = nullptr; - IWICImagingFactory *pImagingFactory = Renderer::getImagingFactory(); + IWICImagingFactory *pImagingFactory = Game::getInstance()->getRenderer()->getImagingFactory(); if (!res.isFile()) { @@ -273,7 +273,7 @@ bool e2d::Image::preload(const Resource& res) if (SUCCEEDED(hr)) { // 从 WIC 位图创建一个 Direct2D 位图 - hr = Renderer::getInstance()->getRenderTarget()->CreateBitmapFromWicBitmap( + hr = Game::getInstance()->getRenderer()->getRenderTarget()->CreateBitmapFromWicBitmap( pConverter, nullptr, &pBitmap diff --git a/core/Custom/Exception.cpp b/core/Custom/Exception.cpp index 5a66bfcd..c3761dd0 100644 --- a/core/Custom/Exception.cpp +++ b/core/Custom/Exception.cpp @@ -6,7 +6,7 @@ e2d::Exception::Exception() E2D_NOEXCEPT { } -e2d::Exception::Exception(const String& message) E2D_NOEXCEPT +e2d::Exception::Exception(const char * message) E2D_NOEXCEPT : _message(message) { } @@ -31,7 +31,7 @@ e2d::Exception::~Exception() E2D_NOEXCEPT { } -e2d::String e2d::Exception::msg() const +const char * e2d::Exception::msg() const { return _message; } diff --git a/core/Custom/SystemException.cpp b/core/Custom/SystemException.cpp index a3e85b44..984c94c4 100644 --- a/core/Custom/SystemException.cpp +++ b/core/Custom/SystemException.cpp @@ -1,12 +1,11 @@ #include "..\e2dcustom.h" e2d::SystemException::SystemException() E2D_NOEXCEPT - : Exception(L"未知的系统异常") + : Exception("Unknown system exception") { } -e2d::SystemException::SystemException(const String& message) E2D_NOEXCEPT +e2d::SystemException::SystemException(const char * message) E2D_NOEXCEPT : Exception(message) { } - diff --git a/core/Custom/TextRenderer.cpp b/core/Custom/TextRenderer.cpp index 73ca61ad..4a1c9ed0 100644 --- a/core/Custom/TextRenderer.cpp +++ b/core/Custom/TextRenderer.cpp @@ -59,16 +59,18 @@ STDMETHODIMP_(void) TextRenderer::SetTextStyle( sOutlineColor_ = outlineColor; fOutlineWidth = 2 * outlineWidth; + auto pRenderer = Game::getInstance()->getRenderer(); + switch (outlineJoin) { case D2D1_LINE_JOIN_MITER: - pCurrStrokeStyle_ = Renderer::getMiterStrokeStyle(); + pCurrStrokeStyle_ = pRenderer->getMiterStrokeStyle(); break; case D2D1_LINE_JOIN_BEVEL: - pCurrStrokeStyle_ = Renderer::getBevelStrokeStyle(); + pCurrStrokeStyle_ = pRenderer->getBevelStrokeStyle(); break; case D2D1_LINE_JOIN_ROUND: - pCurrStrokeStyle_ = Renderer::getRoundStrokeStyle(); + pCurrStrokeStyle_ = pRenderer->getRoundStrokeStyle(); break; default: pCurrStrokeStyle_ = nullptr; diff --git a/core/Event/MouseEvent.cpp b/core/Event/MouseEvent.cpp index 85419fe6..5b67ab95 100644 --- a/core/Event/MouseEvent.cpp +++ b/core/Event/MouseEvent.cpp @@ -1,13 +1,12 @@ #include "..\e2devent.h" #include "..\e2dbase.h" -e2d::MouseEvent::MouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +e2d::MouseEvent::MouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, float dpi) : _message(message) , _wParam(wParam) , _lParam(lParam) , _type(Type(message)) { - float dpi = Window::getInstance()->getDpi(); _pos.x = ((float)(short)LOWORD(lParam)) * 96.f / dpi; _pos.y = ((float)(short)HIWORD(lParam)) * 96.f / dpi; } diff --git a/core/Manager/ActionManager.cpp b/core/Manager/ActionManager.cpp index 7f8e1301..b86dc126 100644 --- a/core/Manager/ActionManager.cpp +++ b/core/Manager/ActionManager.cpp @@ -151,7 +151,7 @@ void e2d::ActionManager::start(Action * action, Node * target, bool paused) } else { - throw Exception(L"该 Action 已有执行目标"); + throw Exception("该 Action 已有执行目标"); } } } diff --git a/core/Manager/SceneManager.cpp b/core/Manager/SceneManager.cpp index 557c1345..c4fbaf48 100644 --- a/core/Manager/SceneManager.cpp +++ b/core/Manager/SceneManager.cpp @@ -188,7 +188,22 @@ void e2d::SceneManager::render() } else if (_currScene) { - _currScene->visit(); + auto renderer = Game::getInstance()->getRenderer(); + _currScene->visit(renderer); + + auto& config = Game::getInstance()->getConfig(); + if (config.isOutlineVisible()) + { + auto brush = renderer->getSolidColorBrush(); + brush->SetColor(D2D1::ColorF(D2D1::ColorF::Red, 0.6f)); + brush->SetOpacity(1.f); + _currScene->drawOutline(renderer); + } + if (config.isColliderVisible()) + { + renderer->getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); + _currScene->drawCollider(); + } } } diff --git a/core/Node/Button.cpp b/core/Node/Button.cpp index d493347f..19aeaba0 100644 --- a/core/Node/Button.cpp +++ b/core/Node/Button.cpp @@ -189,20 +189,20 @@ bool e2d::Button::dispatch(const MouseEvent & e, bool handled) return Node::dispatch(e, handled); } -void e2d::Button::visit() +void e2d::Button::visit(Renderer* renderer) { - Node::visit(); + Node::visit(renderer); if (_visible && !_enabled && _normal && - _normal->containsPoint(Input::getInstance()->getMousePos())) + _normal->containsPoint(Game::getInstance()->getInput()->getMousePos())) { - Window::getInstance()->setCursor(Window::Cursor::No); + Game::getInstance()->getWindow()->setCursor(Window::Cursor::No); } else if (_status == Status::Mouseover || _status == Status::Selected) { - Window::getInstance()->setCursor(Window::Cursor::Hand); + Game::getInstance()->getWindow()->setCursor(Window::Cursor::Hand); } } diff --git a/core/Node/Node.cpp b/core/Node/Node.cpp index 77cd7f4b..f57635b1 100644 --- a/core/Node/Node.cpp +++ b/core/Node/Node.cpp @@ -79,7 +79,7 @@ e2d::Node::~Node() } } -void e2d::Node::visit() +void e2d::Node::visit(Renderer * renderer) { if (!_visible) return; @@ -90,7 +90,7 @@ void e2d::Node::visit() // 保留差别属性 _extrapolate = this->getProperty(); - auto pRT = Renderer::getInstance()->getRenderTarget(); + auto pRT = renderer->getRenderTarget(); if (_clipEnabled) { pRT->SetTransform(_finalMatri); @@ -103,7 +103,7 @@ void e2d::Node::visit() if (_children.empty()) { pRT->SetTransform(_finalMatri); - this->draw(); + this->draw(renderer); } else { @@ -117,7 +117,7 @@ void e2d::Node::visit() // 访问 Order 小于零的节点 if (child->getOrder() < 0) { - child->visit(); + child->visit(renderer); } else { @@ -126,11 +126,11 @@ void e2d::Node::visit() } pRT->SetTransform(_finalMatri); - this->draw(); + this->draw(renderer); // 访问剩余节点 for (; i < _children.size(); ++i) - _children[i]->visit(); + _children[i]->visit(renderer); } if (_clipEnabled) @@ -139,11 +139,10 @@ void e2d::Node::visit() } } -void e2d::Node::_renderOutline() +void e2d::Node::drawOutline(Renderer * renderer) { if (_visible) { - auto renderer = Renderer::getInstance(); renderer->getRenderTarget()->SetTransform(_finalMatri); renderer->getRenderTarget()->DrawRectangle( D2D1::RectF(0, 0, _width, _height), @@ -154,12 +153,12 @@ void e2d::Node::_renderOutline() // 渲染所有子节点的轮廓 for (const auto& child : _children) { - child->_renderOutline(); + child->drawOutline(renderer); } } } -void e2d::Node::_renderCollider() +void e2d::Node::drawCollider() { if (_visible) { @@ -168,7 +167,7 @@ void e2d::Node::_renderCollider() // 绘制所有子节点的几何碰撞体 for (const auto& child : _children) { - child->_renderCollider(); + child->drawCollider(); } } } @@ -610,14 +609,14 @@ void e2d::Node::addChild(Node * child, int order /* = 0 */) { if (child->_parent != nullptr) { - throw Exception(L"节点已有父节点, 不能再添加到其他节点"); + throw Exception("节点已有父节点, 不能再添加到其他节点"); } for (Node * parent = this; parent != nullptr; parent = parent->getParent()) { if (child == parent) { - throw Exception(L"一个节点不能同时是另一个节点的父节点和子节点"); + throw Exception("一个节点不能同时是另一个节点的父节点和子节点"); } } @@ -825,21 +824,23 @@ bool e2d::Node::containsPoint(const Point& point) // 为节点创建一个轮廓 BOOL ret = 0; ID2D1RectangleGeometry * rectGeo = nullptr; - auto factory = Renderer::getFactory(); + auto factory = Game::getInstance()->getRenderer()->getFactory(); - HRESULT hr = factory->CreateRectangleGeometry( - D2D1::RectF(0, 0, _width, _height), - &rectGeo + ThrowIfFailed( + factory->CreateRectangleGeometry( + D2D1::RectF(0, 0, _width, _height), + &rectGeo + ) ); - if (SUCCEEDED(hr)) - { + ThrowIfFailed( rectGeo->FillContainsPoint( D2D1::Point2F(point.x, point.y), _finalMatri, &ret - ); - } + ) + ); + SafeRelease(rectGeo); return ret != 0; @@ -855,48 +856,46 @@ bool e2d::Node::intersects(Node * node) D2D1_GEOMETRY_RELATION relation = D2D1_GEOMETRY_RELATION_UNKNOWN; ID2D1RectangleGeometry *rectGeo = nullptr, *rectGeo2 = nullptr; ID2D1TransformedGeometry *transGeo = nullptr, *transGeo2 = nullptr; - auto factory = Renderer::getFactory(); + auto factory = Game::getInstance()->getRenderer()->getFactory(); - HRESULT hr = factory->CreateRectangleGeometry( - D2D1::RectF(0, 0, _width, _height), - &rectGeo + ThrowIfFailed( + factory->CreateRectangleGeometry( + D2D1::RectF(0, 0, _width, _height), + &rectGeo + ) ); - if (SUCCEEDED(hr)) - { - hr = factory->CreateRectangleGeometry( + ThrowIfFailed( + factory->CreateRectangleGeometry( D2D1::RectF(0, 0, node->_width, node->_height), &rectGeo2 - ); - } + ) + ); - if (SUCCEEDED(hr)) - { - hr = factory->CreateTransformedGeometry( + ThrowIfFailed( + factory->CreateTransformedGeometry( rectGeo, _finalMatri, &transGeo - ); - } + ) + ); - if (SUCCEEDED(hr)) - { - hr = factory->CreateTransformedGeometry( + ThrowIfFailed( + factory->CreateTransformedGeometry( rectGeo2, node->_finalMatri, &transGeo2 - ); - } + ) + ); - if (SUCCEEDED(hr)) - { + ThrowIfFailed( // 获取相交状态 transGeo->CompareWithGeometry( transGeo2, D2D1::Matrix3x2F::Identity(), &relation - ); - } + ) + ); SafeRelease(rectGeo); SafeRelease(rectGeo2); diff --git a/core/Node/Scene.cpp b/core/Node/Scene.cpp index 5eba909d..d55af33c 100644 --- a/core/Node/Scene.cpp +++ b/core/Node/Scene.cpp @@ -9,22 +9,3 @@ e2d::Scene::Scene() e2d::Scene::~Scene() { } - -void e2d::Scene::visit() -{ - Node::visit(); - - if (Game::getInstance()->getConfig().isOutlineVisible()) - { - auto brush = Renderer::getInstance()->getSolidColorBrush(); - brush->SetColor(D2D1::ColorF(D2D1::ColorF::Red, 0.6f)); - brush->SetOpacity(1.f); - Node::_renderOutline(); - } - - if (Game::getInstance()->getConfig().isColliderVisible()) - { - Renderer::getInstance()->getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); - Node::_renderCollider(); - } -} diff --git a/core/Node/Sprite.cpp b/core/Node/Sprite.cpp index be60000a..442d66f7 100644 --- a/core/Node/Sprite.cpp +++ b/core/Node/Sprite.cpp @@ -92,7 +92,7 @@ e2d::Image * e2d::Sprite::getImage() const return _image; } -void e2d::Sprite::draw() const +void e2d::Sprite::draw(Renderer * renderer) const { if (_image && _image->getBitmap()) { @@ -100,7 +100,7 @@ void e2d::Sprite::draw() const float fCropX = _image->getCropX(); float fCropY = _image->getCropY(); // 渲染图片 - Renderer::getInstance()->getRenderTarget()->DrawBitmap( + renderer->getRenderTarget()->DrawBitmap( _image->getBitmap(), D2D1::RectF(0, 0, _width, _height), _displayOpacity, diff --git a/core/Node/Text.cpp b/core/Node/Text.cpp index 2dab2c2c..08749d95 100644 --- a/core/Node/Text.cpp +++ b/core/Node/Text.cpp @@ -287,11 +287,10 @@ void e2d::Text::setOutlineJoin(LineJoin outlineJoin) _style.outlineJoin = outlineJoin; } -void e2d::Text::draw() const +void e2d::Text::draw(Renderer * renderer) const { if (_textLayout) { - auto renderer = Renderer::getInstance(); // 创建文本区域 D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, _width, _height); // 设置画刷颜色和透明度 @@ -321,7 +320,7 @@ void e2d::Text::_createFormat() { SafeRelease(_textFormat); - HRESULT hr = Renderer::getWriteFactory()->CreateTextFormat( + HRESULT hr = Game::getInstance()->getRenderer()->getWriteFactory()->CreateTextFormat( (const WCHAR *)_font.family, nullptr, DWRITE_FONT_WEIGHT(_font.weight), @@ -384,14 +383,14 @@ void e2d::Text::_createLayout() return; } - UINT32 length = (UINT32)_text.getLength(); - - // 创建 TextLayout HRESULT hr; + UINT32 length = (UINT32)_text.getLength(); + auto writeFactory = Game::getInstance()->getRenderer()->getWriteFactory(); + // 对文本自动换行情况下进行处理 if (_style.wrapping) { - hr = Renderer::getWriteFactory()->CreateTextLayout( + hr = writeFactory->CreateTextLayout( (const WCHAR *)_text, length, _textFormat, @@ -410,7 +409,7 @@ void e2d::Text::_createLayout() } else { - hr = Renderer::getWriteFactory()->CreateTextLayout((const WCHAR *)_text, length, _textFormat, 0, 0, &_textLayout); + hr = writeFactory->CreateTextLayout((const WCHAR *)_text, length, _textFormat, 0, 0, &_textLayout); // 为防止文本对齐问题,根据刚才创建的 layout 宽度重新创建它 if (_textLayout) { @@ -421,7 +420,7 @@ void e2d::Text::_createLayout() this->setSize(metrics.width, metrics.height); // 重新创建 layout SafeRelease(_textLayout); - hr = Renderer::getWriteFactory()->CreateTextLayout((const WCHAR *)_text, length, _textFormat, _width, 0, &_textLayout); + hr = writeFactory->CreateTextLayout((const WCHAR *)_text, length, _textFormat, _width, 0, &_textLayout); } } diff --git a/core/Tool/File.cpp b/core/Tool/File.cpp index 951475c8..125d9c0c 100644 --- a/core/Tool/File.cpp +++ b/core/Tool/File.cpp @@ -160,11 +160,14 @@ bool e2d::File::createFolder(const String & dirPath) e2d::String e2d::File::getSaveFilePath(const String& title, const String& defExt) { + auto window = Game::getInstance()->getWindow(); + HWND hwnd = window->getHWnd(); + // 弹出保存对话框 OPENFILENAME ofn = { 0 }; wchar_t strFilename[MAX_PATH] = { 0 }; // 用于接收文件名 ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小 - ofn.hwndOwner = Window::getInstance()->getHWnd(); // 窗口句柄 + ofn.hwndOwner = hwnd; // 窗口句柄 ofn.lpstrFilter = L"所有文件\0*.*\0\0"; // 设置过滤 ofn.nFilterIndex = 1; // 过滤器索引 ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名 diff --git a/core/Transition/Transition.cpp b/core/Transition/Transition.cpp index f92a3437..2544ed7c 100644 --- a/core/Transition/Transition.cpp +++ b/core/Transition/Transition.cpp @@ -41,7 +41,7 @@ bool e2d::Transition::_init(Scene * prev) // 创建图层 HRESULT hr = S_OK; - auto renderer = Renderer::getInstance(); + auto renderer = Game::getInstance()->getRenderer(); if (_inScene) { hr = renderer->getRenderTarget()->CreateLayer(&_inLayer); @@ -57,7 +57,7 @@ bool e2d::Transition::_init(Scene * prev) return false; } - _windowSize = Window::getInstance()->getSize(); + _windowSize = Game::getInstance()->getWindow()->getSize(); _outLayerParam = _inLayerParam = D2D1::LayerParameters( D2D1::InfiniteRect(), nullptr, @@ -86,7 +86,8 @@ void e2d::Transition::_update() void e2d::Transition::_render() { - auto pRT = Renderer::getInstance()->getRenderTarget(); + auto renderer = Game::getInstance()->getRenderer(); + auto pRT = renderer->getRenderTarget(); if (_outScene) { @@ -101,7 +102,7 @@ void e2d::Transition::_render() pRT->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); pRT->PushLayer(_outLayerParam, _outLayer); - _outScene->visit(); + _outScene->visit(renderer); pRT->PopLayer(); pRT->PopAxisAlignedClip(); @@ -120,7 +121,7 @@ void e2d::Transition::_render() pRT->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); pRT->PushLayer(_inLayerParam, _inLayer); - _inScene->visit(); + _inScene->visit(renderer); pRT->PopLayer(); pRT->PopAxisAlignedClip(); diff --git a/core/e2dbase.h b/core/e2dbase.h index 72e4ba2b..9e8d3caa 100644 --- a/core/e2dbase.h +++ b/core/e2dbase.h @@ -72,58 +72,6 @@ protected: }; -// 游戏主体 -class Game -{ -public: - // 获取游戏实例 - static Game * getInstance(); - - // 销毁实例 - static void destroyInstance(); - - // 启动游戏 - void start(); - - // 暂停游戏 - void pause(); - - // 继续游戏 - void resume(); - - // 结束游戏 - void quit(); - - // 清理资源 - void cleanup(); - - // 游戏是否暂停 - bool isPaused(); - - // 修改游戏配置 - void setConfig( - const Config& config - ); - - // 获取游戏配置 - const Config& getConfig(); - -private: - Game(); - - ~Game(); - - E2D_DISABLE_COPY(Game); - -private: - bool _quit; - bool _paused; - Config _config; - - static Game * _instance; -}; - - // 窗体 class Window { @@ -147,11 +95,14 @@ public: }; public: - // 获取窗体实例 - static Window * getInstance(); + Window( + const String& title, /* 窗体标题 */ + int width, /* 窗体宽度 */ + int height, /* 窗体高度 */ + int iconID = 0 /* 窗体图标 */ + ); - // 销毁窗体实例 - static void destroyInstance(); + ~Window(); // 创建窗体互斥体 bool createMutex( @@ -180,22 +131,22 @@ public: ); // 获取窗体标题 - String getTitle(); + String getTitle() const; // 获取窗体宽度 - float getWidth(); + int getWidth() const; // 获取窗体高度 - float getHeight(); + int getHeight() const; // 获取窗体大小 - Size getSize(); + Size getSize() const; // 获取窗口 DPI - float getDpi(); + float getDpi() const; // 获取窗口句柄 - HWND getHWnd(); + HWND getHWnd() const; // 打开或隐藏控制台 void setConsoleEnabled( @@ -220,15 +171,6 @@ public: void poll(); private: - Window(); - - ~Window(); - - E2D_DISABLE_COPY(Window); - - // 注册窗口 - HWND __registerWindow(); - // 根据客户区大小计算合适的窗口区域 Rect __adjustWindow( int width, @@ -237,21 +179,20 @@ private: // Win32 窗口消息回调程序 static LRESULT CALLBACK WndProc( - HWND hWnd, - UINT message, - WPARAM wParam, + HWND hWnd, + UINT uMsg, + WPARAM wParam, LPARAM lParam ); private: HWND _hWnd; MSG _msg; - Size _size; + int _width; + int _height; String _title; int _iconID; float _dpi; - - static Window * _instance; }; @@ -259,11 +200,9 @@ private: class Input { public: - // 获取输入设备实例 - static Input * getInstance(); + Input(); - // 销毁输入设备实例 - static void destroyInstance(); + ~Input(); // 检测键盘某按键是否正被按下 bool isDown( @@ -296,12 +235,10 @@ public: // 刷新输入设备状态 void update(); -private: - Input(); - - ~Input(); - - E2D_DISABLE_COPY(Input); + // 初始化渲染器(不应手动调用该函数) + void init( + Window * window + ); private: IDirectInput8W* _directInput; @@ -309,20 +246,16 @@ private: IDirectInputDevice8W* _mouseDevice; DIMOUSESTATE _mouseState; char _keyBuffer[256]; - - static Input * _instance; }; -// 渲染器 +// 图形设备 class Renderer { public: - // 获取渲染器实例 - static Renderer * getInstance(); + Renderer(); - // 销毁实例 - static void destroyInstance(); + ~Renderer(); // 获取背景色 Color getBackgroundColor(); @@ -332,46 +265,42 @@ public: Color color ); - // 获取文字渲染器 - TextRenderer * getTextRenderer(); - - // 获取 ID2D1HwndRenderTarget 对象 - ID2D1HwndRenderTarget * getRenderTarget(); - - // 获取 ID2D1SolidColorBrush 对象 - ID2D1SolidColorBrush * getSolidColorBrush(); - // 渲染游戏画面 void render(); - // 删除设备相关资源 - void discardDeviceResources(); + // 获取文字渲染器 + TextRenderer * getTextRenderer() const { return _textRenderer; } + + // 获取 ID2D1HwndRenderTarget 对象 + ID2D1HwndRenderTarget * getRenderTarget() const { return _renderTarget; } + + // 获取 ID2D1SolidColorBrush 对象 + ID2D1SolidColorBrush * getSolidColorBrush() const { return _solidBrush; } // 获取 ID2D1Factory 对象 - static ID2D1Factory * getFactory(); + ID2D1Factory * getFactory() const { return _factory; } // 获取 IWICImagingFactory 对象 - static IWICImagingFactory * getImagingFactory(); + IWICImagingFactory * getImagingFactory() const { return _imagingFactory; } // 获取 IDWriteFactory 对象 - static IDWriteFactory * getWriteFactory(); + IDWriteFactory * getWriteFactory() const { return _writeFactory; } // 获取 Miter 样式的 ID2D1StrokeStyle - static ID2D1StrokeStyle * getMiterStrokeStyle(); + ID2D1StrokeStyle * getMiterStrokeStyle(); // 获取 Bevel 样式的 ID2D1StrokeStyle - static ID2D1StrokeStyle * getBevelStrokeStyle(); + ID2D1StrokeStyle * getBevelStrokeStyle(); // 获取 Round 样式的 ID2D1StrokeStyle - static ID2D1StrokeStyle * getRoundStrokeStyle(); + ID2D1StrokeStyle * getRoundStrokeStyle(); + + // 初始化渲染器(不应手动调用该函数) + void init( + Window * window + ); private: - Renderer(); - - ~Renderer(); - - E2D_DISABLE_COPY(Renderer); - // 渲染 FPS void _renderFps(); @@ -384,14 +313,77 @@ private: IDWriteTextLayout* _fpsLayout; ID2D1SolidColorBrush* _solidBrush; ID2D1HwndRenderTarget* _renderTarget; + ID2D1Factory* _factory; + IWICImagingFactory* _imagingFactory; + IDWriteFactory* _writeFactory; + ID2D1StrokeStyle* _miterStrokeStyle; + ID2D1StrokeStyle* _bevelStrokeStyle; + ID2D1StrokeStyle* _roundStrokeStyle; +}; - static ID2D1Factory* _d2dFactory; - static IWICImagingFactory* _imagingFactory; - static IDWriteFactory* _writeFactory; - static ID2D1StrokeStyle* _miterStrokeStyle; - static ID2D1StrokeStyle* _bevelStrokeStyle; - static ID2D1StrokeStyle* _roundStrokeStyle; - static Renderer * _instance; + +// 游戏 +class Game +{ +public: + // 获取 Game 实例 + static Game * getInstance(); + + // 启动游戏 + void start(); + + // 暂停游戏 + void pause(); + + // 继续游戏 + void resume(); + + // 结束游戏 + void quit(); + + // 清理资源 + void cleanup(); + + // 游戏是否暂停 + bool isPaused(); + + // 修改游戏配置 + void setConfig( + const Config& config + ); + + // 获取游戏配置 + const Config& getConfig() const; + + // 设置窗体 + void setWindow( + Window * window + ); + + // 获取窗体 + Window * getWindow() const { return _window; } + + // 获取输入设备 + Input * getInput() const { return _input; } + + // 获取图形设备 + Renderer * getRenderer() const { return _renderer; } + +protected: + Game(); + + ~Game(); + + E2D_DISABLE_COPY(Game); + +private: + bool _quit; + bool _paused; + Config _config; + Window * _window; + Input * _input; + Renderer * _renderer; + }; diff --git a/core/e2dcustom.h b/core/e2dcustom.h index 5a7ffce8..1bdde289 100644 --- a/core/e2dcustom.h +++ b/core/e2dcustom.h @@ -6,17 +6,6 @@ namespace e2d { -template -inline void SafeRelease(Interface*& p) -{ - if (p != nullptr) - { - p->Release(); - p = nullptr; - } -} - - class Music; // 音源回调 @@ -173,7 +162,7 @@ class Exception public: Exception() E2D_NOEXCEPT; - explicit Exception(const String& message) E2D_NOEXCEPT; + explicit Exception(const char * message) E2D_NOEXCEPT; Exception(Exception const& other) E2D_NOEXCEPT; @@ -182,10 +171,10 @@ public: Exception& operator=(Exception const& other) E2D_NOEXCEPT; // 获取异常信息 - virtual String msg() const; + virtual const char * msg() const; private: - String _message; + const char * _message; }; @@ -196,7 +185,30 @@ class SystemException public: SystemException() E2D_NOEXCEPT; - explicit SystemException(const String& message) E2D_NOEXCEPT; + explicit SystemException(const char * message) E2D_NOEXCEPT; }; + +template +inline void SafeRelease(Interface*& p) +{ + if (p != nullptr) + { + p->Release(); + p = nullptr; + } +} + + +inline void ThrowIfFailed(HRESULT hr) +{ + if (FAILED(hr)) + { + // 在此处设置断点以捕获 D2D API 异常. + static char s_str[64] = {}; + sprintf_s(s_str, "Failure with HRESULT of %08X", static_cast(hr)); + throw SystemException(s_str); + } +} + } \ No newline at end of file diff --git a/core/e2devent.h b/core/e2devent.h index 13ddfd8b..d50c0641 100644 --- a/core/e2devent.h +++ b/core/e2devent.h @@ -70,7 +70,8 @@ public: HWND hWnd, UINT message, WPARAM wParam, - LPARAM lParam + LPARAM lParam, + float dpi ); // 获取鼠标横坐标 diff --git a/core/e2dnode.h b/core/e2dnode.h index bbd9b2b2..5a041c02 100644 --- a/core/e2dnode.h +++ b/core/e2dnode.h @@ -47,7 +47,9 @@ public: virtual ~Node(); // 渲染节点 - virtual void draw() const {} + virtual void draw( + Renderer * renderer + ) const {} // 获取节点显示状态 virtual bool isVisible() const; @@ -395,17 +397,21 @@ public: ); // 遍历节点 - virtual void visit(); + virtual void visit( + Renderer * renderer + ); + + // 渲染节点轮廓 + virtual void drawOutline( + Renderer * renderer + ); + + // 渲染碰撞体轮廓 + virtual void drawCollider(); protected: E2D_DISABLE_COPY(Node); - // 渲染节点轮廓 - virtual void _renderOutline(); - - // 渲染碰撞体轮廓 - virtual void _renderCollider(); - // 设置节点所在场景 virtual void _setParentScene( Scene * scene @@ -468,9 +474,6 @@ public: // 说明:返回 false 将阻止窗口关闭 virtual bool onCloseWindow() { return true; } - // 渲染场景 - virtual void visit() override; - protected: E2D_DISABLE_COPY(Scene); }; @@ -531,7 +534,9 @@ public: virtual Image * getImage() const; // 渲染精灵 - virtual void draw() const override; + virtual void draw( + Renderer * renderer + ) const override; protected: E2D_DISABLE_COPY(Sprite); @@ -735,7 +740,9 @@ public: ); // 渲染文字 - virtual void draw() const override; + virtual void draw( + Renderer * renderer + ) const override; protected: E2D_DISABLE_COPY(Text); @@ -837,7 +844,9 @@ public: ) override; // 渲染节点 - virtual void visit() override; + virtual void visit( + Renderer * renderer + ) override; protected: E2D_DISABLE_COPY(Button);