summaryrefslogtreecommitdiff
path: root/pugl
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-08-27 07:09:58 +0000
committerDavid Robillard <d@drobilla.net>2014-08-27 07:09:58 +0000
commitb4dbb3616865cd236cda4f2e4ac806b3b4840b29 (patch)
tree4a78f8298e42b95a074844e44d69a2446cb5eea3 /pugl
parentf25f829a3038db39c83ad8cc92dd5fdc4876751b (diff)
Cairo support on X11.
Diffstat (limited to 'pugl')
-rw-r--r--pugl/gl.h32
-rw-r--r--pugl/glu.h32
-rw-r--r--pugl/pugl.h37
-rw-r--r--pugl/pugl_internal.h13
-rw-r--r--pugl/pugl_x11.c173
5 files changed, 209 insertions, 78 deletions
diff --git a/pugl/gl.h b/pugl/gl.h
new file mode 100644
index 0000000..9a6aeef
--- /dev/null
+++ b/pugl/gl.h
@@ -0,0 +1,32 @@
+/*
+ Copyright 2012-2014 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file gl.h Portable header wrapper for gl.h.
+
+ Unfortunately, GL includes vary across platforms so this header allows for
+ pure portable programs.
+*/
+
+#ifdef __APPLE__
+# include "OpenGL/gl.h"
+#else
+# ifdef _WIN32
+# include <windows.h> /* Broken Windows GL headers require this */
+# endif
+# include "GL/gl.h"
+#endif
+
diff --git a/pugl/glu.h b/pugl/glu.h
new file mode 100644
index 0000000..0ed0055
--- /dev/null
+++ b/pugl/glu.h
@@ -0,0 +1,32 @@
+/*
+ Copyright 2012-2014 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file gl.h Portable header wrapper for glu.h.
+
+ Unfortunately, GL includes vary across platforms so this header allows for
+ pure portable programs.
+*/
+
+#ifdef __APPLE__
+# include "OpenGL/glu.h"
+#else
+# ifdef _WIN32
+# include <windows.h> /* Broken Windows GL headers require this */
+# endif
+# include "GL/glu.h"
+#endif
+
diff --git a/pugl/pugl.h b/pugl/pugl.h
index 360f8e8..8cd8afb 100644
--- a/pugl/pugl.h
+++ b/pugl/pugl.h
@@ -23,20 +23,6 @@
#include <stdint.h>
-/*
- This API is pure portable C and contains no platform specific elements, or
- even a GL dependency. However, unfortunately GL includes vary across
- platforms so they are included here to allow for pure portable programs.
-*/
-#ifdef __APPLE__
-# include "OpenGL/gl.h"
-#else
-# ifdef _WIN32
-# include <windows.h> /* Broken Windows GL headers require this */
-# endif
-# include "GL/gl.h"
-#endif
-
#ifdef PUGL_SHARED
# ifdef _WIN32
# define PUGL_LIB_IMPORT __declspec(dllimport)
@@ -88,6 +74,14 @@ typedef enum {
} PuglStatus;
/**
+ Drawing context type.
+*/
+typedef enum {
+ PUGL_GL,
+ PUGL_CAIRO
+} PuglContextType;
+
+/**
Convenience symbols for ASCII control characters.
*/
typedef enum {
@@ -247,6 +241,12 @@ PUGL_API void
puglInitResizable(PuglView* view, bool resizable);
/**
+ Set the context type before creating a window.
+*/
+PUGL_API void
+puglInitContextType(PuglView* view, PuglContextType type);
+
+/**
Create a window with the settings given by the various puglInit functions.
@return 1 (pugl does not currently support multiple windows).
@@ -285,6 +285,15 @@ PUGL_API PuglHandle
puglGetHandle(PuglView* view);
/**
+ Get the drawing context.
+
+ For PUGL_GL contexts, this is unused and returns NULL.
+ For PUGL_CAIRO contexts, this returns a pointer to a cairo_t.
+*/
+PUGL_API void*
+puglGetContext(PuglView* view);
+
+/**
Return the timestamp (if any) of the currently-processing event.
*/
PUGL_API uint32_t
diff --git a/pugl/pugl_internal.h b/pugl/pugl_internal.h
index b86533a..3db08f7 100644
--- a/pugl/pugl_internal.h
+++ b/pugl/pugl_internal.h
@@ -25,7 +25,9 @@
symbols can be defined to tweak pugl behaviour:
PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus.
- PUGL_VERBOSE: Print GL information to console.
+ PUGL_VERBOSE: Print graphics information to console.
+ PUGL_HAVE_CAIRO: Include Cairo support code.
+ PUGL_HAVE_GL: Include OpenGL support code.
*/
#include "pugl.h"
@@ -55,6 +57,7 @@ struct PuglViewImpl {
PuglInternals* impl;
PuglNativeWindow parent;
+ PuglContextType ctx_type;
int width;
int height;
@@ -110,6 +113,12 @@ puglInitResizable(PuglView* view, bool resizable)
}
void
+puglInitContextType(PuglView* view, PuglContextType type)
+{
+ view->ctx_type = type;
+}
+
+void
puglSetHandle(PuglView* view, PuglHandle handle)
{
view->handle = handle;
@@ -136,6 +145,7 @@ puglGetModifiers(PuglView* view)
void
puglDefaultReshape(PuglView* view, int width, int height)
{
+#ifdef PUGL_HAVE_GL
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, 0, 1);
@@ -143,6 +153,7 @@ puglDefaultReshape(PuglView* view, int width, int height)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
+#endif
return;
// unused
diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c
index e29e3bd..509e527 100644
--- a/pugl/pugl_x11.c
+++ b/pugl/pugl_x11.c
@@ -24,46 +24,34 @@
#include <stdlib.h>
#include <string.h>
-#include <GL/gl.h>
-#include <GL/glx.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
+#include <X11/Xutil.h>
#include <X11/keysym.h>
+#ifdef PUGL_HAVE_GL
+#include <GL/gl.h>
+#include <GL/glx.h>
+#endif
+
+#ifdef PUGL_HAVE_CAIRO
+#include <cairo/cairo.h>
+#include <cairo/cairo-xlib.h>
+#endif
+
#include "pugl_internal.h"
struct PuglInternalsImpl {
Display* display;
int screen;
Window win;
+#ifdef PUGL_HAVE_CAIRO
+ cairo_t* cr;
+#endif
+#ifdef PUGL_HAVE_GL
GLXContext ctx;
Bool doubleBuffered;
-};
-
-/**
- Attributes for single-buffered RGBA with at least
- 4 bits per color and a 16 bit depth buffer.
-*/
-static int attrListSgl[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 4,
- GLX_GREEN_SIZE, 4,
- GLX_BLUE_SIZE, 4,
- GLX_DEPTH_SIZE, 16,
- None
-};
-
-/**
- Attributes for double-buffered RGBA with at least
- 4 bits per color and a 16 bit depth buffer.
-*/
-static int attrListDbl[] = {
- GLX_RGBA, GLX_DOUBLEBUFFER,
- GLX_RED_SIZE, 4,
- GLX_GREEN_SIZE, 4,
- GLX_BLUE_SIZE, 4,
- GLX_DEPTH_SIZE, 16,
- None
+#endif
};
PuglInternals*
@@ -80,21 +68,49 @@ puglCreateWindow(PuglView* view, const char* title)
impl->display = XOpenDisplay(0);
impl->screen = DefaultScreen(impl->display);
- XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl);
- if (!vi) {
- vi = glXChooseVisual(impl->display, impl->screen, attrListSgl);
- impl->doubleBuffered = False;
- PUGL_LOG("no double-buffering available, using single-buffering\n");
- } else {
- impl->doubleBuffered = True;
- PUGL_LOG("using double-buffered rendering\n");
+ XVisualInfo* vi = NULL;
+
+#ifdef PUGL_HAVE_GL
+ if (view->ctx_type == PUGL_GL) {
+ // Try to create double-buffered visual
+ int double_attrs[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ None };
+ vi = glXChooseVisual(impl->display, impl->screen, double_attrs);
+ if (!vi) {
+ // Failed, create single-buffered visual
+ int single_attrs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ None };
+ vi = glXChooseVisual(impl->display, impl->screen, single_attrs);
+ impl->doubleBuffered = False;
+ } else {
+ impl->doubleBuffered = True;
+ }
+
+ impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
+ PUGL_LOGF("GLX depth %d, %s-buffered, %s\n",
+ vi->depth,
+ impl->doubleBuffered ? "double" : "single",
+ (glXIsDirect(impl->display, impl->ctx)
+ ? "direct (set LIBGL_ALWAYS_INDIRECT=1 to disable)"
+ : "indirect"));
}
-
- int glxMajor, glxMinor;
- glXQueryVersion(impl->display, &glxMajor, &glxMinor);
- PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor);
-
- impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
+#endif
+#ifdef PUGL_HAVE_CAIRO
+ if (view->ctx_type == PUGL_CAIRO) {
+ XVisualInfo pat;
+ int n;
+ pat.screen = impl->screen;
+ vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n);
+ }
+#endif
Window xParent = view->parent
? (Window)view->parent
@@ -105,10 +121,10 @@ puglCreateWindow(PuglView* view, const char* title)
XSetWindowAttributes attr;
memset(&attr, 0, sizeof(XSetWindowAttributes));
- attr.colormap = cmap;
- attr.border_pixel = 0;
-
- attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask
+ attr.background_pixel = BlackPixel(impl->display, impl->screen);
+ attr.border_pixel = BlackPixel(impl->display, impl->screen);
+ attr.colormap = cmap;
+ attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask
| ButtonPressMask | ButtonReleaseMask
#ifdef PUGL_GRAB_FOCUS
| EnterWindowMask
@@ -118,7 +134,17 @@ puglCreateWindow(PuglView* view, const char* title)
impl->win = XCreateWindow(
impl->display, xParent,
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
- CWBorderPixel | CWColormap | CWEventMask, &attr);
+ CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr);
+
+#ifdef PUGL_HAVE_CAIRO
+ if (view->ctx_type == PUGL_CAIRO) {
+ cairo_surface_t* surface = cairo_xlib_surface_create(
+ impl->display, impl->win, vi->visual, view->width, view->height);
+ if (!(impl->cr = cairo_create(surface))) {
+ fprintf(stderr, "failed to create cairo context\n");
+ }
+ }
+#endif
XSizeHints sizeHints;
memset(&sizeHints, 0, sizeof(sizeHints));
@@ -140,12 +166,6 @@ puglCreateWindow(PuglView* view, const char* title)
XSetWMProtocols(impl->display, impl->win, &wmDelete, 1);
}
- if (glXIsDirect(impl->display, impl->ctx)) {
- PUGL_LOG("DRI enabled (set LIBGL_ALWAYS_INDIRECT=1 to disable)\n");
- } else {
- PUGL_LOG("no DRI available\n");
- }
-
XFree(vi);
return 0;
@@ -174,7 +194,12 @@ puglDestroy(PuglView* view)
return;
}
- glXDestroyContext(view->impl->display, view->impl->ctx);
+#ifdef PUGL_HAVE_GL
+ if (view->ctx_type == PUGL_GL) {
+ glXDestroyContext(view->impl->display, view->impl->ctx);
+ }
+#endif
+
XDestroyWindow(view->impl->display, view->impl->win);
XCloseDisplay(view->impl->display);
free(view->impl);
@@ -184,7 +209,11 @@ puglDestroy(PuglView* view)
static void
puglReshape(PuglView* view, int width, int height)
{
- glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
+#ifdef PUGL_HAVE_GL
+ if (view->ctx_type == PUGL_GL) {
+ glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
+ }
+#endif
if (view->reshapeFunc) {
view->reshapeFunc(view, width, height);
@@ -199,20 +228,27 @@ puglReshape(PuglView* view, int width, int height)
static void
puglDisplay(PuglView* view)
{
- glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glLoadIdentity();
+#ifdef PUGL_HAVE_GL
+ if (view->ctx_type == PUGL_GL) {
+ glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glLoadIdentity();
+ }
+#endif
if (view->displayFunc) {
view->displayFunc(view);
}
+ view->redisplay = false;
- glFlush();
- if (view->impl->doubleBuffered) {
- glXSwapBuffers(view->impl->display, view->impl->win);
+#ifdef PUGL_HAVE_GL
+ if (view->ctx_type == PUGL_GL) {
+ glFlush();
+ if (view->impl->doubleBuffered) {
+ glXSwapBuffers(view->impl->display, view->impl->win);
+ }
}
-
- view->redisplay = false;
+#endif
}
static PuglKey
@@ -402,3 +438,14 @@ puglGetNativeWindow(PuglView* view)
{
return view->impl->win;
}
+
+void*
+puglGetContext(PuglView* view)
+{
+#ifdef PUGL_HAVE_CAIRO
+ if (view->ctx_type == PUGL_CAIRO) {
+ return view->impl->cr;
+ }
+#endif
+ return NULL;
+}