]> Pileus Git - grits/commitdiff
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 953029a8dce8f5937a872d2a1125177d751cee47..5a1623c7b02ac3a8e282f255fbe5536aae34db50 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 60c52f43161063e7984a66686af65bc3497b7e8f..2a1201d9c02a0e53d17bdb60eceade1cbb0eaff8 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 9cb7454686386f3370978def49aedc56b4ba2fdf..e9b536de50009a5501a17f276791bc5da866a1c8 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 d8eda2752c7299cd33ba052c30869bedd6f2c118..b1316fcd958870ef7ac1f4dd58df9c53fd67c8df 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 67e299d887d4376f50d0aa85d5203317559ebfcf..5be869b6ccc03d635490ae880070278f4ae931c9 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 541f2225602a709746890f7387b293bf99ad58c3..da0ea6a1209d0ccdee58834c42a1a190507b63b2 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 be08279be35c075d66be6f282d7548af7ed55a8d..0ec7fb9e211394b2c1b8c54b610694d5de6e1583 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 0052a5932b04ebbb74ec9a94705ff8154b7617bf..e5c17dda11e9fd15df885b91d21d09c016d8f871 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 e99b32633971981a5a406011455990c073110e78..57813abdb63980cd8a253279d4cdbdc70bd39c25 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 3a1f324f787c7f3b6744017694d8bd3d3691cd67..a22ad0b03f2aea586f0a9be5c3574ec41f11c886 100644 (file)
@@ -25,7 +25,6 @@
  */
 
 #include <math.h>
-#include <gtk/gtkgl.h>
 #include <GL/gl.h>
 
 #include <grits.h>
index d917092e000b0112f37dbd104708039a38d7d6f1..c051806a0b392dc79616ca39c96666b4eb8243b9 100644 (file)
@@ -23,7 +23,6 @@
  * for how to create a plugin.
  */
 
-#include <gtk/gtkgl.h>
 #include <GL/gl.h>
 #include <GL/glu.h>