475 lines
No EOL
12 KiB
C++
Executable file
475 lines
No EOL
12 KiB
C++
Executable file
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
|
|
#include <fmt/printf.h>
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
|
|
#include "platform.hpp"
|
|
|
|
#include <gfx_vulkan.hpp>
|
|
#include <gfx_dummy.hpp>
|
|
#include <gfx_opengl.hpp>
|
|
|
|
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 <engine.hpp>
|
|
|
|
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 <GL/GL.h>
|
|
|
|
#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<int, int> platform::getCursorPosition() {
|
|
POINT p;
|
|
GetCursorPos(&p);
|
|
ScreenToClient(window, &p);
|
|
|
|
return {p.x, p.y};
|
|
}
|
|
|
|
std::tuple<int, int> platform::getWindowPosition() {
|
|
RECT rect;
|
|
GetWindowRect(window, &rect);
|
|
|
|
return {rect.left, rect.top};
|
|
}
|
|
|
|
std::tuple<int, int> 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());
|
|
} |