aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-07-28 16:00:14 -0400
committerDavid Robillard <d@drobilla.net>2016-07-28 16:00:14 -0400
commitcdd47a11d473b592a4516e736a65da957072c428 (patch)
tree2d42951032499edb4e08fc624fbbbd4fda2b0a84
parentbc0c5c6393569ecb0d97fcfb02116452126a4da0 (diff)
Add support for Cairo on GL
-rw-r--r--pugl/cairo_gl.h102
-rw-r--r--pugl/common.h7
-rw-r--r--pugl/pugl_internal.h9
-rw-r--r--pugl/pugl_x11.c114
4 files changed, 201 insertions, 31 deletions
diff --git a/pugl/cairo_gl.h b/pugl/cairo_gl.h
new file mode 100644
index 0000000..a558b42
--- /dev/null
+++ b/pugl/cairo_gl.h
@@ -0,0 +1,102 @@
+/*
+ Copyright 2016 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.
+*/
+
+#if defined(PUGL_HAVE_GL) && defined(PUGL_HAVE_CAIRO)
+
+#include <stdint.h>
+
+typedef struct {
+ unsigned texture_id;
+ uint8_t* buffer;
+} PuglCairoGL;
+
+static cairo_surface_t*
+pugl_cairo_gl_create(PuglCairoGL* ctx, int width, int height, int bpp)
+{
+ free(ctx->buffer);
+ ctx->buffer = (uint8_t*)calloc(bpp * width * height, sizeof(uint8_t));
+ if (!ctx->buffer) {
+ fprintf(stderr, "failed to allocate surface buffer\n");
+ return NULL;
+ }
+
+ return cairo_image_surface_create_for_data(
+ ctx->buffer, CAIRO_FORMAT_ARGB32, width, height, bpp * width);
+}
+
+static void
+pugl_cairo_gl_free(PuglCairoGL* ctx)
+{
+ free(ctx->buffer);
+ ctx->buffer = NULL;
+}
+
+static void
+pugl_cairo_gl_configure(PuglCairoGL* ctx, int width, int height)
+{
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glDeleteTextures(1, &ctx->texture_id);
+ glGenTextures(1, &ctx->texture_id);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ctx->texture_id);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+}
+
+static void
+pugl_cairo_gl_draw(PuglCairoGL* ctx, int width, int height)
+{
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glPushMatrix();
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glEnable(GL_TEXTURE_2D);
+
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ width, height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, ctx->buffer);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, (GLfloat)height);
+ glVertex2f(-1.0f, -1.0f);
+
+ glTexCoord2f((GLfloat)width, (GLfloat)height);
+ glVertex2f(1.0f, -1.0f);
+
+ glTexCoord2f((GLfloat)width, 0.0f);
+ glVertex2f(1.0f, 1.0f);
+
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(-1.0f, 1.0f);
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+ glPopMatrix();
+}
+
+#endif
diff --git a/pugl/common.h b/pugl/common.h
index 54ec6ef..3abab82 100644
--- a/pugl/common.h
+++ b/pugl/common.h
@@ -1,5 +1,5 @@
/*
- Copyright 2014 David Robillard <http://drobilla.net>
+ Copyright 2014-2016 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
@@ -56,8 +56,9 @@ typedef enum {
Drawing context type.
*/
typedef enum {
- PUGL_GL,
- PUGL_CAIRO
+ PUGL_GL = 0x1,
+ PUGL_CAIRO = 0x2,
+ PUGL_CAIRO_GL = 0x3
} PuglContextType;
/**
diff --git a/pugl/pugl_internal.h b/pugl/pugl_internal.h
index 1238ebc..778ff1f 100644
--- a/pugl/pugl_internal.h
+++ b/pugl/pugl_internal.h
@@ -1,5 +1,5 @@
/*
- Copyright 2012-2015 David Robillard <http://drobilla.net>
+ Copyright 2012-2016 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
@@ -86,9 +86,10 @@ puglInit(int* pargc, char** argv)
return NULL;
}
- view->impl = impl;
- view->width = 640;
- view->height = 480;
+ view->ctx_type = PUGL_GL;
+ view->impl = impl;
+ view->width = 640;
+ view->height = 480;
return view;
}
diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c
index 94827f3..e6d240c 100644
--- a/pugl/pugl_x11.c
+++ b/pugl/pugl_x11.c
@@ -1,5 +1,5 @@
/*
- Copyright 2012-2015 David Robillard <http://drobilla.net>
+ Copyright 2012-2016 David Robillard <http://drobilla.net>
Copyright 2013 Robin Gareus <robin@gareus.org>
Copyright 2011-2012 Ben Loftis, Harrison Consoles
@@ -40,6 +40,7 @@
#endif
#include "pugl/event.h"
+#include "pugl/cairo_gl.h"
#include "pugl/pugl_internal.h"
#ifndef MIN
@@ -93,6 +94,9 @@ struct PuglInternalsImpl {
GLXContext ctx;
int doubleBuffered;
#endif
+#if defined(PUGL_HAVE_CAIRO) && defined(PUGL_HAVE_GL)
+ PuglCairoGL cairo_gl;
+#endif
};
PuglInternals*
@@ -108,7 +112,7 @@ getVisual(PuglView* view)
XVisualInfo* vi = NULL;
#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL) {
+ if (view->ctx_type & PUGL_GL) {
for (int* attr = *attrLists; !vi && *attr; ++attr) {
vi = glXChooseVisual(impl->display, impl->screen, attr);
}
@@ -126,38 +130,78 @@ getVisual(PuglView* view)
return vi;
}
-static void
+#ifdef PUGL_HAVE_CAIRO
+static int
+createCairoContext(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+
+ if (impl->cr) {
+ cairo_destroy(impl->cr);
+ }
+
+ impl->cr = cairo_create(impl->surface);
+ return cairo_status(impl->cr);
+}
+#endif
+
+static bool
createContext(PuglView* view, XVisualInfo* vi)
{
PuglInternals* const impl = view->impl;
#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL) {
+ if (view->ctx_type & PUGL_GL) {
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
glXGetConfig(impl->display, vi, GLX_DOUBLEBUFFER, &impl->doubleBuffered);
}
#endif
#ifdef PUGL_HAVE_CAIRO
if (view->ctx_type == PUGL_CAIRO) {
- view->impl->surface = cairo_xlib_surface_create(
+ impl->surface = cairo_xlib_surface_create(
impl->display, impl->win, vi->visual, view->width, view->height);
- if (!(impl->cr = cairo_create(view->impl->surface))) {
- fprintf(stderr, "failed to create cairo context\n");
+ }
+#endif
+#if defined(PUGL_HAVE_GL) && defined(PUGL_HAVE_CAIRO)
+ if (view->ctx_type == PUGL_CAIRO_GL) {
+ impl->surface = pugl_cairo_gl_create(
+ &impl->cairo_gl, view->width, view->height, 4);
+ }
+#endif
+
+#ifdef PUGL_HAVE_CAIRO
+ if (view->ctx_type & PUGL_CAIRO) {
+ if (cairo_surface_status(impl->surface) != CAIRO_STATUS_SUCCESS) {
+ fprintf(stderr, "error: failed to create cairo surface\n");
+ return false;
+ }
+
+ if (createCairoContext(view) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(impl->surface);
+ fprintf(stderr, "error: failed to create cairo context\n");
+ return false;
}
}
#endif
+
+ return true;
}
static void
destroyContext(PuglView* view)
{
+#if defined(PUGL_HAVE_CAIRO) && defined(PUGL_HAVE_GL)
+ if (view->ctx_type == PUGL_CAIRO_GL) {
+ pugl_cairo_gl_free(&view->impl->cairo_gl);
+ }
+#endif
#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL) {
+ if (view->ctx_type & PUGL_GL) {
glXDestroyContext(view->impl->display, view->impl->ctx);
}
#endif
#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO) {
+ if (view->ctx_type & PUGL_CAIRO) {
cairo_destroy(view->impl->cr);
cairo_surface_destroy(view->impl->surface);
}
@@ -168,12 +212,12 @@ void
puglEnterContext(PuglView* view)
{
#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL) {
+ if (view->ctx_type & PUGL_GL) {
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
}
#endif
#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO) {
+ if (view->ctx_type & PUGL_CAIRO) {
cairo_set_source_rgb(view->impl->cr, 0, 0, 0);
cairo_paint(view->impl->cr);
}
@@ -184,12 +228,20 @@ void
puglLeaveContext(PuglView* view, bool flush)
{
#ifdef PUGL_HAVE_GL
- if (view->ctx_type == PUGL_GL && flush) {
+ if (flush && view->ctx_type & PUGL_GL) {
+#ifdef PUGL_HAVE_CAIRO
+ if (view->ctx_type == PUGL_CAIRO_GL) {
+ pugl_cairo_gl_draw(&view->impl->cairo_gl, view->width, view->height);
+ }
+#endif
+
glFlush();
if (view->impl->doubleBuffered) {
glXSwapBuffers(view->impl->display, view->impl->win);
}
}
+
+ glXMakeCurrent(view->impl->display, None, NULL);
#endif
}
@@ -227,7 +279,9 @@ puglCreateWindow(PuglView* view, const char* title)
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
CWColormap | CWEventMask, &attr);
- createContext(view, vi);
+ if (!createContext(view, vi)) {
+ return 2;
+ }
XSizeHints sizeHints;
memset(&sizeHints, 0, sizeof(sizeHints));
@@ -304,17 +358,14 @@ puglHideWindow(PuglView* view)
void
puglDestroy(PuglView* view)
{
- if (!view) {
- return;
+ if (view) {
+ destroyContext(view);
+ XDestroyWindow(view->impl->display, view->impl->win);
+ XCloseDisplay(view->impl->display);
+ free(view->windowClass);
+ free(view->impl);
+ free(view);
}
-
- destroyContext(view);
- XDestroyWindow(view->impl->display, view->impl->win);
- XCloseDisplay(view->impl->display);
- free(view->windowClass);
- free(view->impl);
- free(view);
- view = NULL;
}
static PuglKey
@@ -603,6 +654,21 @@ puglProcessEvents(PuglView* view)
config_event.configure.width,
config_event.configure.height);
}
+#ifdef PUGL_HAVE_GL
+ if (view->ctx_type == PUGL_CAIRO_GL) {
+ view->redisplay = true;
+ cairo_surface_destroy(view->impl->surface);
+ view->impl->surface = pugl_cairo_gl_create(
+ &view->impl->cairo_gl,
+ config_event.configure.width,
+ config_event.configure.height,
+ 4);
+ pugl_cairo_gl_configure(&view->impl->cairo_gl,
+ config_event.configure.width,
+ config_event.configure.height);
+ createCairoContext(view);
+ }
+#endif
#endif
puglDispatchEvent(view, (const PuglEvent*)&config_event);
}
@@ -640,7 +706,7 @@ void*
puglGetContext(PuglView* view)
{
#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO) {
+ if (view->ctx_type & PUGL_CAIRO) {
return view->impl->cr;
}
#endif