237 lines
5.3 KiB
C
237 lines
5.3 KiB
C
#include "shadermeh.h"
|
|
|
|
#ifndef GLX_ARB_create_context
|
|
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
|
#endif
|
|
|
|
#ifndef GLX_ARB_create_context_profile
|
|
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
|
#endif
|
|
|
|
typedef GLXContext (*CREATECONTEXTATTRIBSPROC)(Display *, GLXFBConfig,
|
|
GLXContext, Bool,
|
|
const int *);
|
|
|
|
typedef void (*SWAPINTERVALEXTPROC)(Display *, GLXDrawable, int);
|
|
|
|
static int glversions[][2] = { {4,5}, {4,4}, {4,3}, {4,2}, {4,1}, {4,0},
|
|
{3,3}, {3,2}, {3,1}, {3,0} };
|
|
|
|
static Display *dpy;
|
|
static int dpy_ref = 0;
|
|
static Atom atom_wm_delete;
|
|
static XContext xctx;
|
|
|
|
static int xlib_swallow_errors(Display *display, XErrorEvent *event)
|
|
{
|
|
(void)display; (void)event;
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
window *window_create(unsigned int width, unsigned int height,
|
|
const char *caption)
|
|
{
|
|
CREATECONTEXTATTRIBSPROC CreateContextAttribs;
|
|
XSetWindowAttributes swa;
|
|
int fbcount, attr[20];
|
|
GLXFBConfig fbc, *fbl;
|
|
unsigned int i = 0;
|
|
XSizeHints hints;
|
|
XVisualInfo *vi;
|
|
window *this;
|
|
|
|
this = calloc(1, sizeof(*this));
|
|
if (!this)
|
|
return NULL;
|
|
|
|
if (dpy) {
|
|
++dpy_ref;
|
|
} else {
|
|
dpy = XOpenDisplay(0);
|
|
dpy_ref = 1;
|
|
|
|
if (!dpy) {
|
|
free(this);
|
|
return NULL;
|
|
}
|
|
|
|
XSetErrorHandler(xlib_swallow_errors);
|
|
atom_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
|
|
|
|
xctx = XUniqueContext();
|
|
}
|
|
|
|
attr[ 0] = GLX_BUFFER_SIZE; attr[ 1] = 32;
|
|
attr[ 2] = GLX_RED_SIZE; attr[ 3] = 8;
|
|
attr[ 4] = GLX_GREEN_SIZE; attr[ 5] = 8;
|
|
attr[ 6] = GLX_BLUE_SIZE; attr[ 7] = 8;
|
|
attr[ 8] = GLX_ALPHA_SIZE; attr[ 9] = 8;
|
|
attr[10] = GLX_DEPTH_SIZE; attr[11] = 24;
|
|
attr[12] = GLX_STENCIL_SIZE; attr[13] = 8;
|
|
attr[14] = GLX_DOUBLEBUFFER; attr[15] = True;
|
|
attr[16] = None;
|
|
|
|
fbl = glXChooseFBConfig(dpy, DefaultScreen(dpy), attr, &fbcount);
|
|
|
|
if (!fbl || !fbcount) {
|
|
window_destroy(this);
|
|
return NULL;
|
|
}
|
|
|
|
fbc = fbl[0];
|
|
vi = glXGetVisualFromFBConfig(dpy, fbl[0]);
|
|
XFree(fbl);
|
|
|
|
if (!vi) {
|
|
window_destroy(this);
|
|
return NULL;
|
|
}
|
|
|
|
swa.colormap = XCreateColormap(dpy, RootWindow(dpy,vi->screen),
|
|
vi->visual, AllocNone);
|
|
|
|
if (!swa.colormap) {
|
|
XFree(vi);
|
|
window_destroy(this);
|
|
return NULL;
|
|
}
|
|
|
|
swa.border_pixel = 0;
|
|
|
|
this->wnd = XCreateWindow(dpy, RootWindow(dpy,vi->screen), 0, 0,
|
|
width, height, 0, vi->depth, InputOutput,
|
|
vi->visual, CWBorderPixel|CWColormap, &swa);
|
|
XFree(vi);
|
|
|
|
if (!this->wnd) {
|
|
window_destroy(this);
|
|
return NULL;
|
|
}
|
|
|
|
CreateContextAttribs = (CREATECONTEXTATTRIBSPROC)
|
|
glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
|
|
|
|
if (CreateContextAttribs) {
|
|
attr[0] = GLX_CONTEXT_MAJOR_VERSION_ARB;
|
|
attr[1] = 0;
|
|
attr[2] = GLX_CONTEXT_MINOR_VERSION_ARB;
|
|
attr[3] = 0;
|
|
attr[4] = GLX_CONTEXT_PROFILE_MASK_ARB;
|
|
attr[5] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
|
|
attr[6] = GLX_CONTEXT_FLAGS_ARB;
|
|
attr[7] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
|
attr[8] = None;
|
|
|
|
for (i = 0; !this->gl && i < sizeof(glversions) /
|
|
sizeof(glversions[0]); ++i) {
|
|
attr[1] = glversions[i][0];
|
|
attr[3] = glversions[i][1];
|
|
|
|
this->gl = CreateContextAttribs(dpy, fbc, 0,
|
|
True, attr);
|
|
}
|
|
}
|
|
|
|
if (!this->gl) {
|
|
this->gl = glXCreateNewContext(dpy, fbc, GLX_RGBA_TYPE,
|
|
0, GL_TRUE);
|
|
}
|
|
|
|
if (!this->gl) {
|
|
window_destroy(this);
|
|
return NULL;
|
|
}
|
|
|
|
hints.flags = PSize | PMinSize | PMaxSize;
|
|
hints.min_width = hints.max_width = hints.base_width = width;
|
|
hints.min_height = hints.max_height = hints.base_height = height;
|
|
|
|
XSetWMNormalHints(dpy, this->wnd, &hints);
|
|
|
|
XSelectInput(dpy, this->wnd, StructureNotifyMask |
|
|
KeyPressMask | KeyReleaseMask |
|
|
PointerMotionMask | PropertyChangeMask |
|
|
ButtonPressMask | ButtonReleaseMask);
|
|
XSetWMProtocols(dpy, this->wnd, &atom_wm_delete, 1);
|
|
XFlush(dpy);
|
|
|
|
XStoreName(dpy, this->wnd, caption);
|
|
XMapWindow(dpy, this->wnd);
|
|
XSaveContext(dpy, this->wnd, xctx, (XPointer)this);
|
|
XFlush(dpy);
|
|
return this;
|
|
}
|
|
|
|
void window_make_current(window *this)
|
|
{
|
|
if (this) {
|
|
glXMakeContextCurrent(dpy, this->wnd, this->wnd, this->gl);
|
|
} else {
|
|
glXMakeContextCurrent(dpy, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
void window_swap_buffers(window *this)
|
|
{
|
|
glXSwapBuffers(dpy, this->wnd);
|
|
}
|
|
|
|
void window_set_vsync(window *this, int enable)
|
|
{
|
|
SWAPINTERVALEXTPROC SwapIntervalEXT;
|
|
|
|
SwapIntervalEXT = (SWAPINTERVALEXTPROC)
|
|
glXGetProcAddress((const GLubyte *)"glXSwapIntervalEXT");
|
|
|
|
if (SwapIntervalEXT)
|
|
SwapIntervalEXT(dpy, this->wnd, enable ? 1 : 0);
|
|
}
|
|
|
|
void window_destroy(window *this)
|
|
{
|
|
if (this->gl) {
|
|
glXMakeContextCurrent(dpy, 0, 0, 0);
|
|
glXDestroyContext(dpy, this->gl);
|
|
}
|
|
|
|
if (this->wnd) {
|
|
XDeleteContext(dpy, this->wnd, xctx);
|
|
XDestroyWindow(dpy, this->wnd);
|
|
}
|
|
|
|
if ((--dpy_ref) <= 0) {
|
|
XCloseDisplay(dpy);
|
|
dpy_ref = 0;
|
|
dpy = NULL;
|
|
}
|
|
|
|
free(this);
|
|
}
|
|
|
|
int window_handle_events(void)
|
|
{
|
|
window *this;
|
|
XEvent e;
|
|
|
|
if (XPending(dpy)) {
|
|
XNextEvent(dpy, &e);
|
|
XFindContext(dpy, e.xany.window, xctx, (XPointer *)&this);
|
|
|
|
switch (e.type) {
|
|
case ClientMessage:
|
|
if (e.xclient.data.l[0] == (long)atom_wm_delete) {
|
|
XUnmapWindow(dpy, e.xany.window);
|
|
--dpy_ref;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (dpy_ref > 0);
|
|
}
|