cleaning up cmake defines; adding a Win32 Platform Backend

This commit is contained in:
Noel Berry 2021-03-23 01:56:53 -07:00
parent d34a55e2ac
commit 6fddd34ca5
11 changed files with 1009 additions and 254 deletions

View File

@ -56,6 +56,7 @@ add_library(blah
src/internal/graphics_backend_d3d11.cpp
src/internal/graphics_backend_dummy.cpp
src/internal/platform_backend_sdl2.cpp
src/internal/platform_backend_win32.cpp
)
target_include_directories(blah
@ -66,26 +67,28 @@ target_include_directories(blah
)
# Platform Variables
set(SDL2_ENABLED true CACHE BOOL "Use SDL2 as the System implementation")
set(OPENGL_ENABLED true CACHE BOOL "Use OpenGL graphics implementation")
set(D3D11_ENABLED false CACHE BOOL "Use D3D11 graphics implementation")
set(PLATFORM_SDL2 true CACHE BOOL "Use SDL2 Platform Backend")
set(PLATFORM_WIN32 false CACHE BOOL "Use Win32 Platform Backend")
set(GRAPHICS_OPENGL true CACHE BOOL "Use OpenGL Graphics Backend")
set(GRAPHICS_D3D11 false CACHE BOOL "Use D3D11 Graphics Backend")
set(LIBS "")
# add OpenGL definition if we're using it
if (OPENGL_ENABLED)
add_compile_definitions(BLAH_USE_OPENGL)
endif()
# use the OpenGL Graphics Backend
if (GRAPHICS_OPENGL)
add_compile_definitions(BLAH_GRAPHICS_OPENGL)
# add D3D11 definition if we're using it
if (D3D11_ENABLED)
add_compile_definitions(BLAH_USE_D3D11)
# use the D3D11 Graphics Backend
elseif (GRAPHICS_D3D11)
add_compile_definitions(BLAH_GRAPHICS_D3D11)
set(LIBS ${LIBS} d3d11.lib dxguid.lib D3Dcompiler.lib)
endif()
# Link and create SDL2 Definition if we're using it
if (SDL2_ENABLED)
add_compile_definitions(BLAH_USE_SDL2)
# use the SDL2 Platform Backend
# Link and create SDL2 Definition
if (PLATFORM_SDL2)
add_compile_definitions(BLAH_PLATFORM_SDL2)
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
set_target_properties(blah PROPERTIES COMPILE_FLAGS "-s USE_SDL=2")
else()
@ -96,6 +99,10 @@ if (SDL2_ENABLED)
target_include_directories(blah PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
set(LIBS ${LIBS} ${SDL2_LIBRARIES})
endif()
# use the Win32 Platform Backend
elseif (PLATFORM_WIN32)
add_compile_definitions(BLAH_PLATFORM_WIN32)
endif()
target_link_libraries(blah PUBLIC ${LIBS})

View File

@ -6,11 +6,12 @@ A small 2D C++ Game Framework, using few dependencies and simple code to mainain
#### building
- Requires C++17 and CMake 3.12+
- A single *Platform* backend must be enabled:
- [SDL2](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_sdl2.cpp) can be enabled in CMake with `SDL2_ENABLED`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES`
- [SDL2](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_sdl2.cpp) can be enabled in CMake with `PLATFORM_SDL2`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES`
- [WIN32](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_win32.cpp) (UNFINISHED) can be enabled in CMake with `PLATFORM_WIN32`.
- Additional backends can be added by implementing the [Platform Backend](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend.h)
- A single *Graphics* backend must be enabled:
- [OpenGL](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_gl.cpp) can be enabled in CMake with `OPENGL_ENABLED`.
- [D3D11](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_d3d11.cpp) can be enabled in CMake with `D3D11_ENABLED`.
- [OpenGL](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_gl.cpp) can be enabled in CMake with `GRAPHICS_OPENGL`.
- [D3D11](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_d3d11.cpp) can be enabled in CMake with `GRAPHICS_D3D11`.
- Additional backends can be added by implementing the [Graphics Backend](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend.h).
#### notes

View File

@ -102,7 +102,9 @@ namespace Blah
// Returns whether the application is running
bool is_running();
// Exits the application
// Exits the application.
// This only signals for the application to close, it will not stop
// until the current update and render calls are finished.
void exit();
// Gets the config data used to run the application
@ -120,16 +122,20 @@ namespace Blah
// Gets the height of the window
int height();
// Gets the drawable width of the window
// Gets the drawable width of the window, in pixels.
// This may differ from the width when on platforms with High DPI Displays.
int draw_width();
// Gets the drawable height of the window
// Gets the drawable height of the window, in pixels.
// This may differ from the height when on platforms with High DPI Displays.
int draw_height();
// Gets the content scale based on the OS
// Gets the content scale based on the platform.
// macOS is usually 2.0, other platforms vary.
float content_scale();
// Toggles fullscreen
// Toggles fullscreen if supported on the platform.
// Otherwise this function does nothing.
void fullscreen(bool enabled);
// Returns the Rendering API in use

View File

@ -4,9 +4,12 @@
#include <blah/math/vec2.h>
#include <blah/containers/str.h>
// These are generally copied from the SDL2 Scancode Keys
// These are generally copied from the SDL2 Scancode Keys,
// which are in turn based on the USB standards:
// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
#define BLAH_KEY_DEFINITIONS \
DEFINE_KEY(Unknown, 0) \
\
DEFINE_KEY(A, 4) \
DEFINE_KEY(B, 5) \
DEFINE_KEY(C, 6) \
@ -33,6 +36,7 @@
DEFINE_KEY(X, 27) \
DEFINE_KEY(Y, 28) \
DEFINE_KEY(Z, 29) \
\
DEFINE_KEY(D1, 30) \
DEFINE_KEY(D2, 31) \
DEFINE_KEY(D3, 32) \
@ -43,24 +47,27 @@
DEFINE_KEY(D8, 37) \
DEFINE_KEY(D9, 38) \
DEFINE_KEY(D0, 39) \
\
DEFINE_KEY(Enter, 40) \
DEFINE_KEY(Escape, 41) \
DEFINE_KEY(Backspace, 42) \
DEFINE_KEY(Tab, 43) \
DEFINE_KEY(Space, 44) \
\
DEFINE_KEY(Minus, 45) \
DEFINE_KEY(Equals, 46) \
DEFINE_KEY(LeftBracket, 47) \
DEFINE_KEY(RightBracket, 48) \
DEFINE_KEY(BackSlash, 49) \
DEFINE_KEY(NonUSHash, 50) \
DEFINE_KEY(Backslash, 49) \
DEFINE_KEY(Semicolon, 51) \
DEFINE_KEY(Apostrophe, 52) \
DEFINE_KEY(Grave, 53) \
DEFINE_KEY(Tilde, 53) \
DEFINE_KEY(Comma, 54) \
DEFINE_KEY(Period, 55) \
DEFINE_KEY(Slash, 56) \
\
DEFINE_KEY(Capslock, 57) \
\
DEFINE_KEY(F1, 58) \
DEFINE_KEY(F2, 59) \
DEFINE_KEY(F3, 60) \
@ -73,6 +80,19 @@
DEFINE_KEY(F10, 67) \
DEFINE_KEY(F11, 68) \
DEFINE_KEY(F12, 69) \
DEFINE_KEY(F13, 104) \
DEFINE_KEY(F14, 105) \
DEFINE_KEY(F15, 106) \
DEFINE_KEY(F16, 107) \
DEFINE_KEY(F17, 108) \
DEFINE_KEY(F18, 109) \
DEFINE_KEY(F19, 110) \
DEFINE_KEY(F20, 111) \
DEFINE_KEY(F21, 112) \
DEFINE_KEY(F22, 113) \
DEFINE_KEY(F23, 114) \
DEFINE_KEY(F24, 115) \
\
DEFINE_KEY(PrintScreen, 70) \
DEFINE_KEY(ScrollLock, 71) \
DEFINE_KEY(Pause, 72) \
@ -86,45 +106,17 @@
DEFINE_KEY(Left, 80) \
DEFINE_KEY(Down, 81) \
DEFINE_KEY(Up, 82) \
DEFINE_KEY(NumlockClear, 83) \
DEFINE_KEY(KP_Divide, 84) \
DEFINE_KEY(KP_Multiply, 85) \
DEFINE_KEY(KP_Minus, 86) \
DEFINE_KEY(KP_Plus, 87) \
DEFINE_KEY(KP_Enter, 88) \
DEFINE_KEY(KP_1, 89) \
DEFINE_KEY(KP_2, 90) \
DEFINE_KEY(KP_3, 91) \
DEFINE_KEY(KP_4, 92) \
DEFINE_KEY(KP_5, 93) \
DEFINE_KEY(KP_6, 94) \
DEFINE_KEY(KP_7, 95) \
DEFINE_KEY(KP_8, 96) \
DEFINE_KEY(KP_9, 97) \
DEFINE_KEY(KP_0, 98) \
DEFINE_KEY(KP_Period, 99) \
DEFINE_KEY(NonUSBackSlash, 100) \
\
DEFINE_KEY(Numlock, 83) \
\
DEFINE_KEY(Application, 101) \
DEFINE_KEY(Power, 102) \
DEFINE_KEY(KP_Equals, 103) \
DEFINE_KEY(F13, 104) \
DEFINE_KEY(F14, 105) \
DEFINE_KEY(F15, 106) \
DEFINE_KEY(F16, 107) \
DEFINE_KEY(F17, 108) \
DEFINE_KEY(F18, 109) \
DEFINE_KEY(F19, 110) \
DEFINE_KEY(F20, 111) \
DEFINE_KEY(F21, 112) \
DEFINE_KEY(F22, 113) \
DEFINE_KEY(F23, 114) \
DEFINE_KEY(F24, 115) \
\
DEFINE_KEY(Execute, 116) \
DEFINE_KEY(Help, 117) \
DEFINE_KEY(Menu, 118) \
DEFINE_KEY(Select, 119) \
DEFINE_KEY(Stop, 120) \
DEFINE_KEY(Again, 121) \
DEFINE_KEY(Redo, 121) \
DEFINE_KEY(Undo, 122) \
DEFINE_KEY(Cut, 123) \
DEFINE_KEY(Copy, 124) \
@ -133,92 +125,69 @@
DEFINE_KEY(Mute, 127) \
DEFINE_KEY(VolumeUp, 128) \
DEFINE_KEY(VolumeDown, 129) \
DEFINE_KEY(KP_Comma, 133) \
DEFINE_KEY(KP_EqualsAs400, 134) \
DEFINE_KEY(International1, 135) \
DEFINE_KEY(International2, 136) \
DEFINE_KEY(International3, 137) \
DEFINE_KEY(International4, 138) \
DEFINE_KEY(International5, 139) \
DEFINE_KEY(International6, 140) \
DEFINE_KEY(International7, 141) \
DEFINE_KEY(International8, 142) \
DEFINE_KEY(International9, 143) \
DEFINE_KEY(Language1, 144) \
DEFINE_KEY(Language2, 145) \
DEFINE_KEY(Language3, 146) \
DEFINE_KEY(Language4, 147) \
DEFINE_KEY(Language5, 148) \
DEFINE_KEY(Language6, 149) \
DEFINE_KEY(Language7, 150) \
DEFINE_KEY(Language8, 151) \
DEFINE_KEY(Language9, 152) \
\
DEFINE_KEY(AltErase, 153) \
DEFINE_KEY(SysReq, 154) \
DEFINE_KEY(Cancel, 155) \
DEFINE_KEY(clear, 156) \
DEFINE_KEY(Clear, 156) \
DEFINE_KEY(Prior, 157) \
DEFINE_KEY(Return2, 158) \
DEFINE_KEY(Enter2, 158) \
DEFINE_KEY(Separator, 159) \
DEFINE_KEY(Out, 160) \
DEFINE_KEY(Oper, 161) \
DEFINE_KEY(ClearAgain, 162) \
DEFINE_KEY(CRSEL, 163) \
DEFINE_KEY(EXSEL, 164) \
DEFINE_KEY(KP_00, 176) \
DEFINE_KEY(KP_000, 177) \
DEFINE_KEY(ThousandsSeparator, 178) \
DEFINE_KEY(DecimalSeparator, 179) \
DEFINE_KEY(CurrencyUnit, 180) \
DEFINE_KEY(CurrencySubUnit, 181) \
DEFINE_KEY(KP_LeftParen, 182) \
DEFINE_KEY(KP_RightParent, 183) \
DEFINE_KEY(KP_LeftBrace, 184) \
DEFINE_KEY(KP_RightBrace, 185) \
DEFINE_KEY(KP_Tab, 186) \
DEFINE_KEY(KP_BackSpace, 187) \
DEFINE_KEY(KP_A, 188) \
DEFINE_KEY(KP_B, 189) \
DEFINE_KEY(KP_C, 190) \
DEFINE_KEY(KP_D, 191) \
DEFINE_KEY(KP_E, 192) \
DEFINE_KEY(KP_F, 193) \
DEFINE_KEY(KP_XOR, 194) \
DEFINE_KEY(KP_Power, 195) \
DEFINE_KEY(KP_Percent, 196) \
DEFINE_KEY(KP_Less, 197) \
DEFINE_KEY(KP_Greater, 198) \
DEFINE_KEY(KP_Ampersand, 199) \
DEFINE_KEY(KP_DoubleAmpersand, 200) \
DEFINE_KEY(KP_VerticalBar, 201) \
DEFINE_KEY(KP_DoubleVerticalBar, 202) \
DEFINE_KEY(KP_Colon, 203) \
DEFINE_KEY(KP_Hash, 204) \
DEFINE_KEY(KP_Space, 205) \
DEFINE_KEY(KP_At, 206) \
DEFINE_KEY(KP_EXCLAM, 207) \
DEFINE_KEY(KP_MemStore, 208) \
DEFINE_KEY(KP_MemRecall, 209) \
DEFINE_KEY(KP_MemClear, 210) \
DEFINE_KEY(KP_MemAdd, 211) \
DEFINE_KEY(KP_MemSubstract, 212) \
DEFINE_KEY(KP_MemMultiply, 213) \
DEFINE_KEY(KP_MemDivide, 214) \
DEFINE_KEY(KP_PlusMinus, 215) \
DEFINE_KEY(KP_Clear, 216) \
DEFINE_KEY(KP_ClearEntry, 217) \
DEFINE_KEY(KP_Binary, 218) \
DEFINE_KEY(KP_Octal, 219) \
DEFINE_KEY(KP_Decimal, 220) \
DEFINE_KEY(KP_Hexadecimal, 221) \
\
DEFINE_KEY(KeypadA, 188) \
DEFINE_KEY(KeypadB, 189) \
DEFINE_KEY(KeypadC, 190) \
DEFINE_KEY(KeypadD, 191) \
DEFINE_KEY(KeypadE, 192) \
DEFINE_KEY(KeypadF, 193) \
DEFINE_KEY(Keypad0, 98) \
DEFINE_KEY(Keypad00, 176) \
DEFINE_KEY(Keypad000, 177) \
DEFINE_KEY(Keypad1, 89) \
DEFINE_KEY(Keypad2, 90) \
DEFINE_KEY(Keypad3, 91) \
DEFINE_KEY(Keypad4, 92) \
DEFINE_KEY(Keypad5, 93) \
DEFINE_KEY(Keypad6, 94) \
DEFINE_KEY(Keypad7, 95) \
DEFINE_KEY(Keypad8, 96) \
DEFINE_KEY(Keypad9, 97) \
DEFINE_KEY(KeypadDivide, 84) \
DEFINE_KEY(KeypadMultiply, 85) \
DEFINE_KEY(KeypadMinus, 86) \
DEFINE_KEY(KeypadPlus, 87) \
DEFINE_KEY(KeypadEnter, 88) \
DEFINE_KEY(KeypadPeroid, 99) \
DEFINE_KEY(KeypadEquals, 103) \
DEFINE_KEY(KeypadComma, 133) \
DEFINE_KEY(KeypadLeftParen, 182) \
DEFINE_KEY(KeypadRightParen, 183) \
DEFINE_KEY(KeypadLeftBrace, 184) \
DEFINE_KEY(KeypadRightBrace, 185) \
DEFINE_KEY(KeypadTab, 186) \
DEFINE_KEY(KeypadBackspace, 187) \
DEFINE_KEY(KeypadXor, 194) \
DEFINE_KEY(KeypadPower, 195) \
DEFINE_KEY(KeypadPercent, 196) \
DEFINE_KEY(KeypadLess, 197) \
DEFINE_KEY(KeypadGreater, 198) \
DEFINE_KEY(KeypadAmpersand, 199) \
DEFINE_KEY(KeypadColon, 203) \
DEFINE_KEY(KeypadHash, 204) \
DEFINE_KEY(KeypadSpace, 205) \
DEFINE_KEY(KeypadClear, 216) \
\
DEFINE_KEY(LeftControl, 224) \
DEFINE_KEY(LeftShift, 225) \
DEFINE_KEY(LeftAlt, 226) \
DEFINE_KEY(LeftGui, 227) \
DEFINE_KEY(LeftOS, 227) \
DEFINE_KEY(RightControl, 228) \
DEFINE_KEY(RightShift, 229) \
DEFINE_KEY(RightAlt, 230) \
DEFINE_KEY(RightGui, 231)
DEFINE_KEY(RightOS, 231)
#define BLAH_BUTTON_DEFINITIONS \
DEFINE_BTN(None, -1) \

View File

@ -15,9 +15,7 @@ namespace
// TODO:
// This shader needs to be graphics API agnostic
#ifdef BLAH_USE_OPENGL
const ShaderData shader_data = {
const ShaderData opengl_shader_data = {
// vertex shader
#ifdef __EMSCRIPTEN__
"#version 300 es\n"
@ -62,8 +60,6 @@ namespace
"}"
};
#elif BLAH_USE_D3D11
const char* d3d11_shader = ""
"cbuffer constants : register(b0)\n"
"{\n"
@ -110,7 +106,7 @@ namespace
" input.mask.z * input.color;\n"
"}\n";
const ShaderData shader_data = {
const ShaderData d3d11_shader_data = {
d3d11_shader,
d3d11_shader,
{
@ -121,10 +117,6 @@ namespace
}
};
#else
const ShaderData shader_data;
#endif
const VertexFormat format = VertexFormat(
{
{ 0, VertexType::Float2, false },
@ -384,7 +376,12 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
m_mesh = Mesh::create();
if (!m_default_shader)
m_default_shader = Shader::create(shader_data);
{
if (App::renderer() == Renderer::OpenGL)
m_default_shader = Shader::create(opengl_shader_data);
else if (App::renderer() == Renderer::D3D11)
m_default_shader = Shader::create(d3d11_shader_data);
}
if (!m_default_material)
m_default_material = Material::create(m_default_shader);

View File

@ -1,4 +1,4 @@
#ifdef BLAH_USE_D3D11
#ifdef BLAH_GRAPHICS_D3D11
// TODO:
// Note the D3D11 Implementation is still a work-in-progress
@ -1403,7 +1403,7 @@ namespace Blah
desc.RenderTarget[0].DestBlendAlpha = blend_factor(blend.alpha_dst);
}
for (int i = 1; i < 8; i ++)
for (int i = 1; i < 8; i++)
desc.RenderTarget[i] = desc.RenderTarget[0];
ID3D11BlendState* blend_state = nullptr;
@ -1548,4 +1548,4 @@ namespace Blah
}
}
#endif // BLAH_USE_D3D11
#endif // BLAH_GRAPHICS_D3D11

View File

@ -1,4 +1,4 @@
#if !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11))
#if !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11))
#include "../internal/graphics_backend.h"
#include "../internal/platform_backend.h"
@ -193,7 +193,7 @@ namespace Blah
const RendererFeatures& GraphicsBackend::features()
{
static const RendererFeatures features { false, true, 4096 };
static const RendererFeatures features{ false, true, 4096 };
return features;
}
@ -232,4 +232,4 @@ namespace Blah
}
}
#endif // !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11))
#endif // !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11))

View File

@ -1,4 +1,4 @@
#ifdef BLAH_USE_OPENGL
#ifdef BLAH_GRAPHICS_OPENGL
#include "../internal/graphics_backend.h"
#include "../internal/platform_backend.h"
@ -674,7 +674,7 @@ namespace Blah
GLuint m_id;
int m_width;
int m_height;
StackVector<TextureRef, BLAH_ATTACHMENTS> m_attachments;
StackVector<TextureRef, Attachments::MaxCapacity> m_attachments;
public:
@ -1517,4 +1517,4 @@ namespace Blah
}
}
#endif // BLAH_USE_OPENGL
#endif // BLAH_GRAPHICS_OPENGL

