refactoring

This commit is contained in:
Nomango 2018-08-15 00:06:03 +08:00
parent 09a3850135
commit 83986230a1
24 changed files with 706 additions and 810 deletions

View File

@ -41,10 +41,6 @@ e2d::GC::~GC()
Image::clearCache(); Image::clearCache();
// 删除所有单例 // 删除所有单例
Game::destroyInstance();
Renderer::destroyInstance();
Input::destroyInstance();
Window::destroyInstance();
Timer::destroyInstance(); Timer::destroyInstance();
SceneManager::destroyInstance(); SceneManager::destroyInstance();
ActionManager::destroyInstance(); ActionManager::destroyInstance();

View File

@ -4,35 +4,38 @@
#include <thread> #include <thread>
e2d::Game * e2d::Game::_instance = nullptr;
e2d::Game::Game() e2d::Game::Game()
: _quit(true) : _quit(true)
, _paused(false) , _paused(false)
, _config() , _config()
, _window(nullptr)
, _input(nullptr)
, _renderer(nullptr)
{ {
CoInitialize(nullptr); CoInitialize(nullptr);
_input = new (std::nothrow) Input;
_renderer = new (std::nothrow) Renderer;
} }
e2d::Game::~Game() e2d::Game::~Game()
{ {
if (_renderer)
delete _renderer;
if (_input)
delete _input;
if (_window)
delete _window;
CoUninitialize(); CoUninitialize();
} }
e2d::Game * e2d::Game::getInstance() e2d::Game * e2d::Game::getInstance()
{ {
if (!_instance) static Game instance;
_instance = new (std::nothrow) Game; return &instance;
return _instance;
}
void e2d::Game::destroyInstance()
{
if (_instance)
{
delete _instance;
_instance = nullptr;
}
} }
void e2d::Game::start() void e2d::Game::start()
@ -41,11 +44,11 @@ void e2d::Game::start()
const int minInterval = 5; const int minInterval = 5;
Time last = Time::now(); Time last = Time::now();
HWND hWnd = Window::getInstance()->getHWnd(); HWND hWnd = _window->getHWnd();
::ShowWindow(hWnd, SW_SHOWNORMAL); ::ShowWindow(hWnd, SW_SHOWNORMAL);
::UpdateWindow(hWnd); ::UpdateWindow(hWnd);
Window::getInstance()->poll(); _window->poll();
SceneManager::getInstance()->update(); SceneManager::getInstance()->update();
while (!_quit) while (!_quit)
@ -56,12 +59,12 @@ void e2d::Game::start()
if (dur.milliseconds() > minInterval) if (dur.milliseconds() > minInterval)
{ {
last = now; last = now;
Input::getInstance()->update(); _input->update();
Timer::getInstance()->update(); Timer::getInstance()->update();
ActionManager::getInstance()->update(); ActionManager::getInstance()->update();
SceneManager::getInstance()->update(); SceneManager::getInstance()->update();
Renderer::getInstance()->render(); _renderer->render();
Window::getInstance()->poll(); _window->poll();
GC::getInstance()->flush(); GC::getInstance()->flush();
} }
else else
@ -103,11 +106,18 @@ void e2d::Game::setConfig(const Config& config)
_config = config; _config = config;
} }
const e2d::Config& e2d::Game::getConfig() const e2d::Config& e2d::Game::getConfig() const
{ {
return _config; return _config;
} }
void e2d::Game::setWindow(Window * window)
{
_window = window;
_renderer->init(_window);
_input->init(_window);
}
void e2d::Game::quit() void e2d::Game::quit()
{ {
_quit = true; _quit = true;

View File

@ -3,7 +3,6 @@
#include "..\e2dmanager.h" #include "..\e2dmanager.h"
#pragma comment(lib, "dinput8.lib") #pragma comment(lib, "dinput8.lib")
e2d::Input * e2d::Input::_instance = nullptr;
e2d::Input::Input() e2d::Input::Input()
: _directInput(false) : _directInput(false)
@ -23,52 +22,6 @@ e2d::Input::Input()
(void**)&_directInput, (void**)&_directInput,
nullptr 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() e2d::Input::~Input()
@ -85,20 +38,37 @@ e2d::Input::~Input()
CoUninitialize(); CoUninitialize();
} }
e2d::Input * e2d::Input::getInstance() void e2d::Input::init(Window * window)
{ {
if (!_instance) HWND hwnd = window->getHWnd();
_instance = new (std::nothrow) Input;
return _instance;
}
void e2d::Input::destroyInstance() // 初始化键盘设备
{ ThrowIfFailed(
if (_instance) _directInput->CreateDevice(
{ GUID_SysKeyboard,
delete _instance; &_keyboardDevice,
_instance = nullptr; 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() void e2d::Input::update()
@ -160,7 +130,7 @@ float e2d::Input::getMouseY()
e2d::Point e2d::Input::getMousePos() e2d::Point e2d::Input::getMousePos()
{ {
auto window = Window::getInstance(); auto window = Game::getInstance()->getWindow();
POINT mousePos; POINT mousePos;
::GetCursorPos(&mousePos); ::GetCursorPos(&mousePos);

View File

@ -3,39 +3,6 @@
#include "..\e2dnode.h" #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() e2d::Renderer::Renderer()
: _lastRenderTime(Time::now()) : _lastRenderTime(Time::now())
, _renderTimes(0) , _renderTimes(0)
@ -44,9 +11,40 @@ e2d::Renderer::Renderer()
, _renderTarget(nullptr) , _renderTarget(nullptr)
, _solidBrush(nullptr) , _solidBrush(nullptr)
, _textRenderer(nullptr) , _textRenderer(nullptr)
, _factory(nullptr)
, _imagingFactory(nullptr)
, _writeFactory(nullptr)
, _miterStrokeStyle(nullptr)
, _bevelStrokeStyle(nullptr)
, _roundStrokeStyle(nullptr)
, _clearColor(D2D1::ColorF(D2D1::ColorF::Black)) , _clearColor(D2D1::ColorF(D2D1::ColorF::Black))
{ {
CoInitialize(nullptr); CoInitialize(nullptr);
ThrowIfFailed(
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&_factory
)
);
ThrowIfFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&_imagingFactory)
)
);
ThrowIfFailed(
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&_writeFactory)
)
);
} }
e2d::Renderer::~Renderer() e2d::Renderer::~Renderer()
@ -57,27 +55,69 @@ e2d::Renderer::~Renderer()
SafeRelease(_solidBrush); SafeRelease(_solidBrush);
SafeRelease(_renderTarget); SafeRelease(_renderTarget);
SafeRelease(_miterStrokeStyle);
SafeRelease(_bevelStrokeStyle);
SafeRelease(_roundStrokeStyle);
SafeRelease(_factory);
SafeRelease(_imagingFactory);
SafeRelease(_writeFactory);
CoUninitialize(); CoUninitialize();
} }
void e2d::Renderer::discardDeviceResources() void e2d::Renderer::init(Window * window)
{ {
SafeRelease(_renderTarget); if (!window)
SafeRelease(_solidBrush); return;
SafeRelease(_textRenderer);
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() 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(); SceneManager::getInstance()->render();
@ -89,19 +129,24 @@ void e2d::Renderer::render()
} }
// 终止渲染 // 终止渲染
HRESULT hr = renderTarget->EndDraw(); HRESULT hr = _renderTarget->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) if (hr == D2DERR_RECREATE_TARGET)
{ {
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
// 并在下一次调用时重建资源 // 并在下一次调用时重建资源
hr = S_OK; hr = S_OK;
this->discardDeviceResources();
SafeRelease(_fpsFormat);
SafeRelease(_fpsLayout);
SafeRelease(_textRenderer);
SafeRelease(_solidBrush);
SafeRelease(_renderTarget);
} }
if (FAILED(hr)) if (FAILED(hr))
{ {
throw SystemException(L"Device loss recovery failed"); throw SystemException("Device loss recovery failed");
} }
} }
@ -116,10 +161,10 @@ void e2d::Renderer::_renderFps()
_lastRenderTime = Time::now(); _lastRenderTime = Time::now();
_renderTimes = 0; _renderTimes = 0;
auto writeFactory = Renderer::getWriteFactory();
if (!_fpsFormat) if (!_fpsFormat)
{ {
HRESULT hr = writeFactory->CreateTextFormat( ThrowIfFailed(
_writeFactory->CreateTextFormat(
L"", L"",
nullptr, nullptr,
DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_WEIGHT_NORMAL,
@ -128,36 +173,33 @@ void e2d::Renderer::_renderFps()
20, 20,
L"", L"",
&_fpsFormat &_fpsFormat
)
); );
if (SUCCEEDED(hr)) ThrowIfFailed(
{ _fpsFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP)
_fpsFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); );
}
} }
SafeRelease(_fpsLayout); SafeRelease(_fpsLayout);
if (_fpsFormat) ThrowIfFailed(
{ _writeFactory->CreateTextLayout(
writeFactory->CreateTextLayout(
(const WCHAR *)fpsText, (const WCHAR *)fpsText,
(UINT32)fpsText.getLength(), (UINT32)fpsText.getLength(),
_fpsFormat, _fpsFormat,
0, 0,
0, 0,
&_fpsLayout &_fpsLayout
)
); );
} }
}
if (_fpsLayout) if (_fpsLayout)
{ {
this->getRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity()); _renderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
this->getSolidColorBrush()->SetOpacity(1.0f); _solidBrush->SetOpacity(1.0f);
_textRenderer->SetTextStyle(
auto textRenderer = this->getTextRenderer();
textRenderer->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White), D2D1::ColorF(D2D1::ColorF::White),
TRUE, TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f), D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
@ -165,7 +207,9 @@ void e2d::Renderer::_renderFps()
D2D1_LINE_JOIN_ROUND D2D1_LINE_JOIN_ROUND
); );
_fpsLayout->Draw(nullptr, textRenderer, 10, 0); ThrowIfFailed(
_fpsLayout->Draw(nullptr, _textRenderer, 10, 0)
);
} }
} }
@ -179,139 +223,12 @@ void e2d::Renderer::setBackgroundColor(Color color)
_clearColor = (D2D1_COLOR_F)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<void**>(&_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<IUnknown**>(&_writeFactory)
);
if (FAILED(hr))
{
throw SystemException(L"Create IDWriteFactory failed");
}
}
return _writeFactory;
}
ID2D1StrokeStyle * e2d::Renderer::getMiterStrokeStyle() ID2D1StrokeStyle * e2d::Renderer::getMiterStrokeStyle()
{ {
if (!_miterStrokeStyle) if (!_miterStrokeStyle)
{ {
HRESULT hr = Renderer::getFactory()->CreateStrokeStyle( ThrowIfFailed(
_factory->CreateStrokeStyle(
D2D1::StrokeStyleProperties( D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
@ -323,12 +240,8 @@ ID2D1StrokeStyle * e2d::Renderer::getMiterStrokeStyle()
nullptr, nullptr,
0, 0,
&_miterStrokeStyle &_miterStrokeStyle
)
); );
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
} }
return _miterStrokeStyle; return _miterStrokeStyle;
} }
@ -337,7 +250,8 @@ ID2D1StrokeStyle * e2d::Renderer::getBevelStrokeStyle()
{ {
if (!_bevelStrokeStyle) if (!_bevelStrokeStyle)
{ {
HRESULT hr = Renderer::getFactory()->CreateStrokeStyle( ThrowIfFailed(
_factory->CreateStrokeStyle(
D2D1::StrokeStyleProperties( D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
@ -349,12 +263,8 @@ ID2D1StrokeStyle * e2d::Renderer::getBevelStrokeStyle()
nullptr, nullptr,
0, 0,
&_bevelStrokeStyle &_bevelStrokeStyle
)
); );
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
} }
return _bevelStrokeStyle; return _bevelStrokeStyle;
} }
@ -363,7 +273,8 @@ ID2D1StrokeStyle * e2d::Renderer::getRoundStrokeStyle()
{ {
if (!_roundStrokeStyle) if (!_roundStrokeStyle)
{ {
HRESULT hr = Renderer::getFactory()->CreateStrokeStyle( ThrowIfFailed(
_factory->CreateStrokeStyle(
D2D1::StrokeStyleProperties( D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
@ -375,12 +286,8 @@ ID2D1StrokeStyle * e2d::Renderer::getRoundStrokeStyle()
nullptr, nullptr,
0, 0,
&_roundStrokeStyle &_roundStrokeStyle
)
); );
if (FAILED(hr))
{
throw SystemException(L"Create ID2D1StrokeStyle failed");
}
} }
return _roundStrokeStyle; return _roundStrokeStyle;
} }

View File

@ -8,46 +8,95 @@
#define REGISTER_CLASS L"Easy2DApp" #define REGISTER_CLASS L"Easy2DApp"
e2d::Window * e2d::Window::_instance = nullptr; e2d::Window::Window(const String & title, int width, int height, int iconID)
e2d::Window::Window()
: _hWnd(nullptr) : _hWnd(nullptr)
, _size(640, 480) , _width(width)
, _title(L"Easy2D Game") , _height(height)
, _iconID(0) , _title(title)
, _iconID(iconID)
, _dpi(0.f) , _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<float>(::GetDpiForWindow(hWnd));
}
else
{
::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT);
throw SystemException("Create window failed");
}
} }
e2d::Window::~Window() e2d::Window::~Window()
{ {
// 关闭控制台 // 关闭控制台
if (::GetConsoleWindow()) if (::GetConsoleWindow())
{
::FreeConsole(); ::FreeConsole();
}
// 关闭窗口 // 关闭窗口
if (_hWnd) if (_hWnd)
{
::DestroyWindow(_hWnd); ::DestroyWindow(_hWnd);
_hWnd = nullptr;
}
}
e2d::Window * e2d::Window::getInstance() CoUninitialize();
{
if (!_instance)
_instance = new (std::nothrow) Window;
return _instance;
}
void e2d::Window::destroyInstance()
{
if (_instance)
{
delete _instance;
_instance = nullptr;
}
} }
bool e2d::Window::createMutex(const String & mutex) bool e2d::Window::createMutex(const String & mutex)
@ -87,80 +136,11 @@ bool e2d::Window::createMutex(const String & mutex)
return true; 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<float>(::GetDpiForWindow(hWnd));
}
else
{
::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT);
}
return hWnd;
}
e2d::Rect e2d::Window::__adjustWindow(int width, int height) e2d::Rect e2d::Window::__adjustWindow(int width, int height)
{ {
float dpiScaleX = 0.f, dpiScaleY = 0.f; 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 result;
RECT wRECT = { 0, 0, LONG(ceil(width * dpiScaleX / 96.f)), LONG(ceil(height * dpiScaleY / 96.f)) }; 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; return _dpi;
} }
e2d::String e2d::Window::getTitle() e2d::String e2d::Window::getTitle() const
{ {
return _title; return _title;
} }
HWND e2d::Window::getHWnd() HWND e2d::Window::getHWnd() const
{ {
if (!_hWnd)
{
_hWnd = __registerWindow();
if (_hWnd == nullptr)
{
throw SystemException(L"注册窗口失败");
}
}
return _hWnd; return _hWnd;
} }
void e2d::Window::setSize(int width, int height) void e2d::Window::setSize(int width, int height)
{ {
_size = Size(static_cast<float>(width), static_cast<float>(height)); if (_width == width && _height == height)
return;
_width = width;
_height = height;
if (_hWnd) if (_hWnd)
{ {
Rect wRect = __adjustWindow(width, height); Rect wRect = __adjustWindow(width, height);
@ -390,12 +367,33 @@ 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; LRESULT result = 0;
bool hasHandled = false;
switch (message) if (uMsg == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
Window *window = (Window *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hWnd,
GWLP_USERDATA,
PtrToUlong(window)
);
result = 1;
}
else
{
bool hasHandled = false;
Window *window = reinterpret_cast<Window *>(
static_cast<LONG_PTR>(
::GetWindowLongPtrW(hWnd, GWLP_USERDATA)
)
);
switch (uMsg)
{ {
// 处理鼠标消息 // 处理鼠标消息
@ -411,7 +409,7 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
{ {
SceneManager::getInstance()->dispatch(MouseEvent(hWnd, message, wParam, lParam)); SceneManager::getInstance()->dispatch(MouseEvent(hWnd, uMsg, wParam, lParam, window->_dpi));
} }
result = 0; result = 0;
hasHandled = true; hasHandled = true;
@ -421,7 +419,7 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
case WM_KEYDOWN: case WM_KEYDOWN:
case WM_KEYUP: case WM_KEYUP:
{ {
SceneManager::getInstance()->dispatch(KeyEvent(hWnd, message, wParam, lParam)); SceneManager::getInstance()->dispatch(KeyEvent(hWnd, uMsg, wParam, lParam));
} }
result = 0; result = 0;
hasHandled = true; hasHandled = true;
@ -435,14 +433,15 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
if (wParam == SIZE_RESTORED) if (wParam == SIZE_RESTORED)
{ {
_instance->_size.width = width * 96.f / _instance->_dpi; window->_width = static_cast<int>(width * 96.f / window->_dpi);
_instance->_size.height = height * 96.f / _instance->_dpi; window->_height = static_cast<int>(height * 96.f / window->_dpi);
} }
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标适当。它可能会调用失败,但是这里可以忽略有可能的 // 目标适当。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生 // 错误,因为这个错误将在下一次调用 EndDraw 时产生
auto pRT = Renderer::getInstance()->getRenderTarget(); auto renderer = Game::getInstance()->getRenderer();
auto pRT = renderer->getRenderTarget();
if (pRT) if (pRT)
{ {
pRT->Resize(D2D1::SizeU(width, height)); pRT->Resize(D2D1::SizeU(width, height));
@ -453,7 +452,7 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
// 处理窗口标题变化消息 // 处理窗口标题变化消息
case WM_SETTEXT: case WM_SETTEXT:
{ {
_instance->_title = (const wchar_t*)lParam; window->_title = (const wchar_t*)lParam;
} }
break; break;
@ -470,7 +469,8 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
// 重绘窗口 // 重绘窗口
case WM_PAINT: case WM_PAINT:
{ {
e2d::Renderer::getInstance()->render(); auto renderer = Game::getInstance()->getRenderer();
renderer->render();
ValidateRect(hWnd, nullptr); ValidateRect(hWnd, nullptr);
} }
result = 0; result = 0;
@ -503,8 +503,8 @@ LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar
if (!hasHandled) if (!hasHandled)
{ {
result = DefWindowProc(hWnd, message, wParam, lParam); result = DefWindowProc(hWnd, uMsg, wParam, lParam);
}
} }
return result; return result;
} }

View File

@ -80,7 +80,7 @@ void e2d::Collider::render()
{ {
if (_geometry && _enabled && _visible) if (_geometry && _enabled && _visible)
{ {
auto renderer = Renderer::getInstance(); auto renderer = Game::getInstance()->getRenderer();
// 获取纯色画刷 // 获取纯色画刷
ID2D1SolidColorBrush * brush = renderer->getSolidColorBrush(); ID2D1SolidColorBrush * brush = renderer->getSolidColorBrush();
// 设置画刷颜色和透明度 // 设置画刷颜色和透明度
@ -131,13 +131,14 @@ void e2d::Collider::recreate()
return; return;
SafeRelease(_geometry); SafeRelease(_geometry);
auto factory = Game::getInstance()->getRenderer()->getFactory();
switch (_shape) switch (_shape)
{ {
case Shape::Rect: case Shape::Rect:
{ {
ID2D1RectangleGeometry* rectangle = nullptr; ID2D1RectangleGeometry* rectangle = nullptr;
Renderer::getFactory()->CreateRectangleGeometry( factory->CreateRectangleGeometry(
D2D1::RectF(0, 0, _parentNode->getRealWidth(), _parentNode->getRealHeight()), D2D1::RectF(0, 0, _parentNode->getRealWidth(), _parentNode->getRealHeight()),
&rectangle &rectangle
); );
@ -150,7 +151,7 @@ void e2d::Collider::recreate()
float minSide = std::min(_parentNode->getRealWidth(), _parentNode->getRealHeight()); float minSide = std::min(_parentNode->getRealWidth(), _parentNode->getRealHeight());
ID2D1EllipseGeometry* circle = nullptr; ID2D1EllipseGeometry* circle = nullptr;
Renderer::getFactory()->CreateEllipseGeometry( factory->CreateEllipseGeometry(
D2D1::Ellipse( D2D1::Ellipse(
D2D1::Point2F( D2D1::Point2F(
_parentNode->getRealWidth() / 2, _parentNode->getRealWidth() / 2,
@ -171,7 +172,7 @@ void e2d::Collider::recreate()
halfHeight = _parentNode->getHeight() / 2; halfHeight = _parentNode->getHeight() / 2;
ID2D1EllipseGeometry* ellipse = nullptr; ID2D1EllipseGeometry* ellipse = nullptr;
Renderer::getFactory()->CreateEllipseGeometry( factory->CreateEllipseGeometry(
D2D1::Ellipse( D2D1::Ellipse(
D2D1::Point2F( D2D1::Point2F(
halfWidth, halfWidth,
@ -186,7 +187,7 @@ void e2d::Collider::recreate()
} }
ID2D1TransformedGeometry * _transformed; ID2D1TransformedGeometry * _transformed;
Renderer::getFactory()->CreateTransformedGeometry( factory->CreateTransformedGeometry(
_geometry, _geometry,
_parentNode->_finalMatri, _parentNode->_finalMatri,
&_transformed &_transformed

View File

@ -160,7 +160,7 @@ bool e2d::Image::preload(const Resource& res)
IWICStream *pStream = nullptr; IWICStream *pStream = nullptr;
IWICFormatConverter *pConverter = nullptr; IWICFormatConverter *pConverter = nullptr;
ID2D1Bitmap *pBitmap = nullptr; ID2D1Bitmap *pBitmap = nullptr;
IWICImagingFactory *pImagingFactory = Renderer::getImagingFactory(); IWICImagingFactory *pImagingFactory = Game::getInstance()->getRenderer()->getImagingFactory();
if (!res.isFile()) if (!res.isFile())
{ {
@ -273,7 +273,7 @@ bool e2d::Image::preload(const Resource& res)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 从 WIC 位图创建一个 Direct2D 位图 // 从 WIC 位图创建一个 Direct2D 位图
hr = Renderer::getInstance()->getRenderTarget()->CreateBitmapFromWicBitmap( hr = Game::getInstance()->getRenderer()->getRenderTarget()->CreateBitmapFromWicBitmap(
pConverter, pConverter,
nullptr, nullptr,
&pBitmap &pBitmap

View File

@ -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) : _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; return _message;
} }

View File

@ -1,12 +1,11 @@
#include "..\e2dcustom.h" #include "..\e2dcustom.h"
e2d::SystemException::SystemException() E2D_NOEXCEPT 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) : Exception(message)
{ {
} }

View File

@ -59,16 +59,18 @@ STDMETHODIMP_(void) TextRenderer::SetTextStyle(
sOutlineColor_ = outlineColor; sOutlineColor_ = outlineColor;
fOutlineWidth = 2 * outlineWidth; fOutlineWidth = 2 * outlineWidth;
auto pRenderer = Game::getInstance()->getRenderer();
switch (outlineJoin) switch (outlineJoin)
{ {
case D2D1_LINE_JOIN_MITER: case D2D1_LINE_JOIN_MITER:
pCurrStrokeStyle_ = Renderer::getMiterStrokeStyle(); pCurrStrokeStyle_ = pRenderer->getMiterStrokeStyle();
break; break;
case D2D1_LINE_JOIN_BEVEL: case D2D1_LINE_JOIN_BEVEL:
pCurrStrokeStyle_ = Renderer::getBevelStrokeStyle(); pCurrStrokeStyle_ = pRenderer->getBevelStrokeStyle();
break; break;
case D2D1_LINE_JOIN_ROUND: case D2D1_LINE_JOIN_ROUND:
pCurrStrokeStyle_ = Renderer::getRoundStrokeStyle(); pCurrStrokeStyle_ = pRenderer->getRoundStrokeStyle();
break; break;
default: default:
pCurrStrokeStyle_ = nullptr; pCurrStrokeStyle_ = nullptr;

View File

@ -1,13 +1,12 @@
#include "..\e2devent.h" #include "..\e2devent.h"
#include "..\e2dbase.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) : _message(message)
, _wParam(wParam) , _wParam(wParam)
, _lParam(lParam) , _lParam(lParam)
, _type(Type(message)) , _type(Type(message))
{ {
float dpi = Window::getInstance()->getDpi();
_pos.x = ((float)(short)LOWORD(lParam)) * 96.f / dpi; _pos.x = ((float)(short)LOWORD(lParam)) * 96.f / dpi;
_pos.y = ((float)(short)HIWORD(lParam)) * 96.f / dpi; _pos.y = ((float)(short)HIWORD(lParam)) * 96.f / dpi;
} }

View File

@ -151,7 +151,7 @@ void e2d::ActionManager::start(Action * action, Node * target, bool paused)
} }
else else
{ {
throw Exception(L"该 Action 已有执行目标"); throw Exception("该 Action 已有执行目标");
} }
} }
} }

View File

@ -188,7 +188,22 @@ void e2d::SceneManager::render()
} }
else if (_currScene) 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();
}
} }
} }

View File

@ -189,20 +189,20 @@ bool e2d::Button::dispatch(const MouseEvent & e, bool handled)
return Node::dispatch(e, handled); return Node::dispatch(e, handled);
} }
void e2d::Button::visit() void e2d::Button::visit(Renderer* renderer)
{ {
Node::visit(); Node::visit(renderer);
if (_visible && if (_visible &&
!_enabled && !_enabled &&
_normal && _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) else if (_status == Status::Mouseover || _status == Status::Selected)
{ {
Window::getInstance()->setCursor(Window::Cursor::Hand); Game::getInstance()->getWindow()->setCursor(Window::Cursor::Hand);
} }
} }

View File

@ -79,7 +79,7 @@ e2d::Node::~Node()
} }
} }
void e2d::Node::visit() void e2d::Node::visit(Renderer * renderer)
{ {
if (!_visible) if (!_visible)
return; return;
@ -90,7 +90,7 @@ void e2d::Node::visit()
// 保留差别属性 // 保留差别属性
_extrapolate = this->getProperty(); _extrapolate = this->getProperty();
auto pRT = Renderer::getInstance()->getRenderTarget(); auto pRT = renderer->getRenderTarget();
if (_clipEnabled) if (_clipEnabled)
{ {
pRT->SetTransform(_finalMatri); pRT->SetTransform(_finalMatri);
@ -103,7 +103,7 @@ void e2d::Node::visit()
if (_children.empty()) if (_children.empty())
{ {
pRT->SetTransform(_finalMatri); pRT->SetTransform(_finalMatri);
this->draw(); this->draw(renderer);
} }
else else
{ {
@ -117,7 +117,7 @@ void e2d::Node::visit()
// 访问 Order 小于零的节点 // 访问 Order 小于零的节点
if (child->getOrder() < 0) if (child->getOrder() < 0)
{ {
child->visit(); child->visit(renderer);
} }
else else
{ {
@ -126,11 +126,11 @@ void e2d::Node::visit()
} }
pRT->SetTransform(_finalMatri); pRT->SetTransform(_finalMatri);
this->draw(); this->draw(renderer);
// 访问剩余节点 // 访问剩余节点
for (; i < _children.size(); ++i) for (; i < _children.size(); ++i)
_children[i]->visit(); _children[i]->visit(renderer);
} }
if (_clipEnabled) if (_clipEnabled)
@ -139,11 +139,10 @@ void e2d::Node::visit()
} }
} }
void e2d::Node::_renderOutline() void e2d::Node::drawOutline(Renderer * renderer)
{ {
if (_visible) if (_visible)
{ {
auto renderer = Renderer::getInstance();
renderer->getRenderTarget()->SetTransform(_finalMatri); renderer->getRenderTarget()->SetTransform(_finalMatri);
renderer->getRenderTarget()->DrawRectangle( renderer->getRenderTarget()->DrawRectangle(
D2D1::RectF(0, 0, _width, _height), D2D1::RectF(0, 0, _width, _height),
@ -154,12 +153,12 @@ void e2d::Node::_renderOutline()
// 渲染所有子节点的轮廓 // 渲染所有子节点的轮廓
for (const auto& child : _children) for (const auto& child : _children)
{ {
child->_renderOutline(); child->drawOutline(renderer);
} }
} }
} }
void e2d::Node::_renderCollider() void e2d::Node::drawCollider()
{ {
if (_visible) if (_visible)
{ {
@ -168,7 +167,7 @@ void e2d::Node::_renderCollider()
// 绘制所有子节点的几何碰撞体 // 绘制所有子节点的几何碰撞体
for (const auto& child : _children) 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) if (child->_parent != nullptr)
{ {
throw Exception(L"节点已有父节点, 不能再添加到其他节点"); throw Exception("节点已有父节点, 不能再添加到其他节点");
} }
for (Node * parent = this; parent != nullptr; parent = parent->getParent()) for (Node * parent = this; parent != nullptr; parent = parent->getParent())
{ {
if (child == parent) if (child == parent)
{ {
throw Exception(L"一个节点不能同时是另一个节点的父节点和子节点"); throw Exception("一个节点不能同时是另一个节点的父节点和子节点");
} }
} }
@ -825,21 +824,23 @@ bool e2d::Node::containsPoint(const Point& point)
// 为节点创建一个轮廓 // 为节点创建一个轮廓
BOOL ret = 0; BOOL ret = 0;
ID2D1RectangleGeometry * rectGeo = nullptr; ID2D1RectangleGeometry * rectGeo = nullptr;
auto factory = Renderer::getFactory(); auto factory = Game::getInstance()->getRenderer()->getFactory();
HRESULT hr = factory->CreateRectangleGeometry( ThrowIfFailed(
factory->CreateRectangleGeometry(
D2D1::RectF(0, 0, _width, _height), D2D1::RectF(0, 0, _width, _height),
&rectGeo &rectGeo
)
); );
if (SUCCEEDED(hr)) ThrowIfFailed(
{
rectGeo->FillContainsPoint( rectGeo->FillContainsPoint(
D2D1::Point2F(point.x, point.y), D2D1::Point2F(point.x, point.y),
_finalMatri, _finalMatri,
&ret &ret
)
); );
}
SafeRelease(rectGeo); SafeRelease(rectGeo);
return ret != 0; return ret != 0;
@ -855,48 +856,46 @@ bool e2d::Node::intersects(Node * node)
D2D1_GEOMETRY_RELATION relation = D2D1_GEOMETRY_RELATION_UNKNOWN; D2D1_GEOMETRY_RELATION relation = D2D1_GEOMETRY_RELATION_UNKNOWN;
ID2D1RectangleGeometry *rectGeo = nullptr, *rectGeo2 = nullptr; ID2D1RectangleGeometry *rectGeo = nullptr, *rectGeo2 = nullptr;
ID2D1TransformedGeometry *transGeo = nullptr, *transGeo2 = nullptr; ID2D1TransformedGeometry *transGeo = nullptr, *transGeo2 = nullptr;
auto factory = Renderer::getFactory(); auto factory = Game::getInstance()->getRenderer()->getFactory();
HRESULT hr = factory->CreateRectangleGeometry( ThrowIfFailed(
factory->CreateRectangleGeometry(
D2D1::RectF(0, 0, _width, _height), D2D1::RectF(0, 0, _width, _height),
&rectGeo &rectGeo
)
); );
if (SUCCEEDED(hr)) ThrowIfFailed(
{ factory->CreateRectangleGeometry(
hr = factory->CreateRectangleGeometry(
D2D1::RectF(0, 0, node->_width, node->_height), D2D1::RectF(0, 0, node->_width, node->_height),
&rectGeo2 &rectGeo2
)
); );
}
if (SUCCEEDED(hr)) ThrowIfFailed(
{ factory->CreateTransformedGeometry(
hr = factory->CreateTransformedGeometry(
rectGeo, rectGeo,
_finalMatri, _finalMatri,
&transGeo &transGeo
)
); );
}
if (SUCCEEDED(hr)) ThrowIfFailed(
{ factory->CreateTransformedGeometry(
hr = factory->CreateTransformedGeometry(
rectGeo2, rectGeo2,
node->_finalMatri, node->_finalMatri,
&transGeo2 &transGeo2
)
); );
}
if (SUCCEEDED(hr)) ThrowIfFailed(
{
// 获取相交状态 // 获取相交状态
transGeo->CompareWithGeometry( transGeo->CompareWithGeometry(
transGeo2, transGeo2,
D2D1::Matrix3x2F::Identity(), D2D1::Matrix3x2F::Identity(),
&relation &relation
)
); );
}
SafeRelease(rectGeo); SafeRelease(rectGeo);
SafeRelease(rectGeo2); SafeRelease(rectGeo2);

View File

@ -9,22 +9,3 @@ e2d::Scene::Scene()
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();
}
}

View File

@ -92,7 +92,7 @@ e2d::Image * e2d::Sprite::getImage() const
return _image; return _image;
} }
void e2d::Sprite::draw() const void e2d::Sprite::draw(Renderer * renderer) const
{ {
if (_image && _image->getBitmap()) if (_image && _image->getBitmap())
{ {
@ -100,7 +100,7 @@ void e2d::Sprite::draw() const
float fCropX = _image->getCropX(); float fCropX = _image->getCropX();
float fCropY = _image->getCropY(); float fCropY = _image->getCropY();
// äÖȾͼƬ // äÖȾͼƬ
Renderer::getInstance()->getRenderTarget()->DrawBitmap( renderer->getRenderTarget()->DrawBitmap(
_image->getBitmap(), _image->getBitmap(),
D2D1::RectF(0, 0, _width, _height), D2D1::RectF(0, 0, _width, _height),
_displayOpacity, _displayOpacity,

View File

@ -287,11 +287,10 @@ void e2d::Text::setOutlineJoin(LineJoin outlineJoin)
_style.outlineJoin = outlineJoin; _style.outlineJoin = outlineJoin;
} }
void e2d::Text::draw() const void e2d::Text::draw(Renderer * renderer) const
{ {
if (_textLayout) if (_textLayout)
{ {
auto renderer = Renderer::getInstance();
// 创建文本区域 // 创建文本区域
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, _width, _height); D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, _width, _height);
// 设置画刷颜色和透明度 // 设置画刷颜色和透明度
@ -321,7 +320,7 @@ void e2d::Text::_createFormat()
{ {
SafeRelease(_textFormat); SafeRelease(_textFormat);
HRESULT hr = Renderer::getWriteFactory()->CreateTextFormat( HRESULT hr = Game::getInstance()->getRenderer()->getWriteFactory()->CreateTextFormat(
(const WCHAR *)_font.family, (const WCHAR *)_font.family,
nullptr, nullptr,
DWRITE_FONT_WEIGHT(_font.weight), DWRITE_FONT_WEIGHT(_font.weight),
@ -384,14 +383,14 @@ void e2d::Text::_createLayout()
return; return;
} }
UINT32 length = (UINT32)_text.getLength();
// ´´½¨ TextLayout
HRESULT hr; HRESULT hr;
UINT32 length = (UINT32)_text.getLength();
auto writeFactory = Game::getInstance()->getRenderer()->getWriteFactory();
// 对文本自动换行情况下进行处理 // 对文本自动换行情况下进行处理
if (_style.wrapping) if (_style.wrapping)
{ {
hr = Renderer::getWriteFactory()->CreateTextLayout( hr = writeFactory->CreateTextLayout(
(const WCHAR *)_text, (const WCHAR *)_text,
length, length,
_textFormat, _textFormat,
@ -410,7 +409,7 @@ void e2d::Text::_createLayout()
} }
else 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 宽度重新创建它 // 为防止文本对齐问题,根据刚才创建的 layout 宽度重新创建它
if (_textLayout) if (_textLayout)
{ {
@ -421,7 +420,7 @@ void e2d::Text::_createLayout()
this->setSize(metrics.width, metrics.height); this->setSize(metrics.width, metrics.height);
// 重新创建 layout // 重新创建 layout
SafeRelease(_textLayout); 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);
} }
} }

View File

@ -160,11 +160,14 @@ bool e2d::File::createFolder(const String & dirPath)
e2d::String e2d::File::getSaveFilePath(const String& title, const String& defExt) e2d::String e2d::File::getSaveFilePath(const String& title, const String& defExt)
{ {
auto window = Game::getInstance()->getWindow();
HWND hwnd = window->getHWnd();
// 弹出保存对话框 // 弹出保存对话框
OPENFILENAME ofn = { 0 }; OPENFILENAME ofn = { 0 };
wchar_t strFilename[MAX_PATH] = { 0 }; // 用于接收文件名 wchar_t strFilename[MAX_PATH] = { 0 }; // 用于接收文件名
ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小 ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小
ofn.hwndOwner = Window::getInstance()->getHWnd(); // ´°¿Ú¾ä±ú ofn.hwndOwner = hwnd; // ´°¿Ú¾ä±ú
ofn.lpstrFilter = L"所有文件\0*.*\0\0"; // 设置过滤 ofn.lpstrFilter = L"所有文件\0*.*\0\0"; // 设置过滤
ofn.nFilterIndex = 1; // 过滤器索引 ofn.nFilterIndex = 1; // 过滤器索引
ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名 ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名

View File

@ -41,7 +41,7 @@ bool e2d::Transition::_init(Scene * prev)
// ´´½¨Í¼²ã // ´´½¨Í¼²ã
HRESULT hr = S_OK; HRESULT hr = S_OK;
auto renderer = Renderer::getInstance(); auto renderer = Game::getInstance()->getRenderer();
if (_inScene) if (_inScene)
{ {
hr = renderer->getRenderTarget()->CreateLayer(&_inLayer); hr = renderer->getRenderTarget()->CreateLayer(&_inLayer);
@ -57,7 +57,7 @@ bool e2d::Transition::_init(Scene * prev)
return false; return false;
} }
_windowSize = Window::getInstance()->getSize(); _windowSize = Game::getInstance()->getWindow()->getSize();
_outLayerParam = _inLayerParam = D2D1::LayerParameters( _outLayerParam = _inLayerParam = D2D1::LayerParameters(
D2D1::InfiniteRect(), D2D1::InfiniteRect(),
nullptr, nullptr,
@ -86,7 +86,8 @@ void e2d::Transition::_update()
void e2d::Transition::_render() void e2d::Transition::_render()
{ {
auto pRT = Renderer::getInstance()->getRenderTarget(); auto renderer = Game::getInstance()->getRenderer();
auto pRT = renderer->getRenderTarget();
if (_outScene) if (_outScene)
{ {
@ -101,7 +102,7 @@ void e2d::Transition::_render()
pRT->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); pRT->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
pRT->PushLayer(_outLayerParam, _outLayer); pRT->PushLayer(_outLayerParam, _outLayer);
_outScene->visit(); _outScene->visit(renderer);
pRT->PopLayer(); pRT->PopLayer();
pRT->PopAxisAlignedClip(); pRT->PopAxisAlignedClip();
@ -120,7 +121,7 @@ void e2d::Transition::_render()
pRT->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); pRT->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
pRT->PushLayer(_inLayerParam, _inLayer); pRT->PushLayer(_inLayerParam, _inLayer);
_inScene->visit(); _inScene->visit(renderer);
pRT->PopLayer(); pRT->PopLayer();
pRT->PopAxisAlignedClip(); pRT->PopAxisAlignedClip();

View File

@ -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 class Window
{ {
@ -147,11 +95,14 @@ public:
}; };
public: public:
// 获取窗体实例 Window(
static Window * getInstance(); const String& title, /* 窗体标题 */
int width, /* 窗体宽度 */
int height, /* 窗体高度 */
int iconID = 0 /* 窗体图标 */
);
// 销毁窗体实例 ~Window();
static void destroyInstance();
// 创建窗体互斥体 // 创建窗体互斥体
bool createMutex( 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 // 获取窗口 DPI
float getDpi(); float getDpi() const;
// 获取窗口句柄 // 获取窗口句柄
HWND getHWnd(); HWND getHWnd() const;
// 打开或隐藏控制台 // 打开或隐藏控制台
void setConsoleEnabled( void setConsoleEnabled(
@ -220,15 +171,6 @@ public:
void poll(); void poll();
private: private:
Window();
~Window();
E2D_DISABLE_COPY(Window);
// 注册窗口
HWND __registerWindow();
// 根据客户区大小计算合适的窗口区域 // 根据客户区大小计算合适的窗口区域
Rect __adjustWindow( Rect __adjustWindow(
int width, int width,
@ -238,7 +180,7 @@ private:
// Win32 窗口消息回调程序 // Win32 窗口消息回调程序
static LRESULT CALLBACK WndProc( static LRESULT CALLBACK WndProc(
HWND hWnd, HWND hWnd,
UINT message, UINT uMsg,
WPARAM wParam, WPARAM wParam,
LPARAM lParam LPARAM lParam
); );
@ -246,12 +188,11 @@ private:
private: private:
HWND _hWnd; HWND _hWnd;
MSG _msg; MSG _msg;
Size _size; int _width;
int _height;
String _title; String _title;
int _iconID; int _iconID;
float _dpi; float _dpi;
static Window * _instance;
}; };
@ -259,11 +200,9 @@ private:
class Input class Input
{ {
public: public:
// 获取输入设备实例 Input();
static Input * getInstance();
// 销毁输入设备实例 ~Input();
static void destroyInstance();
// 检测键盘某按键是否正被按下 // 检测键盘某按键是否正被按下
bool isDown( bool isDown(
@ -296,12 +235,10 @@ public:
// 刷新输入设备状态 // 刷新输入设备状态
void update(); void update();
private: // 初始化渲染器(不应手动调用该函数)
Input(); void init(
Window * window
~Input(); );
E2D_DISABLE_COPY(Input);
private: private:
IDirectInput8W* _directInput; IDirectInput8W* _directInput;
@ -309,20 +246,16 @@ private:
IDirectInputDevice8W* _mouseDevice; IDirectInputDevice8W* _mouseDevice;
DIMOUSESTATE _mouseState; DIMOUSESTATE _mouseState;
char _keyBuffer[256]; char _keyBuffer[256];
static Input * _instance;
}; };
// 渲染器 // 图形设备
class Renderer class Renderer
{ {
public: public:
// 获取渲染器实例 Renderer();
static Renderer * getInstance();
// 销毁实例 ~Renderer();
static void destroyInstance();
// 获取背景色 // 获取背景色
Color getBackgroundColor(); Color getBackgroundColor();
@ -332,46 +265,42 @@ public:
Color color Color color
); );
// 获取文字渲染器
TextRenderer * getTextRenderer();
// 获取 ID2D1HwndRenderTarget 对象
ID2D1HwndRenderTarget * getRenderTarget();
// 获取 ID2D1SolidColorBrush 对象
ID2D1SolidColorBrush * getSolidColorBrush();
// 渲染游戏画面 // 渲染游戏画面
void render(); void render();
// 删除设备相关资源 // 获取文字渲染器
void discardDeviceResources(); TextRenderer * getTextRenderer() const { return _textRenderer; }
// 获取 ID2D1HwndRenderTarget 对象
ID2D1HwndRenderTarget * getRenderTarget() const { return _renderTarget; }
// 获取 ID2D1SolidColorBrush 对象
ID2D1SolidColorBrush * getSolidColorBrush() const { return _solidBrush; }
// 获取 ID2D1Factory 对象 // 获取 ID2D1Factory 对象
static ID2D1Factory * getFactory(); ID2D1Factory * getFactory() const { return _factory; }
// 获取 IWICImagingFactory 对象 // 获取 IWICImagingFactory 对象
static IWICImagingFactory * getImagingFactory(); IWICImagingFactory * getImagingFactory() const { return _imagingFactory; }
// 获取 IDWriteFactory 对象 // 获取 IDWriteFactory 对象
static IDWriteFactory * getWriteFactory(); IDWriteFactory * getWriteFactory() const { return _writeFactory; }
// 获取 Miter 样式的 ID2D1StrokeStyle // 获取 Miter 样式的 ID2D1StrokeStyle
static ID2D1StrokeStyle * getMiterStrokeStyle(); ID2D1StrokeStyle * getMiterStrokeStyle();
// 获取 Bevel 样式的 ID2D1StrokeStyle // 获取 Bevel 样式的 ID2D1StrokeStyle
static ID2D1StrokeStyle * getBevelStrokeStyle(); ID2D1StrokeStyle * getBevelStrokeStyle();
// 获取 Round 样式的 ID2D1StrokeStyle // 获取 Round 样式的 ID2D1StrokeStyle
static ID2D1StrokeStyle * getRoundStrokeStyle(); ID2D1StrokeStyle * getRoundStrokeStyle();
// 初始化渲染器(不应手动调用该函数)
void init(
Window * window
);
private: private:
Renderer();
~Renderer();
E2D_DISABLE_COPY(Renderer);
// 渲染 FPS // 渲染 FPS
void _renderFps(); void _renderFps();
@ -384,14 +313,77 @@ private:
IDWriteTextLayout* _fpsLayout; IDWriteTextLayout* _fpsLayout;
ID2D1SolidColorBrush* _solidBrush; ID2D1SolidColorBrush* _solidBrush;
ID2D1HwndRenderTarget* _renderTarget; ID2D1HwndRenderTarget* _renderTarget;
ID2D1Factory* _factory;
IWICImagingFactory* _imagingFactory;
IDWriteFactory* _writeFactory;
ID2D1StrokeStyle* _miterStrokeStyle;
ID2D1StrokeStyle* _bevelStrokeStyle;
ID2D1StrokeStyle* _roundStrokeStyle;
};
// 游戏
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;
static ID2D1Factory* _d2dFactory;
static IWICImagingFactory* _imagingFactory;
static IDWriteFactory* _writeFactory;
static ID2D1StrokeStyle* _miterStrokeStyle;
static ID2D1StrokeStyle* _bevelStrokeStyle;
static ID2D1StrokeStyle* _roundStrokeStyle;
static Renderer * _instance;
}; };

View File

@ -6,17 +6,6 @@ namespace e2d
{ {
template<class Interface>
inline void SafeRelease(Interface*& p)
{
if (p != nullptr)
{
p->Release();
p = nullptr;
}
}
class Music; class Music;
// 音源回调 // 音源回调
@ -173,7 +162,7 @@ class Exception
public: public:
Exception() E2D_NOEXCEPT; Exception() E2D_NOEXCEPT;
explicit Exception(const String& message) E2D_NOEXCEPT; explicit Exception(const char * message) E2D_NOEXCEPT;
Exception(Exception const& other) E2D_NOEXCEPT; Exception(Exception const& other) E2D_NOEXCEPT;
@ -182,10 +171,10 @@ public:
Exception& operator=(Exception const& other) E2D_NOEXCEPT; Exception& operator=(Exception const& other) E2D_NOEXCEPT;
// 获取异常信息 // 获取异常信息
virtual String msg() const; virtual const char * msg() const;
private: private:
String _message; const char * _message;
}; };
@ -196,7 +185,30 @@ class SystemException
public: public:
SystemException() E2D_NOEXCEPT; SystemException() E2D_NOEXCEPT;
explicit SystemException(const String& message) E2D_NOEXCEPT; explicit SystemException(const char * message) E2D_NOEXCEPT;
}; };
template<class Interface>
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<unsigned int>(hr));
throw SystemException(s_str);
}
}
} }

View File

@ -70,7 +70,8 @@ public:
HWND hWnd, HWND hWnd,
UINT message, UINT message,
WPARAM wParam, WPARAM wParam,
LPARAM lParam LPARAM lParam,
float dpi
); );
// 資函報炎罪恫炎 // 資函報炎罪恫炎

View File

@ -47,7 +47,9 @@ public:
virtual ~Node(); virtual ~Node();
// 渲染节点 // 渲染节点
virtual void draw() const {} virtual void draw(
Renderer * renderer
) const {}
// 获取节点显示状态 // 获取节点显示状态
virtual bool isVisible() 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: protected:
E2D_DISABLE_COPY(Node); E2D_DISABLE_COPY(Node);
// 渲染节点轮廓
virtual void _renderOutline();
// 渲染碰撞体轮廓
virtual void _renderCollider();
// 设置节点所在场景 // 设置节点所在场景
virtual void _setParentScene( virtual void _setParentScene(
Scene * scene Scene * scene
@ -468,9 +474,6 @@ public:
// 说明:返回 false 将阻止窗口关闭 // 说明:返回 false 将阻止窗口关闭
virtual bool onCloseWindow() { return true; } virtual bool onCloseWindow() { return true; }
// 渲染场景
virtual void visit() override;
protected: protected:
E2D_DISABLE_COPY(Scene); E2D_DISABLE_COPY(Scene);
}; };
@ -531,7 +534,9 @@ public:
virtual Image * getImage() const; virtual Image * getImage() const;
// 渲染精灵 // 渲染精灵
virtual void draw() const override; virtual void draw(
Renderer * renderer
) const override;
protected: protected:
E2D_DISABLE_COPY(Sprite); E2D_DISABLE_COPY(Sprite);
@ -735,7 +740,9 @@ public:
); );
// 渲染文字 // 渲染文字
virtual void draw() const override; virtual void draw(
Renderer * renderer
) const override;
protected: protected:
E2D_DISABLE_COPY(Text); E2D_DISABLE_COPY(Text);
@ -837,7 +844,9 @@ public:
) override; ) override;
// 渲染节点 // 渲染节点
virtual void visit() override; virtual void visit(
Renderer * renderer
) override;
protected: protected:
E2D_DISABLE_COPY(Button); E2D_DISABLE_COPY(Button);