aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pugl/pugl.h33
-rw-r--r--pugl/pugl_internal.h56
-rw-r--r--pugl/pugl_internal_types.h39
-rw-r--r--pugl/pugl_osx.m4
-rw-r--r--pugl/pugl_win.cpp2
-rw-r--r--pugl/pugl_x11.c6
-rw-r--r--pugl/pugl_x11_gl.c143
7 files changed, 221 insertions, 62 deletions
diff --git a/pugl/pugl.h b/pugl/pugl.h
index 05366be..e57eb71 100644
--- a/pugl/pugl.h
+++ b/pugl/pugl.h
@@ -86,6 +86,33 @@ typedef enum {
} PuglContextType;
/**
+ Window hint.
+*/
+typedef enum {
+ PUGL_USE_COMPAT_PROFILE, /**< Use compatible (not core) OpenGL profile */
+ PUGL_CONTEXT_VERSION_MAJOR, /**< OpenGL context major version */
+ PUGL_CONTEXT_VERSION_MINOR, /**< OpenGL context minor version */
+ PUGL_RED_BITS, /**< Number of bits for red channel */
+ PUGL_GREEN_BITS, /**< Number of bits for green channel */
+ PUGL_BLUE_BITS, /**< Number of bits for blue channel */
+ PUGL_ALPHA_BITS, /**< Number of bits for alpha channel */
+ PUGL_DEPTH_BITS, /**< Number of bits for depth buffer */
+ PUGL_STENCIL_BITS, /**< Number of bits for stencil buffer */
+ PUGL_SAMPLES, /**< Number of samples per pixel (AA) */
+ PUGL_DOUBLE_BUFFER, /**< True if double buffering should be used */
+ PUGL_RESIZABLE, /**< True if window should be resizable */
+} PuglWindowHint;
+
+/**
+ Special window hint value.
+*/
+typedef enum {
+ PUGL_DONT_CARE = -1, /**< Use best available value */
+ PUGL_FALSE = 0, /**< Explicitly false */
+ PUGL_TRUE = 1 /**< Explicitly true */
+} PuglWindowHintValue;
+
+/**
Convenience symbols for ASCII control characters.
*/
typedef enum {
@@ -381,6 +408,12 @@ PUGL_API PuglView*
puglInit(int* pargc, char** argv);
/**
+ Set a hint before creating a window.
+*/
+PUGL_API void
+puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value);
+
+/**
Set the window class name before creating a window.
*/
PUGL_API void
diff --git a/pugl/pugl_internal.h b/pugl/pugl_internal.h
index 2b09761..2b54de4 100644
--- a/pugl/pugl_internal.h
+++ b/pugl/pugl_internal.h
@@ -36,6 +36,15 @@
PuglInternals* puglInitInternals(void);
+static PuglHints
+puglDefaultHints()
+{
+ static const PuglHints hints = {
+ 2, 0, 4, 4, 4, 4, 24, 8, 0, true, true, false
+ };
+ return hints;
+}
+
PuglView*
puglInit(int* pargc, char** argv)
{
@@ -44,6 +53,8 @@ puglInit(int* pargc, char** argv)
return NULL;
}
+ view->hints = puglDefaultHints();
+
PuglInternals* impl = puglInitInternals();
if (!impl) {
return NULL;
@@ -58,6 +69,49 @@ puglInit(int* pargc, char** argv)
}
void
+puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value)
+{
+ switch (hint) {
+ case PUGL_USE_COMPAT_PROFILE:
+ view->hints.use_compat_profile = value;
+ break;
+ case PUGL_CONTEXT_VERSION_MAJOR:
+ view->hints.context_version_major = value;
+ break;
+ case PUGL_CONTEXT_VERSION_MINOR:
+ view->hints.context_version_minor = value;
+ break;
+ case PUGL_RED_BITS:
+ view->hints.red_bits = value;
+ break;
+ case PUGL_GREEN_BITS:
+ view->hints.green_bits = value;
+ break;
+ case PUGL_BLUE_BITS:
+ view->hints.blue_bits = value;
+ break;
+ case PUGL_ALPHA_BITS:
+ view->hints.alpha_bits = value;
+ break;
+ case PUGL_DEPTH_BITS:
+ view->hints.depth_bits = value;
+ break;
+ case PUGL_STENCIL_BITS:
+ view->hints.stencil_bits = value;
+ break;
+ case PUGL_SAMPLES:
+ view->hints.samples = value;
+ break;
+ case PUGL_DOUBLE_BUFFER:
+ view->hints.double_buffer = value;
+ break;
+ case PUGL_RESIZABLE:
+ view->hints.resizable = value;
+ break;
+ }
+}
+
+void
puglInitWindowSize(PuglView* view, int width, int height)
{
view->width = width;
@@ -103,7 +157,7 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
void
puglInitResizable(PuglView* view, bool resizable)
{
- view->resizable = resizable;
+ view->hints.resizable = resizable;
}
void
diff --git a/pugl/pugl_internal_types.h b/pugl/pugl_internal_types.h
index 63b81cd..bbc39c0 100644
--- a/pugl/pugl_internal_types.h
+++ b/pugl/pugl_internal_types.h
@@ -29,6 +29,21 @@
/** Platform-specific internals. */
typedef struct PuglInternalsImpl PuglInternals;
+typedef struct {
+ int context_version_major;
+ int context_version_minor;
+ int red_bits;
+ int green_bits;
+ int blue_bits;
+ int alpha_bits;
+ int depth_bits;
+ int stencil_bits;
+ int samples;
+ bool use_compat_profile;
+ bool double_buffer;
+ bool resizable;
+} PuglHints;
+
/** Cross-platform view definition. */
struct PuglViewImpl {
PuglHandle handle;
@@ -41,18 +56,18 @@ struct PuglViewImpl {
PuglContextType ctx_type;
uintptr_t transient_parent;
- int width;
- int height;
- int min_width;
- int min_height;
- int min_aspect_x;
- int min_aspect_y;
- int max_aspect_x;
- int max_aspect_y;
- bool ignoreKeyRepeat;
- bool redisplay;
- bool resizable;
- bool visible;
+ PuglHints hints;
+ int width;
+ int height;
+ int min_width;
+ int min_height;
+ int min_aspect_x;
+ int min_aspect_y;
+ int max_aspect_x;
+ int max_aspect_y;
+ bool ignoreKeyRepeat;
+ bool redisplay;
+ bool visible;
};
/** Opaque surface used by draw context. */
diff --git a/pugl/pugl_osx.m b/pugl/pugl_osx.m
index 712f5fc..8e40907 100644
--- a/pugl/pugl_osx.m
+++ b/pugl/pugl_osx.m
@@ -583,7 +583,7 @@ puglCreateWindow(PuglView* view, const char* title)
puglConstraint(impl->glview, NSLayoutAttributeWidth, view->min_width)];
[impl->glview addConstraint:
puglConstraint(impl->glview, NSLayoutAttributeHeight, view->min_height)];
- if (!view->resizable) {
+ if (!view->hints.resizable) {
[impl->glview setAutoresizingMask:NSViewNotSizable];
}
@@ -598,7 +598,7 @@ puglCreateWindow(PuglView* view, const char* title)
encoding:NSUTF8StringEncoding];
NSRect frame = NSMakeRect(0, 0, view->min_width, view->min_height);
unsigned style = NSClosableWindowMask | NSTitledWindowMask;
- if (view->resizable) {
+ if (view->hints.resizable) {
style |= NSResizableWindowMask;
}
diff --git a/pugl/pugl_win.cpp b/pugl/pugl_win.cpp
index fd14593..2c092eb 100644
--- a/pugl/pugl_win.cpp
+++ b/pugl/pugl_win.cpp
@@ -138,7 +138,7 @@ puglCreateWindow(PuglView* view, const char* title)
}
int winFlags = WS_POPUPWINDOW | WS_CAPTION;
- if (view->resizable) {
+ if (view->hints.resizable) {
winFlags |= WS_SIZEBOX;
if (view->min_width || view->min_height) {
// Adjust the minimum window size to accomodate requested view size
diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c
index 5218433..6315759 100644
--- a/pugl/pugl_x11.c
+++ b/pugl/pugl_x11.c
@@ -88,8 +88,8 @@ puglCreateWindow(PuglView* view, const char* title)
return 1;
}
- impl->ctx.configure(view);
- if (!impl->vi) {
+ if (impl->ctx.configure(view) || !impl->vi) {
+ impl->ctx.destroy(view);
return 2;
}
@@ -120,7 +120,7 @@ puglCreateWindow(PuglView* view, const char* title)
XSizeHints sizeHints;
memset(&sizeHints, 0, sizeof(sizeHints));
- if (!view->resizable) {
+ if (!view->hints.resizable) {
sizeHints.flags = PMinSize|PMaxSize;
sizeHints.min_width = view->width;
sizeHints.min_height = view->height;
diff --git a/pugl/pugl_x11_gl.c b/pugl/pugl_x11_gl.c
index d6242f2..6c007b1 100644
--- a/pugl/pugl_x11_gl.c
+++ b/pugl/pugl_x11_gl.c
@@ -22,62 +22,117 @@
#include <GL/glx.h>
#include <stdlib.h>
+#include <stdio.h>
typedef struct {
- GLXContext ctx;
- int doubleBuffered;
+ GLXFBConfig fb_config;
+ GLXContext ctx;
+ int double_buffered;
} PuglX11GlSurface;
static int
+puglX11GlHintValue(const int value)
+{
+ return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value;
+}
+
+static int
+puglX11GlGetAttrib(Display* const display,
+ const GLXFBConfig fb_config,
+ const int attrib)
+{
+ int value = 0;
+ glXGetFBConfigAttrib(display, fb_config, attrib, &value);
+ return value;
+}
+
+static int
puglX11GlConfigure(PuglView* view)
{
- PuglInternals* const impl = view->impl;
-
- /** Attributes for double-buffered RGBA. */
- static int attrListDbl[] = { GLX_RGBA,
- GLX_DOUBLEBUFFER, True,
- GLX_RED_SIZE, 4,
- GLX_GREEN_SIZE, 4,
- GLX_BLUE_SIZE, 4,
- GLX_DEPTH_SIZE, 16,
- /* GLX_SAMPLE_BUFFERS , 1, */
- /* GLX_SAMPLES , 4, */
- None };
-
- /** Attributes for single-buffered RGBA. */
- static int attrListSgl[] = { GLX_RGBA,
- GLX_DOUBLEBUFFER, False,
- GLX_RED_SIZE, 4,
- GLX_GREEN_SIZE, 4,
- GLX_BLUE_SIZE, 4,
- GLX_DEPTH_SIZE, 16,
- /* GLX_SAMPLE_BUFFERS , 1, */
- /* GLX_SAMPLES , 4, */
- None };
-
- /** Null-terminated list of attributes in order of preference. */
- static int* attrLists[] = { attrListDbl, attrListSgl, NULL };
-
- if (view->ctx_type & PUGL_GL) {
- for (int* attr = *attrLists; !impl->vi && *attr; ++attr) {
- impl->vi = glXChooseVisual(impl->display, impl->screen, attr);
- }
+ PuglInternals* const impl = view->impl;
+ const int screen = impl->screen;
+ Display* const display = impl->display;
+
+ PuglX11GlSurface* const surface =
+ (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface));
+ impl->surface = surface;
+
+ const int attrs[] = {
+ GLX_X_RENDERABLE, True,
+ GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_SAMPLES, view->hints.samples,
+ GLX_RED_SIZE, puglX11GlHintValue(view->hints.red_bits),
+ GLX_GREEN_SIZE, puglX11GlHintValue(view->hints.green_bits),
+ GLX_BLUE_SIZE, puglX11GlHintValue(view->hints.blue_bits),
+ GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints.alpha_bits),
+ GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints.depth_bits),
+ GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints.stencil_bits),
+ GLX_DOUBLEBUFFER, (view->hints.samples
+ ? GLX_DONT_CARE
+ : view->hints.double_buffer),
+ None
+ };
+
+ int n_fbc = 0;
+ GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc);
+ if (n_fbc <= 0) {
+ fprintf(stderr, "error: Failed to create GL context\n");
+ return 1;
}
+ surface->fb_config = fbc[0];
+ impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]);
+
+ printf("Using visual 0x%lX: R=%d G=%d B=%d A=%d D=%d"
+ " DOUBLE=%d SAMPLES=%d\n",
+ impl->vi->visualid,
+ puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE),
+ puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER),
+ puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES));
+
return 0;
}
static int
puglX11GlCreate(PuglView* view)
{
- PuglInternals* const impl = view->impl;
-
- PuglX11GlSurface* surface = (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface));
+ PuglInternals* const impl = view->impl;
+ PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface;
+ Display* const display = impl->display;
+ const GLXFBConfig fb_config = surface->fb_config;
+
+ const int ctx_attrs[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints.context_version_major,
+ GLX_CONTEXT_MINOR_VERSION_ARB, view->hints.context_version_minor,
+ GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints.use_compat_profile
+ ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
+ : GLX_CONTEXT_CORE_PROFILE_BIT_ARB),
+ 0};
+
+ typedef GLXContext (*CreateContextAttribs)(
+ Display*, GLXFBConfig, GLXContext, Bool, const int*);
+
+ CreateContextAttribs create_context =
+ (CreateContextAttribs)glXGetProcAddress(
+ (GLubyte*)"glXCreateContextAttribsARB");
impl->surface = surface;
- surface->ctx = glXCreateContext(impl->display, impl->vi, 0, GL_TRUE);
- glXGetConfig(
- impl->display, impl->vi, GLX_DOUBLEBUFFER, &surface->doubleBuffered);
+ surface->ctx = create_context(display, fb_config, 0, GL_TRUE, ctx_attrs);
+ if (!surface->ctx) {
+ surface->ctx =
+ glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True);
+ }
+
+ glXGetConfig(impl->display,
+ impl->vi,
+ GLX_DOUBLEBUFFER,
+ &surface->double_buffered);
return 0;
}
@@ -86,9 +141,11 @@ static int
puglX11GlDestroy(PuglView* view)
{
PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
- glXDestroyContext(view->impl->display, surface->ctx);
- free(surface);
- view->impl->surface = NULL;
+ if (surface) {
+ glXDestroyContext(view->impl->display, surface->ctx);
+ free(surface);
+ view->impl->surface = NULL;
+ }
return 0;
}
@@ -110,7 +167,7 @@ puglX11GlLeave(PuglView* view, bool flush)
}
glXMakeCurrent(view->impl->display, None, NULL);
- if (surface->doubleBuffered) {
+ if (surface->double_buffered) {
glXSwapBuffers(view->impl->display, view->impl->win);
}