Lumenarium/src_v2/platform/win32/lumenarium_win32_window.cpp

423 lines
12 KiB
C++

typedef u32 Win32_Window_Event_Flags;
enum
{
WindowEventFlag_None = 0,
WindowEventFlag_CloseRequested = 1,
WindowEventFlag_WindowIsActive = 2,
};
struct Win32_Window_OpenGL_Info
{
BYTE bits_color;
BYTE bits_alpha;
BYTE bits_depth;
HGLRC rc;
};
struct Win32_Window_Info
{
char* name;
char* class_name;
s32 width;
s32 height;
};
struct Win32_Window
{
Win32_Window_Info info;
WNDCLASSEX window_class;
WNDPROC window_event_handler;
HWND window_handle;
HDC dc;
Win32_Window_OpenGL_Info opengl_info;
};
//////////////////////////////////////////
// Main Window
//
// At the moment, we only need one window, so this is easier to
// track globally. Replace this if we need more windows
global Win32_Window_Event_Flags win32_window_event_flags = 0;
global Win32_Window win32_main_window = {};
//////////////////////////////////////////
//
internal bool
win32_window_create(
Win32_Window* dest,
HINSTANCE hinstance,
char* window_name,
s32 width,
s32 height,
WNDPROC window_event_handler
)
{
dest->info.name = window_name;
dest->info.class_name = window_name;
dest->info.width = width;
dest->info.height = height;
dest->window_event_handler = window_event_handler;
dest->window_class = {};
dest->window_class.cbSize = sizeof(WNDCLASSEX);
dest->window_class.style = (
CS_HREDRAW |
CS_VREDRAW |
CS_OWNDC // TODO(PS): need to know what this is
);
dest->window_class.lpfnWndProc = window_event_handler;
dest->window_class.cbClsExtra = 0;
dest->window_class.cbWndExtra = 0;
dest->window_class.hInstance = hinstance;
dest->window_class.hIcon = NULL;
dest->window_class.hCursor = NULL;
dest->window_class.hbrBackground = NULL;
dest->window_class.lpszMenuName = 0;
dest->window_class.lpszClassName = window_name; // "main_window_class";
dest->window_class.hIconSm = NULL;
if (RegisterClassEx(&dest->window_class))
{
dest->window_handle = CreateWindowEx(
0,
dest->window_class.lpszClassName,
window_name,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
0,
0,
hinstance,
0
);
return true;
}
return false;
}
internal void
win32_window_update_dim(Win32_Window* win)
{
RECT client_rect;
GetClientRect(win->window_handle, &client_rect);
win->info.width = client_rect.right - client_rect.left;
win->info.height = client_rect.bottom - client_rect.top;
}
internal void win32_window_opengl_ctx_create(Win32_Window* win, Win32_Window_OpenGL_Info info, HINSTANCE hinstance);
LRESULT CALLBACK
win32_window_event_handler(HWND window_handle, UINT msg, WPARAM wparam, LPARAM lparam)
{
LRESULT result = 0;
switch (msg)
{
case WM_CREATE:
{
win32_main_window.dc = GetDC(window_handle);
HINSTANCE hinstance = GetModuleHandle(NULL);
win32_window_opengl_ctx_create(&win32_main_window, { 32, 8, 0 }, hinstance);
}break;
case WM_SIZE:
{
win32_window_update_dim(&win32_main_window);
}break;
case WM_CLOSE:
{
if (win32_main_window.opengl_info.rc)
{
wglDeleteContext(win32_main_window.opengl_info.rc);
win32_main_window.opengl_info.rc = NULL;
}
if (win32_main_window.dc)
{
ReleaseDC(win32_main_window.window_handle, win32_main_window.dc);
win32_main_window.dc = NULL;
}
add_flag(win32_window_event_flags, WindowEventFlag_CloseRequested);
running = false;
DestroyWindow(win32_main_window.window_handle);
}break;
case WM_DESTROY:
{
if (win32_main_window.opengl_info.rc)
{
wglDeleteContext(win32_main_window.opengl_info.rc);
win32_main_window.opengl_info.rc = NULL;
}
if (win32_main_window.dc)
{
ReleaseDC(win32_main_window.window_handle, win32_main_window.dc);
win32_main_window.dc = NULL;
}
//PostQuitMessage(0);
//result = DefWindowProc(window_handle, msg, wparam, lparam);
}break;
case WM_PAINT:
{
PAINTSTRUCT paint_struct;
HDC device_ctx;
b32 paint_result;
device_ctx = BeginPaint(window_handle, &paint_struct);
paint_result = EndPaint(window_handle, &paint_struct);
}break;
case WM_ACTIVATE:
{
bool WindowIsActive = (
LOWORD(wparam) == WA_ACTIVE || LOWORD(wparam) == WA_CLICKACTIVE
);
if (WindowIsActive)
{
add_flag(win32_window_event_flags, WindowEventFlag_WindowIsActive);
}
else
{
rem_flag(win32_window_event_flags, WindowEventFlag_WindowIsActive);
}
}break;
default:
{
result = DefWindowProc(window_handle, msg, wparam, lparam);
}
}
return result;
}
////////////////////////////////////////////
// OpenGL dummy window functions
LRESULT CALLBACK
win32_opengl_event_handler(HWND window_handle, UINT msg, WPARAM wparam, LPARAM lparam)
{
LRESULT result = 0;
switch (msg)
{
case WM_CREATE: { }break;
case WM_CLOSE: { DestroyWindow(window_handle); }break;
case WM_DESTROY: { } break;
default: { return DefWindowProc(window_handle, msg, wparam, lparam); } break;
}
return result;
}
internal void
win32_window_opengl_ctx_create_no_ext(HDC dc, Win32_Window_OpenGL_Info* info)
{
// Setup pixel format
{
PIXELFORMATDESCRIPTOR pixel_format_desc = { 0 };
pixel_format_desc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixel_format_desc.nVersion = 1;
pixel_format_desc.dwFlags = (
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER
);
pixel_format_desc.cColorBits = info->bits_color;
pixel_format_desc.cAlphaBits = info->bits_alpha;
pixel_format_desc.cDepthBits = info->bits_depth;
pixel_format_desc.iPixelType = PFD_TYPE_RGBA;
pixel_format_desc.dwLayerMask = PFD_MAIN_PLANE;
s32 pixel_fmt = ChoosePixelFormat(dc, &pixel_format_desc);
if (pixel_fmt == 0)
{
win32_get_last_error();
invalid_code_path;
}
if ((pixel_fmt = ChoosePixelFormat(dc, &pixel_format_desc)) == 0)
{
win32_get_last_error();
invalid_code_path;
}
if (SetPixelFormat(dc, pixel_fmt, &pixel_format_desc) == FALSE)
{
win32_get_last_error();
invalid_code_path;
}
}
// Create rendering context
{
info->rc = wglCreateContext(dc);
if (info->rc == NULL) {
win32_get_last_error();
invalid_code_path;
}
if (!wglMakeCurrent(dc, info->rc))
{
win32_get_last_error();
invalid_code_path;
}
}
}
// Based on documentation at:
// https://www.opengl.org/wiki/Creating_an_OpenGL_Context_(WGL)#Proper_Context_Creation
internal void
win32_window_opengl_ctx_create_ext(HDC dc, Win32_Window_OpenGL_Info* info)
{
const int pixel_fmt_attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0
};
s32 pixel_fmt;
u32 num_formats;
// this will contain the description of pixel_fmt after we set it
PIXELFORMATDESCRIPTOR pixel_format_desc = { 0 };
if (!gl.wglChoosePixelFormatARB(dc, pixel_fmt_attribs, NULL, 1, &pixel_fmt, &num_formats))
{
win32_get_last_error();
invalid_code_path;
}
if (SetPixelFormat(dc, pixel_fmt, &pixel_format_desc) == FALSE)
{
win32_get_last_error();
invalid_code_path;
}
int ctx_flags = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
#if defined(DEBUG)
ctx_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
#endif
const int ctx_attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_FLAGS_ARB, ctx_flags,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0, 0,
};
info->rc = gl.wglCreateContextAttribsARB(dc, 0, ctx_attribs);
if (info->rc == NULL) {
win32_get_last_error();
invalid_code_path;
}
if (!wglMakeCurrent(dc, info->rc))
{
win32_get_last_error();
invalid_code_path;
}
char* version_string = (char*)glGetString(GL_VERSION);
err_write("OpenGL Version: %s\n", version_string);
}
internal void
win32_window_opengl_make_current(Win32_Window* win)
{
}
#define wgl_load_ext(e,n) e.n = (proc_##n*)wglGetProcAddress(#n); assert((e.n) != 0)
internal Win32_OpenGL_Extensions
win32_window_opengl_get_wgl_ext(HINSTANCE hinstance)
{
Win32_OpenGL_Extensions result = {0};
WNDCLASSEX window_class = {};
window_class.cbSize = sizeof(WNDCLASSEX);
window_class.style = (CS_HREDRAW | CS_VREDRAW | CS_OWNDC);
window_class.lpfnWndProc = win32_opengl_event_handler;
window_class.hInstance = hinstance;
window_class.lpszClassName = "opengl_window_class";
if (RegisterClassEx(&window_class))
{
HWND window_handle = CreateWindowEx(0, window_class.lpszClassName,
"opengl_window", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 32, 32, 0, 0, hinstance, 0
);
HDC dc = GetDC(window_handle);
Win32_Window_OpenGL_Info info = { 32, 24, 8 };
win32_window_opengl_ctx_create_no_ext(dc, &info);
wgl_load_ext(result, wglGetExtensionsStringARB);
if (result.wglGetExtensionsStringARB != 0)
{
const char* extension_string = result.wglGetExtensionsStringARB(dc);
OutputDebugStringA("OpenGL Extensions: \n");
OutputDebugStringA(extension_string);
OutputDebugStringA("\n\n");
wgl_load_ext(result, wglChoosePixelFormatARB);
wgl_load_ext(result, wglCreateContextAttribsARB);
wgl_load_ext(result, glGenVertexArrays);
wgl_load_ext(result, glBindVertexArray);
wgl_load_ext(result, glGenBuffers);
wgl_load_ext(result, glBindBuffer);
wgl_load_ext(result, glBufferData);
wgl_load_ext(result, glBufferSubData);
wgl_load_ext(result, glCreateShader);
wgl_load_ext(result, glShaderSource);
wgl_load_ext(result, glCompileShader);
wgl_load_ext(result, glCreateProgram);
wgl_load_ext(result, glAttachShader);
wgl_load_ext(result, glLinkProgram);
wgl_load_ext(result, glUseProgram);
wgl_load_ext(result, glGetAttribLocation);
wgl_load_ext(result, glVertexAttribPointer);
wgl_load_ext(result, glEnableVertexAttribArray);
wgl_load_ext(result, glGetShaderiv);
wgl_load_ext(result, glGetShaderInfoLog);
wgl_load_ext(result, glGetProgramiv);
wgl_load_ext(result, glGetProgramInfoLog);
wgl_load_ext(result, glGetUniformLocation);
wgl_load_ext(result, glUniformMatrix4fv);
}
wglMakeCurrent(NULL, NULL);
wglDeleteContext(info.rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
}
return result;
}
internal void
win32_window_opengl_ctx_create(Win32_Window* win, Win32_Window_OpenGL_Info info, HINSTANCE hinstance)
{
if (gl.wglGetExtensionsStringARB == 0)
{
gl = win32_window_opengl_get_wgl_ext(hinstance);
}
win32_window_opengl_ctx_create_ext(win->dc, &info);
win->opengl_info = info;
}