Switch from GtkGLExt to internal OpenGL handling
authorAndy Spencer <andy753421@gmail.com>
Tue, 7 Jun 2011 08:43:32 +0000 (08:43 +0000)
committerAndy Spencer <andy753421@gmail.com>
Tue, 7 Jun 2011 10:17:44 +0000 (10:17 +0000)
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.

13 files changed:
configure.ac
examples/plugin/teapot.c
src/Makefile.am
src/grits-opengl.c
src/grits-test.c
src/grits.pc.in
src/gtkgl.c [new file with mode: 0644]
src/gtkgl.h [new file with mode: 0644]
src/objects/grits-volume.c
src/plugins/Makefile.am
src/plugins/elev.c
src/plugins/env.c
src/plugins/test.c

index 953029a..5a1623c 100644 (file)
@@ -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
index 60c52f4..2a1201d 100644 (file)
@@ -15,8 +15,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <gtk/gtkgl.h>
 #include <GL/gl.h>
+#include <GL/glut.h>
 
 #include <grits.h>
 
@@ -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);
 }
 
 
index 9cb7454..e9b536d 100644 (file)
@@ -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
index d8eda27..b1316fc 100644 (file)
@@ -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 <config.h>
 #include <string.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
-#include <gtk/gtkgl.h>
 #include <GL/gl.h>
 #include <GL/glu.h>
 
 #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)
index 67e299d..5be869b 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <config.h>
 #include <gtk/gtk.h>
-#include <gtk/gtkgl.h>
 #include <gdk/gdkkeysyms.h>
 
 #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);
index 541f222..da0ea6a 100644 (file)
@@ -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 (file)
index 0000000..9a2909a
--- /dev/null
@@ -0,0 +1,190 @@
+#include <gtk/gtk.h>
+
+/***************************
+ * GtkGlExt implementation *
+ ***************************/
+#if defined(USE_GTKGLEXT)
+#include <gtk/gtkgl.h>
+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 <GL/glx.h>
+#include <gdk/gdkx.h>
+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 <windows.h>
+#include <gdk/gdkwin32.h>
+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 (file)
index 0000000..174fc76
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 Andy Spencer <andy753421@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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
index be08279..0ec7fb9 100644 (file)
@@ -30,7 +30,6 @@
 #include <math.h>
 #include <glib.h>
 #include <GL/gl.h>
-#include <gdk/gdkgl.h>
 #include "grits-volume.h"
 
 /* Drawing */
index 0052a59..e5c17dd 100644 (file)
@@ -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 )
index e99b326..57813ab 100644 (file)
@@ -25,7 +25,6 @@
  * greyscale elevation overlay on the planets surface.
  */
 
-#include <gtk/gtkgl.h>
 #include <glib/gstdio.h>
 #include <GL/gl.h>
 
index 3a1f324..a22ad0b 100644 (file)
@@ -25,7 +25,6 @@
  */
 
 #include <math.h>
-#include <gtk/gtkgl.h>
 #include <GL/gl.h>
 
 #include <grits.h>
index d917092..c051806 100644 (file)
@@ -23,7 +23,6 @@
  * for how to create a plugin.
  */
 
-#include <gtk/gtkgl.h>
 #include <GL/gl.h>
 #include <GL/glu.h>