Archived
1
Fork 0
This repository has been archived on 2025-04-12. You can view files and clone it, but cannot push or open issues or pull requests.
prism/platforms/windows/main.cpp.in
2020-08-11 12:07:21 -04:00

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());
}