packages feed

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; }