win32 stuff moved under pltf
This commit is contained in:
@@ -8,7 +8,7 @@ cargs = [
|
|||||||
'-Og',
|
'-Og',
|
||||||
'-g',
|
'-g',
|
||||||
'-DBOUNDS_CHECK',
|
'-DBOUNDS_CHECK',
|
||||||
'-DSHADERS_PATH="../src/shaders/"'
|
'-DSHADERS_PATH="../src/shaders/"',
|
||||||
]
|
]
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -53,8 +53,8 @@ endif
|
|||||||
|
|
||||||
executable(
|
executable(
|
||||||
'scuffedcraft',
|
'scuffedcraft',
|
||||||
'src/pltf/gl_funcs.c',
|
'src/pltf/win32/gl_funcs.c',
|
||||||
'src/pltf/pltf.c',
|
'src/pltf/win32/pltf.c',
|
||||||
'src/DynArray.c',
|
'src/DynArray.c',
|
||||||
'src/DynString.c',
|
'src/DynString.c',
|
||||||
'src/log.c',
|
'src/log.c',
|
||||||
|
|||||||
382
src/main.c
382
src/main.c
@@ -1,366 +1,19 @@
|
|||||||
#include <GL/glcorearb.h>
|
|
||||||
#include <GL/wglext.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <shobjidl.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wchar.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <windowsx.h>
|
|
||||||
#include <winuser.h>
|
|
||||||
|
|
||||||
#include "DynArray.h"
|
|
||||||
#include "DynString.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "pltf/gl_funcs.h"
|
|
||||||
#include "pltf/pltf.h"
|
#include "pltf/pltf.h"
|
||||||
|
#include "pltf/gl_funcs.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
// int _main() {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #ifdef __MINGW32__
|
|
||||||
|
|
||||||
DynArray_DynString wgl_extensions = { 0 };
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
HGLRC gl_ctx;
|
|
||||||
} State;
|
|
||||||
|
|
||||||
bool has_wgl_extension(const DynString* name) {
|
|
||||||
assert(!DynString_is_null(name));
|
|
||||||
assert(!DynArray_DynString_is_null(&wgl_extensions));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < wgl_extensions.len; i++) {
|
|
||||||
if (DynString_equal(name, DynArray_DynString_at(&wgl_extensions, i))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_wgl_extension_c_str(const char* name) {
|
|
||||||
DynString name_dstr = DynString_alloc(name, strlen(name));
|
|
||||||
const bool res = has_wgl_extension(&name_dstr);
|
|
||||||
DynString_free(&name_dstr);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_opengl_info() {
|
|
||||||
// assert(glGetIntegerv != NULL);
|
|
||||||
|
|
||||||
if (glGetIntegerv == NULL) {
|
|
||||||
glGetIntegerv = (PFNGLGETINTEGERVPROC) pltf_gl_function_load("glGetIntegerv");
|
|
||||||
if (glGetIntegerv == NULL) {
|
|
||||||
LOG_FATAL("Could not load glGetIntegerv");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int major = 0;
|
|
||||||
int minor = 0;
|
|
||||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
|
||||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
|
||||||
|
|
||||||
int profile_mask = 0;
|
|
||||||
char profile[sizeof("compatibility")] = { 0 };
|
|
||||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
|
|
||||||
if (profile_mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
|
||||||
strncpy(profile, "core", strlen("core"));
|
|
||||||
} else if (profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) {
|
|
||||||
strncpy(profile, "compatibility", strlen("compatibility"));
|
|
||||||
} else {
|
|
||||||
LOG_ERRORF(
|
|
||||||
"GL_CONTEXT_PROFILE_MASK did not contain either bit. profile_mask: %d",
|
|
||||||
profile_mask
|
|
||||||
);
|
|
||||||
}
|
|
||||||
printf("OpenGL version %d.%d %s\n", major, minor, profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnSize(HWND hwnd, UINT flag, int width, int height) {
|
|
||||||
printf("Window resize: flag: %d, width: %d, height: %d\n", flag, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
||||||
State* pState = NULL;
|
|
||||||
if (uMsg == WM_CREATE) {
|
|
||||||
CREATESTRUCT* pCreate = (CREATESTRUCT*) lParam;
|
|
||||||
pState = (State*) pCreate->lpCreateParams;
|
|
||||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) pState);
|
|
||||||
} else {
|
|
||||||
LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
||||||
pState = (State*) ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (uMsg) {
|
|
||||||
// case WM_LBUTTONDOWN: {
|
|
||||||
// printf("State: msg: %s, num: %d\n", pState->msg, pState->num);
|
|
||||||
//
|
|
||||||
// printf("lParam: %llx\n", lParam);
|
|
||||||
// int mouse_x = GET_X_LPARAM(lParam);
|
|
||||||
// printf("mouse_x: %x\n", mouse_x);
|
|
||||||
// int mouse_y = GET_Y_LPARAM(lParam);
|
|
||||||
// printf("mouse_y: %x\n", mouse_y);
|
|
||||||
// printf("x: %d y: %d\n", mouse_x, mouse_y);
|
|
||||||
//
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
case WM_CREATE: {
|
|
||||||
const PIXELFORMATDESCRIPTOR pfd = {
|
|
||||||
sizeof(PIXELFORMATDESCRIPTOR),
|
|
||||||
1,
|
|
||||||
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
|
||||||
PFD_TYPE_RGBA,
|
|
||||||
32, // Color depth
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
24, // Depth buffer bits
|
|
||||||
8, // Stencil buffer bits
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
HDC hdc = GetDC(hwnd);
|
|
||||||
if (hdc == NULL) {
|
|
||||||
LOG_ERROR("Failed to get window DC");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
const int pixel_format = ChoosePixelFormat(hdc, &pfd);
|
|
||||||
if (SetPixelFormat(hdc, pixel_format, &pfd) == FALSE) {
|
|
||||||
LOG_ERRORF("Failed to set pixel format. Error: %d", GetLastError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pState->gl_ctx = wglCreateContext(hdc);
|
|
||||||
if (pState->gl_ctx == NULL) {
|
|
||||||
LOG_ERRORF("Failed to create OpenGL context. Error: %d", GetLastError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wglMakeCurrent(hdc, pState->gl_ctx) == FALSE) {
|
|
||||||
LOG_ERRORF("Failed to make OpenGL context current. Error: %d", GetLastError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Dummy context info: ");
|
|
||||||
print_opengl_info();
|
|
||||||
|
|
||||||
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) pltf_gl_function_load("wglGetExtensionsStringARB");
|
|
||||||
|
|
||||||
char* wgl_extensions_str = (char*) wglGetExtensionsStringARB(hdc);
|
|
||||||
|
|
||||||
char* wgl_extensions_str_copy = strdup(wgl_extensions_str);
|
|
||||||
|
|
||||||
if (!DynArray_DynString_alloc(&wgl_extensions)) {
|
|
||||||
LOG_ERROR("Failed to allocate wgl_extensions");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ext = strtok(wgl_extensions_str_copy, " ");
|
|
||||||
if (ext == NULL) {
|
|
||||||
LOG_ERROR("wgl_extensions_str was empty");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
while (ext != NULL) {
|
|
||||||
DynString ext_dstr = DynString_alloc(ext, strlen(ext));
|
|
||||||
|
|
||||||
if (!DynArray_DynString_push_back(&wgl_extensions, &ext_dstr)) {
|
|
||||||
LOG_ERROR("Failed to push back extension string");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ext = strtok(NULL, " ");
|
|
||||||
if (ext == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(wgl_extensions_str_copy);
|
|
||||||
|
|
||||||
// printf("Available WGL extensions:\n");
|
|
||||||
// for (size_t i = 0; i < wgl_extensions.len; i++) {
|
|
||||||
// const DynString* ext = DynArray_DynString_at(&wgl_extensions, i);
|
|
||||||
// printf("%.*s\n", DYN_STRING_FMT(*ext));
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!has_wgl_extension_c_str("WGL_ARB_pixel_format")) {
|
|
||||||
LOG_FATAL("WGL_ARB_create_context extension required.");
|
|
||||||
}
|
|
||||||
if (!has_wgl_extension_c_str("WGL_ARB_create_context")) {
|
|
||||||
LOG_FATAL("WGL_ARB_create_context extension is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) pltf_gl_function_load("wglChoosePixelFormatARB");
|
|
||||||
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) pltf_gl_function_load("wglCreateContextAttribsARB");
|
|
||||||
|
|
||||||
int wgl_pixel_format = 0;
|
|
||||||
{
|
|
||||||
UINT num_formats = 0;
|
|
||||||
const int attribIList[] = {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
if (wglChoosePixelFormatARB(hdc, attribIList, NULL, 1, &wgl_pixel_format, &num_formats) == FALSE) {
|
|
||||||
LOG_FATAL("Failed to get pixel format with wglChoosePixelFormatARB");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SetPixelFormat(hdc, wgl_pixel_format, &pfd) == FALSE) {
|
|
||||||
LOG_FATAL("Failed to set wgl_pixel_format");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wglDeleteContext(pState->gl_ctx) == FALSE) {
|
|
||||||
LOG_FATAL("Failed to delete dummy context");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const int attribIList[] = {
|
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
|
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB, 6,
|
|
||||||
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB
|
|
||||||
};
|
|
||||||
pState->gl_ctx = wglCreateContextAttribsARB(hdc, NULL, attribIList);
|
|
||||||
if (pState->gl_ctx == NULL) {
|
|
||||||
LOG_FATAL("wglCreateContextAttribsARB did not create a context");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wglMakeCurrent(hdc, pState->gl_ctx) == FALSE) {
|
|
||||||
LOG_FATAL("Failed to set proper context as current");
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Proper context info: ");
|
|
||||||
print_opengl_info();
|
|
||||||
|
|
||||||
pltf_load_gl_funcs();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
|
||||||
if (wParam == VK_ESCAPE) {
|
|
||||||
PostMessage(hwnd, WM_DESTROY, 0, 0);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case WM_DESTROY:
|
|
||||||
wglDeleteContext(pState->gl_ctx);
|
|
||||||
PostQuitMessage(0);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case WM_CLOSE:
|
|
||||||
if (MessageBox(hwnd, L"Really quit?", L"My Application", MB_OKCANCEL) == IDOK) {
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case WM_SIZE: {
|
|
||||||
int width = LOWORD(lParam);
|
|
||||||
int height = HIWORD(lParam);
|
|
||||||
OnSize(hwnd, (UINT) wParam, width, height);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// case WM_PAINT: {
|
|
||||||
// PAINTSTRUCT ps;
|
|
||||||
// HDC hdc = BeginPaint(hwnd, &ps);
|
|
||||||
//
|
|
||||||
// FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW + 1));
|
|
||||||
// RECT blue = {
|
|
||||||
// .bottom = 100,
|
|
||||||
// .left = 0,
|
|
||||||
// .right = 100,
|
|
||||||
// .top = 0
|
|
||||||
// };
|
|
||||||
// FillRect(hdc, &blue, (HBRUSH) (COLOR_BACKGROUND + 1));
|
|
||||||
//
|
|
||||||
// EndPaint(hwnd, &ps);
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
pltf_init();
|
pltf_init();
|
||||||
|
pltf_window_create();
|
||||||
|
pltf_gl_ctx_create();
|
||||||
|
pltf_gl_funcs_load();
|
||||||
|
|
||||||
HMODULE module = GetModuleHandle(NULL);
|
pltf_gl_ctx_info_print();
|
||||||
if (module == NULL) {
|
|
||||||
LOG_FATAL("Failed to get module");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the window class
|
|
||||||
const wchar_t* CLASS_NAME = L"Sample Window Class";
|
|
||||||
|
|
||||||
WNDCLASS wc = { };
|
|
||||||
wc.lpfnWndProc = WindowProc;
|
|
||||||
wc.hInstance = module;
|
|
||||||
wc.lpszClassName = CLASS_NAME;
|
|
||||||
wc.style = CS_OWNDC;
|
|
||||||
|
|
||||||
RegisterClass(&wc);
|
|
||||||
|
|
||||||
State s = {
|
|
||||||
.gl_ctx = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the window
|
|
||||||
HWND hwnd = CreateWindowEx(
|
|
||||||
0, // Optional window styles
|
|
||||||
CLASS_NAME, // Window class
|
|
||||||
L"Learn to Program Windows", // Window text
|
|
||||||
WS_OVERLAPPEDWINDOW, // Window style
|
|
||||||
|
|
||||||
// Size and position
|
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
||||||
|
|
||||||
NULL, // Parent window
|
|
||||||
NULL, // Menu
|
|
||||||
module, // Instance handle
|
|
||||||
&s // Additional application data
|
|
||||||
);
|
|
||||||
|
|
||||||
if (hwnd == NULL) {
|
|
||||||
LOG_ERROR("ERROR: hwnd was NULL\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowWindow(hwnd, SW_SHOWDEFAULT);
|
|
||||||
|
|
||||||
// Message loop
|
|
||||||
|
|
||||||
GLenum gl_err = 0;
|
|
||||||
glClearColor(0.0f, 0.0f, 0.8f, 1.0f);
|
|
||||||
float colors[4] = { 0 };
|
|
||||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, colors);
|
|
||||||
printf("Clear color: %f, %f, %f, %f\n", colors[0], colors[1], colors[2], colors[3]);
|
|
||||||
gl_err = glGetError();
|
|
||||||
if (gl_err != GL_NO_ERROR) {
|
|
||||||
LOG_FATALF("gl error: %d", gl_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
HDC hdc = GetDC(hwnd);
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const float triangle_verts[] = {
|
const float triangle_verts[] = {
|
||||||
@@ -404,33 +57,26 @@ int main() {
|
|||||||
"shader.frag"
|
"shader.frag"
|
||||||
);
|
);
|
||||||
|
|
||||||
MSG msg = { 0 };
|
glClearColor(0.0f, 0.0f, 0.8f, 1.0f);
|
||||||
int exit_code = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
if (pltf_window_event_handle() == PLTF_WE_QUIT) {
|
||||||
TranslateMessage(&msg);
|
goto cleanup;
|
||||||
DispatchMessage(&msg);
|
|
||||||
if (msg.message == WM_QUIT) {
|
|
||||||
exit_code = msg.wParam;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
glUseProgram(shader);
|
glUseProgram(shader);
|
||||||
glBindVertexArray(triangle_vao);
|
glBindVertexArray(triangle_vao);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, triangle_vert_count);
|
glDrawArrays(GL_TRIANGLES, 0, triangle_vert_count);
|
||||||
|
|
||||||
wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);
|
pltf_swap_buffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
UnregisterClass(CLASS_NAME, module);
|
pltf_gl_ctx_destroy();
|
||||||
return exit_code;
|
pltf_window_destroy();
|
||||||
|
pltf_deinit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,6 @@ PLTF_GL_FUNCS(X)
|
|||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
void* pltf_gl_function_load(const char* name);
|
void* pltf_gl_function_load(const char* name);
|
||||||
void pltf_load_gl_funcs();
|
void pltf_gl_funcs_load();
|
||||||
|
|
||||||
#endif // GL_FUNCS_H_
|
#endif // GL_FUNCS_H_
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
#include <minwindef.h>
|
|
||||||
|
|
||||||
#include "pltf.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
HMODULE opengl_module = NULL;
|
|
||||||
|
|
||||||
void pltf_init() {
|
|
||||||
opengl_module = LoadLibraryA("opengl32.dll");
|
|
||||||
if (opengl_module == NULL) {
|
|
||||||
LOG_FATAL("Failed to load opengl32.dll");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,21 @@
|
|||||||
#ifndef PLTF_H_
|
#ifndef PLTF_H_
|
||||||
#define PLTF_H_
|
#define PLTF_H_
|
||||||
|
|
||||||
#include <minwindef.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
extern HMODULE opengl_module;
|
typedef enum {
|
||||||
|
PLTF_WE_NULL,
|
||||||
|
PLTF_WE_QUIT
|
||||||
|
} PltfWindowEvent;
|
||||||
|
|
||||||
void pltf_init();
|
void pltf_init();
|
||||||
|
void pltf_deinit();
|
||||||
|
void pltf_window_create();
|
||||||
|
void pltf_window_destroy();
|
||||||
|
void pltf_gl_ctx_create();
|
||||||
|
void pltf_gl_ctx_destroy();
|
||||||
|
void pltf_gl_ctx_info_print();
|
||||||
|
void pltf_swap_buffers();
|
||||||
|
PltfWindowEvent pltf_window_event_handle();
|
||||||
|
|
||||||
#endif // PLTF_H_
|
#endif // PLTF_H_
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "gl_funcs.h"
|
#include "../gl_funcs.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pltf.h"
|
#include "pltf_win32.h"
|
||||||
|
|
||||||
#define X(type, name) \
|
#define X(type, name) \
|
||||||
type name = NULL
|
type name = NULL
|
||||||
@@ -27,7 +27,7 @@ void* pltf_gl_function_load(const char* name) {
|
|||||||
return gl_func;
|
return gl_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pltf_load_gl_funcs() {
|
void pltf_gl_funcs_load() {
|
||||||
PLTF_GL_FUNCS(X)
|
PLTF_GL_FUNCS(X)
|
||||||
}
|
}
|
||||||
|
|
||||||
343
src/pltf/win32/pltf.c
Normal file
343
src/pltf/win32/pltf.c
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
#include <GL/glcorearb.h>
|
||||||
|
#include <GL/wglext.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
#include "../gl_funcs.h"
|
||||||
|
#include "../pltf.h"
|
||||||
|
#include "DynArray.h"
|
||||||
|
#include "DynString.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HGLRC gl_ctx;
|
||||||
|
} State;
|
||||||
|
|
||||||
|
HMODULE opengl_module = NULL;
|
||||||
|
|
||||||
|
static const wchar_t* wc_name = L"Sample Window Class";
|
||||||
|
static HMODULE exe_module = NULL;
|
||||||
|
static HWND hwnd = NULL;
|
||||||
|
static HDC hdc = NULL;
|
||||||
|
static DynArray_DynString wgl_extensions = { 0 };
|
||||||
|
static State window_state = {
|
||||||
|
.gl_ctx = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
void pltf_init() {
|
||||||
|
exe_module = GetModuleHandle(NULL);
|
||||||
|
if (exe_module == NULL) {
|
||||||
|
LOG_FATAL("Failed to get module");
|
||||||
|
}
|
||||||
|
|
||||||
|
opengl_module = LoadLibraryA("opengl32.dll");
|
||||||
|
if (opengl_module == NULL) {
|
||||||
|
LOG_FATAL("Failed to load opengl32.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the window class
|
||||||
|
WNDCLASS wc = { };
|
||||||
|
wc.lpfnWndProc = WindowProc;
|
||||||
|
wc.hInstance = exe_module;
|
||||||
|
wc.lpszClassName = wc_name;
|
||||||
|
wc.style = CS_OWNDC;
|
||||||
|
|
||||||
|
RegisterClass(&wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_deinit() {
|
||||||
|
UnregisterClass(wc_name, exe_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pltf_has_wgl_extension(const DynString* name) {
|
||||||
|
for (size_t i = 0; i < wgl_extensions.len; i++) {
|
||||||
|
if (DynString_equal(name, DynArray_DynString_at(&wgl_extensions, i))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pltf_has_wgl_extension_c_str(const char* name) {
|
||||||
|
DynString name_dstr = DynString_alloc(name, strlen(name));
|
||||||
|
const bool res = pltf_has_wgl_extension(&name_dstr);
|
||||||
|
DynString_free(&name_dstr);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_window_create() {
|
||||||
|
// Create the window
|
||||||
|
hwnd = CreateWindowEx(
|
||||||
|
0, // Optional window styles
|
||||||
|
wc_name, // Window class
|
||||||
|
L"Learn to Program Windows", // Window text
|
||||||
|
WS_OVERLAPPEDWINDOW, // Window style
|
||||||
|
|
||||||
|
// Size and position
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
|
||||||
|
NULL, // Parent window
|
||||||
|
NULL, // Menu
|
||||||
|
exe_module, // Instance handle
|
||||||
|
&window_state // Additional application data
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hwnd == NULL) {
|
||||||
|
LOG_FATAL("ERROR: hwnd was NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
hdc = GetDC(hwnd);
|
||||||
|
if (hdc == NULL) {
|
||||||
|
LOG_FATAL("Failed to get HDC");
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowWindow(hwnd, SW_SHOWDEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_window_destroy() {
|
||||||
|
if (hwnd != NULL) {
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
hwnd = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_gl_ctx_create() {
|
||||||
|
const PIXELFORMATDESCRIPTOR pfd = {
|
||||||
|
sizeof(PIXELFORMATDESCRIPTOR),
|
||||||
|
1,
|
||||||
|
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
||||||
|
PFD_TYPE_RGBA,
|
||||||
|
32, // Color depth
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
24, // Depth buffer bits
|
||||||
|
8, // Stencil buffer bits
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
HDC hdc = GetDC(hwnd);
|
||||||
|
if (hdc == NULL) {
|
||||||
|
LOG_ERROR("Failed to get window DC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int pixel_format = ChoosePixelFormat(hdc, &pfd);
|
||||||
|
if (SetPixelFormat(hdc, pixel_format, &pfd) == FALSE) {
|
||||||
|
LOG_ERRORF("Failed to set pixel format. Error: %d", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_state.gl_ctx = wglCreateContext(hdc);
|
||||||
|
if (window_state.gl_ctx == NULL) {
|
||||||
|
LOG_ERRORF("Failed to create OpenGL context. Error: %d", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wglMakeCurrent(hdc, window_state.gl_ctx) == FALSE) {
|
||||||
|
LOG_ERRORF("Failed to make OpenGL context current. Error: %d", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) pltf_gl_function_load("wglGetExtensionsStringARB");
|
||||||
|
|
||||||
|
char* wgl_extensions_str = (char*) wglGetExtensionsStringARB(hdc);
|
||||||
|
|
||||||
|
char* wgl_extensions_str_copy = strdup(wgl_extensions_str);
|
||||||
|
|
||||||
|
if (!DynArray_DynString_alloc(&wgl_extensions)) {
|
||||||
|
LOG_ERROR("Failed to allocate wgl_extensions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* ext = strtok(wgl_extensions_str_copy, " ");
|
||||||
|
if (ext == NULL) {
|
||||||
|
LOG_ERROR("wgl_extensions_str was empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (ext != NULL) {
|
||||||
|
DynString ext_dstr = DynString_alloc(ext, strlen(ext));
|
||||||
|
|
||||||
|
if (!DynArray_DynString_push_back(&wgl_extensions, &ext_dstr)) {
|
||||||
|
LOG_ERROR("Failed to push back extension string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext = strtok(NULL, " ");
|
||||||
|
if (ext == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(wgl_extensions_str_copy);
|
||||||
|
|
||||||
|
if (!pltf_has_wgl_extension_c_str("WGL_ARB_pixel_format")) {
|
||||||
|
LOG_FATAL("WGL_ARB_create_context extension required.");
|
||||||
|
}
|
||||||
|
if (!pltf_has_wgl_extension_c_str("WGL_ARB_create_context")) {
|
||||||
|
LOG_FATAL("WGL_ARB_create_context extension is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) pltf_gl_function_load("wglChoosePixelFormatARB");
|
||||||
|
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) pltf_gl_function_load("wglCreateContextAttribsARB");
|
||||||
|
|
||||||
|
int wgl_pixel_format = 0;
|
||||||
|
{
|
||||||
|
UINT num_formats = 0;
|
||||||
|
const int attribIList[] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
if (wglChoosePixelFormatARB(hdc, attribIList, NULL, 1, &wgl_pixel_format, &num_formats) == FALSE) {
|
||||||
|
LOG_FATAL("Failed to get pixel format with wglChoosePixelFormatARB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SetPixelFormat(hdc, wgl_pixel_format, &pfd) == FALSE) {
|
||||||
|
LOG_FATAL("Failed to set wgl_pixel_format");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wglDeleteContext(window_state.gl_ctx) == FALSE) {
|
||||||
|
LOG_FATAL("Failed to delete dummy context");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const int attribIList[] = {
|
||||||
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||||
|
WGL_CONTEXT_MINOR_VERSION_ARB, 6,
|
||||||
|
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||||
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB
|
||||||
|
};
|
||||||
|
window_state.gl_ctx = wglCreateContextAttribsARB(hdc, NULL, attribIList);
|
||||||
|
if (window_state.gl_ctx == NULL) {
|
||||||
|
LOG_FATAL("wglCreateContextAttribsARB did not create a context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wglMakeCurrent(hdc, window_state.gl_ctx) == FALSE) {
|
||||||
|
LOG_FATAL("Failed to set proper context as current");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_gl_ctx_destroy() {
|
||||||
|
wglDeleteContext(window_state.gl_ctx);
|
||||||
|
window_state.gl_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_gl_ctx_info_print() {
|
||||||
|
if (glGetIntegerv == NULL) {
|
||||||
|
glGetIntegerv = (PFNGLGETINTEGERVPROC) pltf_gl_function_load("glGetIntegerv");
|
||||||
|
if (glGetIntegerv == NULL) {
|
||||||
|
LOG_FATAL("Could not load glGetIntegerv");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int major = 0;
|
||||||
|
int minor = 0;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||||
|
|
||||||
|
int profile_mask = 0;
|
||||||
|
char* profile;
|
||||||
|
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
|
||||||
|
if (profile_mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
||||||
|
profile = "core";
|
||||||
|
} else if (profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) {
|
||||||
|
profile = "compatibility";
|
||||||
|
} else {
|
||||||
|
LOG_ERRORF(
|
||||||
|
"GL_CONTEXT_PROFILE_MASK did not contain either bit. profile_mask: %d",
|
||||||
|
profile_mask
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("OpenGL version %d.%d %s\n", major, minor, profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pltf_swap_buffers() {
|
||||||
|
wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);
|
||||||
|
}
|
||||||
|
|
||||||
|
PltfWindowEvent pltf_window_event_handle() {
|
||||||
|
MSG msg = { 0 };
|
||||||
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
if (msg.message == WM_QUIT) {
|
||||||
|
return PLTF_WE_QUIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PLTF_WE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
State* pState = NULL;
|
||||||
|
if (uMsg == WM_CREATE) {
|
||||||
|
CREATESTRUCT* pCreate = (CREATESTRUCT*) lParam;
|
||||||
|
pState = (State*) pCreate->lpCreateParams;
|
||||||
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) pState);
|
||||||
|
} else {
|
||||||
|
LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||||
|
pState = (State*) ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (uMsg) {
|
||||||
|
// case WM_LBUTTONDOWN: {
|
||||||
|
// printf("State: msg: %s, num: %d\n", pState->msg, pState->num);
|
||||||
|
//
|
||||||
|
// printf("lParam: %llx\n", lParam);
|
||||||
|
// int mouse_x = GET_X_LPARAM(lParam);
|
||||||
|
// printf("mouse_x: %x\n", mouse_x);
|
||||||
|
// int mouse_y = GET_Y_LPARAM(lParam);
|
||||||
|
// printf("mouse_y: %x\n", mouse_y);
|
||||||
|
// printf("x: %d y: %d\n", mouse_x, mouse_y);
|
||||||
|
//
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
case WM_CREATE: {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (wParam == VK_ESCAPE) {
|
||||||
|
PostMessage(hwnd, WM_DESTROY, 0, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
wglDeleteContext(pState->gl_ctx);
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_CLOSE:
|
||||||
|
if (MessageBox(hwnd, L"Really quit?", L"My Application", MB_OKCANCEL) == IDOK) {
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
8
src/pltf/win32/pltf_win32.h
Normal file
8
src/pltf/win32/pltf_win32.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef PLTF_WIN32_H_
|
||||||
|
#define PLTF_WIN32_H_
|
||||||
|
|
||||||
|
#include <windef.h>
|
||||||
|
|
||||||
|
extern HMODULE opengl_module;
|
||||||
|
|
||||||
|
#endif // PLTF_WIN32_H_
|
||||||
Reference in New Issue
Block a user