#ifndef UNICODE #define UNICODE #endif #include #include #include #include "platform.hpp" #include #include #include typedef HGLRC WINAPI wglCreateContextAttribsARB_type(HDC hdc, HGLRC hShareContext, const int *attribList); wglCreateContextAttribsARB_type *wglCreateContextAttribsARB; // See https://www.opengl.org/registry/specs/ARB/wgl_create_context.txt for all values #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 typedef BOOL WINAPI wglChoosePixelFormatARB_type(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); wglChoosePixelFormatARB_type *wglChoosePixelFormatARB; // See https://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt for all values #define WGL_DRAW_TO_WINDOW_ARB 0x2001 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_FULL_ACCELERATION_ARB 0x2027 #define WGL_TYPE_RGBA_ARB 0x202B #if @IS_GAME@ #include <@GAME_INCLUDE@> #else #include <@EDITOR_INCLUDE@> #endif #include GFX* ginterface = nullptr; #if @IS_GAME@ @GAME_CLASS@* game = nullptr; #else @EDITOR_CLASS@* editor = nullptr; #endif HINSTANCE instance = NULL; HWND window = NULL; int cmdShow = 0; HDC windowDC = NULL; int defaultWidth, defaultHeight; bool shouldConfineMouse = false; #include #pragma comment (lib, "opengl32.lib") const wchar_t CLASS_NAME[] = L"@GAME_NAME@"; wchar_t* convertToUnicode(const char* str) { size_t ret = 0; mbsrtowcs_s(&ret, NULL, 0, &str, 0, NULL); wchar_t * buf = new wchar_t[ret + 1](); mbsrtowcs_s(&ret, buf, ret + 1 , &str, ret + 1, NULL); return buf; } void platform::openWindow(const char* title, int x, int y, int width, int height, WindowFlags flags) { RECT wr = {0, 0, width, height}; AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); defaultWidth = width; defaultHeight = height; std::string new_title = title + std::string(" (") + ginterface->getName() + ")"; wchar_t* title_uni = convertToUnicode(new_title.c_str()); window = CreateWindowEx( 0, CLASS_NAME, title_uni, flags == WindowFlags::Resizable ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX), // Window style x, y, wr.right - wr.left, wr.bottom - wr.top, NULL, NULL, instance, NULL ); delete[] title_uni; ShowWindow(window, cmdShow); engine->addWindow(window, width, height); } void platform::closeWindow() { // does nothing } bool showingCursor = true; void platform::setCaptureMouse(bool capture) { shouldConfineMouse = capture; // the reason why we do this is because windows expects a ShowCursor(false) to be followed by a ShowCursor(true), // if you don't do this your cursor pretty much gets sent to bill gate's purgatory and it can never escape // so this code is to ensure every ShowCursor call gets matched by it's counterpart when you call setCaptureMouse if(showingCursor && capture) { ShowCursor(false); showingCursor = false; } else if(!showingCursor && !capture) { ShowCursor(true); showingCursor = true; } } std::tuple platform::getCursorPosition() { POINT p; GetCursorPos(&p); ScreenToClient(window, &p); return {p.x, p.y}; } std::tuple platform::getWindowPosition() { RECT rect; GetWindowRect(window, &rect); return {rect.left, rect.top}; } std::tuple platform::getWindowSize() { RECT rect; GetClientRect(window, &rect); int width = rect.right - rect.left; int height = rect.bottom- rect.top; return {width, height}; } static void init_opengl_extensions(void) { // Before we can load extensions, we need a dummy OpenGL context, created using a dummy window. // We use a dummy window because you can only set the pixel format for a window once. For the // real window, we want to use wglChoosePixelFormatARB (so we can potentially specify options // that aren't available in PIXELFORMATDESCRIPTOR), but we can't load and use that before we // have a context. WNDCLASSA window_class = {}; window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; window_class.lpfnWndProc = DefWindowProcA; window_class.hInstance = GetModuleHandle(0); window_class.lpszClassName = "Dummy_WGL_djuasiodwa"; if (!RegisterClassA(&window_class)) { fmt::print("Failed to register dummy OpenGL window.\n"); } HWND dummy_window = CreateWindowExA( 0, window_class.lpszClassName, "Dummy OpenGL Window", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, window_class.hInstance, 0); if (!dummy_window) { fmt::print("Failed to create dummy OpenGL window.\n"); } HDC dummy_dc = GetDC(dummy_window); PIXELFORMATDESCRIPTOR pfd = {}; pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.iPixelType = PFD_TYPE_RGBA; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.cColorBits = 32; pfd.cAlphaBits = 8; pfd.iLayerType = PFD_MAIN_PLANE; pfd.cDepthBits = 24; pfd.cStencilBits = 8; int pixel_format = ChoosePixelFormat(dummy_dc, &pfd); if (!pixel_format) { fmt::print("Failed to find a suitable pixel format.\n"); } if (!SetPixelFormat(dummy_dc, pixel_format, &pfd)) { fmt::print("Failed to set the pixel format."); } HGLRC dummy_context = wglCreateContext(dummy_dc); if (!dummy_context) { fmt::print("Failed to create a dummy OpenGL rendering context.\n"); } if (!wglMakeCurrent(dummy_dc, dummy_context)) { fmt::print("Failed to activate dummy OpenGL rendering context.\n"); } wglCreateContextAttribsARB = (wglCreateContextAttribsARB_type*)wglGetProcAddress( "wglCreateContextAttribsARB"); wglChoosePixelFormatARB = (wglChoosePixelFormatARB_type*)wglGetProcAddress( "wglChoosePixelFormatARB"); wglMakeCurrent(dummy_dc, 0); wglDeleteContext(dummy_context); ReleaseDC(dummy_window, dummy_dc); DestroyWindow(dummy_window); } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) { AllocConsole(); FILE* stream; freopen_s(&stream, "CONOUT$", "w", stdout); freopen_s(&stream, "CONOUT$", "w", stderr); WNDCLASS wc {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); instance = hInstance; cmdShow = nCmdShow; engine = new Engine(); ginterface = new GFXVulkan(); if(ginterface->initialize()) { engine->setGFX(ginterface); } else { return -1; } #if @IS_GAME@ game = new @GAME_CLASS@(); engine->setGame(game); #else editor = new @EDITOR_CLASS@(); engine->setEditor(editor); #endif app::open(engine); #if @IS_GAME@ game->initializeRender(); #else editor->initializeRender(); #endif MSG msg = { }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } #if @IS_GAME@ delete game; #else delete editor; #endif delete ginterface; delete engine; fclose(stream); return 0; } int timeout = 0; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: { if(ginterface->requiredContext() == GFXContext::OpenGL) { fmt::print("Creating OpenGL context...\n"); init_opengl_extensions(); PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. 32, // Colordepth of the framebuffer. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, // Number of bits for the depthbuffer 8, // Number of bits for the stencilbuffer 0, // Number of Aux buffers in the framebuffer. PFD_MAIN_PLANE, 0, 0, 0, 0 }; HDC ourWindowHandleToDeviceContext = GetDC(hwnd); int letWindowsChooseThisPixelFormat; letWindowsChooseThisPixelFormat = ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); SetPixelFormat(ourWindowHandleToDeviceContext,letWindowsChooseThisPixelFormat, &pfd); int attribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MINOR_VERSION_ARB, 3, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, }; HGLRC ourOpenGLRenderingContext = wglCreateContextAttribsARB(ourWindowHandleToDeviceContext,0, attribs); wglMakeCurrent (ourWindowHandleToDeviceContext, ourOpenGLRenderingContext); windowDC = GetDC(hwnd); MessageBoxA(0,(char*)glGetString(GL_VERSION), "OPENGL VERSION",0); } } return 0; case WM_DESTROY: { engine->prepareQuit(); PostQuitMessage(0); } return 0; case WM_PAINT: { if(shouldConfineMouse && timeout > 5) { RECT rect; GetClientRect(hwnd, &rect); int width = rect.right - rect.left; int height = rect.bottom- rect.top; POINT p; p.x = width / 2; p.y = height / 2; ClientToScreen(window, &p); SetCursorPos(p.x, p.y); timeout = 0; } timeout++; HCURSOR arrowCursor = LoadCursor(NULL, IDC_ARROW); SetCursor(arrowCursor); #if @IS_GAME@ #else editor->beginFrame(); #endif engine->update(1.0f / 60.0f); engine->render(); if(ginterface->requiredContext() == GFXContext::OpenGL) SwapBuffers(windowDC); if(engine->isQuitting()) { engine->prepareQuit(); PostQuitMessage(0); } } return 0; case WM_LBUTTONDOWN: { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); engine->processMouse(0, xPos, yPos); } return 0; case WM_LBUTTONUP: { engine->processMouseReleased(0); } return 0; case WM_RBUTTONDOWN: { engine->processMouse(1, 0, 0); } return 0; case WM_RBUTTONUP: { engine->processMouseReleased(1); } return 0; case WM_MOUSEMOVE: { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); engine->processMouseMove(xPos, yPos); } return 0; case WM_KEYDOWN: { engine->processKey((unsigned int)wParam); } return 0; case WM_KEYUP: { engine->processKeyUp((unsigned int)wParam); } return 0; case WM_SIZE: { RECT rect; GetClientRect(hwnd, &rect); int width = rect.right - rect.left; int height = rect.bottom- rect.top; if(width == defaultWidth && height == defaultHeight) { // don't resize when the window was first created!! } else { engine->resize(width, height); } } return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } void platform::setWindowTitle(const char* title) { std::string new_title = title + std::string(" (") + ginterface->getName() + ")"; SetWindowTextA(window, new_title.c_str()); }