GLHUI-1.1.0: c/HsGLWindow.c
#include "HsGLWindow.h"
static Display *display;
static Window window;
static GLXContext context;
static int width, height, scrwidth, scrheight;
static unsigned frame = 0;
static double ftime, dtime;
static int fullscreen = 0;
typedef struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
} Hints;
// OpenGL 3 specific functions:
// GLXContext glXCreateContextAttribsARB (Display *, GLXFBConfig, GLXContext, Bool direct, const int *);
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef Bool (*glXMakeContextCurrentARBProc)(Display*, GLXDrawable, GLXDrawable, GLXContext);
static glXCreateContextAttribsARBProc createContext = 0;
static glXMakeContextCurrentARBProc makeContextCurrent = 0;
void WindowSetFullscreen(int f)
{
XWindowChanges changes;
Hints hints;
Atom property = XInternAtom(display,"_MOTIF_WM_HINTS",True);
hints.flags = 2;
if(f) {
hints.decorations = False;
changes.x = 0;
changes.y = 0;
changes.width = width = scrwidth;
changes.height = height = scrheight;
changes.stack_mode = Above;
fullscreen = 1;
} else {
hints.decorations = True;
changes.x = scrwidth/4;
changes.y = scrheight/4;
changes.width = width = scrwidth/2;
changes.height = height = scrheight/2;
changes.stack_mode = Above;
fullscreen = 0;
}
XChangeProperty(display, window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
XConfigureWindow(display, window, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes);
//XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
//XGrabPointer(display, window, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
//XMapRaised(display, window);
}
// GL Attributes
static const int basicAttribs[] = { GLX_RGBA
, GLX_DEPTH_SIZE, 24
, GLX_DOUBLEBUFFER
, None
};
static const int gl3Attribs[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT
, GLX_X_RENDERABLE, True
, GLX_DOUBLEBUFFER, 1
, GLX_RED_SIZE, 8
, GLX_GREEN_SIZE, 8
, GLX_BLUE_SIZE, 8
, None
};
typedef struct {
unsigned int major, minor, GLSLMajor, GLSLMinor;
} support;
// This function creates a throw away context that is only used to query
// for support of specific features, like what version of opengl is supported
// the minimal context needs a display and a visual;
support _initSupport(Display *dpy) {
XVisualInfo *vi = glXChooseVisual(dpy, 0, (int*)basicAttribs);
if(vi == NULL) {
fprintf(stderr, "Unable to create the throw away context");
fprintf(stderr, "No appropriate visual found");
// TODO: return invalid support
}
Window root;
Colormap cmap;
XSetWindowAttributes swa;
Window win;
GLXContext glc;
root = DefaultRootWindow(dpy);
cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
swa.colormap = cmap;
win = XCreateWindow(dpy, root, 0, 0, 16, 16, 0, vi->depth, InputOutput, vi->visual, CWColormap, &swa);
glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
glXMakeCurrent(dpy, win, glc);
char const * version = glGetString(GL_VERSION);
unsigned int major = version[0] - '0';
unsigned int minor = version[2] - '0';
unsigned int glslMajor = 0;
unsigned int glslMinor = 0;
if(major >= 2) {
char const * glsl = glGetString(GL_SHADING_LANGUAGE_VERSION);
glslMajor = glsl[0] - '0';
glslMinor = glsl[2] - '0';
}
// printf("TMP CONTEXT: OpenGL:\n\tvendor %s\n\trenderer %s\n\tversion %s\n\tshader language %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION));
/* get the required extensions */
createContext = (glXCreateContextAttribsARBProc)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB");
makeContextCurrent = (glXMakeContextCurrentARBProc)glXGetProcAddressARB( (const GLubyte *) "glXMakeContextCurrent");
if ( !(createContext && makeContextCurrent) && major > 2){
fprintf(stderr, "missing support for GLX_ARB_create_context\n");
// TODO: return invalid support
}
glXDestroyContext(dpy, glc);
XDestroyWindow(dpy, win);
support s = { major, minor, glslMajor, glslMinor };
return s;
}
int WindowInit(unsigned int const major, unsigned int const minor)
{
display = XOpenDisplay(NULL);
if(display == NULL) {
puts("Cannot connect to the X server.\n");
return -1;
}
support s = _initSupport(display); // check what the system supports
// printf("Opengl Major: %d, Opengl Minor: %d, GLSL Major: %d, GLSL Minor %d\n", s.openGLMajor, s.openGLMinor, s.GLSLMajor, s.GLSLMinor);
int nscreen = DefaultScreen(display);
scrwidth = XDisplayWidth(display, nscreen);
scrheight = XDisplayHeight(display, nscreen);
width = scrwidth / 2;
height = scrheight / 2;
int const * glattr;
if(s.major > 2) {
glattr = gl3Attribs;
} else {
glattr = basicAttribs;
}
XVisualInfo *visual = glXChooseVisual(display, nscreen, (int*)glattr);
if(visual == NULL) {
puts("Could not find a visual.\n");
return -2;
}
if(major >= 3) {
int elemc;
GLXFBConfig *fbcfg = glXChooseFBConfig(display, nscreen, glattr, &elemc);
if(fbcfg == NULL) {
puts("Could not find FB config.\n");
return -3;
}
int gl3attr[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, major
, GLX_CONTEXT_MINOR_VERSION_ARB, minor
, GLX_CONTEXT_FLAGS_ARB
, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
, None
};
context = createContext(display, fbcfg[0], 0, 1, gl3attr);
XFree(fbcfg);
} else {
context = glXCreateContext(display, visual, NULL, GL_TRUE);
}
Window root = RootWindow(display, visual->screen);
XSetWindowAttributes xattr;
xattr.event_mask = KeyPressMask | ButtonPressMask | StructureNotifyMask;
xattr.colormap = XCreateColormap(display, root, visual->visual, AllocNone);
window = XCreateWindow(display, root, 0, 0, width, height, 0, visual->depth, InputOutput, visual->visual, CWColormap | CWEventMask, &xattr);
XSetStandardProperties(display, window, "United Colors Of Funk", 0, None, 0, 0, 0);
XGrabKeyboard(display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabPointer(display, window, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
XMapRaised(display, window);
glXMakeCurrent(display, window, context);
glViewport(0, 0, width, height);
XFree(visual);
printf("OpenGL:\n\tvendor %s\n\trenderer %s\n\tversion %s\n\tshader language %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION));
return 1;
}
void WindowLoop(void (*Loop)())
{
struct timespec ts[3]; // even, odd, initial
int done = 0;
XEvent event;
clock_gettime(CLOCK_MONOTONIC, ts+2);
ts[0] = ts[1] = ts[2];
while(!done)
{
while(XPending(display) > 0)
{
XNextEvent(display, &event);
switch(event.type)
{
case ConfigureNotify:
if((event.xconfigure.width != width) || (event.xconfigure.height != height))
{
width = event.xconfigure.width;
height = event.xconfigure.height;
glViewport(0, 0, width, height);
}
break;
case ButtonPress:
done = 1;
break;
case KeyPress:
if(XLookupKeysym(&event.xkey, 0) == XK_Escape)
done = 1;
else if(XLookupKeysym(&event.xkey, 0) == XK_F1)
WindowSetFullscreen(!fullscreen);
break;
}
}
Loop();
glXSwapBuffers(display, window);
frame++;
clock_gettime(CLOCK_MONOTONIC, ts+(frame%2));
dtime = 1e-9*(ts[frame%2].tv_nsec - ts[!(frame%2)].tv_nsec) + (ts[frame%2].tv_sec - ts[!(frame%2)].tv_sec);
ftime = 1e-9*(ts[frame%2].tv_nsec - ts[2].tv_nsec) + (ts[frame%2].tv_sec - ts[2].tv_sec);
}
//WindowKill(0);
}
void WindowKill()
{
puts("Bye.");
if(context) {
XDestroyWindow(display, window);
glXMakeCurrent(display, 0, 0);
glXDestroyContext(display, context);
context = 0;
}
XCloseDisplay(display);
}
unsigned WindowFrame(){ return frame; }
double WindowTime(){ return ftime; }
double WindowDTime(){ return dtime; }
unsigned WindowWidth(){ return width; }
unsigned WindowHeight(){ return height; }
unsigned WindowScrWidth(){ return scrwidth; }
unsigned WindowScrHeight(){ return scrheight; }