diff --git a/meson.build b/meson.build index 2147058..8b54dcc 100644 --- a/meson.build +++ b/meson.build @@ -40,6 +40,8 @@ endif executable( 'scuffedcraft', + 'src/pltf/gl_funcs.c', + 'src/pltf/pltf.c', 'src/DynArray.c', 'src/DynString.c', 'src/log.c', diff --git a/src/main.c b/src/main.c index f06ae90..c967f5f 100644 --- a/src/main.c +++ b/src/main.c @@ -13,11 +13,8 @@ #include "DynArray.h" #include "DynString.h" #include "log.h" - -#include -#include - -HMODULE opengl_module = NULL; +#include "pltf/gl_funcs.h" +#include "pltf/pltf.h" // int _main() { // return 0; @@ -32,23 +29,6 @@ typedef struct { int num; } State; -void* gl_function_load(const char* name) { - assert(opengl_module != NULL); - void* gl_func = (void*) wglGetProcAddress(name); - if (gl_func == NULL || gl_func == (void*) 1 || gl_func == (void*) 2 || gl_func == (void*) 3 || gl_func == (void*) -1) { - void* gl32_func = (void*) GetProcAddress(opengl_module, name); - if (gl32_func == NULL || gl32_func == (void*) 1 || gl32_func == (void*) 2 || gl32_func == (void*) 3 || gl32_func == (void*) -1) { - LOG_ERRORF("wglGetProcAddress failed to load gl function %s. Returned %p\n", name, gl_func); - LOG_ERRORF("GetProcAddress failed to load gl function %s. Returned %p\n", name, gl32_func); - return NULL; - } - - return gl32_func; - } - - return gl_func; -} - bool has_wgl_extension(const DynString* name) { assert(!DynString_is_null(name)); assert(!DynArray_DynString_is_null(&wgl_extensions)); @@ -69,12 +49,35 @@ bool has_wgl_extension_c_str(const char* name) { return res; } -struct timespec thread_time_get() { - struct timespec t = { 0 }; - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t) == -1) { - LOG_FATALF("Failed to get thread time. errno: %d", errno); +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"); + } } - return t; + + 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) { @@ -131,7 +134,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 0, }; - HDC hdc = GetWindowDC(hwnd); + HDC hdc = GetDC(hwnd); if (hdc == NULL) { LOG_ERROR("Failed to get window DC"); return 1; @@ -153,37 +156,12 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return 1; } - PFNGLGETINTEGERVPROC glGetIntegerv = (PFNGLGETINTEGERVPROC) gl_function_load("glGetIntegerv"); - if (glGetIntegerv == NULL) { - return 1; - } - int major = 0; - int minor = 0; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - printf("OpenGL version %d.%d\n", major, minor); + printf("Dummy context info: "); + print_opengl_info(); - int profile_mask = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask); - if (profile_mask & GL_CONTEXT_CORE_PROFILE_BIT) { - printf("OpenGL profile: core\n"); - } else if (profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) { - printf("OpenGL profile: compatibility\n"); - } else { - LOG_ERRORF( - "GL_CONTEXT_PROFILE_MASK did not contain either bit. profile_mask: %d", - profile_mask - ); - } - - PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) gl_function_load("wglGetExtensionsStringARB"); - if (wglGetExtensionsStringARB == NULL) { - LOG_ERROR("Could not load wgl extensions string."); - return 1; - } + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) pltf_gl_function_load("wglGetExtensionsStringARB"); char* wgl_extensions_str = (char*) wglGetExtensionsStringARB(hdc); - printf("wgl extensions: %s\n", wgl_extensions_str); char* wgl_extensions_str_copy = strdup(wgl_extensions_str); @@ -209,20 +187,73 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (ext == NULL) { break; } - } free(wgl_extensions_str_copy); - 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)); + // 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"); } - const struct timespec b = thread_time_get(); - has_wgl_extension_c_str("WGL_ARB_create_context"); - const struct timespec a = thread_time_get(); - printf("time: %ld\n", a.tv_nsec - b.tv_nsec); + 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(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 + }; + gl_ctx = wglCreateContextAttribsARB(hdc, NULL, attribIList); + if (gl_ctx == NULL) { + LOG_FATAL("wglCreateContextAttribsARB did not create a context"); + } + } + + if (wglMakeCurrent(hdc, 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; } @@ -271,7 +302,9 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow) { - opengl_module = LoadLibraryA("opengl32.dll"); + // opengl_module = LoadLibraryA("opengl32.dll"); + + pltf_init(); // Register the window class const wchar_t* CLASS_NAME = L"Sample Window Class"; @@ -314,10 +347,136 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, // Message loop - MSG msg = { }; - while (GetMessage(&msg, NULL, 0, 0) > 0) { + 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 + const float triangle_verts[] = { + // pos + 0.0f, 0.5f, 0.0f, // top + -0.5f, -0.5f, 0.0f, // bottom-left + 0.5f, -0.5f, 0.0f // bottom-right + + }; + // clang-format on + + const size_t triangle_vert_count = sizeof(triangle_verts) / sizeof(triangle_verts[0]) / 3; + + unsigned int triangle_vao = 0; + glGenVertexArrays(1, &triangle_vao); + glBindVertexArray(triangle_vao); + + unsigned int triangle_vbo = 0; + glGenBuffers(1, &triangle_vbo); + glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(triangle_verts), + triangle_verts, + GL_STATIC_DRAW + ); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(float) * 3, + (void*) 0 + ); + + glBindVertexArray(0); + + // clang-format off + const char* vertex_shader_src = + "#version 460 core\n" + "layout (location = 0) in vec3 a_pos;\n" + "void main() {\n" + " gl_Position = vec4(a_pos, 1.0);\n" + "}\n" + ; + + const char* fragment_shader_src = + "#version 460 core\n" + "out vec4 frag_color;\n" + "void main() {\n" + " frag_color = vec4(0.0, 0.0, 0.0, 1.0);\n" + "}\n" + ; + // clang-format on + + const unsigned int vert_shader = glCreateShader(GL_VERTEX_SHADER); + { + const int len = strlen(vertex_shader_src); + glShaderSource(vert_shader, 1, &vertex_shader_src, &len); + glCompileShader(vert_shader); + int compile_status = 0; + glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &compile_status); + if (compile_status != GL_TRUE) { + int info_log_len = 0; + glGetShaderiv(vert_shader, GL_INFO_LOG_LENGTH, &info_log_len); + char* err_str = (char*) malloc(sizeof(char) * info_log_len); + glGetShaderInfoLog(vert_shader, info_log_len - 1, NULL, err_str); + LOG_FATALF("Failed to compile vertex shader: %s", err_str); + } + } + const unsigned int frag_shader = glCreateShader(GL_FRAGMENT_SHADER); + { + const int len = strlen(fragment_shader_src); + glShaderSource(frag_shader, 1, &fragment_shader_src, &len); + glCompileShader(frag_shader); + int compile_status = 0; + glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &compile_status); + if (compile_status != GL_TRUE) { + int info_log_len = 0; + glGetShaderiv(frag_shader, GL_INFO_LOG_LENGTH, &info_log_len); + char* err_str = (char*) malloc(sizeof(char) * info_log_len); + glGetShaderInfoLog(frag_shader, info_log_len - 1, NULL, err_str); + LOG_FATALF("Failed to compile fragment shader: %s", err_str); + } + } + + const unsigned int shader_program = glCreateProgram(); + { + + glAttachShader(shader_program, vert_shader); + glAttachShader(shader_program, frag_shader); + glLinkProgram(shader_program); + int compile_status = 0; + glGetProgramiv(shader_program, GL_LINK_STATUS, &compile_status); + if (compile_status != GL_TRUE) { + LOG_FATAL("Failed to link shader program."); + } + glDeleteShader(vert_shader); + glDeleteShader(frag_shader); + } + + MSG msg = { 0 }; + while (true) { + if (GetMessage(&msg, NULL, 0, 0) <= 0) { + break; + } TranslateMessage(&msg); DispatchMessage(&msg); + + printf("MSG LOOP\n"); + + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(shader_program); + glBindVertexArray(triangle_vao); + glDrawArrays(GL_TRIANGLE_STRIP, 0, triangle_vert_count); + + wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE); } return 0; diff --git a/src/pltf/gl_funcs.c b/src/pltf/gl_funcs.c new file mode 100644 index 0000000..7b02e0a --- /dev/null +++ b/src/pltf/gl_funcs.c @@ -0,0 +1,33 @@ +#include "gl_funcs.h" +#include "log.h" +#include "pltf.h" + +#define X(type, name) \ +type name = NULL + +PLTF_GL_FUNCS(X) +#undef X + +#define X(type, name) \ +name = (type) pltf_gl_function_load(#name) + +void* pltf_gl_function_load(const char* name) { + void* gl_func = (void*) wglGetProcAddress(name); + if (gl_func == NULL || gl_func == (void*) 1 || gl_func == (void*) 2 || gl_func == (void*) 3 || gl_func == (void*) -1) { + void* gl32_func = (void*) GetProcAddress(opengl_module, name); + if (gl32_func == NULL || gl32_func == (void*) 1 || gl32_func == (void*) 2 || gl32_func == (void*) 3 || gl32_func == (void*) -1) { + LOG_ERRORF("wglGetProcAddress failed to load gl function %s. Returned %p\n", name, gl_func); + LOG_ERRORF("GetProcAddress failed to load gl function %s. Returned %p\n", name, gl32_func); + return NULL; + } + + return gl32_func; + } + + return gl_func; +} + +void pltf_load_gl_funcs() { + PLTF_GL_FUNCS(X) +} + diff --git a/src/pltf/gl_funcs.h b/src/pltf/gl_funcs.h new file mode 100644 index 0000000..0ff4781 --- /dev/null +++ b/src/pltf/gl_funcs.h @@ -0,0 +1,40 @@ +#ifndef GL_FUNCS_H_ +#define GL_FUNCS_H_ + +#include + +#define PLTF_GL_FUNCS(X) \ +X(PFNGLGETINTEGERVPROC, glGetIntegerv); \ +X(PFNGLGETFLOATVPROC, glGetFloatv); \ +X(PFNGLCLEARCOLORPROC, glClearColor); \ +X(PFNGLCLEARPROC, glClear); \ +X(PFNGLGETERRORPROC, glGetError); \ +X(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays); \ +X(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray); \ +X(PFNGLGENBUFFERSPROC, glGenBuffers); \ +X(PFNGLBINDBUFFERPROC, glBindBuffer); \ +X(PFNGLBUFFERDATAPROC, glBufferData); \ +X(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer); \ +X(PFNGLCREATESHADERPROC, glCreateShader); \ +X(PFNGLSHADERSOURCEPROC, glShaderSource); \ +X(PFNGLCOMPILESHADERPROC, glCompileShader); \ +X(PFNGLGETSHADERIVPROC, glGetShaderiv); \ +X(PFNGLCREATEPROGRAMPROC, glCreateProgram); \ +X(PFNGLATTACHSHADERPROC, glAttachShader); \ +X(PFNGLLINKPROGRAMPROC, glLinkProgram); \ +X(PFNGLGETPROGRAMIVPROC, glGetProgramiv); \ +X(PFNGLUSEPROGRAMPROC, glUseProgram); \ +X(PFNGLDRAWARRAYSPROC, glDrawArrays); \ +X(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog); \ +X(PFNGLDELETESHADERPROC, glDeleteShader); \ +X(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray); \ + +#define X(type, name) extern type name + +PLTF_GL_FUNCS(X) +#undef X + +void* pltf_gl_function_load(const char* name); +void pltf_load_gl_funcs(); + +#endif // GL_FUNCS_H_ diff --git a/src/pltf/pltf.c b/src/pltf/pltf.c new file mode 100644 index 0000000..f597d36 --- /dev/null +++ b/src/pltf/pltf.c @@ -0,0 +1,14 @@ +#include +#include + +#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"); + } +} diff --git a/src/pltf/pltf.h b/src/pltf/pltf.h new file mode 100644 index 0000000..7363622 --- /dev/null +++ b/src/pltf/pltf.h @@ -0,0 +1,10 @@ +#ifndef PLTF_H_ +#define PLTF_H_ + +#include + +extern HMODULE opengl_module; + +void pltf_init(); + +#endif // PLTF_H_