From b4dbb3616865cd236cda4f2e4ac806b3b4840b29 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 27 Aug 2014 07:09:58 +0000 Subject: Cairo support on X11. --- pugl/gl.h | 32 ++++++++++ pugl/glu.h | 32 ++++++++++ pugl/pugl.h | 37 ++++++----- pugl/pugl_internal.h | 13 +++- pugl/pugl_x11.c | 173 ++++++++++++++++++++++++++++++++------------------- 5 files changed, 209 insertions(+), 78 deletions(-) create mode 100644 pugl/gl.h create mode 100644 pugl/glu.h (limited to 'pugl') 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 + + 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 /* 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 + + 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 /* 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 -/* - 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 /* Broken Windows GL headers require this */ -# endif -# include "GL/gl.h" -#endif - #ifdef PUGL_SHARED # ifdef _WIN32 # define PUGL_LIB_IMPORT __declspec(dllimport) @@ -87,6 +73,14 @@ typedef enum { PUGL_SUCCESS = 0 } PuglStatus; +/** + Drawing context type. +*/ +typedef enum { + PUGL_GL, + PUGL_CAIRO +} PuglContextType; + /** Convenience symbols for ASCII control characters. */ @@ -246,6 +240,12 @@ puglInitWindowSize(PuglView* view, int width, int height); 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. @@ -284,6 +284,15 @@ puglSetHandle(PuglView* view, PuglHandle handle); 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. */ 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; @@ -109,6 +112,12 @@ puglInitResizable(PuglView* view, bool resizable) view->resizable = resizable; } +void +puglInitContextType(PuglView* view, PuglContextType type) +{ + view->ctx_type = type; +} + void puglSetHandle(PuglView* view, PuglHandle 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 #include -#include -#include #include #include +#include #include +#ifdef PUGL_HAVE_GL +#include +#include +#endif + +#ifdef PUGL_HAVE_CAIRO +#include +#include +#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; +} -- cgit v1.2.3