*
**************************************************************************/
-#include "glimports.hpp"
+#include <assert.h>
+#include <stdlib.h>
+
+#include <iostream>
+
#include "glws.hpp"
+#include "glproc.hpp"
+
namespace glws {
+static Display *display = NULL;
+static int screen = 0;
+
+static unsigned glxVersion = 0;
+static const char *extensions = 0;
+static bool has_GLX_ARB_create_context = false;
+
+
class GlxVisual : public Visual
{
public:
+ GLXFBConfig fbconfig;
XVisualInfo *visinfo;
- GlxVisual(XVisualInfo *vi) :
- visinfo(vi)
+ GlxVisual() :
+ fbconfig(0),
+ visinfo(0)
{}
~GlxVisual() {
XFree(visinfo);
+ XFree(fbconfig);
}
};
+static void describeEvent(const XEvent &event) {
+ if (0) {
+ switch (event.type) {
+ case ConfigureNotify:
+ std::cerr << "ConfigureNotify";
+ break;
+ case Expose:
+ std::cerr << "Expose";
+ break;
+ case KeyPress:
+ std::cerr << "KeyPress";
+ break;
+ case MapNotify:
+ std::cerr << "MapNotify";
+ break;
+ case ReparentNotify:
+ std::cerr << "ReparentNotify";
+ break;
+ default:
+ std::cerr << "Event " << event.type;
+ }
+ std::cerr << " " << event.xany.window << "\n";
+ }
+}
+
class GlxDrawable : public Drawable
{
public:
- Display *display;
Window window;
- GlxDrawable(const Visual *vis, Display *dpy, Window win) :
- Drawable(vis),
- display(dpy),
- window(win)
- {}
+ GlxDrawable(const Visual *vis, int w, int h) :
+ Drawable(vis, w, h)
+ {
+ XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
+
+ Window root = RootWindow(display, screen);
+
+ /* window attributes */
+ XSetWindowAttributes attr;
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask;
+
+ unsigned long mask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ int x = 0, y = 0;
+
+ window = XCreateWindow(
+ display, root,
+ x, y, width, height,
+ 0,
+ visinfo->depth,
+ InputOutput,
+ visinfo->visual,
+ mask,
+ &attr);
+
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(display, window, &sizehints);
+
+ const char *name = "glretrace";
+ XSetStandardProperties(
+ display, window, name, name,
+ None, (char **)NULL, 0, &sizehints);
+
+ glXWaitX();
+ }
+
+ void waitForEvent(int type) {
+ XEvent event;
+ do {
+ XWindowEvent(display, window, StructureNotifyMask, &event);
+ describeEvent(event);
+ } while (event.type != type);
+ }
~GlxDrawable() {
XDestroyWindow(display, window);
}
-
+
void
- resize(unsigned w, unsigned h) {
+ resize(int w, int h) {
+ if (w == width && h == height) {
+ return;
+ }
+
glXWaitGL();
+
+ // We need to ensure that pending events are processed here, and XSync
+ // with discard = True guarantees that, but it appears the limited
+ // event processing we do so far is sufficient
+ //XSync(display, True);
+
Drawable::resize(w, h);
+
XResizeWindow(display, window, w, h);
+
+ // Tell the window manager to respect the requested size
+ XSizeHints size_hints;
+ size_hints.max_width = size_hints.min_width = w;
+ size_hints.max_height = size_hints.min_height = h;
+ size_hints.flags = PMinSize | PMaxSize;
+ XSetWMNormalHints(display, window, &size_hints);
+
+ waitForEvent(ConfigureNotify);
+
glXWaitX();
}
+ void show(void) {
+ if (visible) {
+ return;
+ }
+
+ glXWaitGL();
+
+ XMapWindow(display, window);
+
+ waitForEvent(MapNotify);
+
+ glXWaitX();
+
+ Drawable::show();
+ }
+
void swapBuffers(void) {
glXSwapBuffers(display, window);
}
class GlxContext : public Context
{
public:
- Display *display;
GLXContext context;
-
- GlxContext(const Visual *vis, Display *dpy, GLXContext ctx) :
+
+ GlxContext(const Visual *vis, GLXContext ctx) :
Context(vis),
- display(dpy),
context(ctx)
{}
}
};
+void
+init(void) {
+ display = XOpenDisplay(NULL);
+ if (!display) {
+ std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
+ exit(1);
+ }
-class GlxWindowSystem : public WindowSystem
-{
-private:
- Display *display;
- int screen;
+ screen = DefaultScreen(display);
-public:
- GlxWindowSystem() {
- display = XOpenDisplay(NULL);
- screen = DefaultScreen(display);
- }
+ int major = 0, minor = 0;
+ glXQueryVersion(display, &major, &minor);
+ glxVersion = (major << 8) | minor;
- ~GlxWindowSystem() {
+ extensions = glXQueryExtensionsString(display, screen);
+ has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
+}
+
+void
+cleanup(void) {
+ if (display) {
XCloseDisplay(display);
+ display = NULL;
}
+}
- Visual *
- createVisual(bool doubleBuffer) {
- int single_attribs[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DEPTH_SIZE, 1,
- GLX_STENCIL_SIZE, 1,
- None
- };
-
- int double_attribs[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DOUBLEBUFFER,
- GLX_DEPTH_SIZE, 1,
- GLX_STENCIL_SIZE, 1,
- None
- };
-
- XVisualInfo *visinfo;
-
- visinfo = glXChooseVisual(display, screen, doubleBuffer ? double_attribs : single_attribs);
-
- return new GlxVisual(visinfo);
- }
-
- Drawable *
- createDrawable(const Visual *visual)
- {
- XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
-
- Window root = RootWindow(display, screen);
+Visual *
+createVisual(bool doubleBuffer) {
+ GlxVisual *visual = new GlxVisual;
+
+ if (glxVersion >= 0x0103) {
+ Attributes<int> attribs;
+ attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
+ attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
+ attribs.add(GLX_RED_SIZE, 1);
+ attribs.add(GLX_GREEN_SIZE, 1);
+ attribs.add(GLX_BLUE_SIZE, 1);
+ attribs.add(GLX_ALPHA_SIZE, 1);
+ attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
+ attribs.add(GLX_DEPTH_SIZE, 1);
+ attribs.add(GLX_STENCIL_SIZE, 1);
+ attribs.end();
+
+ int num_configs = 0;
+ GLXFBConfig * fbconfigs;
+ fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
+ assert(num_configs && fbconfigs);
+ visual->fbconfig = fbconfigs[0];
+ assert(visual->fbconfig);
+ visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
+ assert(visual->visinfo);
+ } else {
+ Attributes<int> attribs;
+ attribs.add(GLX_RGBA);
+ attribs.add(GLX_RED_SIZE, 1);
+ attribs.add(GLX_GREEN_SIZE, 1);
+ attribs.add(GLX_BLUE_SIZE, 1);
+ attribs.add(GLX_ALPHA_SIZE, 1);
+ if (doubleBuffer) {
+ attribs.add(GLX_DOUBLEBUFFER);
+ }
+ attribs.add(GLX_DEPTH_SIZE, 1);
+ attribs.add(GLX_STENCIL_SIZE, 1);
+ attribs.end();
- /* window attributes */
- XSetWindowAttributes attr;
- attr.background_pixel = 0;
- attr.border_pixel = 0;
- attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
- attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
-
- unsigned long mask;
- mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+ visual->visinfo = glXChooseVisual(display, screen, attribs);
+ }
- int x = 0, y = 0, width = 256, height = 256;
+ return visual;
+}
- Window window = XCreateWindow(
- display, root,
- x, y, width, height,
- 0,
- visinfo->depth,
- InputOutput,
- visinfo->visual,
- mask,
- &attr);
+Drawable *
+createDrawable(const Visual *visual, int width, int height)
+{
+ return new GlxDrawable(visual, width, height);
+}
- XSizeHints sizehints;
- sizehints.x = x;
- sizehints.y = y;
- sizehints.width = width;
- sizehints.height = height;
- sizehints.flags = USSize | USPosition;
- XSetNormalHints(display, window, &sizehints);
-
- const char *name = "glretrace";
- XSetStandardProperties(
- display, window, name, name,
- None, (char **)NULL, 0, &sizehints);
+Context *
+createContext(const Visual *_visual, Context *shareContext)
+{
+ const GlxVisual *visual = dynamic_cast<const GlxVisual *>(_visual);
+ GLXContext share_context = NULL;
+ GLXContext context;
- XMapWindow(display, window);
-
- return new GlxDrawable(visual, display, window);
+ if (shareContext) {
+ share_context = dynamic_cast<GlxContext*>(shareContext)->context;
}
- Context *
- createContext(const Visual *visual)
- {
- XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
- GLXContext context = glXCreateContext(display, visinfo, NULL, True);
- return new GlxContext(visual, display, context);
+ if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
+ Attributes<int> attribs;
+ attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
+ if (debug) {
+ attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
+ }
+ attribs.end();
+
+ context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
+ } else
+ if (glxVersion >= 0x103) {
+ context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
+ } else {
+ context = glXCreateContext(display, visual->visinfo, share_context, True);
}
- bool
- makeCurrent(Drawable *drawable, Context *context)
- {
- if (!drawable || !context) {
- return glXMakeCurrent(display, None, NULL);
- } else {
- GlxDrawable *glxDrawable = dynamic_cast<GlxDrawable *>(drawable);
- GlxContext *glxContext = dynamic_cast<GlxContext *>(context);
+ return new GlxContext(visual, context);
+}
- return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
- }
- }
+bool
+makeCurrent(Drawable *drawable, Context *context)
+{
+ if (!drawable || !context) {
+ return glXMakeCurrent(display, None, NULL);
+ } else {
+ GlxDrawable *glxDrawable = dynamic_cast<GlxDrawable *>(drawable);
+ GlxContext *glxContext = dynamic_cast<GlxContext *>(context);
- bool
- processEvents(void) {
- while (XPending(display) > 0) {
- XEvent event;
- XNextEvent(display, &event);
- // TODO
- }
- return true;
+ return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
}
-};
-
+}
-WindowSystem *createNativeWindowSystem(void) {
- return new GlxWindowSystem();
+bool
+processEvents(void) {
+ while (XPending(display) > 0) {
+ XEvent event;
+ XNextEvent(display, &event);
+ describeEvent(event);
+ }
+ return true;
}
-} /* namespace glretrace */
+} /* namespace glws */