diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5fd25af --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +lib/ +main +main.exe +valgrind-out.txt +*.o +sample/ +other/ diff --git a/Makefile b/Makefile index dd31f3e..5ec3fbd 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -FLAGS=-fPIC --shared +FLAGS=-fPIC --shared -Wall -Wextra LINUX_FILES=src/openwindow.c deps/lib/glad_linux.a @@ -11,7 +11,7 @@ all: libopenwindow.so libopenwindow.dll libopenwindow.so: glad_linux.a mkdir -p ${OUTPUT} - gcc ${FLAGS} -o ${OUTPUT}libopenwindow.so ${LINUX_FILES} + gcc ${FLAGS} -o ${OUTPUT}libopenwindow.so ${LINUX_FILES} -lX11 -lGLX -lOpenGL libopenwindow.dll: glad_windows.a mkdir -p ${OUTPUT} @@ -21,9 +21,9 @@ GLAD_FLAGS=-fPIC -c GLAD_FILES=deps/src/glad.c glad_linux.a: deps/src/glad.c - gcc ${GLAD_FLAGS} -o deps/src/glad_linux.o ${GLAD_FILES} - ar rcs deps/lib/glad_linux.a deps/src/glad_linux.o + gcc ${GLAD_FLAGS} -o deps/lib/glad_linux.o ${GLAD_FILES} + ar rcs deps/lib/glad_linux.a deps/lib/glad_linux.o glad_windows.a: deps/src/glad.c - x86_64-w64-mingw32-gcc ${GLAD_FLAGS} -o deps/src/glad_windows.o ${GLAD_FILES} - ar rcs deps/lib/glad_windows.a deps/src/glad_windows.o + x86_64-w64-mingw32-gcc ${GLAD_FLAGS} -o deps/lib/glad_windows.o ${GLAD_FILES} + ar rcs deps/lib/glad_windows.a deps/lib/glad_windows.o diff --git a/deps/GLAD_LICENSE b/deps/GLAD_LICENSE new file mode 100644 index 0000000..4965a6b --- /dev/null +++ b/deps/GLAD_LICENSE @@ -0,0 +1,63 @@ +The glad source code: + + The MIT License (MIT) + + Copyright (c) 2013-2022 David Herberth + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +The Khronos Specifications: + + Copyright (c) 2013-2020 The Khronos Group Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +The EGL Specification and various headers: + + Copyright (c) 2007-2016 The Khronos Group Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and/or associated documentation files (the + "Materials"), to deal in the Materials without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Materials, and to + permit persons to whom the Materials are furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Materials. + + THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/deps/lib/libGLESv2.dll b/deps/lib/libGLESv2.dll deleted file mode 100644 index 22971b4..0000000 Binary files a/deps/lib/libGLESv2.dll and /dev/null differ diff --git a/deps/lib/libwinpthread-1.dll b/deps/lib/libwinpthread-1.dll deleted file mode 100644 index 37a6757..0000000 Binary files a/deps/lib/libwinpthread-1.dll and /dev/null differ diff --git a/main.c b/main.c index bf06544..993a4f8 100644 --- a/main.c +++ b/main.c @@ -1,81 +1,34 @@ #include -#include -#include "deps/include/glad/glad.h" +#include "GL/gl.h" + #include "src/openwindow.h" -#ifndef _WIN32 - -#include - -#define Window X11Window -#include -#undef Window - -void xevent(Window * w, XEvent xev) { - switch (xev.type) - { - case MotionNotify: - printf("motion: %d %d\n", xev.xbutton.x, xev.xbutton.y); - break; - case KeyRelease: - printf("release (%s)\n", XKeysymToString(XLookupKeysym(&xev.xkey, 0))); - break; - case KeyPress: - if (XLookupKeysym(&xev.xkey, 0) == XK_Escape) w->close = true; - printf("keypress (%s)\n", XKeysymToString(XLookupKeysym(&xev.xkey, 0))); - break; - case ButtonPress: - printf("BPress: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y); - printf("Type=%d\n", (int)xev.xbutton.type); - break; - case ButtonRelease: - printf("BRelease: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y); - printf("Type=%d\n", (int)xev.xbutton.type); - break; - default: - printf("Unknown event!\n"); - } -} - -#else - -#include - -#endif // _WIN32 - -const char * fss = -"#version 330 core\n" -"precision mediump float;" -"out vec4 FragColor;\n" -"void main()\n" -"{\n" -" FragColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n" -"}"; - int main(void) { - Window w = openWindow("Window", 800, 600); + Window * w = openWindow("Window", 800, 600); - // TODO: do this -#ifndef _WIN32 - windowSetEventHandler(&w, xevent); -#endif // _WIN32 + while (!windowKeyPressed(w, WINDOW_KEY_ESC)) { + windowHandleEvents(w); - while (!w.close) - { - windowHandleEvents(&w); + if (windowKeyPressed(w, WINDOW_KEY_A)) + printf("A is being pressed\n"); - glClearColor(0.1f, 0.2f, 0.3f, 1.0f); + if (windowKeyReleased(w, WINDOW_KEY_A)) + printf("A is being released\n"); + + glClearColor(0.1, 0.2, 0.3, 1); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 800, 600); - - glColor3f(1.0, 0, 0); glBegin(GL_TRIANGLES); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.5, -0.5); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.5, -0.5); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.0, 0.5); glEnd(); + glFlush(); windowDraw(w); } diff --git a/sample/x11 b/sample/x11 deleted file mode 100755 index 26d84d8..0000000 Binary files a/sample/x11 and /dev/null differ diff --git a/sample/x11.c b/sample/x11.c deleted file mode 100644 index dbb794a..0000000 --- a/sample/x11.c +++ /dev/null @@ -1,256 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); - -// Helper to check for extension string presence. Adapted from: -// http://www.opengl.org/resources/features/OGLextensions/ -static bool isExtensionSupported(const char *extList, const char *extension) -{ - const char *start; - const char *where, *terminator; - - /* Extension names should not have spaces. */ - where = strchr(extension, ' '); - if (where || *extension == '\0') - return false; - - /* It takes a bit of care to be fool-proof about parsing the - OpenGL extensions string. Don't be fooled by sub-strings, - etc. */ - for (start=extList;;) { - where = strstr(start, extension); - - if (!where) - break; - - terminator = where + strlen(extension); - - if ( where == start || *(where - 1) == ' ' ) - if ( *terminator == ' ' || *terminator == '\0' ) - return true; - - start = terminator; - } - - return false; -} - -int main(int argc, char* argv[]) -{ - Display *display = XOpenDisplay(NULL); - - if (!display) - { - printf("Failed to open X display\n"); - exit(1); - } - - // Get a matching FB config - static int visual_attribs[] = - { - GLX_X_RENDERABLE , True, - GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, - GLX_RENDER_TYPE , GLX_RGBA_BIT, - GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, - GLX_RED_SIZE , 8, - GLX_GREEN_SIZE , 8, - GLX_BLUE_SIZE , 8, - GLX_ALPHA_SIZE , 8, - GLX_DEPTH_SIZE , 24, - GLX_STENCIL_SIZE , 8, - GLX_DOUBLEBUFFER , True, - //GLX_SAMPLE_BUFFERS , 1, - //GLX_SAMPLES , 4, - None - }; - - int glx_major, glx_minor; - - // FBConfigs were added in GLX version 1.3. - if ( !glXQueryVersion( display, &glx_major, &glx_minor ) || - ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) - { - printf("Invalid GLX version"); - exit(1); - } - - printf( "Getting matching framebuffer configs\n" ); - int fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount); - if (!fbc) - { - printf( "Failed to retrieve a framebuffer config\n" ); - exit(1); - } - printf( "Found %d matching FB configs.\n", fbcount ); - - // Pick the FB config/visual with the most samples per pixel - printf( "Getting XVisualInfos\n" ); - int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; - - int i; - for (i=0; i visualid, samp_buf, samples ); - - if ( best_fbc < 0 || samp_buf && samples > best_num_samp ) - best_fbc = i, best_num_samp = samples; - if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) - worst_fbc = i, worst_num_samp = samples; - } - XFree( vi ); - } - - GLXFBConfig bestFbc = fbc[ best_fbc ]; - - // Be sure to free the FBConfig list allocated by glXChooseFBConfig() - XFree( fbc ); - - // Get a visual - XVisualInfo *vi = glXGetVisualFromFBConfig( display, bestFbc ); - printf( "Chosen visual ID = 0x%x\n", vi->visualid ); - - printf( "Creating colormap\n" ); - XSetWindowAttributes swa; - Colormap cmap; - swa.colormap = cmap = XCreateColormap( display, - RootWindow( display, vi->screen ), - vi->visual, AllocNone ); - swa.background_pixmap = None ; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - printf( "Creating window\n" ); - Window win = XCreateWindow( display, RootWindow( display, vi->screen ), - 0, 0, 100, 100, 0, vi->depth, InputOutput, - vi->visual, - CWBorderPixel|CWColormap|CWEventMask, &swa ); - if ( !win ) - { - printf( "Failed to create window.\n" ); - exit(1); - } - - // Done with the visual info data - XFree( vi ); - - XStoreName( display, win, "GL 3.0 Window" ); - - printf( "Mapping window\n" ); - XMapWindow( display, win ); - - // Get the default screen's GLX extension list - //const char *glxExts = glXQueryExtensionsString( display, - // DefaultScreen( display ) ); - - // NOTE: It is not necessary to create or make current to a context before - // calling glXGetProcAddressARB - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) - glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); - - GLXContext ctx = 0; - - // Install an X error handler so the application won't exit if GL 3.0 - // context allocation fails. - // - // Note this error handler is global. All display connections in all threads - // of a process use the same error handler, so be sure to guard against other - // threads issuing X commands while this code is running. - //ctxErrorOccurred = false; - //int (*oldHandler)(Display*, XErrorEvent*) = - // XSetErrorHandler(&ctxErrorHandler); - - // Check for the GLX_ARB_create_context extension string and the function. - // If either is not present, use GLX 1.3 context creation method. - //if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) || - // !glXCreateContextAttribsARB ) - //{ - // printf( "glXCreateContextAttribsARB() not found" - // " ... using old-style GLX context\n" ); - // ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True ); - //} else - //{ - int context_attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - None - }; - - printf( "Creating context\n" ); - ctx = glXCreateContextAttribsARB( display, bestFbc, 0, - True, context_attribs ); - - // Sync to ensure any errors generated are processed. - //XSync( display, False ); - //if (ctxErrorOccurred && !ctx) - //{ - // context_attribs[1] = 1; - // context_attribs[3] = 0; - - // ctxErrorOccurred = false; - - // printf( "Failed to create GL 3.0 context" - // " ... using old-style GLX context\n" ); - // ctx = glXCreateContextAttribsARB( display, bestFbc, 0, - // True, context_attribs ); - //} - //} - - //XSync( display, False ); - //XSetErrorHandler( oldHandler ); - - //if ( ctxErrorOccurred || !ctx ) - //{ - // printf( "Failed to create an OpenGL context\n" ); - // exit(1); - //} - - printf( "Making context current\n" ); - glXMakeCurrent( display, win, ctx ); - - const GLubyte * v = glGetString(GL_VERSION); - printf("%s\n", v); - - glClearColor( 0, 0.5, 1, 1 ); - glClear( GL_COLOR_BUFFER_BIT ); - glXSwapBuffers ( display, win ); - - sleep( 1 ); - - glClearColor ( 1, 0.5, 0, 1 ); - glClear ( GL_COLOR_BUFFER_BIT ); - glXSwapBuffers ( display, win ); - - sleep( 1 ); - - glXMakeCurrent( display, 0, 0 ); - glXDestroyContext( display, ctx ); - - XDestroyWindow( display, win ); - XFreeColormap( display, cmap ); - XCloseDisplay( display ); - - return 0; -} diff --git a/src/openwindow.c b/src/openwindow.c index 270fab0..8ddf370 100644 --- a/src/openwindow.c +++ b/src/openwindow.c @@ -1,6 +1,9 @@ +// TODO: Add all the error handling to the glx part + #include "openwindow.h" #include +#include int initOpenGL() { if (getOpenGLProcs() == 0) return -1; @@ -10,10 +13,34 @@ int initOpenGL() { return 0; } +#define OPENWINDOW_OPENGL_VERSSION_MAJOR 3 +#define OPENWINDOW_OPENGL_VERSSION_MINOR 0 + #ifndef _WIN32 +#include + typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); +void windowDefaultEventHandler(Window * w, XEvent xev) { + switch (xev.type) + { + case KeyPress: + case KeyRelease: + XQueryKeymap(w->x.display, w->io.current); + break; + } +} + +void windowEventHandler(Window * w, XEvent event) { + if (w->eventHandler == NULL) { + windowDefaultEventHandler(w, event); + } + else { + w->eventHandler(w, event); + } +} + bool checkGLXVersion(Window window) { int glx_major, glx_minor; @@ -53,12 +80,12 @@ int initGLX(Window * window) return -1; int attribs[] = { - GLX_X_RENDERABLE , True, + GLX_X_RENDERABLE , True, GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, GLX_RENDER_TYPE , GLX_RGBA_BIT, GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, GLX_RED_SIZE , 8, - GLX_GREEN_SIZE , 8, + GLX_GREEN_SIZE , 8, GLX_BLUE_SIZE , 8, GLX_ALPHA_SIZE , 8, GLX_DEPTH_SIZE , 24, @@ -85,9 +112,9 @@ int initGLX(Window * window) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); int context_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 6, - GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + GLX_CONTEXT_MAJOR_VERSION_ARB, OPENWINDOW_OPENGL_VERSSION_MAJOR, + GLX_CONTEXT_MINOR_VERSION_ARB, OPENWINDOW_OPENGL_VERSSION_MINOR, + GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_CORE_PROFILE_BIT_ARB, None }; window->glx.context = glXCreateContextAttribsARB(window->x.display, window->glx.config, 0, True, context_attribs); @@ -97,6 +124,7 @@ int initGLX(Window * window) int init(Window * window, const char * name, size_t width, size_t height) { window->x.display = XOpenDisplay(NULL); + if (window->x.display == NULL) { fprintf(stderr, "Failed to open xdisplay!\n"); return -1; @@ -155,10 +183,11 @@ int init(Window * window, const char * name, size_t width, size_t height) { return 0; } -Window openWindow(const char * name, size_t width, size_t height) { - Window w = {0}; +Window * openWindow(const char * name, size_t width, size_t height) { + Window * w = calloc(1, sizeof(Window)); + w->fps = WINDOW_DEFAULT_FPS; - if (init(&w, name, width, height) < 0) { + if (init(w, name, width, height) < 0) { fprintf(stderr, "Failed to initialize window: X11 error!\n"); exit(1); } @@ -171,34 +200,65 @@ Window openWindow(const char * name, size_t width, size_t height) { return w; } -void windowDraw(Window window) { - glXSwapBuffers(window.x.display, window.x.window); +void windowSetFps(Window * window, uint32_t fps) { + window->fps = fps; +} + +void windowDraw(Window * window) { + glXSwapBuffers(window->x.display, window->x.window); + usleep(1 / window->fps); } void windowSetEventHandler(Window * window, WindowEventHandler handler) { window->eventHandler = handler; } -void windowHandleEvents(Window * window) { - if (window->eventHandler == NULL) { - fprintf(stderr, "Window event handler is not defined. Use `setEventHandler' to set it!\n"); - exit(1); - } - - XEvent xev; - - if (XPending(window->x.display)) - if (XCheckWindowEvent(window->x.display, window->x.window, window->x.eventMask, &xev)) - window->eventHandler(window, xev); +void resetIOState(Window * window) { + memcpy(window->io.last, window->io.current, WINDOW_KEY_COUNT); } -void closeWindow(Window window) { - glXMakeCurrent(window.x.display, None, None); - glXDestroyContext(window.x.display, window.glx.context); +void windowHandleEvents(Window * window) { + XEvent xev = {0}; - XFreeColormap(window.x.display, window.x.cmap); - XDestroyWindow(window.x.display, window.x.window); - XCloseDisplay(window.x.display); + resetIOState(window); + + while (XPending(window->x.display)) { + if (XCheckWindowEvent(window->x.display, window->x.window, window->x.eventMask, &xev)) { + if (window->eventHandler != NULL) { + window->eventHandler(window, xev); + } else { + windowEventHandler(window, xev); + } + } + } +} + +void closeWindow(Window * window) { + glXMakeCurrent(window->x.display, None, None); + glXDestroyContext(window->x.display, window->glx.context); + + XFreeColormap(window->x.display, window->x.cmap); + XDestroyWindow(window->x.display, window->x.window); + XCloseDisplay(window->x.display); + free(window); +} + +bool windowKeyPressed(Window * window, char * key) { + KeySym keysym = XStringToKeysym(key); + if (keysym == NoSymbol) return false; + + KeyCode keycode = XKeysymToKeycode(window->x.display, keysym); + + return window->io.current[keycode / 8] & (1 << (keycode % 8)); +} + +bool windowKeyReleased(Window * window, char * key) { + KeySym keysym = XStringToKeysym(key); + if (keysym == NoSymbol) return false; + + KeyCode keycode = XKeysymToKeycode(window->x.display, keysym); + + return (window->io.last[keycode / 8] & (1 << (keycode % 8))) && !(window->io.current[keycode / 8] & (1 << (keycode % 8))); } #else @@ -206,22 +266,37 @@ void closeWindow(Window window) { #include #include +//TODO: Change this every time we open a window #define WND_CLASS_NAME "OpenWindowWndClass" -LRESULT CALLBACK wndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam) -{ - Window * window = (Window *)(LONG_PTR)GetWindowLong(hwnd, GWLP_USERDATA); +void windowDefaultEventHandler(Window * window, unsigned int event, WPARAM wParam, LPARAM lParam) { + (void) wParam; + (void) lParam; - switch (msg) + switch (event) { case WM_KEYDOWN: - { - if (wParam == VK_ESCAPE) window->close = true; + case WM_KEYUP: + GetKeyboardState(window->io.current); + break; + case WM_TIMER: + InvalidateRect(window->wgl.window, NULL, FALSE); break; - } } +} - return (DefWindowProc(hwnd, msg, wParam, lParam)); +LRESULT CALLBACK windowEventHandler(HWND hwnd, unsigned int event, WPARAM wParam, LPARAM lParam) { + Window * window = (Window *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (window == NULL) goto uninit; + + if (window->eventHandler == NULL) { + windowDefaultEventHandler(window, event, wParam, lParam); + } else { + window->eventHandler(window, event, wParam, lParam); + } + +uninit: + return (DefWindowProc(hwnd, event, wParam, lParam)); } int init(Window * window, const char * title, size_t width, size_t height) { @@ -230,7 +305,7 @@ int init(Window * window, const char * title, size_t width, size_t height) { wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_CLASSDC; - wcex.lpfnWndProc = wndProc; + wcex.lpfnWndProc = windowEventHandler; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = window->wgl.instance; @@ -254,14 +329,17 @@ int init(Window * window, const char * title, size_t width, size_t height) { NULL, NULL, window->wgl.instance, - window + NULL ); - if (window->wgl.window == NULL) return -1; + if (window->wgl.window == NULL) { + fprintf(stderr, "Failed to create window!\n"); + return -1; + } ShowWindow(window->wgl.window, SW_SHOW); - SetWindowLong(window->wgl.window, GWLP_USERDATA, (LONG_PTR)window); + SetWindowLongPtr(window->wgl.window, GWLP_USERDATA, (LONG_PTR)window); window->wgl.display = GetDC(window->wgl.window); PIXELFORMATDESCRIPTOR pfd = {0}; @@ -300,12 +378,12 @@ int init(Window * window, const char * title, size_t width, size_t height) { if (!wglMakeCurrent(window->wgl.display, tempContext)) return -1; - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)(void *)wglGetProcAddress("wglCreateContextAttribsARB"); if (wglCreateContextAttribsARB == NULL) return -1; int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 4, - WGL_CONTEXT_MINOR_VERSION_ARB, 6, + WGL_CONTEXT_MAJOR_VERSION_ARB, OPENWINDOW_OPENGL_VERSSION_MAJOR, + WGL_CONTEXT_MINOR_VERSION_ARB, OPENWINDOW_OPENGL_VERSSION_MINOR, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0 }; @@ -321,13 +399,16 @@ int init(Window * window, const char * title, size_t width, size_t height) { wglMakeCurrent(window->wgl.display, window->wgl.context); + SetTimer(window->wgl.window, 1, (1 / window->fps) * 1000, NULL); + return 0; } -Window openWindow(const char * name, size_t width, size_t height) { - Window w = {0}; +Window * openWindow(const char * name, size_t width, size_t height) { + Window * w = calloc(1, sizeof(Window)); + w->fps = WINDOW_DEFAULT_FPS; - if (init(&w, name, width, height) < 0) { + if (init(w, name, width, height) < 0) { fprintf(stderr, "Failed to initialize wgl!\n"); exit(1); } @@ -340,24 +421,45 @@ Window openWindow(const char * name, size_t width, size_t height) { return w; } -void windowDraw(Window window) { - SwapBuffers(window.wgl.display); +void windowDraw(Window * window) { + SwapBuffers(window->wgl.display); +} + +void windowSetEventHandler(Window * window, WindowEventHandler handler) { + window->eventHandler = handler; +} + +void resetIOState(Window * window) { + memcpy(window->io.last, window->io.current, WINDOW_KEY_COUNT); } void windowHandleEvents(Window * window) { - MSG msg; + (void) window; + + resetIOState(window); + + MSG msg = {0}; GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg); DispatchMessage(&msg); } -void closeWindow(Window window) { +void closeWindow(Window * window) { wglMakeCurrent(NULL, NULL); - wglDeleteContext(window.wgl.context); - ReleaseDC(window.wgl.window, window.wgl.display); + wglDeleteContext(window->wgl.context); + ReleaseDC(window->wgl.window, window->wgl.display); - DestroyWindow(window.wgl.window); - UnregisterClass(WND_CLASS_NAME, window.wgl.instance); + DestroyWindow(window->wgl.window); + UnregisterClass(WND_CLASS_NAME, window->wgl.instance); + free(window); +} + +bool windowKeyPressed(Window * window, int key) { + return window->io.current[key] & 0x80; +} + +bool windowKeyReleased(Window * window, int key) { + return (window->io.last[key] & 0x80) && !(window->io.current[key] & 0x80); } #endif // _WIN32 diff --git a/src/openwindow.h b/src/openwindow.h index ace7d37..3af11e4 100644 --- a/src/openwindow.h +++ b/src/openwindow.h @@ -1,11 +1,18 @@ #ifndef _OPEN_WINDOW_H_ #define _OPEN_WINDOW_H_ +#define WINDOW_DEFAULT_FPS 60 + +#define WINDOW_KEY_COUNT 256 + #include +#include #include #include -#include "../deps/include/glad/glad.h" +int gladLoadGL(void); + +#include "GL/gl.h" #ifndef _WIN32 @@ -27,22 +34,54 @@ typedef struct { Colormap cmap; long eventMask; } X11; - + +typedef struct { + char current[WINDOW_KEY_COUNT]; + char last[WINDOW_KEY_COUNT]; +} WindowIOState; + typedef struct Window Window; -typedef void(* WindowEventHandler)(Window * w, XEvent xev); +typedef void(* WindowEventHandler)(Window * window, XEvent event); typedef struct Window { + WindowIOState io; GLX glx; - X11 x; + X11 x; WindowEventHandler eventHandler; - bool close; + uint32_t fps; } Window; -Window openWindow(const char * name, size_t width, size_t height); -void windowDraw(Window window); -void windowSetEventHandler(Window * window, WindowEventHandler handler); -void windowHandleEvents(Window * window); -void closeWindow(Window w); +#define WINDOW_KEY_Q ("q") +#define WINDOW_KEY_W ("w") +#define WINDOW_KEY_E ("e") +#define WINDOW_KEY_R ("r") +#define WINDOW_KEY_T ("t") +#define WINDOW_KEY_Y ("y") +#define WINDOW_KEY_U ("u") +#define WINDOW_KEY_I ("i") +#define WINDOW_KEY_O ("o") +#define WINDOW_KEY_P ("p") +#define WINDOW_KEY_A ("a") +#define WINDOW_KEY_S ("s") +#define WINDOW_KEY_D ("d") +#define WINDOW_KEY_F ("f") +#define WINDOW_KEY_G ("g") +#define WINDOW_KEY_H ("h") +#define WINDOW_KEY_J ("j") +#define WINDOW_KEY_K ("k") +#define WINDOW_KEY_L ("l") +#define WINDOW_KEY_Z ("z") +#define WINDOW_KEY_X ("x") +#define WINDOW_KEY_C ("c") +#define WINDOW_KEY_V ("v") +#define WINDOW_KEY_B ("b") +#define WINDOW_KEY_N ("n") +#define WINDOW_KEY_M ("m") + +#define WINDOW_KEY_ESC ("Escape") + +bool windowKeyPressed(Window * window, char * key); +bool windowKeyReleased(Window * window, char * key); #else @@ -55,24 +94,66 @@ typedef struct { HGLRC context; } WGL; +typedef struct { + BYTE current[WINDOW_KEY_COUNT]; + BYTE last[WINDOW_KEY_COUNT]; +} WindowIOState; + typedef struct Window Window; +typedef void(* WindowEventHandler)(Window * window, unsigned int event, WPARAM wParam, LPARAM lParam); typedef struct Window { + WindowIOState io; WGL wgl; - //WindowEventHandler eventHandler; - bool close; + WindowEventHandler eventHandler; + uint32_t fps; } Window; -Window openWindow(const char * name, size_t width, size_t height); -void windowDraw(Window window); -void windowHandleEvents(Window * window); -void closeWindow(Window w); +#define WINDOW_KEY_Q ('Q') +#define WINDOW_KEY_W ('W') +#define WINDOW_KEY_E ('E') +#define WINDOW_KEY_R ('R') +#define WINDOW_KEY_T ('T') +#define WINDOW_KEY_Y ('Y') +#define WINDOW_KEY_U ('U') +#define WINDOW_KEY_I ('I') +#define WINDOW_KEY_O ('O') +#define WINDOW_KEY_P ('P') +#define WINDOW_KEY_A ('A') +#define WINDOW_KEY_S ('S') +#define WINDOW_KEY_D ('D') +#define WINDOW_KEY_F ('F') +#define WINDOW_KEY_G ('G') +#define WINDOW_KEY_H ('H') +#define WINDOW_KEY_J ('J') +#define WINDOW_KEY_K ('K') +#define WINDOW_KEY_L ('L') +#define WINDOW_KEY_Z ('Z') +#define WINDOW_KEY_X ('X') +#define WINDOW_KEY_C ('C') +#define WINDOW_KEY_V ('V') +#define WINDOW_KEY_B ('B') +#define WINDOW_KEY_N ('N') +#define WINDOW_KEY_M ('M') + +#define WINDOW_KEY_ESC (VK_ESCAPE) + +bool windowKeyPressed(Window * window, int key); +bool windowKeyReleased(Window * window, int key); #endif // _WIN32 -// depends on glad +Window * openWindow(const char * name, size_t width, size_t height); +void windowSetFps(Window * window, uint32_t fps); +void windowDraw(Window * window); +void windowSetEventHandler(Window * window, WindowEventHandler handler); +void windowHandleEvents(Window * window); +void closeWindow(Window * window); + +typedef enum { + WindowKeyPress = 0, +} WindowEvent; + int getOpenGLProcs(void); #endif // _OPEN_WINDOW_H_ - -// TODO: Add all the error handling to the glx