View File

@ -1,4 +1,4 @@
#ifdef BLAH_USE_SDL2
#ifdef BLAH_PLATFORM_SDL2
#include "../internal/platform_backend.h"
#include "../internal/input_backend.h"
@ -722,4 +722,4 @@ void* PlatformBackend::d3d11_get_hwnd()
#endif
}
#endif // BLAH_USE_SDL2
#endif // BLAH_PLATFORM_SDL2

View File

@ -0,0 +1,776 @@
#ifdef BLAH_PLATFORM_WIN32
// Note:
// This backend implementation is unfinished!
// It's missing a few things, namely:
// - Controller Support
// - Mouse wheel
// - Text input
// - Probably other stuff?
// (And error testing)
#include "../internal/platform_backend.h"
#include "../internal/input_backend.h"
#include "../internal/graphics_backend.h"
#include <blah/input/input.h>
#include <blah/core/app.h>
#include <blah/core/filesystem.h>
#include <blah/core/common.h>
#include <blah/core/time.h>
#include <blah/math/stopwatch.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winuser.h> // for SetProcessDPIAware
#include <filesystem> // for File Reading/Writing
#include <shellapi.h> // for file explore
#include <shlobj.h> // for known folder
#include <chrono> // for ticks method
using namespace Blah;
namespace fs = std::filesystem;
namespace
{
// Primary Window
HWND g_hwnd;
// Working Directories
FilePath g_working_directory;
FilePath g_user_directory;
// Timestamp for calculating ticks
std::chrono::system_clock::duration g_start_time;
// OpenGL Methods
// These are only loaded if built using the OpenGL Backend
HMODULE g_opengl_dll;
void* (WINAPI* g_wglGetProcAddress) (const char* proc);
HGLRC(WINAPI* g_wglCreateContext) (HDC hdc);
BOOL(WINAPI* g_wglDeleteContext) (HGLRC hglrc);
BOOL(WINAPI* g_wglMakeCurrent) (HDC hdc, HGLRC hglrc);
// fullscreen state
RECT g_windowed_position;
bool g_fullscreen = false;
}
Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool PlatformBackend::init(const Config* config)
{
// Required to call this for Windows
// I'm not sure why SDL2 doesn't do this on Windows automatically?
SetProcessDPIAware();
// Get the hInstance
HINSTANCE hInstance = GetModuleHandle(NULL);
// Create the Window Class
WNDCLASS wc = {};
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = "BLAH WINDOW";
wc.hInstance = hInstance;
wc.lpfnWndProc = blah_window_procedure;
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
// Register the Window class
RegisterClass(&wc);
// Create the Window Instance
g_hwnd = CreateWindow("BLAH WINDOW", config->name, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 640, 480, NULL, NULL, hInstance, NULL);
// Failed to create the Window
if (g_hwnd == NULL)
{
Log::error("Window Creation Failed");
return false;
}
// Create the OpenGL device info
if (App::renderer() == Renderer::OpenGL)
{
// Load the DLL
g_opengl_dll = LoadLibraryA("opengl32.dll");
if (g_opengl_dll == NULL)
{
Log::error("OpenGL Instantiation Failed - unable to fine opengl32.dll");
return false;
}
// Get the Windows GL functions we need
g_wglGetProcAddress = (void*(WINAPI*) (const char*))GetProcAddress(g_opengl_dll, "wglGetProcAddress");
g_wglCreateContext = (HGLRC(WINAPI*) (HDC))GetProcAddress(g_opengl_dll, "wglCreateContext");
g_wglDeleteContext = (BOOL(WINAPI*) (HGLRC))GetProcAddress(g_opengl_dll, "wglDeleteContext");
g_wglMakeCurrent = (BOOL(WINAPI*) (HDC, HGLRC))GetProcAddress(g_opengl_dll, "wglMakeCurrent");
// TODO:
// Allow the user to apply (some of) these values before instantiation.
// Also applies to the SDL2 Backend
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
24, // 32-bit z-buffer
8, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
HDC hdc = GetDC(g_hwnd);
// get the best available match of pixel format for the device context
int pixel_format = ChoosePixelFormat(hdc, &pfd);
// make that the pixel format of the device context
SetPixelFormat(hdc, pixel_format, &pfd);
}
// Reset our game timer
g_start_time = std::chrono::system_clock::now().time_since_epoch();
// Get Working Directory
{
TCHAR buffer[MAX_PATH];
GetModuleFileName(NULL, buffer, MAX_PATH);
auto normalized = Path::normalize(buffer);
auto end = normalized.last_index_of('/');;
if (end >= 0)
g_working_directory = FilePath(normalized.begin(), normalized.begin() + end);
else
g_working_directory = normalized;
g_working_directory.append("/");
}
// Get Application User Directory
{
PWSTR path = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, NULL, &path)))
{
auto end = path;
while (*end != 0) end++;
FilePath result;
result.append_utf16((u16*)path, (u16*)end);
g_user_directory = Path::join(Path::normalize(result), config->name) + "/";
}
CoTaskMemFree(path);
}
// Not currently fullscreen
g_fullscreen = false;
// Finished Platform Setup
return true;
}
void PlatformBackend::ready()
{
// Setup Window Size
{
auto scale = get_content_scale();
int sw = (int)(App::config()->width * scale);
int sh = (int)(App::config()->height * scale);
set_size(sw, sh);
}
// Display the game window
ShowWindow(g_hwnd, SW_SHOW);
}
void PlatformBackend::shutdown()
{
DestroyWindow(g_hwnd);
}
u64 PlatformBackend::ticks()
{
// Todo:
// This should account for whatever Time::ticks_per_second is set to
auto now = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::microseconds>(now - g_start_time).count();
}
LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
{
auto config = App::config();
if (config->on_exit_request != nullptr)
config->on_exit_request();
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_LBUTTONDOWN:
InputBackend::on_mouse_down(MouseButton::Left);
return 0;
case WM_LBUTTONUP:
InputBackend::on_mouse_up(MouseButton::Left);
return 0;
case WM_RBUTTONDOWN:
InputBackend::on_mouse_down(MouseButton::Right);
return 0;
case WM_RBUTTONUP:
InputBackend::on_mouse_up(MouseButton::Right);
return 0;
case WM_MBUTTONDOWN:
InputBackend::on_mouse_down(MouseButton::Middle);
return 0;
case WM_MBUTTONUP:
InputBackend::on_mouse_up(MouseButton::Middle);
return 0;
case WM_MOUSEMOVE:
InputBackend::on_mouse_move((u16)(lParam), lParam >> 16);
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
auto is_repeat = ((lParam & (1 << 30)) >> 30) == 1;
if (!is_repeat)
{
auto key = blah_scancode_to_key(wParam, lParam);
if (key != Key::Unknown)
InputBackend::on_key_down(key);
}
return 0;
}
case WM_KEYUP:
case WM_SYSKEYUP:
{
auto key = blah_scancode_to_key(wParam, lParam);
if (key != Key::Unknown)
InputBackend::on_key_up(key);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void PlatformBackend::frame()
{
// Catch & Dispatch Window Messages
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void PlatformBackend::sleep(int milliseconds)
{
if (milliseconds > 0)
Sleep(milliseconds);
}
void PlatformBackend::present()
{
if (App::renderer() == Renderer::OpenGL)
{
HDC hdc = GetDC(g_hwnd);
SwapBuffers(hdc);
}
}
const char* PlatformBackend::get_title()
{
return nullptr;
}
void PlatformBackend::set_title(const char* title)
{
SetWindowText(g_hwnd, title);
}
void PlatformBackend::get_position(int* x, int* y)
{
RECT rect;
if (GetWindowRect(g_hwnd, &rect))
{
*x = rect.left;
*y = rect.top;
}
}
void PlatformBackend::set_position(int x, int y)
{
int w, h;
get_size(&w, &h);
SetWindowPos(g_hwnd, NULL, x, y, w, h, 0);
}
void PlatformBackend::set_fullscreen(bool enabled)
{
if (g_fullscreen == enabled)
return;
g_fullscreen = enabled;
if (g_fullscreen)
{
GetWindowRect(g_hwnd, &g_windowed_position);
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
SetWindowLongPtr(g_hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
SetWindowPos(g_hwnd, HWND_TOP, 0, 0, w, h, 0);
ShowWindow(g_hwnd, SW_SHOW);
}
else
{
SetWindowLongPtr(g_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
SetWindowPos(g_hwnd, HWND_TOP,
g_windowed_position.left,
g_windowed_position.top,
g_windowed_position.right - g_windowed_position.left,
g_windowed_position.bottom - g_windowed_position.top, 0);
ShowWindow(g_hwnd, SW_SHOW);
}
}
void PlatformBackend::get_size(int* width, int* height)
{
RECT rect;
if (GetClientRect(g_hwnd, &rect))
{
*width = rect.right - rect.left;
*height = rect.bottom - rect.top;
}
}
void PlatformBackend::set_size(int width, int height)
{
RECT client_rect;
RECT border_rect;
GetClientRect(g_hwnd, &client_rect);
GetWindowRect(g_hwnd, &border_rect);
int border_width = (border_rect.right - border_rect.left) - (client_rect.right - client_rect.left);
int border_height = (border_rect.bottom - border_rect.top) - (client_rect.bottom - client_rect.top);
SetWindowPos(g_hwnd, NULL, border_rect.left, border_rect.top, width + border_width, height + border_height, 0);
}
void PlatformBackend::get_draw_size(int* width, int* height)
{
RECT rect;
if (GetClientRect(g_hwnd, &rect))
{
*width = rect.right - rect.left;
*height = rect.bottom - rect.top;
}
}
float PlatformBackend::get_content_scale()
{
// base value of Windows DPI
// as seen here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow
constexpr float base_raw_value = 96.0f;
UINT raw_value = GetDpiForWindow(g_hwnd);
return (raw_value / base_raw_value);
}
// FILE IO
const char* PlatformBackend::app_path()
{
return g_working_directory.cstr();
}
const char* PlatformBackend::user_path()
{
return g_user_directory.cstr();
}
bool PlatformBackend::file_exists(const char* path)
{
return fs::is_regular_file(path);
}
bool PlatformBackend::file_delete(const char* path)
{
return fs::remove(path);
}
bool PlatformBackend::dir_create(const char* path)
{
std::error_code error;
return fs::create_directories(path, error);
}
bool PlatformBackend::dir_exists(const char* path)
{
return fs::is_directory(path);
}
bool PlatformBackend::dir_delete(const char* path)
{
BLAH_ERROR("not implemented");
return false;
}
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{
if (fs::is_directory(path))
{
if (recursive)
{
for (auto& p : fs::recursive_directory_iterator(path))
list.emplace_back(p.path().string().c_str());
}
else
{
for (auto& p : fs::directory_iterator(path))
list.emplace_back(p.path().string().c_str());
}
}
}
void PlatformBackend::dir_explore(const char* path)
{
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT);
}
bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* handle, FileMode mode)
{
int access = 0;
int creation = 0;
if (((int)mode & (int)FileMode::Read) == (int)FileMode::Read)
{
access |= GENERIC_READ;
creation = OPEN_EXISTING;
}
if (((int)mode & (int)FileMode::Write) == (int)FileMode::Write)
{
access |= GENERIC_WRITE;
creation = OPEN_ALWAYS;
}
auto result = CreateFile(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
if (result == INVALID_HANDLE_VALUE)
return false;
*handle = result;
return true;
}
i64 PlatformBackend::file_length(PlatformBackend::FileHandle handle)
{
// Todo: cache this value? not sure how performant it is
LARGE_INTEGER file_size;
if (GetFileSizeEx(handle, &file_size))
return file_size.QuadPart;
return 0;
}
i64 PlatformBackend::file_position(PlatformBackend::FileHandle handle)
{
// Todo: handle 64-bit values properly
// Todo: cache this value? not sure how performant it is
return SetFilePointer(handle, 0, NULL, FILE_CURRENT);
}
i64 PlatformBackend::file_seek(PlatformBackend::FileHandle handle, i64 seekTo)
{
// Todo: handle 64-bit values properly
return SetFilePointer(handle, seekTo, NULL, FILE_BEGIN);
}
i64 PlatformBackend::file_read(PlatformBackend::FileHandle handle, void* ptr, i64 length)
{
DWORD read = 0;
if (ReadFile(handle, ptr, length, &read, NULL))
return read;
return 0;
}
i64 PlatformBackend::file_write(PlatformBackend::FileHandle handle, const void* ptr, i64 length)
{
DWORD written = 0;
if (WriteFile(handle, ptr, length, &written, NULL))
return written;
return 0;
}
void PlatformBackend::file_close(PlatformBackend::FileHandle handle)
{
CloseHandle(handle);
}
void* PlatformBackend::gl_get_func(const char* name)
{
// this check is taken from https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions
// wglGetProcAddress doesn't always return valid pointers for some specific methods?
void* p = (void*)g_wglGetProcAddress(name);
if ((p == 0) ||
(p == (void*)0x1) ||
(p == (void*)0x2) ||
(p == (void*)0x3) ||
(p == (void*)-1))
{
p = (void*)GetProcAddress(g_opengl_dll, name);
}
return p;
}
void* PlatformBackend::gl_context_create()
{
HDC hdc = GetDC(g_hwnd);
return g_wglCreateContext(hdc);
}
void PlatformBackend::gl_context_make_current(void* context)
{
if (context != nullptr)
{
HDC hdc = GetDC(g_hwnd);
g_wglMakeCurrent(hdc, (HGLRC)context);
}
else
g_wglMakeCurrent(NULL, NULL);
}
void PlatformBackend::gl_context_destroy(void* context)
{
g_wglDeleteContext((HGLRC)context);
}
void* PlatformBackend::d3d11_get_hwnd()
{
return g_hwnd;
}
Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam)
{
Key key = Key::Unknown;
switch (wParam)
{
case VK_CANCEL: key = Key::Cancel; break;
case VK_BACK: key = Key::Backspace; break;
case VK_TAB: key = Key::Tab; break;
case VK_CLEAR: key = Key::Clear; break;
case VK_RETURN: key = Key::Enter; break;
case VK_SHIFT: key = Key::LeftShift; break;
case VK_CONTROL: key = Key::LeftControl; break;
case VK_MENU: key = Key::Menu; break;
case VK_PAUSE: key = Key::Pause; break;
case VK_CAPITAL: key = Key::Capslock; break;
case VK_ESCAPE: key = Key::Escape; break;
case VK_SPACE: key = Key::Space; break;
case VK_PRIOR: key = Key::Prior; break;
case VK_END: key = Key::End; break;
case VK_HOME: key = Key::Home; break;
case VK_LEFT: key = Key::Left; break;
case VK_UP: key = Key::Up; break;
case VK_RIGHT: key = Key::Right; break;
case VK_DOWN: key = Key::Down; break;
case VK_SELECT: key = Key::Select; break;
case VK_PRINT: key = Key::PrintScreen; break;
case VK_EXECUTE: key = Key::Execute; break;
case VK_SNAPSHOT: key = Key::PrintScreen; break;
case VK_INSERT: key = Key::Insert; break;
case VK_DELETE: key = Key::Delete; break;
case VK_HELP: key = Key::Help; break;
case VK_LWIN: key = Key::LeftOS; break;
case VK_RWIN: key = Key::RightOS; break;
case VK_APPS: key = Key::Application; break;
case VK_SLEEP: key = Key::Unknown; break;
case VK_NUMPAD0: key = Key::Keypad0; break;
case VK_NUMPAD1: key = Key::Keypad1; break;
case VK_NUMPAD2: key = Key::Keypad2; break;
case VK_NUMPAD3: key = Key::Keypad3; break;
case VK_NUMPAD4: key = Key::Keypad4; break;
case VK_NUMPAD5: key = Key::Keypad5; break;
case VK_NUMPAD6: key = Key::Keypad6; break;
case VK_NUMPAD7: key = Key::Keypad7; break;
case VK_NUMPAD8: key = Key::Keypad8; break;
case VK_NUMPAD9: key = Key::Keypad9; break;
case VK_F1: key = Key::F1; break;
case VK_F2: key = Key::F2; break;
case VK_F3: key = Key::F3; break;
case VK_F4: key = Key::F4; break;
case VK_F5: key = Key::F5; break;
case VK_F6: key = Key::F6; break;
case VK_F7: key = Key::F7; break;
case VK_F8: key = Key::F8; break;
case VK_F9: key = Key::F9; break;
case VK_F10: key = Key::F10; break;
case VK_F11: key = Key::F11; break;
case VK_F12: key = Key::F12; break;
case VK_F13: key = Key::F13; break;
case VK_F14: key = Key::F14; break;
case VK_F15: key = Key::F15; break;
case VK_F16: key = Key::F16; break;
case VK_F17: key = Key::F17; break;
case VK_F18: key = Key::F18; break;
case VK_F19: key = Key::F19; break;
case VK_F20: key = Key::F20; break;
case VK_F21: key = Key::F21; break;
case VK_F22: key = Key::F22; break;
case VK_F23: key = Key::F23; break;
case VK_F24: key = Key::F24; break;
case VK_NUMLOCK: key = Key::Numlock; break;
case VK_LSHIFT: key = Key::LeftShift; break;
case VK_RSHIFT: key = Key::RightShift; break;
case VK_LCONTROL: key = Key::LeftControl; break;
case VK_RCONTROL: key = Key::RightControl; break;
case VK_VOLUME_MUTE: key = Key::Mute; break;
case VK_VOLUME_DOWN: key = Key::VolumeDown; break;
case VK_VOLUME_UP: key = Key::VolumeUp; break;
}
if (key == Key::Unknown)
{
int scancode = (lParam >> 16) & 0xFF;
switch (scancode)
{
case 1: key = Key::Escape; break;
case 2: key = Key::D1; break;
case 3: key = Key::D2; break;
case 4: key = Key::D3; break;
case 5: key = Key::D4; break;
case 6: key = Key::D5; break;
case 7: key = Key::D6; break;
case 8: key = Key::D7; break;
case 9: key = Key::D8; break;
case 10: key = Key::D9; break;
case 11: key = Key::D0; break;
case 12: key = Key::Minus; break;
case 13: key = Key::Equals; break;
case 14: key = Key::Backspace; break;
case 15: key = Key::Tab; break;
case 16: key = Key::Q; break;
case 17: key = Key::W; break;
case 18: key = Key::E; break;
case 19: key = Key::R; break;
case 20: key = Key::T; break;
case 21: key = Key::Y; break;
case 22: key = Key::U; break;
case 23: key = Key::I; break;
case 24: key = Key::O; break;
case 25: key = Key::P; break;
case 26: key = Key::LeftBracket; break;
case 27: key = Key::RightBracket; break;
case 28: key = Key::Enter; break;
case 29: key = Key::LeftControl; break;
case 30: key = Key::A; break;
case 31: key = Key::S; break;
case 32: key = Key::D; break;
case 33: key = Key::F; break;
case 34: key = Key::G; break;
case 35: key = Key::H; break;
case 36: key = Key::J; break;
case 37: key = Key::K; break;
case 38: key = Key::L; break;
case 39: key = Key::Semicolon; break;
case 40: key = Key::Apostrophe; break;
case 41: key = Key::Tilde; break;
case 42: key = Key::LeftShift; break;
case 43: key = Key::Backslash; break;
case 44: key = Key::Z; break;
case 45: key = Key::X; break;
case 46: key = Key::C; break;
case 47: key = Key::V; break;
case 48: key = Key::B; break;
case 49: key = Key::N; break;
case 50: key = Key::M; break;
case 51: key = Key::Comma; break;
case 52: key = Key::Period; break;
case 53: key = Key::Slash; break;
case 54: key = Key::RightShift; break;
case 55: key = Key::PrintScreen; break;
case 56: key = Key::LeftAlt; break;
case 57: key = Key::Space; break;
case 58: key = Key::Capslock; break;
case 59: key = Key::F1; break;
case 60: key = Key::F2; break;
case 61: key = Key::F3; break;
case 62: key = Key::F4; break;
case 63: key = Key::F5; break;
case 64: key = Key::F6; break;
case 65: key = Key::F7; break;
case 66: key = Key::F8; break;
case 67: key = Key::F9; break;
case 68: key = Key::F10; break;
case 71: key = Key::Home; break;
case 72: key = Key::Up; break;
case 73: key = Key::PageUp; break;
case 74: key = Key::KeypadMinus; break;
case 75: key = Key::Left; break;
case 76: key = Key::Keypad5; break;
case 77: key = Key::Right; break;
case 78: key = Key::KeypadPlus; break;
case 79: key = Key::End; break;
case 80: key = Key::Down; break;
case 81: key = Key::PageDown; break;
case 82: key = Key::Insert; break;
case 83: key = Key::Delete; break;
case 87: key = Key::F11; break;
case 88: key = Key::F12; break;
case 89: key = Key::Pause; break;
case 91: key = Key::LeftOS; break;
case 92: key = Key::RightOS; break;
case 93: key = Key::Application; break;
case 100: key = Key::F13; break;
case 101: key = Key::F14; break;
case 102: key = Key::F15; break;
case 103: key = Key::F16; break;
case 104: key = Key::F17; break;
case 105: key = Key::F18; break;
case 106: key = Key::F19; break;
}
}
return key;
}
#endif // BLAH_PLATFORM_WINDOWS

View File

@ -19,7 +19,6 @@ u64 Stopwatch::milliseconds()
return microseconds() / 1000;
}
u64 Stopwatch::microseconds()
{
return std::chrono::duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count() - start_time;