Magic_Game/Easy2D/Base/EApp.cpp

837 lines
17 KiB
C++
Raw Normal View History

#include "..\ebase.h"
2017-10-10 01:14:03 +08:00
#include "..\Win\winbase.h"
#include "..\emanagers.h"
2017-10-17 21:22:25 +08:00
#include "..\enodes.h"
#include "..\etransitions.h"
2017-10-10 01:14:03 +08:00
#include <stack>
#include <thread>
#include <imm.h>
2017-10-17 21:22:25 +08:00
#pragma comment (lib ,"imm32.lib")
2017-10-12 02:44:44 +08:00
using namespace std::this_thread;
2017-10-17 21:22:25 +08:00
using namespace std::chrono;
2017-10-12 02:44:44 +08:00
2017-10-17 21:22:25 +08:00
// Ψһʵ<D2BB><CAB5>ָ<EFBFBD><D6B8>
static e2d::EApp * s_pInstance = nullptr;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD>ջ
static std::stack<e2d::EScene*> s_SceneStack;
// <20><>Ϸ<EFBFBD><CFB7>ʼʱ<CABC><CAB1>
static steady_clock::time_point s_tStart;
2017-10-12 02:44:44 +08:00
e2d::EApp::EApp()
: m_bEnd(false)
, m_bPaused(false)
, m_bManualPaused(false)
, m_bTransitional(false)
, m_bTopMost(false)
2017-10-17 21:22:25 +08:00
, nAnimationInterval(17LL)
, m_ClearColor(EColor::BLACK)
2017-10-12 02:44:44 +08:00
, m_pCurrentScene(nullptr)
, m_pNextScene(nullptr)
2017-09-10 23:56:52 +08:00
{
2017-10-17 21:22:25 +08:00
ASSERT(s_pInstance == nullptr, "EApp instance already exists!");
2017-09-10 23:56:52 +08:00
s_pInstance = this; // <20><><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2017-10-17 21:22:25 +08:00
CoInitializeEx(NULL, COINIT_MULTITHREADED);
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
e2d::EApp::~EApp()
2017-09-10 23:56:52 +08:00
{
2017-10-17 21:22:25 +08:00
// <20>ͷ<EFBFBD><CDB7><EFBFBD>Դ
SafeReleaseInterface(&GetSolidColorBrush());
2017-10-12 02:44:44 +08:00
SafeReleaseInterface(&GetRenderTarget());
2017-10-17 21:22:25 +08:00
SafeReleaseInterface(&GetFactory());
2017-10-19 00:50:04 +08:00
SafeReleaseInterface(&GetImagingFactory());
SafeReleaseInterface(&GetDirectWriteFactory());
2017-10-17 21:22:25 +08:00
CoUninitialize();
2017-09-10 23:56:52 +08:00
}
e2d::EApp * e2d::EApp::get()
2017-09-10 23:56:52 +08:00
{
2017-10-14 01:07:34 +08:00
ASSERT(s_pInstance != nullptr, "Nonexistent EApp instance.");
2017-10-12 02:44:44 +08:00
return s_pInstance; // <20><>ȡ EApp <20><>Ψһʵ<D2BB><CAB5>
2017-09-10 23:56:52 +08:00
}
2017-10-17 21:22:25 +08:00
bool e2d::EApp::init(const EString &title, UINT32 width, UINT32 height, bool showConsole /* = false */)
2017-09-10 23:56:52 +08:00
{
2017-10-21 19:09:31 +08:00
return init(title, width, height, EWindowStyle(), showConsole);
2017-10-12 02:44:44 +08:00
}
2017-10-15 02:46:24 +08:00
2017-10-21 19:09:31 +08:00
bool e2d::EApp::init(const EString &title, UINT32 width, UINT32 height, EWindowStyle wStyle, bool showConsole /* = false */)
2017-10-12 02:44:44 +08:00
{
HRESULT hr;
2017-10-17 21:22:25 +08:00
// <20><>ʾ<EFBFBD><CABE><EFBFBD>رտ<D8B1><D5BF><EFBFBD>̨
EApp::showConsole(showConsole);
2017-10-13 11:42:36 +08:00
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޹<EFBFBD><DEB9><EFBFBD>Դ
2017-10-15 02:46:24 +08:00
hr = _createDeviceIndependentResources();
2017-10-13 11:42:36 +08:00
if (SUCCEEDED(hr))
{
// ע<><EFBFBD><E1B4B0><EFBFBD><EFBFBD>
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
UINT style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
if (wStyle.m_bNoClose)
{
style |= CS_NOCLOSE;
}
wcex.style = style;
2017-10-13 11:42:36 +08:00
wcex.lpfnWndProc = EApp::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
2017-10-17 21:22:25 +08:00
wcex.hbrBackground = (HBRUSH)(GetStockObject(BLACK_BRUSH));
2017-10-13 11:42:36 +08:00
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDI_APPLICATION);
2017-10-17 21:22:25 +08:00
wcex.lpszClassName = L"Easy2DApp";
if (wStyle.m_pIconID)
2017-10-21 19:09:31 +08:00
{
wcex.hIcon = (HICON)::LoadImage(GetModuleHandle(NULL), wStyle.m_pIconID, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
2017-10-21 19:09:31 +08:00
}
2017-10-13 11:42:36 +08:00
RegisterClassEx(&wcex);
// Because the CreateWindow function takes its size in pixels,
// obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
// The factory returns the current system DPI. This is also the value it will use
// to create its own windows.
GetFactory()->GetDesktopDpi(&dpiX, &dpiY);
2017-10-17 21:22:25 +08:00
width = static_cast<UINT>(ceil(width * dpiX / 96.f));
height = static_cast<UINT>(ceil(height * dpiY / 96.f));
// <20><>ȡ<EFBFBD><C8A1>Ļ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD>
UINT screenWidth = static_cast<UINT>(GetSystemMetrics(SM_CXSCREEN));
UINT screenHeight = static_cast<UINT>(GetSystemMetrics(SM_CYSCREEN));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>ڴ<EFBFBD>С<EFBFBD>ȷֱ<C8B7><D6B1>ʴ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
WARN_IF(screenWidth < width || screenHeight < height, "The window is larger than screen!");
width = min(width, screenWidth);
height = min(height, screenHeight);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ
DWORD dwStyle = WS_OVERLAPPED | WS_SYSMENU;
if (!wStyle.m_bNoMiniSize)
{
2017-10-21 19:09:31 +08:00
dwStyle |= WS_MINIMIZEBOX;
}
2017-10-21 19:09:31 +08:00
// <20><><EFBFBD><EFBFBD><E6B4B0><EFBFBD>Ƿ<EFBFBD><C7B7>ö<EFBFBD><C3B6><EFBFBD>ʾ
m_bTopMost = wStyle.m_bTopMost;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><E6B4B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2017-10-13 11:42:36 +08:00
m_sTitle = title;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2017-10-13 11:42:36 +08:00
GetHWnd() = CreateWindow(
2017-10-17 21:22:25 +08:00
L"Easy2DApp",
2017-10-13 11:42:36 +08:00
m_sTitle.c_str(),
dwStyle,
0,
0,
width,
height,
2017-10-13 11:42:36 +08:00
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
2017-10-12 02:44:44 +08:00
2017-10-13 11:42:36 +08:00
hr = GetHWnd() ? S_OK : E_FAIL;
2017-10-17 21:22:25 +08:00
if (SUCCEEDED(hr))
2017-10-12 02:44:44 +08:00
{
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
this->setKeyboardLayoutEnable(false);
// <20><><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD>С
this->setWindowSize(width, height);
2017-10-12 02:44:44 +08:00
}
2017-10-14 01:07:34 +08:00
else
{
2017-10-17 21:22:25 +08:00
UnregisterClass(L"E2DApp", HINST_THISCOMPONENT);
2017-10-14 01:07:34 +08:00
}
2017-10-12 02:44:44 +08:00
}
if (FAILED(hr))
{
MessageBox(nullptr, L"Initialize Failed!", L"Error", MB_OK);
}
2017-10-12 02:44:44 +08:00
return SUCCEEDED(hr);
}
void e2d::EApp::pause()
{
EApp::get()->m_bManualPaused = true;
}
void e2d::EApp::resume()
{
if (isPaused())
{
EApp::get()->m_bPaused = false;
EApp::get()->m_bManualPaused = false;
2017-10-21 19:09:31 +08:00
// ˢ<>µ<EFBFBD>ǰʱ<C7B0><CAB1>
GetNow() = steady_clock::now();
// <20><><EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>Ͷ<EFBFBD>ʱ<EFBFBD><CAB1>
EActionManager::_resetAllActions();
ETimerManager::_resetAllTimers();
}
}
bool e2d::EApp::isPaused()
{
return s_pInstance->m_bPaused || s_pInstance->m_bManualPaused;
}
2017-10-17 21:22:25 +08:00
void e2d::EApp::showConsole(bool show)
{
// <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD><D1B4>ڵĿ<DAB5><C4BF><EFBFBD>̨<EFBFBD><CCA8><EFBFBD><EFBFBD>
HWND hwnd = GetConsoleWindow();
static FILE * stdoutstream = nullptr;
static FILE * stdinstream = nullptr;
static FILE * stderrstream = nullptr;
// <20>رտ<D8B1><D5BF><EFBFBD>̨
if (show)
{
if (hwnd)
{
ShowWindow(hwnd, SW_SHOWNORMAL);
}
else
{
// <20><>ʾһ<CABE><D2BB><EFBFBD>¿<EFBFBD><C2BF><EFBFBD>̨
if (AllocConsole())
{
freopen_s(&stdoutstream, "CONOUT$", "w+t", stdout);
freopen_s(&stderrstream, "CONOUT$", "w+t", stderr);
freopen_s(&stdinstream, "CONIN$", "r+t", stdin);
}
else
{
MessageBox(nullptr, L"Alloc Console Failed!", L"Error", MB_OK);
}
}
}
else
{
if (hwnd)
{
if (stdoutstream)
{
fclose(stdoutstream);
fclose(stdinstream);
fclose(stderrstream);
stdoutstream = stdinstream = stderrstream = nullptr;
}
FreeConsole();
}
}
}
2017-10-12 02:44:44 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ
void e2d::EApp::run()
{
2017-10-17 21:22:25 +08:00
ASSERT(GetHWnd() != nullptr, "Cannot find Game Window.");
2017-10-13 11:42:36 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
_enterNextScene();
2017-10-12 02:44:44 +08:00
// <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>
ShowWindow(GetHWnd(), SW_SHOWNORMAL);
UpdateWindow(GetHWnd());
// <20><><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD>ö<EFBFBD>
if (m_bTopMost)
{
SetWindowPos(GetHWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
// <20><>¼<EFBFBD><C2BC>ʼʱ<CABC><CAB1>
s_tStart = steady_clock::now();
2017-09-10 23:56:52 +08:00
2017-10-12 02:44:44 +08:00
MSG msg;
2017-10-10 01:14:03 +08:00
while (!m_bEnd)
2017-09-10 23:56:52 +08:00
{
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
while (PeekMessage(&msg, GetHWnd(), 0, 0, PM_REMOVE))
2017-09-10 23:56:52 +08:00
{
2017-10-12 02:44:44 +08:00
TranslateMessage(&msg);
DispatchMessage(&msg);
2017-09-10 23:56:52 +08:00
}
2017-10-17 21:22:25 +08:00
// ִ<><D6B4><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD>
_mainLoop();
2017-09-10 23:56:52 +08:00
}
2017-10-15 02:46:24 +08:00
2017-10-17 21:22:25 +08:00
// <20>رտ<D8B1><D5BF><EFBFBD>̨
EApp::showConsole(false);
}
void e2d::EApp::setFPS(UINT32 fps)
{
fps = min(max(fps, 30), 120);
s_pInstance->nAnimationInterval = 1000 / fps;
2017-10-17 21:22:25 +08:00
}
bool e2d::EApp::onActivate()
{
return true;
}
bool e2d::EApp::onInactive()
{
return true;
}
bool e2d::EApp::onCloseWindow()
2017-10-17 21:22:25 +08:00
{
return true;
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
void e2d::EApp::_mainLoop()
2017-09-10 23:56:52 +08:00
{
2017-10-12 02:44:44 +08:00
// ʱ<><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static LONGLONG nInterval = 0LL;
// <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
static LONGLONG nWaitMS = 0L;
2017-10-21 19:09:31 +08:00
// <20><>һ֡<D2BB><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
2017-10-17 21:22:25 +08:00
static steady_clock::time_point tLast = steady_clock::now();
2017-10-21 19:09:31 +08:00
// ˢ<>µ<EFBFBD>ǰʱ<C7B0><CAB1>
2017-10-17 21:22:25 +08:00
GetNow() = steady_clock::now();
2017-10-12 02:44:44 +08:00
// <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2017-10-17 21:22:25 +08:00
nInterval = GetInterval(tLast);
2017-10-12 02:44:44 +08:00
// <20>жϼ<D0B6><CFBC><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>Ƿ<EFBFBD><C7B7>
if (nInterval >= nAnimationInterval)
2017-09-10 23:56:52 +08:00
{
// <20><>¼<EFBFBD><C2BC>ǰʱ<C7B0><CAB1>
2017-10-21 19:09:31 +08:00
tLast += microseconds(nAnimationInterval);
// <20><>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
_onControl();
// ˢ<><CBA2><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>
_onRender();
2017-09-10 23:56:52 +08:00
}
else
{
2017-10-12 02:44:44 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
nWaitMS = nAnimationInterval - nInterval - 1;
// <20><><EFBFBD><EFBFBD><EFBFBD>̣߳<DFB3><CCA3>ͷ<EFBFBD> CPU ռ<><D5BC>
if (nWaitMS > 1LL)
{
2017-10-17 21:22:25 +08:00
sleep_for(milliseconds(nWaitMS));
2017-10-12 02:44:44 +08:00
}
2017-09-10 23:56:52 +08:00
}
}
2017-10-12 02:44:44 +08:00
void e2d::EApp::_onControl()
2017-09-10 23:56:52 +08:00
{
2017-10-21 19:09:31 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>ִ<EFBFBD>г<EFBFBD><D0B3><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>
if (m_bTransitional)
2017-09-10 23:56:52 +08:00
{
2017-10-21 19:09:31 +08:00
EActionManager::ActionProc();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>к<EFBFBD><D0BA><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>
if (m_bTransitional)
{
return;
}
}
2017-10-21 19:09:31 +08:00
// <20><>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>ָ<EFBFBD>벻Ϊ<EBB2BB><CEAA>ʱ<EFBFBD><CAB1><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>
if (m_pNextScene)
{
2017-10-21 19:09:31 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
_enterNextScene();
2017-09-10 23:56:52 +08:00
}
2017-09-10 23:56:52 +08:00
// <20><><EFBFBD>Ե<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD>
2017-10-14 01:07:34 +08:00
ASSERT(m_pCurrentScene != nullptr, "Current scene NULL pointer exception.");
2017-09-10 23:56:52 +08:00
2017-10-19 00:50:04 +08:00
ETimerManager::TimerProc(); // <20><>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>г<EFBFBD><D0B3><EFBFBD>
EActionManager::ActionProc(); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>г<EFBFBD><D0B3><EFBFBD>
EObjectManager::__flush(); // ˢ<><CBA2><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD>
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
// This method discards device-specific
// resources if the Direct3D device dissapears during execution and
// recreates the resources the next time it's invoked.
void e2d::EApp::_onRender()
2017-10-10 01:14:03 +08:00
{
2017-10-12 02:44:44 +08:00
HRESULT hr = S_OK;
hr = _createDeviceResources();
2017-10-12 02:44:44 +08:00
if (SUCCEEDED(hr))
2017-10-10 01:14:03 +08:00
{
// <20><>ʼ<EFBFBD><CABC>ͼ
2017-10-12 02:44:44 +08:00
GetRenderTarget()->BeginDraw();
2017-10-17 21:22:25 +08:00
// ʹ<>ñ<EFBFBD><C3B1><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ
GetRenderTarget()->Clear(D2D1::ColorF(m_ClearColor));
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD>Ƶ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>
2017-10-21 19:09:31 +08:00
if (m_pCurrentScene)
{
m_pCurrentScene->_onRender();
}
// <20>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>ͬʱ<CDAC><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (m_bTransitional && m_pNextScene)
{
m_pNextScene->_onRender();
}
// <20><>ֹ<EFBFBD><D6B9>ͼ
2017-10-12 02:44:44 +08:00
hr = GetRenderTarget()->EndDraw();
2017-10-17 21:22:25 +08:00
// ˢ<>½<EFBFBD><C2BD><EFBFBD>
UpdateWindow(GetHWnd());
2017-10-12 02:44:44 +08:00
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
_discardDeviceResources();
2017-10-12 02:44:44 +08:00
}
if (FAILED(hr))
{
MessageBox(GetHWnd(), L"Game Render Failed!", L"Error", MB_OK);
this->quit();
}
2017-09-27 17:56:28 +08:00
}
2017-10-17 21:22:25 +08:00
void e2d::EApp::setWindowSize(UINT32 width, UINT32 height)
2017-09-10 23:56:52 +08:00
{
2017-09-12 12:53:34 +08:00
// <20><>ȡ<EFBFBD><C8A1>Ļ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD>
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// <20><>ȡ<EFBFBD><C8A1><EFBFBD>ڴ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD>
2017-10-12 02:44:44 +08:00
tagRECT rcWindow;
2017-09-12 12:53:34 +08:00
GetWindowRect(GetHWnd(), &rcWindow);
// <20><>ȡ<EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD>С
2017-10-12 02:44:44 +08:00
tagRECT rcClient;
2017-09-12 12:53:34 +08:00
GetClientRect(GetHWnd(), &rcClient);
// <20><><EFBFBD><EFBFBD><EFBFBD>߿<EFBFBD><DFBF><EFBFBD>С
width += (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left);
height += (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top);
// <20>޸Ĵ<DEB8><C4B4>ڴ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD>
2017-10-14 01:07:34 +08:00
MoveWindow(GetHWnd(), (screenWidth - width) / 2, (screenHeight - height) / 2, width, height, TRUE);
2017-09-10 23:56:52 +08:00
}
2017-10-17 21:22:25 +08:00
void e2d::EApp::setWindowTitle(const EString &title)
2017-09-10 23:56:52 +08:00
{
// <20><><EFBFBD>ô<EFBFBD><C3B4>ڱ<EFBFBD><DAB1><EFBFBD>
SetWindowText(GetHWnd(), title.c_str());
// <20><><EFBFBD>浱ǰ<E6B5B1><C7B0><EFBFBD><EFBFBD><E2A3AC><EFBFBD><EFBFBD><EFBFBD>޸Ĵ<DEB8><C4B4>ڴ<EFBFBD>Сʱ<D0A1>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>
2017-10-14 01:07:34 +08:00
get()->m_sTitle = title;
2017-09-10 23:56:52 +08:00
}
e2d::EString e2d::EApp::getTitle()
2017-09-20 14:52:50 +08:00
{
2017-10-14 01:07:34 +08:00
return get()->m_sTitle;
2017-09-20 14:52:50 +08:00
}
2017-10-21 19:09:31 +08:00
float e2d::EApp::getWidth()
2017-09-10 23:56:52 +08:00
{
2017-10-21 19:09:31 +08:00
return GetRenderTarget()->GetSize().width;
2017-09-10 23:56:52 +08:00
}
2017-10-21 19:09:31 +08:00
float e2d::EApp::getHeight()
2017-10-12 02:44:44 +08:00
{
2017-10-21 19:09:31 +08:00
return GetRenderTarget()->GetSize().height;
2017-10-12 02:44:44 +08:00
}
void e2d::EApp::enterScene(EScene * scene, bool saveCurrentScene /* = true */)
2017-09-10 23:56:52 +08:00
{
enterScene(scene, nullptr, saveCurrentScene);
}
void e2d::EApp::enterScene(EScene * scene, ETransition * transition, bool saveCurrentScene /* = true */)
{
scene->retain();
2017-09-10 23:56:52 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
2017-10-14 01:07:34 +08:00
get()->m_pNextScene = scene;
2017-09-10 23:56:52 +08:00
// <20>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>Ƿ񱣴浱ǰ<E6B5B1><C7B0><EFBFBD><EFBFBD>
2017-10-14 18:43:32 +08:00
if (get()->m_pCurrentScene)
{
get()->m_pCurrentScene->m_bWillSave = saveCurrentScene;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (transition)
{
get()->m_bTransitional = true;
transition->_setTarget(
get()->m_pCurrentScene,
get()->m_pNextScene,
get()->m_bTransitional
);
}
else
{
get()->m_bTransitional = false;
2017-10-14 18:43:32 +08:00
}
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
void e2d::EApp::backScene()
{
backScene(nullptr);
}
void e2d::EApp::backScene(ETransition * transition)
2017-09-10 23:56:52 +08:00
{
2017-10-17 21:22:25 +08:00
ASSERT(s_SceneStack.size(), "Scene stack now is empty!");
2017-09-10 23:56:52 +08:00
// <20><>ջ<EFBFBD><D5BB>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EBA3AC>Ϊ<EFBFBD><CEAA>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
2017-10-14 01:07:34 +08:00
get()->m_pNextScene = s_SceneStack.top();
2017-10-14 18:43:32 +08:00
s_SceneStack.pop();
2017-09-10 23:56:52 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD>浱ǰ<E6B5B1><C7B0><EFBFBD><EFBFBD>
2017-10-14 18:43:32 +08:00
if (get()->m_pCurrentScene)
{
get()->m_pCurrentScene->m_bWillSave = false;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (transition)
{
get()->m_bTransitional = true;
transition->_setTarget(
get()->m_pCurrentScene,
get()->m_pNextScene,
get()->m_bTransitional
);
}
else
{
get()->m_bTransitional = false;
}
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
void e2d::EApp::clearScene()
2017-09-18 23:59:08 +08:00
{
// <20><><EFBFBD>ճ<EFBFBD><D5B3><EFBFBD>ջ
2017-10-10 01:14:03 +08:00
while (s_SceneStack.size())
2017-09-18 23:59:08 +08:00
{
2017-10-10 01:14:03 +08:00
auto temp = s_SceneStack.top();
2017-10-21 19:09:31 +08:00
SafeReleaseAndClear(&temp);
2017-10-10 01:14:03 +08:00
s_SceneStack.pop();
2017-09-18 23:59:08 +08:00
}
}
e2d::EScene * e2d::EApp::getCurrentScene()
2017-10-12 02:44:44 +08:00
{
2017-10-14 01:07:34 +08:00
return get()->m_pCurrentScene;
}
2017-10-17 21:22:25 +08:00
void e2d::EApp::setAppName(const EString &appname)
2017-09-20 14:52:50 +08:00
{
2017-09-27 17:56:28 +08:00
s_pInstance->m_sAppName = appname;
2017-09-20 14:52:50 +08:00
}
e2d::EString e2d::EApp::getAppName()
2017-09-20 14:52:50 +08:00
{
2017-10-17 21:22:25 +08:00
if (s_pInstance->m_sAppName.empty())
s_pInstance->m_sAppName = s_pInstance->m_sTitle;
2017-09-27 17:56:28 +08:00
return s_pInstance->m_sAppName;
2017-09-20 14:52:50 +08:00
}
void e2d::EApp::setBkColor(UINT32 color)
2017-10-12 02:44:44 +08:00
{
2017-10-14 01:07:34 +08:00
get()->m_ClearColor = color;
2017-10-12 02:44:44 +08:00
}
2017-10-17 21:22:25 +08:00
void e2d::EApp::setKeyboardLayoutEnable(bool value)
{
static HIMC hImc = NULL;
if (value)
{
if (hImc != NULL)
{
ImmAssociateContext(GetHWnd(), hImc);
hImc = NULL;
}
}
else
{
if (hImc == NULL)
{
hImc = ImmAssociateContext(GetHWnd(), NULL);
}
}
}
HWND e2d::EApp::getHWnd()
{
return GetHWnd();
}
LONGLONG e2d::EApp::getTotalDurationFromStart()
{
return GetInterval(s_tStart);
}
void e2d::EApp::hideWindow()
2017-10-12 02:44:44 +08:00
{
ShowWindow(GetHWnd(), SW_HIDE);
}
2017-10-17 21:22:25 +08:00
void e2d::EApp::showWindow()
2017-09-12 12:53:34 +08:00
{
2017-10-17 21:22:25 +08:00
ShowWindow(GetHWnd(), SW_SHOWNORMAL);
2017-09-12 12:53:34 +08:00
}
void e2d::EApp::quit()
2017-10-12 02:44:44 +08:00
{
get()->m_bEnd = true;
2017-10-12 02:44:44 +08:00
}
void e2d::EApp::end()
2017-10-12 02:44:44 +08:00
{
get()->m_bEnd = true;
2017-10-12 02:44:44 +08:00
}
void e2d::EApp::_enterNextScene()
2017-09-10 23:56:52 +08:00
{
if (m_pNextScene == nullptr)
return;
// ִ<>е<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> onCloseWindow <20><><EFBFBD><EFBFBD>
2017-10-06 16:40:10 +08:00
if (m_pCurrentScene)
{
m_pCurrentScene->onExit();
2017-10-14 18:43:32 +08:00
if (m_pCurrentScene->m_bWillSave)
2017-10-06 16:40:10 +08:00
{
// <20><>Ҫ<EFBFBD><D2AA><EFBFBD>浱ǰ<E6B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>
2017-10-10 01:14:03 +08:00
s_SceneStack.push(m_pCurrentScene);
2017-10-06 16:40:10 +08:00
}
else
{
2017-10-21 19:09:31 +08:00
SafeReleaseAndClear(&m_pCurrentScene);
2017-10-06 16:40:10 +08:00
}
}
// ִ<><D6B4><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> onEnter <20><><EFBFBD><EFBFBD>
m_pNextScene->onEnter();
2017-10-14 01:07:34 +08:00
2017-10-06 16:40:10 +08:00
m_pCurrentScene = m_pNextScene; // <20>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>
m_pNextScene = nullptr; // <20><>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD>
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
// Creates resources that are not bound to a particular device.
// Their lifetime effectively extends for the duration of the
// application.
HRESULT e2d::EApp::_createDeviceIndependentResources()
2017-09-10 23:56:52 +08:00
{
2017-10-12 02:44:44 +08:00
HRESULT hr = S_OK;
2017-09-10 23:56:52 +08:00
2017-10-12 02:44:44 +08:00
// Create a Direct2D factory.
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &GetFactory());
2017-09-10 23:56:52 +08:00
if (FAILED(hr))
{
2017-10-13 11:42:36 +08:00
MessageBox(nullptr, L"Create Device Independent Resources Failed!", L"Error", MB_OK);
}
2017-10-12 02:44:44 +08:00
return hr;
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
// Creates resources that are bound to a particular
// Direct3D device. These resources need to be recreated
// if the Direct3D device dissapears, such as when the isVisiable
2017-10-12 02:44:44 +08:00
// changes, the window is remoted, etc.
HRESULT e2d::EApp::_createDeviceResources()
2017-09-10 23:56:52 +08:00
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
GetRenderTarget();
2017-10-12 02:44:44 +08:00
return S_OK;
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
// Discards device-dependent resources. These resources must be
// recreated when the Direct3D device is lost.
void e2d::EApp::_discardDeviceResources()
2017-09-10 23:56:52 +08:00
{
2017-10-12 02:44:44 +08:00
SafeReleaseInterface(&GetRenderTarget());
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
// If the application receives a WM_SIZE message, this method
// re2d::ESizes the render target appropriately.
2017-10-17 21:22:25 +08:00
void e2d::EApp::_onResize(UINT32 width, UINT32 height)
2017-09-10 23:56:52 +08:00
{
2017-10-12 02:44:44 +08:00
if (GetRenderTarget())
{
// Note: This method can fail, but it's okay to ignore the
// error here, because the error will be returned again
// the next time EndDraw is called.
GetRenderTarget()->Resize(D2D1::SizeU(width, height));
}
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
// Handles window messages.
LRESULT e2d::EApp::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2017-09-10 23:56:52 +08:00
{
2017-10-12 02:44:44 +08:00
LRESULT result = 0;
if (message == WM_CREATE)
2017-09-10 23:56:52 +08:00
{
2017-10-17 21:22:25 +08:00
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD> WM_CREATE <20><>Ϣ<EFBFBD><CFA2> EApp ʵ<><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
2017-10-12 02:44:44 +08:00
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
2017-10-13 11:42:36 +08:00
e2d::EApp *pEApp = (e2d::EApp *)pcs->lpCreateParams;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD> EApp ָ<>뵽 GWLP_USERDATA <20>ֶ<EFBFBD>
2017-10-12 02:44:44 +08:00
::SetWindowLongPtrW(
2017-10-13 11:42:36 +08:00
hWnd,
2017-10-12 02:44:44 +08:00
GWLP_USERDATA,
PtrToUlong(pEApp)
);
result = 1;
2017-09-10 23:56:52 +08:00
}
2017-10-12 02:44:44 +08:00
else
{
2017-10-17 21:22:25 +08:00
// <20><> GWLP_USERDATA <20>ֶ<EFBFBD>ȡ<EFBFBD><C8A1> EApp ָ<><D6B8>
2017-10-13 11:42:36 +08:00
e2d::EApp *pEApp = reinterpret_cast<e2d::EApp *>(static_cast<LONG_PTR>(
2017-10-12 02:44:44 +08:00
::GetWindowLongPtrW(
2017-10-13 11:42:36 +08:00
hWnd,
2017-10-12 02:44:44 +08:00
GWLP_USERDATA
)));
bool wasHandled = false;
if (pEApp)
{
switch (message)
{
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
2017-10-13 11:42:36 +08:00
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:
{
// ִ<>г<EFBFBD><D0B3><EFBFBD><EFBFBD>л<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ΰ<EFBFBD><CEB0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
2017-10-21 19:09:31 +08:00
if (!pEApp->m_bTransitional && !pEApp->m_pNextScene)
{
EMsgManager::MouseProc(message, wParam, lParam);
}
2017-10-13 17:14:00 +08:00
}
result = 0;
2017-10-17 21:22:25 +08:00
wasHandled = true;
2017-10-13 17:14:00 +08:00
break;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
2017-10-13 17:14:00 +08:00
case WM_KEYDOWN:
case WM_KEYUP:
{
// ִ<>г<EFBFBD><D0B3><EFBFBD><EFBFBD>л<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ΰ<EFBFBD><CEB0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
2017-10-21 19:09:31 +08:00
if (!pEApp->m_bTransitional && !pEApp->m_pNextScene)
{
EMsgManager::KeyboardProc(message, wParam, lParam);
}
2017-10-13 11:42:36 +08:00
}
result = 0;
2017-10-17 21:22:25 +08:00
wasHandled = true;
2017-10-13 11:42:36 +08:00
break;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>С<EFBFBD><EFBFBD><E4BBAF>Ϣ
2017-10-12 02:44:44 +08:00
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
pEApp->_onResize(width, height);
}
result = 0;
wasHandled = true;
break;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><D6B1>ʱ仯<CAB1><E4BBAF>Ϣ
2017-10-12 02:44:44 +08:00
case WM_DISPLAYCHANGE:
{
2017-10-17 21:22:25 +08:00
// <20>ػ<EFBFBD><D8BB>ͻ<EFBFBD><CDBB><EFBFBD>
2017-10-13 11:42:36 +08:00
InvalidateRect(hWnd, NULL, FALSE);
2017-10-12 02:44:44 +08:00
}
result = 0;
wasHandled = true;
break;
2017-10-17 21:22:25 +08:00
// <20>ػ洰<D8BB><E6B4B0>
2017-10-12 02:44:44 +08:00
case WM_PAINT:
{
pEApp->_onRender();
2017-10-13 11:42:36 +08:00
ValidateRect(hWnd, NULL);
2017-10-12 02:44:44 +08:00
}
result = 0;
wasHandled = true;
break;
// <20><><EFBFBD>ڼ<EFBFBD><DABC><EFBFBD><EFBFBD><EFBFBD>Ϣ
case WM_ACTIVATE:
{
if (LOWORD(wParam) == WA_INACTIVE)
{
2017-10-21 19:09:31 +08:00
if (pEApp->getCurrentScene() &&
pEApp->getCurrentScene()->onInactive() &&
pEApp->onInactive())
{
pEApp->m_bPaused = true;
}
}
else
{
2017-10-21 19:09:31 +08:00
if (pEApp->getCurrentScene() &&
pEApp->getCurrentScene()->onActivate() &&
pEApp->onActivate())
{
pEApp->m_bPaused = false;
}
}
}
result = 1;
wasHandled = true;
break;
2017-10-17 21:22:25 +08:00
// <20><><EFBFBD>ڹر<DAB9><D8B1><EFBFBD>Ϣ
case WM_CLOSE:
2017-10-12 02:44:44 +08:00
{
2017-10-21 19:09:31 +08:00
if (!pEApp->getCurrentScene())
2017-10-14 01:07:34 +08:00
{
2017-10-21 19:09:31 +08:00
if (pEApp->onCloseWindow())
{
DestroyWindow(hWnd);
}
}
else
{
if (pEApp->getCurrentScene()->onCloseWindow() &&
pEApp->onCloseWindow())
{
DestroyWindow(hWnd);
}
2017-10-14 01:07:34 +08:00
}
2017-10-17 21:22:25 +08:00
}
result = 1;
wasHandled = true;
break;
// <20><><EFBFBD>ڱ<EFBFBD><DAB1><EFBFBD><EFBFBD><EFBFBD>
case WM_DESTROY:
{
// <20>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD>
pEApp->quit();
// <20><><EFBFBD><EFBFBD><EFBFBD>˳<EFBFBD><CBB3><EFBFBD>Ϣ
2017-10-12 02:44:44 +08:00
PostQuitMessage(0);
}
result = 1;
wasHandled = true;
break;
}
}
if (!wasHandled)
{
2017-10-13 11:42:36 +08:00
result = DefWindowProc(hWnd, message, wParam, lParam);
2017-10-12 02:44:44 +08:00
}
}
return result;
2017-09-10 23:56:52 +08:00
}