From: Andy Spencer Date: Tue, 7 Jun 2011 08:43:32 +0000 (+0000) Subject: Switch from GtkGLExt to internal OpenGL handling X-Git-Tag: v0.5~6 X-Git-Url: http://pileus.org/git/?p=grits;a=commitdiff_plain;h=07448c519e963bae1cfde4f1ff353478dd28136c Switch from GtkGLExt to internal OpenGL handling GtkGLExt has many problems: - It's code is bloated and convoluted - It doesn't work on Win32 - It doesn't work with gtk+-3.0 - The last release was in early 2006 Using our own lets us fix these issues and should be easier to maintain than trying to figure out the GtkGLExt mess, or waiting for someone else to fix it. --- diff --git a/configure.ac b/configure.ac index 953029a..5a1623c 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ GTK_DOC_CHECK(1.9) # Check for required packages PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.14 gobject-2.0 gthread-2.0) PKG_CHECK_MODULES(CAIRO, cairo) -PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.16 gtkglext-1.0) +PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.16) PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.26) # Test for Windows vs. Unix @@ -40,6 +40,17 @@ fi AM_CONDITIONAL([WIN32], test "$WIN32" = "yes") AM_CONDITIONAL([NOTWIN32], test "$WIN32" = "no") +# Configure GL flags +if test "$WIN32" = yes; then + GL_CFLAGS="" + GL_LIBS="-lglu32 -lopengl32" +else + GL_CFLAGS="" + GL_LIBS="-lGL -lGLU" +fi +AC_SUBST([GL_CFLAGS]) +AC_SUBST([GL_LIBS]) + # Output AC_CONFIG_FILES([ Makefile diff --git a/examples/plugin/teapot.c b/examples/plugin/teapot.c index 60c52f4..2a1201d 100644 --- a/examples/plugin/teapot.c +++ b/examples/plugin/teapot.c @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#include #include +#include #include @@ -59,7 +59,7 @@ static void expose(GritsCallback *callback, GritsOpenGL *opengl, gpointer _teapo glRotatef(teapot->rotation, 1, 1, 0); glColor4f(0.9, 0.9, 0.7, 1.0); glDisable(GL_CULL_FACE); - gdk_gl_draw_teapot(TRUE, 0.25); + glutSolidTeapot(2.5); } diff --git a/src/Makefile.am b/src/Makefile.am index 9cb7454..e9b536d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,8 @@ SUBDIRS = data objects . plugins AM_CFLAGS = -Wall --std=gnu99 -I$(top_srcdir)/src -AM_CPPFLAGS = $(GLIB_CFLAGS) $(GTK_CFLAGS) $(SOUP_CFLAGS) -AM_LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(SOUP_LIBS) +AM_CPPFLAGS = $(GLIB_CFLAGS) $(GTK_CFLAGS) $(GL_CFLAGS) $(SOUP_CFLAGS) +AM_LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(GL_LIBS) $(SOUP_LIBS) AM_LDFLAGS = --as-needed -no-undefined BUILT_SOURCES = grits-marshal.c grits-marshal.h @@ -35,6 +35,7 @@ libgrits_la_SOURCES = grits.h \ grits-marshal.c grits-marshal.h \ grits-util.c grits-util.h \ roam.c roam.h \ + gtkgl.c gtkgl.h \ gpqueue.c gpqueue.h libgrits_la_CPPFLAGS = $(AM_CPPFLAGS) \ -DPKGDATADIR="\"$(dots)$(datadir)/$(GRITS_SUBDIR)\"" \ @@ -47,10 +48,12 @@ libgrits_la_LDFLAGS = $(AM_LDFLAGS) \ # Demo program if WIN32 -AM_LDFLAGS += -mwindows -dots = .. +AM_CPPFLAGS += -DUSE_WGL +AM_LDFLAGS += -mwindows +dots = .. else -BINLDFLAGS = -static +AM_CPPFLAGS += -DUSE_GLX +BINLDFLAGS = -static endif bin_PROGRAMS = grits-demo diff --git a/src/grits-opengl.c b/src/grits-opengl.c index d8eda27..b1316fc 100644 --- a/src/grits-opengl.c +++ b/src/grits-opengl.c @@ -24,7 +24,7 @@ * algorithm for updating surface mesh the planet. The only thing GritsOpenGL * can actually render on it's own is a wireframe of a sphere. * - * GritsOpenGL relies on #GtkGlExt and requires (at least) OpenGL 2.0. + * GritsOpenGL requires (at least) OpenGL 2.0. */ #include @@ -32,12 +32,12 @@ #include #include #include -#include #include #include #include "grits-opengl.h" #include "grits-util.h" +#include "gtkgl.h" #include "roam.h" // #define ROAM_DEBUG @@ -206,8 +206,7 @@ static gboolean on_expose(GritsOpenGL *opengl, GdkEventExpose *event, gpointer _ g_mutex_unlock(opengl->objects_lock); #endif - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(opengl)); - gdk_gl_drawable_swap_buffers(gldrawable); + gtk_gl_end(GTK_WIDGET(opengl)); g_debug("GritsOpenGL: on_expose - end\n"); return FALSE; @@ -271,12 +270,7 @@ static gboolean on_idle(GritsOpenGL *opengl) static void on_realize(GritsOpenGL *opengl, gpointer _) { g_debug("GritsOpenGL: on_realize"); - - /* Start OpenGL */ - GdkGLContext *glcontext = gtk_widget_get_gl_context(GTK_WIDGET(opengl)); - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(opengl)); - if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) - g_assert_not_reached(); + gtk_gl_begin(GTK_WIDGET(opengl)); /* Connect signals and idle functions now that opengl is fully initialized */ gtk_widget_add_events(GTK_WIDGET(opengl), GDK_KEY_PRESS_MASK); @@ -454,19 +448,7 @@ static void grits_opengl_init(GritsOpenGL *opengl) opengl->objects_lock = g_mutex_new(); opengl->sphere = roam_sphere_new(opengl); opengl->sphere_lock = g_mutex_new(); - - /* Set OpenGL before "realize" */ - GdkGLConfig *glconfig = gdk_gl_config_new_by_mode( - GDK_GL_MODE_RGBA | GDK_GL_MODE_DEPTH | - GDK_GL_MODE_DOUBLE | GDK_GL_MODE_ALPHA); - if (!glconfig) - g_error("Failed to create glconfig"); - if (!gtk_widget_set_gl_capability(GTK_WIDGET(opengl), - glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE)) - g_error("GL lacks required capabilities"); - g_object_unref(glconfig); - - /* Finish OpenGL init after it's realized */ + gtk_gl_enable(GTK_WIDGET(opengl)); g_signal_connect(opengl, "realize", G_CALLBACK(on_realize), NULL); } static void grits_opengl_dispose(GObject *_opengl) diff --git a/src/grits-test.c b/src/grits-test.c index 67e299d..5be869b 100644 --- a/src/grits-test.c +++ b/src/grits-test.c @@ -17,7 +17,6 @@ #include #include -#include #include #include "grits.h" @@ -69,7 +68,6 @@ int main(int argc, char **argv) g_thread_init(NULL); gdk_threads_init(); gtk_init(&argc, &argv); - gtk_gl_init(&argc, &argv); prefs = grits_prefs_new(NULL, NULL); plugins = grits_plugins_new(g_getenv("GRITS_PLUGIN_PATH"), prefs); diff --git a/src/grits.pc.in b/src/grits.pc.in index 541f222..da0ea6a 100644 --- a/src/grits.pc.in +++ b/src/grits.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: Grits Description: Grits is a Virtual Globe library Version: @VERSION@ -Requires: gmodule-2.0 gtk+-2.0 gtkglext-1.0 libsoup-2.4 -Libs: -L${libdir} -lgrits -Cflags: -I${includedir}/grits +Requires: gmodule-2.0 gtk+-2.0 libsoup-2.4 +Libs: -L${libdir} -lgrits @GL_LIBS@ +Cflags: -I${includedir}/grits @GL_CFLAGS@ diff --git a/src/gtkgl.c b/src/gtkgl.c new file mode 100644 index 0000000..9a2909a --- /dev/null +++ b/src/gtkgl.c @@ -0,0 +1,190 @@ +#include + +/*************************** + * GtkGlExt implementation * + ***************************/ +#if defined(USE_GTKGLEXT) +#include +void gtk_gl_enable(GtkWidget *widget) +{ + GdkGLConfig *glconfig = gdk_gl_config_new_by_mode( + GDK_GL_MODE_RGBA | GDK_GL_MODE_DEPTH | + GDK_GL_MODE_ALPHA | GDK_GL_MODE_DOUBLE); + gtk_widget_set_gl_capability(widget, + glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); +} + +void gtk_gl_begin(GtkWidget *widget) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); + gdk_gl_drawable_gl_begin(gldrawable, glcontext); +} + +void gtk_gl_end(GtkWidget *widget) +{ + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); + gdk_gl_drawable_swap_buffers(gldrawable); + gdk_gl_drawable_gl_end(gldrawable); +} + +void gtk_gl_disable(GtkWidget *widget) +{ +} + + +/********************** + * X11 implementation * + **********************/ +#elif defined(USE_GLX) +#include +#include +void gtk_gl_enable(GtkWidget *widget) +{ + g_debug("GtkGl: enable"); + GdkScreen *screen = gdk_screen_get_default(); + Display *xdisplay = GDK_SCREEN_XDISPLAY(screen); + gint nscreen = GDK_SCREEN_XNUMBER(screen); + + /* Create context */ + int attribs[] = {GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None}; + XVisualInfo *xvinfo = glXChooseVisual(xdisplay, nscreen, attribs); + GLXContext context = glXCreateContext(xdisplay, xvinfo, NULL, False); + g_object_set_data(G_OBJECT(widget), "glcontext", context); + + /* Fix up colormap */ + GdkVisual *visual = gdk_x11_screen_lookup_visual(screen, xvinfo->visualid); + GdkColormap *cmap = gdk_colormap_new(visual, FALSE); + gtk_widget_set_colormap(widget, cmap); + + /* Disable GTK double buffering */ + gtk_widget_set_double_buffered(widget, FALSE); +} + +void gtk_gl_begin(GtkWidget *widget) +{ + g_debug("GtkGl: begin"); + Display *xdisplay = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget)); + Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(widget)); + GLXContext context = g_object_get_data(G_OBJECT(widget), "glcontext"); + glXMakeCurrent(xdisplay, xwindow, context); +} + +void gtk_gl_end(GtkWidget *widget) +{ + g_debug("GtkGl: end"); + Display *xdisplay = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget)); + Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(widget)); + glXSwapBuffers(xdisplay, xwindow); +} + +void gtk_gl_disable(GtkWidget *widget) +{ + g_debug("GtkGl: disable"); + Display *xdisplay = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget)); + GLXContext context = g_object_get_data(G_OBJECT(widget), "glcontext"); + glXDestroyContext(xdisplay, context); +} + + +/************************ + * Win32 implementation * + ************************/ +#elif defined(USE_WGL) +#include +#include +static void on_realize(GtkWidget *widget, gpointer _) +{ + g_debug("GtkGl: on_realize"); + gdk_window_ensure_native(gtk_widget_get_window(widget)); + gtk_widget_set_double_buffered(widget, FALSE); + + HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget)); + HDC hDC = GetDC(hwnd); + + PIXELFORMATDESCRIPTOR pfd = { + .nSize = sizeof(pfd), + .nVersion = 1, + .dwFlags = PFD_DRAW_TO_WINDOW + | PFD_SUPPORT_OPENGL + | PFD_DOUBLEBUFFER, + //.dwFlags = PFD_SUPPORT_OPENGL + // | PFD_DRAW_TO_WINDOW, + .iPixelType = PFD_TYPE_RGBA, + .cColorBits = 24, + .cAlphaBits = 8, + .cDepthBits = 32, + .iLayerType = PFD_MAIN_PLANE, + }; + int pf = ChoosePixelFormat(hDC, &pfd); + if (pf == 0) + g_error("GtkGl: ChoosePixelFormat failed"); + if (!SetPixelFormat(hDC, pf, &pfd)) + g_error("GtkGl: SetPixelFormat failed"); + HGLRC hRC = wglCreateContext(hDC); + if (hRC == NULL) + g_error("GtkGl: wglCreateContext failed"); + g_object_set_data(G_OBJECT(widget), "glcontext", hRC); +} + +void gtk_gl_enable(GtkWidget *widget) +{ + g_debug("GtkGl: enable"); + g_signal_connect(widget, "realize", G_CALLBACK(on_realize), NULL); +} + +void gtk_gl_begin(GtkWidget *widget) +{ + g_debug("GtkGl: begin"); + HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget)); + HDC hDC = GetDC(hwnd); + HGLRC hRC = g_object_get_data(G_OBJECT(widget), "glcontext"); + if (!wglMakeCurrent(hDC, hRC)) + g_error("GtkGl: wglMakeCurrent failed"); +} + +void gtk_gl_end(GtkWidget *widget) +{ + g_debug("GtkGl: end"); + HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget)); + HDC hDC = GetDC(hwnd); + if (!SwapBuffers(hDC)) + g_error("GtkGl: SwapBuffers failed"); +} + +void gtk_gl_disable(GtkWidget *widget) +{ + g_debug("GtkGl: disable"); + HGLRC hRC = g_object_get_data(G_OBJECT(widget), "glcontext"); + wglDeleteContext(hRC); +} + + + +/************************** + * Mac OSX implementation * + **************************/ +#elif defined(USE_CGL) +void gtk_gl_enable(GtkWidget *widget) { } +void gtk_gl_begin(GtkWidget *widget) { } +void gtk_gl_end(GtkWidget *widget) { } +void gtk_gl_disable(GtkWidget *widget) { } + + +/**************************** + * Undefined implementation * + ****************************/ +#else +#warning "Unimplemented GtkGl" +void gtk_gl_enable(GtkWidget *widget) { } +void gtk_gl_begin(GtkWidget *widget) { } +void gtk_gl_end(GtkWidget *widget) { } +void gtk_gl_disable(GtkWidget *widget) { } +#endif diff --git a/src/gtkgl.h b/src/gtkgl.h new file mode 100644 index 0000000..174fc76 --- /dev/null +++ b/src/gtkgl.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GTK_GL_H__ +#define __GTK_GL_H__ + +/* Call before widget is realized */ +void gtk_gl_enable(GtkWidget *widget); + +/* Call at the start of "expose" */ +void gtk_gl_begin(GtkWidget *widget); + +/* Call at the end of "expose-event" */ +void gtk_gl_end(GtkWidget *widget); + +/* Call when done to cleanup data */ +void gtk_gl_disable(GtkWidget *widget); + +#endif diff --git a/src/objects/grits-volume.c b/src/objects/grits-volume.c index be08279..0ec7fb9 100644 --- a/src/objects/grits-volume.c +++ b/src/objects/grits-volume.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "grits-volume.h" /* Drawing */ diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 0052a59..e5c17dd 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -14,10 +14,12 @@ map_la_SOURCES = map.c map.h env_la_SOURCES = env.c env.h test_la_SOURCES = test.c test.h +if NOTWIN32 noinst_LTLIBRARIES = teapot.la teapot_la_SOURCES = \ $(top_srcdir)/examples/plugin/teapot.c \ $(top_srcdir)/examples/plugin/teapot.h +endif test: ( cd ../; make test ) diff --git a/src/plugins/elev.c b/src/plugins/elev.c index e99b326..57813ab 100644 --- a/src/plugins/elev.c +++ b/src/plugins/elev.c @@ -25,7 +25,6 @@ * greyscale elevation overlay on the planets surface. */ -#include #include #include diff --git a/src/plugins/env.c b/src/plugins/env.c index 3a1f324..a22ad0b 100644 --- a/src/plugins/env.c +++ b/src/plugins/env.c @@ -25,7 +25,6 @@ */ #include -#include #include #include diff --git a/src/plugins/test.c b/src/plugins/test.c index d917092..c051806 100644 --- a/src/plugins/test.c +++ b/src/plugins/test.c @@ -23,7 +23,6 @@ * for how to create a plugin. */ -#include #include #include