added windowKeyPressed and windowKeyReleased

This commit is contained in:
Maciej Samborski 2025-07-26 22:56:01 +02:00
parent 98af446a2f
commit 14342c8c9f
10 changed files with 346 additions and 396 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
lib/
main
main.exe
valgrind-out.txt
*.o
sample/
other/

View File

@ -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

63
deps/GLAD_LICENSE vendored Normal file
View File

@ -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.

BIN
deps/lib/libGLESv2.dll vendored

Binary file not shown.

Binary file not shown.

77
main.c
View File

@ -1,81 +1,34 @@
#include <stdio.h>
#include <stdbool.h>
#include "deps/include/glad/glad.h"
#include "GL/gl.h"
#include "src/openwindow.h"
#ifndef _WIN32
#include <X11/keysym.h>
#define Window X11Window
#include <X11/Xlib.h>
#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 <windows.h>
#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);
}

Binary file not shown.

View File

@ -1,256 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>
#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<fbcount; ++i)
{
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
if ( vi )
{
int samp_buf, samples;
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
" SAMPLES = %d\n",
i, vi -> 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;
}

View File

@ -1,6 +1,9 @@
// TODO: Add all the error handling to the glx part
#include "openwindow.h"
#include <stdio.h>
#include <string.h>
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 <unistd.h>
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;
@ -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 <windows.h>
#include <GL/wgl.h>
//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;
}
}
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);
}
return (DefWindowProc(hwnd, msg, 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

View File

@ -1,11 +1,18 @@
#ifndef _OPEN_WINDOW_H_
#define _OPEN_WINDOW_H_
#define WINDOW_DEFAULT_FPS 60
#define WINDOW_KEY_COUNT 256
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "../deps/include/glad/glad.h"
int gladLoadGL(void);
#include "GL/gl.h"
#ifndef _WIN32
@ -28,21 +35,53 @@ typedef struct {
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;
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