diff --git a/NonEuclidean/Engine.cpp b/NonEuclidean/Engine.cpp index 8409651..b2ebeba 100644 --- a/NonEuclidean/Engine.cpp +++ b/NonEuclidean/Engine.cpp @@ -6,7 +6,11 @@ #include "Level4.h" #include "Level5.h" #include "Level6.h" -#include +#if defined(_WIN32) + #include +#else + #include +#endif #include #include #include @@ -17,20 +21,13 @@ const Input* GH_INPUT = nullptr; int GH_REC_LEVEL = 0; int64_t GH_FRAME = 0; -LRESULT WINAPI StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - Engine* eng = (Engine*)GetWindowLongPtr(hWnd, GWLP_USERDATA); - if (eng) { - return eng->WindowProc(hWnd, uMsg, wParam, lParam); - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -Engine::Engine() : hWnd(NULL), hDC(NULL), hRC(NULL) { +Engine::Engine() { GH_ENGINE = this; GH_INPUT = &input; isFullscreen = false; - SetProcessDPIAware(); + isGood = InitOSWrapper(); + CreateGLWindow(); InitGLObjects(); SetupInputs(); @@ -52,82 +49,36 @@ Engine::Engine() : hWnd(NULL), hDC(NULL), hRC(NULL) { } Engine::~Engine() { - ClipCursor(NULL); - wglMakeCurrent(NULL, NULL); - ReleaseDC(hWnd, hDC); - wglDeleteContext(hRC); - DestroyWindow(hWnd); + DestroyGLWindow(); } int Engine::Run() { - if (!hWnd || !hDC || !hRC) { - return 1; - } + EnterMessageLoop(); + DestroyGLObjects(); + return 0; +} - //Recieve events from this window - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)this); - - //Setup the timer - const int64_t ticks_per_step = timer.SecondsToTicks(GH_DT); - int64_t cur_ticks = timer.GetTicks(); - GH_FRAME = 0; - - //Game loop - MSG msg; - while (true) { - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - //Handle windows messages - if (msg.message == WM_QUIT) { - break; - } else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } else { - //Confine the cursor - ConfineCursor(); - - if (input.key_press['1']) { - LoadScene(0); - } else if (input.key_press['2']) { - LoadScene(1); - } else if (input.key_press['3']) { - LoadScene(2); - } else if (input.key_press['4']) { - LoadScene(3); - } else if (input.key_press['5']) { - LoadScene(4); - } else if (input.key_press['6']) { - LoadScene(5); - } else if (input.key_press['7']) { - LoadScene(6); - } +void Engine::PeriodicRender(int64_t cur_ticks) { - //Used fixed time steps for updates - const int64_t new_ticks = timer.GetTicks(); - for (int i = 0; cur_ticks < new_ticks && i < GH_MAX_STEPS; ++i) { - Update(); - cur_ticks += ticks_per_step; - GH_FRAME += 1; - input.EndFrame(); - } - cur_ticks = (cur_ticks < new_ticks ? new_ticks: cur_ticks); - - //Setup camera for rendering - const float n = GH_CLAMP(NearestPortalDist() * 0.5f, GH_NEAR_MIN, GH_NEAR_MAX); - main_cam.worldView = player->WorldToCam(); - main_cam.SetSize(iWidth, iHeight, n, GH_FAR); - main_cam.UseViewport(); - - //Render scene - GH_REC_LEVEL = GH_MAX_RECURSION; - Render(main_cam, 0, nullptr); - SwapBuffers(hDC); - } + //Used fixed time steps for updates + const int64_t new_ticks = timer.GetTicks(); + for (int i = 0; cur_ticks < new_ticks && i < GH_MAX_STEPS; ++i) { + Update(); + cur_ticks += ticks_per_step; + GH_FRAME += 1; + input.EndFrame(); } + cur_ticks = (cur_ticks < new_ticks ? new_ticks: cur_ticks); - DestroyGLObjects(); - return 0; + //Setup camera for rendering + const float n = GH_CLAMP(NearestPortalDist() * 0.5f, GH_NEAR_MIN, GH_NEAR_MAX); + main_cam.worldView = player->WorldToCam(); + main_cam.SetSize(iWidth, iHeight, n, GH_FAR); + main_cam.UseViewport(); + + //Render scene + GH_REC_LEVEL = GH_MAX_RECURSION; + Render(main_cam, 0, nullptr); } void Engine::LoadScene(int ix) { @@ -269,149 +220,6 @@ void Engine::Render(const Camera& cam, GLuint curFBO, const Portal* skipPortal) #endif } -LRESULT Engine::WindowProc(HWND hCurWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - static PAINTSTRUCT ps; - static BYTE lpb[256]; - static UINT dwSize = sizeof(lpb); - - switch (uMsg) { - case WM_SYSCOMMAND: - if (wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) { - return 0; - } - break; - - case WM_PAINT: - BeginPaint(hCurWnd, &ps); - EndPaint(hCurWnd, &ps); - return 0; - - case WM_SIZE: - iWidth = LOWORD(lParam); - iHeight = HIWORD(lParam); - PostMessage(hCurWnd, WM_PAINT, 0, 0); - return 0; - - case WM_KEYDOWN: - //Ignore repeat keys - if (lParam & 0x40000000) { return 0; } - input.key[wParam & 0xFF] = true; - input.key_press[wParam & 0xFF] = true; - if (wParam == VK_ESCAPE) { - PostQuitMessage(0); - } - return 0; - - case WM_SYSKEYDOWN: - if (wParam == VK_RETURN) { - ToggleFullscreen(); - return 0; - } - break; - - case WM_KEYUP: - input.key[wParam & 0xFF] = false; - return 0; - - case WM_INPUT: - dwSize = sizeof(lpb); - GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)); - input.UpdateRaw((const RAWINPUT*)lpb); - break; - - case WM_CLOSE: - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hCurWnd, uMsg, wParam, lParam); -} - -void Engine::CreateGLWindow() { - WNDCLASSEX wc; - hInstance = GetModuleHandle(NULL); - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)StaticWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = GH_CLASS; - wc.hIconSm = NULL; - - if (!RegisterClassEx(&wc)) { - MessageBoxEx(NULL, "RegisterClass() failed: Cannot register window class.", "Error", MB_OK, 0); - return; - } - - //Always start in windowed mode - iWidth = GH_SCREEN_WIDTH; - iHeight = GH_SCREEN_HEIGHT; - - //Create the window - hWnd = CreateWindowEx( - WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, - GH_CLASS, - GH_TITLE, - WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - GH_SCREEN_X, - GH_SCREEN_Y, - iWidth, - iHeight, - NULL, - NULL, - hInstance, - NULL); - - if (hWnd == NULL) { - MessageBoxEx(NULL, "CreateWindow() failed: Cannot create a window.", "Error", MB_OK, 0); - return; - } - - hDC = GetDC(hWnd); - - PIXELFORMATDESCRIPTOR pfd; - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 32; - pfd.cDepthBits = 32; - pfd.iLayerType = PFD_MAIN_PLANE; - - const int pf = ChoosePixelFormat(hDC, &pfd); - if (pf == 0) { - MessageBoxEx(NULL, "ChoosePixelFormat() failed: Cannot find a suitable pixel format.", "Error", MB_OK, 0); - return; - } - - if (SetPixelFormat(hDC, pf, &pfd) == FALSE) { - MessageBoxEx(NULL, "SetPixelFormat() failed: Cannot set format specified.", "Error", MB_OK, 0); - return; - } - - DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - - hRC = wglCreateContext(hDC); - wglMakeCurrent(hDC, hRC); - - if (GH_START_FULLSCREEN) { - ToggleFullscreen(); - } - if (GH_HIDE_MOUSE) { - ShowCursor(FALSE); - } - - ShowWindow(hWnd, SW_SHOW); - SetForegroundWindow(hWnd); - SetFocus(hWnd); -} - void Engine::InitGLObjects() { //Initialize extensions glewInit(); @@ -427,8 +235,7 @@ void Engine::InitGLObjects() { //Check GL functionality glGetQueryiv(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB, &occlusionCullingSupported); - //Attempt to enalbe vsync (if failure then oh well) - wglSwapIntervalEXT(1); + EnableVSync(); } void Engine::DestroyGLObjects() { @@ -437,43 +244,6 @@ void Engine::DestroyGLObjects() { vPortals.clear(); } -void Engine::SetupInputs() { - static const int HID_USAGE_PAGE_GENERIC = 0x01; - static const int HID_USAGE_GENERIC_MOUSE = 0x02; - static const int HID_USAGE_GENERIC_JOYSTICK = 0x04; - static const int HID_USAGE_GENERIC_GAMEPAD = 0x05; - - RAWINPUTDEVICE Rid[3]; - - //Mouse - Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; - Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; - Rid[0].dwFlags = RIDEV_INPUTSINK; - Rid[0].hwndTarget = hWnd; - - //Joystick - Rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC; - Rid[1].usUsage = HID_USAGE_GENERIC_JOYSTICK; - Rid[1].dwFlags = 0; - Rid[1].hwndTarget = 0; - - //Gamepad - Rid[2].usUsagePage = HID_USAGE_PAGE_GENERIC; - Rid[2].usUsage = HID_USAGE_GENERIC_GAMEPAD; - Rid[2].dwFlags = 0; - Rid[2].hwndTarget = 0; - - RegisterRawInputDevices(Rid, 3, sizeof(Rid[0])); -} - -void Engine::ConfineCursor() { - if (GH_HIDE_MOUSE) { - RECT rect; - GetWindowRect(hWnd, &rect); - SetCursorPos((rect.right + rect.left) / 2, (rect.top + rect.bottom) / 2); - } -} - float Engine::NearestPortalDist() const { float dist = FLT_MAX; for (size_t i = 0; i < vPortals.size(); ++i) { @@ -481,22 +251,3 @@ float Engine::NearestPortalDist() const { } return dist; } - -void Engine::ToggleFullscreen() { - isFullscreen = !isFullscreen; - if (isFullscreen) { - iWidth = GetSystemMetrics(SM_CXSCREEN); - iHeight = GetSystemMetrics(SM_CYSCREEN); - SetWindowLong(hWnd, GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); - SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW); - SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, - iWidth, iHeight, SWP_SHOWWINDOW); - } else { - iWidth = GH_SCREEN_WIDTH; - iHeight = GH_SCREEN_HEIGHT; - SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); - SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); - SetWindowPos(hWnd, HWND_TOP, GH_SCREEN_X, GH_SCREEN_Y, - iWidth, iHeight, SWP_SHOWWINDOW); - } -} diff --git a/NonEuclidean/Engine.h b/NonEuclidean/Engine.h index ea8e9d1..d15d1a6 100644 --- a/NonEuclidean/Engine.h +++ b/NonEuclidean/Engine.h @@ -9,7 +9,11 @@ #include "Scene.h" #include "Sky.h" #include -#include +#if defined(_WIN32) + #include +#else + #include "SDL.h" +#endif #include #include @@ -23,26 +27,46 @@ class Engine { void Render(const Camera& cam, GLuint curFBO, const Portal* skipPortal); void LoadScene(int ix); +#if defined(_WIN32) LRESULT WindowProc(HWND hCurWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +#endif const Player& GetPlayer() const { return *player; } float NearestPortalDist() const; private: + bool InitOSWrapper(); void CreateGLWindow(); + void DestroyGLWindow(); void InitGLObjects(); void DestroyGLObjects(); void SetupInputs(); void ConfineCursor(); void ToggleFullscreen(); + int EnterMessageLoop(); + void PeriodicRender(int64_t cur_ticks); + void SwapBuffers(); + void EnableVSync(); - HDC hDC; // device context - HGLRC hRC; // opengl context - HWND hWnd; // window - HINSTANCE hInstance; // process id +#if defined(_WIN32) + HWND hWnd = nullptr; // window + HDC hDC = nullptr; // device context + HGLRC hRC = nullptr; // opengl context + HINSTANCE hInstance; // process id LONG iWidth; // window width LONG iHeight; // window height +#else + SDL_Window* window = nullptr; + SDL_GLContext glContext = nullptr; + int iWidth = 0; + int iHeight = 0; +#endif + + int64_t ticks_per_step = 0; + + bool isGood = false; // initialized without problems + bool isWindowGood = false; // window successfully created and initialized bool isFullscreen; // fullscreen state Camera main_cam; diff --git a/NonEuclidean/Engine_SDL2.cpp b/NonEuclidean/Engine_SDL2.cpp new file mode 100644 index 0000000..5126346 --- /dev/null +++ b/NonEuclidean/Engine_SDL2.cpp @@ -0,0 +1,130 @@ +#include "Engine.h" +#include "Physical.h" +#include "Level1.h" +#include "Level2.h" +#include "Level3.h" +#include "Level4.h" +#include "Level5.h" +#include "Level6.h" +#include "SDL.h" +#include +#include +#include +#include + +// --- SDL2-specific code ------------------------------------------------ + +bool Engine::InitOSWrapper() { + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { + SDL_Log("Unable to initialize SDL: %s", SDL_GetError()); + return false; + } + + atexit(SDL_Quit); // SDL will be shut down automatically on app exit + return true; +} + +void Engine::SetupInputs() { + // not needed +} + +void Engine::CreateGLWindow() { + iWidth = GH_SCREEN_WIDTH; + iHeight = GH_SCREEN_HEIGHT; + + window = SDL_CreateWindow( + GH_TITLE, + GH_SCREEN_X, GH_SCREEN_Y, + iWidth, iHeight, + SDL_WINDOW_OPENGL|SDL_WINDOW_ALLOW_HIGHDPI| + (GH_START_FULLSCREEN ? SDL_WINDOW_FULLSCREEN : 0) + ); + if (!window) { + SDL_Log("Unable to create GL window: %s", SDL_GetError()); + return; + } + + // window successfully created + + glContext = SDL_GL_CreateContext(window); + if (!glContext) { + SDL_Log("Unable to create GL context: %s", SDL_GetError()); + return; + } + + // GL context is created and is current for the calling thread + + isWindowGood = true; +} + +void Engine::DestroyGLWindow() { + if (glContext) { + SDL_GL_DeleteContext(glContext); + } + if (window) { + SDL_DestroyWindow(window); + } +} + +void Engine::EnableVSync() { + + // try adaptive vsync first, if not supported, go full vsync + if (SDL_GL_SetSwapInterval(-1) != 0) { + SDL_GL_SetSwapInterval(1); + } +} + +int Engine::EnterMessageLoop() { + + //Setup the timer + ticks_per_step = timer.SecondsToTicks(GH_DT); + int64_t cur_ticks = timer.GetTicks(); + GH_FRAME = 0; + + SDL_Event event; + while(true) { + if (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + break; + } + } + else { + + input.UpdateRaw(); + + //Confine the cursor + ConfineCursor(); + + if (input.key_press['1']) { + LoadScene(0); + } else if (input.key_press['2']) { + LoadScene(1); + } else if (input.key_press['3']) { + LoadScene(2); + } else if (input.key_press['4']) { + LoadScene(3); + } else if (input.key_press['5']) { + LoadScene(4); + } else if (input.key_press['6']) { + LoadScene(5); + } else if (input.key_press['7']) { + LoadScene(6); + } + + PeriodicRender(cur_ticks); + SwapBuffers(); + } + } + + return 0; +} + +void Engine::ConfineCursor() +{ + // TODO +} + +void Engine::SwapBuffers() +{ + SDL_GL_SwapWindow(window); +} diff --git a/NonEuclidean/Engine_Win32.cpp b/NonEuclidean/Engine_Win32.cpp new file mode 100644 index 0000000..ef326cf --- /dev/null +++ b/NonEuclidean/Engine_Win32.cpp @@ -0,0 +1,298 @@ +#include "Engine.h" +#include "Physical.h" +#include "Level1.h" +#include "Level2.h" +#include "Level3.h" +#include "Level4.h" +#include "Level5.h" +#include "Level6.h" +#if defined(_WIN32) + #include +#endif +#include +#include +#include + +// --- Windows-specific code ------------------------------------------------ + +#if defined(_WIN32) + +LRESULT WINAPI StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + Engine* eng = (Engine*)GetWindowLongPtr(hWnd, GWLP_USERDATA); + if (eng) { + return eng->WindowProc(hWnd, uMsg, wParam, lParam); + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +LRESULT Engine::WindowProc(HWND hCurWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + static PAINTSTRUCT ps; + static BYTE lpb[256]; + static UINT dwSize = sizeof(lpb); + + switch (uMsg) { + case WM_SYSCOMMAND: + if (wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) { + return 0; + } + break; + + case WM_PAINT: + BeginPaint(hCurWnd, &ps); + EndPaint(hCurWnd, &ps); + return 0; + + case WM_SIZE: + iWidth = LOWORD(lParam); + iHeight = HIWORD(lParam); + PostMessage(hCurWnd, WM_PAINT, 0, 0); + return 0; + + case WM_KEYDOWN: + //Ignore repeat keys + if (lParam & 0x40000000) { return 0; } + input.key[wParam & 0xFF] = true; + input.key_press[wParam & 0xFF] = true; + if (wParam == VK_ESCAPE) { + PostQuitMessage(0); + } + return 0; + + case WM_SYSKEYDOWN: + if (wParam == VK_RETURN) { + ToggleFullscreen(); + return 0; + } + break; + + case WM_KEYUP: + input.key[wParam & 0xFF] = false; + return 0; + + case WM_INPUT: + dwSize = sizeof(lpb); + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)); + input.UpdateRaw((const RAWINPUT*)lpb); + break; + + case WM_CLOSE: + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hCurWnd, uMsg, wParam, lParam); +} + +bool Engine::InitOSWrapper() { + return true; // there is no wrapper, we are using Windows API directly +} + +void Engine::ToggleFullscreen() { + isFullscreen = !isFullscreen; + if (isFullscreen) { + iWidth = GetSystemMetrics(SM_CXSCREEN); + iHeight = GetSystemMetrics(SM_CYSCREEN); + SetWindowLong(hWnd, GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); + SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW); + SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, + iWidth, iHeight, SWP_SHOWWINDOW); + } else { + iWidth = GH_SCREEN_WIDTH; + iHeight = GH_SCREEN_HEIGHT; + SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); + SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); + SetWindowPos(hWnd, HWND_TOP, GH_SCREEN_X, GH_SCREEN_Y, + iWidth, iHeight, SWP_SHOWWINDOW); + } +} + +void Engine::SetupInputs() { + static const int HID_USAGE_PAGE_GENERIC = 0x01; + static const int HID_USAGE_GENERIC_MOUSE = 0x02; + static const int HID_USAGE_GENERIC_JOYSTICK = 0x04; + static const int HID_USAGE_GENERIC_GAMEPAD = 0x05; + + RAWINPUTDEVICE Rid[3]; + + //Mouse + Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; + Rid[0].dwFlags = RIDEV_INPUTSINK; + Rid[0].hwndTarget = hWnd; + + //Joystick + Rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC; + Rid[1].usUsage = HID_USAGE_GENERIC_JOYSTICK; + Rid[1].dwFlags = 0; + Rid[1].hwndTarget = 0; + + //Gamepad + Rid[2].usUsagePage = HID_USAGE_PAGE_GENERIC; + Rid[2].usUsage = HID_USAGE_GENERIC_GAMEPAD; + Rid[2].dwFlags = 0; + Rid[2].hwndTarget = 0; + + RegisterRawInputDevices(Rid, 3, sizeof(Rid[0])); +} + +void Engine::ConfineCursor() { + if (GH_HIDE_MOUSE) { + RECT rect; + GetWindowRect(hWnd, &rect); + SetCursorPos((rect.right + rect.left) / 2, (rect.top + rect.bottom) / 2); + } +} + +void Engine::CreateGLWindow() { + SetProcessDPIAware(); + + WNDCLASSEX wc; + hInstance = GetModuleHandle(NULL); + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)StaticWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = GH_CLASS; + wc.hIconSm = NULL; + + if (!RegisterClassEx(&wc)) { + MessageBoxEx(NULL, "RegisterClass() failed: Cannot register window class.", "Error", MB_OK, 0); + return; + } + + //Always start in windowed mode + iWidth = GH_SCREEN_WIDTH; + iHeight = GH_SCREEN_HEIGHT; + + //Create the window + hWnd = CreateWindowEx( + WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, + GH_CLASS, + GH_TITLE, + WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + GH_SCREEN_X, + GH_SCREEN_Y, + iWidth, + iHeight, + NULL, + NULL, + hInstance, + NULL); + + if (hWnd == NULL) { + MessageBoxEx(NULL, "CreateWindow() failed: Cannot create a window.", "Error", MB_OK, 0); + return; + } + + hDC = GetDC(hWnd); + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 32; + pfd.iLayerType = PFD_MAIN_PLANE; + + const int pf = ChoosePixelFormat(hDC, &pfd); + if (pf == 0) { + MessageBoxEx(NULL, "ChoosePixelFormat() failed: Cannot find a suitable pixel format.", "Error", MB_OK, 0); + return; + } + + if (SetPixelFormat(hDC, pf, &pfd) == FALSE) { + MessageBoxEx(NULL, "SetPixelFormat() failed: Cannot set format specified.", "Error", MB_OK, 0); + return; + } + + DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + + if (GH_START_FULLSCREEN) { + ToggleFullscreen(); + } + if (GH_HIDE_MOUSE) { + ShowCursor(FALSE); + } + + ShowWindow(hWnd, SW_SHOW); + SetForegroundWindow(hWnd); + SetFocus(hWnd); +} + +void Engine::DestroyGLWindow() { + ClipCursor(NULL); + wglMakeCurrent(NULL, NULL); + ReleaseDC(hWnd, hDC); + wglDeleteContext(hRC); + DestroyWindow(hWnd); +} + +int Engine::EnterMessageLoop() { + if (!hWnd || !hDC || !hRC) { + return 1; + } + + //Recieve events from this window + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)this); + + //Setup the timer + ticks_per_step = timer.SecondsToTicks(GH_DT); + int64_t cur_ticks = timer.GetTicks(); + GH_FRAME = 0; + + //Game loop + MSG msg; + while (true) { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + //Handle windows messages + if (msg.message == WM_QUIT) { + break; + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } else { + //Confine the cursor + ConfineCursor(); + + if (input.key_press['1']) { + LoadScene(0); + } else if (input.key_press['2']) { + LoadScene(1); + } else if (input.key_press['3']) { + LoadScene(2); + } else if (input.key_press['4']) { + LoadScene(3); + } else if (input.key_press['5']) { + LoadScene(4); + } else if (input.key_press['6']) { + LoadScene(5); + } else if (input.key_press['7']) { + LoadScene(6); + } + + PeriodicRender(cur_ticks); + SwapBuffers(hDC); + } + } + + return 0; +} + +void Engine::EnableVSync() { + //Attempt to enalbe vsync (if failure then oh well) + wglSwapIntervalEXT(1); +} + +#endif // _WIN32 diff --git a/NonEuclidean/Input.cpp b/NonEuclidean/Input.cpp index 3faaa4f..1843e2b 100644 --- a/NonEuclidean/Input.cpp +++ b/NonEuclidean/Input.cpp @@ -1,6 +1,10 @@ #include "Input.h" #include "GameHeader.h" -#include +#if defined(_WIN32) + #include +#else + #include "SDL.h" +#endif #include Input::Input() { @@ -16,6 +20,8 @@ void Input::EndFrame() { mouse_ddy = 0.0f; } +#if defined(_WIN32) + void Input::UpdateRaw(const tagRAWINPUT* raw) { static BYTE buffer[2048]; static UINT buffer_size = sizeof(buffer); @@ -44,3 +50,41 @@ void Input::UpdateRaw(const tagRAWINPUT* raw) { //TODO: } } + +#else + +void Input::UpdateRaw() { + + // read mouse position and buttons + int mouse_x, mouse_y; + uint32_t state = SDL_GetRelativeMouseState(&mouse_x, &mouse_y); + mouse_dx = (float)mouse_x; + mouse_dy = (float)mouse_y; + mouse_ddx += mouse_dx; + mouse_ddy += mouse_dy; + if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) { + mouse_button[0] = true; + mouse_button_press[0] = true; + } + if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) { + mouse_button[1] = true; + mouse_button_press[1] = true; + } + if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) { + mouse_button[2] = true; + mouse_button_press[2] = true; + } + + // read key state + const uint8_t* immediate_keys = SDL_GetKeyboardState(nullptr); + for (int k='A'; k<='Z'; k++) { + key[k] = immediate_keys[SDL_SCANCODE_A + (k - 'A')]; + key_press[k] = immediate_keys[SDL_SCANCODE_A + (k - 'A')]; + } + for (int k='0'; k<='9'; k++) { + key[k] = immediate_keys[SDL_SCANCODE_0 + (k - '0')]; + key_press[k] = immediate_keys[SDL_SCANCODE_0 + (k - '0')]; + } +} + +#endif diff --git a/NonEuclidean/Input.h b/NonEuclidean/Input.h index febe919..775564b 100644 --- a/NonEuclidean/Input.h +++ b/NonEuclidean/Input.h @@ -6,7 +6,12 @@ class Input { Input(); void EndFrame(); + +#if defined(_WIN32) void UpdateRaw(const tagRAWINPUT* raw); +#else + void UpdateRaw(); +#endif //Keyboard bool key[256]; diff --git a/NonEuclidean/Main.cpp b/NonEuclidean/Main.cpp index d2a2e11..96362cd 100644 --- a/NonEuclidean/Main.cpp +++ b/NonEuclidean/Main.cpp @@ -1,6 +1,12 @@ -#define _CRT_SECURE_NO_WARNINGS +#if defined(_WIN32) + #define _CRT_SECURE_NO_WARNINGS +#endif #include "Engine.h" +#if defined(_WIN32) + +// --- Windows -------------------------------------------------------------- + int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpszCmdLine, int nCmdShow) { //Open console in debug mode #ifdef _DEBUG @@ -14,3 +20,14 @@ int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpsz Engine engine; return engine.Run(); } + +#else + +// --- non-Windows ---------------------------------------------------------- + +int main(int argc, char** argv) { + Engine engine; + return engine.Run(); +} + +#endif diff --git a/NonEuclidean/Makefile b/NonEuclidean/Makefile new file mode 100644 index 0000000..d0b064c --- /dev/null +++ b/NonEuclidean/Makefile @@ -0,0 +1,31 @@ +CXX=g++ -c +CXXFLAGS=-O2 -ggdb -I/usr/include/SDL2 +LINK=g++ +LINKFLAGS=-lm -lSDL2 -lSDL2main -lGLEW -lGL + +EXE=NonEuclidean + +HEADERS=Camera.h Collider.h Engine.h Floorplan.h FrameBuffer.h GameHeader.h \ + Ground.h House.h Input.h Mesh.h Object.h Physical.h Pillar.h PillarRoom.h \ + Player.h Portal.h Resources.h Scene.h Shader.h Sky.h Sphere.h Statue.h \ + Texture.h Timer.h Tunnel.h Vector.h \ + Level1.h Level2.h Level3.h Level4.h Level5.h Level6.h + +OBJS=Camera.o Collider.o Engine.o Engine_Win32.o Engine_SDL2.o \ + FrameBuffer.o Input.o \ + Level1.o Level2.o Level3.o Level4.o Level5.o Level6.o \ + Main.o Mesh.o Object.o Physical.o Player.o Portal.o \ + Resources.o Shader.o Texture.o + +.PHONY: all clean + +all: ${EXE} + +clean: + rm ${OBJS} + +${EXE}: ${OBJS} + ${LINK} ${LINKFLAGS} $^ -o ${EXE} + +%.o : %.cpp ${HEADERS} + ${CXX} ${CXXFLAGS} $*.cpp -o $*.o diff --git a/NonEuclidean/Player.cpp b/NonEuclidean/Player.cpp index 69c66e7..a4f18b4 100644 --- a/NonEuclidean/Player.cpp +++ b/NonEuclidean/Player.cpp @@ -1,7 +1,9 @@ #include "Player.h" #include "Input.h" #include "GameHeader.h" -#include +#if defined(_WIN32) + #include +#endif #include Player::Player() { diff --git a/NonEuclidean/Shader.h b/NonEuclidean/Shader.h index 6ff91ea..b17a3f2 100644 --- a/NonEuclidean/Shader.h +++ b/NonEuclidean/Shader.h @@ -1,4 +1,6 @@ #pragma once +#include +#include #include #include diff --git a/NonEuclidean/Timer.h b/NonEuclidean/Timer.h index 9713a11..501bd54 100644 --- a/NonEuclidean/Timer.h +++ b/NonEuclidean/Timer.h @@ -1,4 +1,9 @@ #pragma once + +#if defined(_WIN32) + +// --- Windows -------------------------------------------------------------- + #include class Timer { @@ -35,3 +40,46 @@ class Timer { LARGE_INTEGER frequency; // ticks per second LARGE_INTEGER t1, t2; // ticks }; + +#else + +// --- non-Windows ---------------------------------------------------------- + +#include "SDL.h" + +class Timer { +public: + Timer() { + frequency = SDL_GetPerformanceFrequency(); + } + + void Start() { + t1 = SDL_GetPerformanceCounter(); + } + + float Stop() { + t2 = SDL_GetPerformanceCounter(); + return float(t2 - t1) / frequency; + } + + int64_t GetTicks() { + t2 = SDL_GetPerformanceCounter(); + return t2; + } + + int64_t SecondsToTicks(float s) { + return int64_t(float(frequency) * s); + } + + float StopStart() { + const float result = Stop(); + t1 = t2; + return result; + } + +private: + int64_t frequency; // ticks per second + int64_t t1, t2; // ticks +}; + +#endif