pltf.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #ifdef _WIN32
  2. #include <GL/glcorearb.h>
  3. #include <GL/wglext.h>
  4. #include <assert.h>
  5. #include <stdio.h>
  6. #include <windows.h>
  7. #include <windowsx.h>
  8. #include "../gl_funcs.h"
  9. #include "../pltf.h"
  10. #include "DynArray.h"
  11. #include "DynString.h"
  12. #include "internal.h"
  13. #include "log.h"
  14. #include "win_proc.h"
  15. void pltf_init() {
  16. pltf_state.exe_module = GetModuleHandle(NULL);
  17. if (pltf_state.exe_module == NULL) {
  18. LOG_FATAL("Failed to get module");
  19. }
  20. opengl_module = LoadLibraryA("opengl32.dll");
  21. if (opengl_module == NULL) {
  22. LOG_FATAL("Failed to load opengl32.dll");
  23. }
  24. // Register the window class
  25. WNDCLASS wc = { };
  26. wc.lpfnWndProc = WindowProc;
  27. wc.hInstance = pltf_state.exe_module;
  28. wc.lpszClassName = pltf_state.wc_name;
  29. wc.style = CS_OWNDC;
  30. RegisterClass(&wc);
  31. }
  32. void pltf_deinit() {
  33. UnregisterClass(pltf_state.wc_name, pltf_state.exe_module);
  34. }
  35. void pltf_window_create() {
  36. // Create the window
  37. pltf_state.hwnd = CreateWindowEx(
  38. 0, // Optional window styles
  39. pltf_state.wc_name, // Window class
  40. L"Learn to Program Windows", // Window text
  41. WS_OVERLAPPEDWINDOW, // Window style
  42. // Size and position
  43. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  44. NULL, // Parent window
  45. NULL, // Menu
  46. pltf_state.exe_module, // Instance handle
  47. &pltf_state.window_state // Additional application data
  48. );
  49. if (pltf_state.hwnd == NULL) {
  50. LOG_FATAL("ERROR: hwnd was NULL");
  51. }
  52. pltf_state.hdc = GetDC(pltf_state.hwnd);
  53. if (pltf_state.hdc == NULL) {
  54. LOG_FATAL("Failed to get HDC");
  55. }
  56. ShowWindow(pltf_state.hwnd, SW_SHOWDEFAULT);
  57. }
  58. void pltf_window_close() {
  59. PostMessage(pltf_state.hwnd, WM_CLOSE, 0, 0);
  60. }
  61. void pltf_window_destroy() {
  62. if (pltf_state.hwnd != NULL) {
  63. DestroyWindow(pltf_state.hwnd);
  64. pltf_state.hwnd = NULL;
  65. }
  66. }
  67. void pltf_gl_ctx_create() {
  68. const PIXELFORMATDESCRIPTOR pfd = {
  69. sizeof(PIXELFORMATDESCRIPTOR),
  70. 1,
  71. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
  72. PFD_TYPE_RGBA,
  73. 32, // Color depth
  74. 0,
  75. 0,
  76. 0,
  77. 0,
  78. 0,
  79. 0,
  80. 0,
  81. 0,
  82. 0,
  83. 0,
  84. 0,
  85. 0,
  86. 0,
  87. 24, // Depth buffer bits
  88. 8, // Stencil buffer bits
  89. 0,
  90. };
  91. HDC hdc = GetDC(pltf_state.hwnd);
  92. if (hdc == NULL) {
  93. LOG_ERROR("Failed to get window DC");
  94. return;
  95. }
  96. const int pixel_format = ChoosePixelFormat(hdc, &pfd);
  97. if (SetPixelFormat(hdc, pixel_format, &pfd) == FALSE) {
  98. LOG_ERRORF("Failed to set pixel format. Error: %d", GetLastError());
  99. return;
  100. }
  101. pltf_state.window_state.gl_ctx = wglCreateContext(hdc);
  102. if (pltf_state.window_state.gl_ctx == NULL) {
  103. LOG_ERRORF("Failed to create OpenGL context. Error: %d", GetLastError());
  104. return;
  105. }
  106. if (wglMakeCurrent(hdc, pltf_state.window_state.gl_ctx) == FALSE) {
  107. LOG_ERRORF("Failed to make OpenGL context current. Error: %d", GetLastError());
  108. return;
  109. }
  110. PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) pltf_gl_function_load("wglGetExtensionsStringARB");
  111. // Copy to prevent modifying the original string. Might be useless but doing it just in case.
  112. char* wgl_extensions_str = strdup(wglGetExtensionsStringARB(hdc));
  113. if (!DynArray_DynString_alloc(&pltf_state.wgl_extensions)) {
  114. LOG_ERROR("Failed to allocate wgl_extensions");
  115. return;
  116. }
  117. char* ext = strtok(wgl_extensions_str, " ");
  118. if (ext == NULL) {
  119. LOG_ERROR("wgl_extensions_str was empty");
  120. return;
  121. }
  122. while (ext != NULL) {
  123. DynString ext_dstr = DynString_alloc(ext, strlen(ext));
  124. if (!DynArray_DynString_push_back(&pltf_state.wgl_extensions, &ext_dstr)) {
  125. LOG_ERROR("Failed to push back extension string");
  126. return;
  127. }
  128. ext = strtok(NULL, " ");
  129. if (ext == NULL) {
  130. break;
  131. }
  132. }
  133. free(wgl_extensions_str);
  134. if (!pltf_has_wgl_extension("WGL_ARB_pixel_format")) {
  135. LOG_FATAL("WGL_ARB_create_context extension required.");
  136. }
  137. if (!pltf_has_wgl_extension("WGL_ARB_create_context")) {
  138. LOG_FATAL("WGL_ARB_create_context extension is required");
  139. }
  140. PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) pltf_gl_function_load("wglChoosePixelFormatARB");
  141. PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) pltf_gl_function_load("wglCreateContextAttribsARB");
  142. int wgl_pixel_format = 0;
  143. {
  144. UINT num_formats = 0;
  145. const int attribIList[] = {
  146. WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
  147. WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
  148. WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
  149. WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
  150. WGL_COLOR_BITS_ARB, 32,
  151. WGL_DEPTH_BITS_ARB, 24,
  152. WGL_STENCIL_BITS_ARB, 8,
  153. 0
  154. };
  155. if (wglChoosePixelFormatARB(hdc, attribIList, NULL, 1, &wgl_pixel_format, &num_formats) == FALSE) {
  156. LOG_FATAL("Failed to get pixel format with wglChoosePixelFormatARB");
  157. }
  158. }
  159. if (SetPixelFormat(hdc, wgl_pixel_format, &pfd) == FALSE) {
  160. LOG_FATAL("Failed to set wgl_pixel_format");
  161. }
  162. if (wglDeleteContext(pltf_state.window_state.gl_ctx) == FALSE) {
  163. LOG_FATAL("Failed to delete dummy context");
  164. }
  165. {
  166. const int attribIList[] = {
  167. WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
  168. WGL_CONTEXT_MINOR_VERSION_ARB, 6,
  169. WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
  170. WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB
  171. };
  172. pltf_state.window_state.gl_ctx = wglCreateContextAttribsARB(hdc, NULL, attribIList);
  173. if (pltf_state.window_state.gl_ctx == NULL) {
  174. LOG_FATAL("wglCreateContextAttribsARB did not create a context");
  175. }
  176. }
  177. if (wglMakeCurrent(hdc, pltf_state.window_state.gl_ctx) == FALSE) {
  178. LOG_FATAL("Failed to set proper context as current");
  179. }
  180. }
  181. void pltf_gl_ctx_destroy() {
  182. wglDeleteContext(pltf_state.window_state.gl_ctx);
  183. pltf_state.window_state.gl_ctx = NULL;
  184. }
  185. void pltf_gl_ctx_info_print() {
  186. if (glGetIntegerv == NULL) {
  187. glGetIntegerv = (PFNGLGETINTEGERVPROC) pltf_gl_function_load("glGetIntegerv");
  188. if (glGetIntegerv == NULL) {
  189. LOG_FATAL("Could not load glGetIntegerv");
  190. }
  191. }
  192. int major = 0;
  193. int minor = 0;
  194. glGetIntegerv(GL_MAJOR_VERSION, &major);
  195. glGetIntegerv(GL_MINOR_VERSION, &minor);
  196. int profile_mask = 0;
  197. char* profile;
  198. glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask);
  199. if (profile_mask & GL_CONTEXT_CORE_PROFILE_BIT) {
  200. profile = "core";
  201. } else if (profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) {
  202. profile = "compatibility";
  203. } else {
  204. LOG_ERRORF(
  205. "GL_CONTEXT_PROFILE_MASK did not contain either bit. profile_mask: %d",
  206. profile_mask
  207. );
  208. return;
  209. }
  210. printf("OpenGL version %d.%d %s\n", major, minor, profile);
  211. }
  212. void pltf_swap_buffers() {
  213. wglSwapLayerBuffers(pltf_state.hdc, WGL_SWAP_MAIN_PLANE);
  214. }
  215. PltfWindowEvent pltf_window_event_handle() {
  216. MSG msg = { 0 };
  217. if (PeekMessage(&msg, pltf_state.hwnd, 0, 0, PM_REMOVE)) {
  218. TranslateMessage(&msg);
  219. DispatchMessage(&msg);
  220. switch (msg.message) {
  221. case WM_DESTROY:
  222. return PLTF_WE_DESTROY;
  223. }
  224. }
  225. return PLTF_WE_NONE;
  226. }
  227. #define PLTF_KEYS_X(lower, upper) \
  228. case PLTF_KEY_##upper: { \
  229. pltf_state.key_##lower##_cb = cb; \
  230. pltf_state.key_##lower##_cb_user_data = (void*) user_data; \
  231. break; \
  232. }
  233. void pltf_key_callback_set(
  234. const PltfKey key,
  235. const PltfKeyCallback cb,
  236. void* user_data
  237. ) {
  238. switch (key) {
  239. case PLTF_KEY_NONE:
  240. break;
  241. PLTF_KEYS(PLTF_KEYS_X);
  242. }
  243. }
  244. #undef PLTF_KEYS_X
  245. #endif // _WIN32