[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: pcb.git: branch: master updated (d9f4025a8c9adbbedcdef5aee4f5af3036b326a8)



The branch, master has been updated
       via  d9f4025a8c9adbbedcdef5aee4f5af3036b326a8 (commit)
      from  9acdd88e22717510ff5dde277ecbd6f1de60b69d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 configure.ac            |   55 +++-
 src/Makefile.am         |   21 +-
 src/hid/common/hidgl.c  |  557 +++++++++++++++++++++++
 src/hid/common/hidgl.h  |   79 ++++
 src/hid/gtk/gtkhid-gl.c | 1159 +++++++++++++++++++++++++++++++++++++++++++++++
 src/hid/gtk/gui.h       |    2 +-
 6 files changed, 1868 insertions(+), 5 deletions(-)
 create mode 100644 src/hid/common/hidgl.c
 create mode 100644 src/hid/common/hidgl.h
 create mode 100644 src/hid/gtk/gtkhid-gl.c


=================
 Commit Messages
=================

commit d9f4025a8c9adbbedcdef5aee4f5af3036b326a8
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    hid/gtk: Drop in GL renderer - WOOT!
    
    Much of the generic GL drawing stuff lives in a new common helper,
    hid/common/hidgl.[ch]. Unavoidably, there is a lot of GUI specific
    setup and teardown code.
    
    There are probably still bits of code in hid/gtk/gtkhid-gl.c which
    could be moved to a shared place if / when other HIDs wish to use
    GL rendering.
    
    Currently only rat lines are drawn transparent, as we need to sub-
    composite each layer to avoid a confusing field of hightlights being
    drawn where line ends overlap.
    
    configure --enable-gl now checks for the required GL, glu and GtkGLEext.
    
    More good stuff to come soon!
    
    Credits:
    
      Algorithm to calculate number of segments to use in circular
      curve approximation suggested by DJ Delorie.
    
      Thanks to Krzysztof KoÅ?ciuszkiewicz for testing and debugging
      some issues with the GL_SCISSOR_TEST being used.
    
      An small team of dedicated testers who have provided feedback,
      bug reports and encoragement throught the long development of
      this branch.

:100644 100644 ab6986f... 2637495... M	configure.ac
:100644 100644 5abbfb2... 8129207... M	src/Makefile.am
:000000 100644 0000000... 1745891... A	src/hid/common/hidgl.c
:000000 100644 0000000... 282b144... A	src/hid/common/hidgl.h
:000000 100644 0000000... 0923110... A	src/hid/gtk/gtkhid-gl.c
:100644 100644 d52d088... 7a18906... M	src/hid/gtk/gui.h

=========
 Changes
=========

commit d9f4025a8c9adbbedcdef5aee4f5af3036b326a8
Author: Peter Clifton <pcjc2@xxxxxxxxx>
Commit: Peter Clifton <pcjc2@xxxxxxxxx>

    hid/gtk: Drop in GL renderer - WOOT!
    
    Much of the generic GL drawing stuff lives in a new common helper,
    hid/common/hidgl.[ch]. Unavoidably, there is a lot of GUI specific
    setup and teardown code.
    
    There are probably still bits of code in hid/gtk/gtkhid-gl.c which
    could be moved to a shared place if / when other HIDs wish to use
    GL rendering.
    
    Currently only rat lines are drawn transparent, as we need to sub-
    composite each layer to avoid a confusing field of hightlights being
    drawn where line ends overlap.
    
    configure --enable-gl now checks for the required GL, glu and GtkGLEext.
    
    More good stuff to come soon!
    
    Credits:
    
      Algorithm to calculate number of segments to use in circular
      curve approximation suggested by DJ Delorie.
    
      Thanks to Krzysztof KoÅ?ciuszkiewicz for testing and debugging
      some issues with the GL_SCISSOR_TEST being used.
    
      An small team of dedicated testers who have provided feedback,
      bug reports and encoragement throught the long development of
      this branch.

diff --git a/configure.ac b/configure.ac
index ab6986f..2637495 100644
--- a/configure.ac
+++ b/configure.ac
@@ -389,6 +389,46 @@ $DBUS_PKG_ERRORS])]
 
 fi
 
+
+AC_MSG_CHECKING([for whether to use GL drawing])
+AC_ARG_ENABLE([gl],
+[  --enable-gl           Enable GL drawing (with GTK HID)],
+[],[enable_gl=no])
+
+AC_MSG_RESULT([$enable_gl])
+AM_CONDITIONAL(USE_GL, test x$enable_gl = xyes)
+
+if test "x$enable_gl" = "xyes"; then
+	case " $with_gui " in
+		*\ gtk\ *) ;;
+		* ) AC_MSG_ERROR([GL drawing enabled but only works with the GTK HID.
+Either do not use --enable-gl or enable the gtk HID.])
+	;;
+	esac
+
+	AC_CHECK_HEADERS(GL/gl.h)
+	case $ac_cv_header_GL_gl_h in
+	  no )
+	    AC_MSG_ERROR([You don't seem to have the GL library headers installed.])
+	    ;;
+	  * ) ;;
+	esac
+
+	AC_CHECK_HEADERS(GL/glu.h)
+	case $ac_cv_header_GL_glu_h in
+	  no )
+	    AC_MSG_ERROR([You don't seem to have the GL glu library headers installed.])
+	    ;;
+	  * ) ;;
+	esac
+
+	GLU_CFLAGS=
+	GLU_LIBS=-lGLU
+
+	AC_DEFINE([ENABLE_GL], 1,
+		[Define to 1 if GL support is to be compiled in])
+fi
+
 AC_MSG_CHECKING([for which printer to use])
 AC_ARG_WITH([printer],
 [  --with-printer= 	  Specify the printer: lpr [[default=lpr]]],
@@ -723,6 +763,17 @@ $GTK_PKG_ERRORS])]
 	)
 	GTK_VERSION=`$PKG_CONFIG gtk+-2.0 --modversion`
 	GLIB_VERSION=`$PKG_CONFIG glib-2.0 --modversion`
+
+	if test "x$enable_gl" = "xyes"; then
+		# Check for GtkGLExt
+		PKG_CHECK_MODULES(GTKGLEXT, gtkglext-1.0 >= 1.0.0, , [AC_MSG_ERROR([
+*** Required version of gtkglext is not installed - please install first ***
+Please review the following errors:
+$GTKGLEXT_PKG_ERRORS])]
+		)
+	GTKGLEXT_VER=`$PKG_CONFIG gtkglext-1.0 --modversion`
+	fi
+
 	;;
 
       gcode|nelma|png )
@@ -1015,8 +1066,8 @@ AX_FUNC_MKDIR
 
 # ------------- Complete set of CFLAGS and LIBS -------------------
 
-CFLAGS="$CFLAGS $X_CFLAGS $DBUS_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS $CAIRO_CFLAGS"
-LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GLIB_LIBS $GTK_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS $CAIRO_LIBS"
+CFLAGS="$CFLAGS $X_CFLAGS $DBUS_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS $CAIRO_CFLAGS $GTKGLEXT_CFLAGS $GLU_CFLAGS"
+LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GLIB_LIBS $GTK_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS $CAIRO_LIBS $GTKGLEXT_LIBS $GLU_LIBS"
 
 
 # if we have gcc then add -Wall
diff --git a/src/Makefile.am b/src/Makefile.am
index 5abbfb2..8129207 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -157,13 +157,23 @@ PCB_SRCS = \
 	hid/common/hid_resource.h \
 	hid/hidint.h 
 
-EXTRA_pcb_SOURCES = ${DBUS_SRCS} toporouter.c toporouter.h
+EXTRA_pcb_SOURCES = ${DBUS_SRCS} ${GL_SRCS} toporouter.c toporouter.h
 DBUS_SRCS= \
 	dbus-pcbmain.c \
 	dbus-pcbmain.h \
 	dbus.h \
 	dbus.c
 
+LIBGTK_GDK_SRCS= \
+	hid/gtk/gtkhid-gdk.c
+
+LIBGTK_GL_SRCS= \
+	hid/gtk/gtkhid-gl.c
+
+GL_SRCS= \
+	hid/common/hidgl.c \
+	hid/common/hidgl.h
+
 BUILT_SOURCES = \
 	core_lists.h \
 	gpcb-menu.h \
@@ -250,7 +260,6 @@ LIBGTK_SRCS = \
 	dolists.h \
 	hid/hidint.h \
 	hid/gtk/gtkhid-main.c \
-	hid/gtk/gtkhid-gdk.c \
 	hid/gtk/gtkhid.h \
 	hid/gtk/gui.h \
 	hid/gtk/gui-command-window.c \
@@ -294,6 +303,14 @@ BUILT_SOURCES+=	dbus-introspect.h
 
 endif
 
+# If we are building with GL support, we need some extra files
+if USE_GL
+PCB_SRCS+=	${GL_SRCS}
+LIBGTK_SRCS+=	${LIBGTK_GL_SRCS}
+else
+LIBGTK_SRCS+=	${LIBGTK_GDK_SRCS}
+endif
+
 # If we are building on win32, then compile in some icons for the
 # desktop and application toolbar
 if WIN32
diff --git a/src/hid/common/hidgl.c b/src/hid/common/hidgl.c
new file mode 100644
index 0000000..1745891
--- /dev/null
+++ b/src/hid/common/hidgl.c
@@ -0,0 +1,557 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2009-2011 PCB Contributers (See ChangeLog for details)
+ *
+ *  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 2 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <math.h>
+#include <assert.h>
+
+/* The Linux OpenGL ABI 1.0 spec requires that we define
+ * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
+ * in order to get prototypes:
+ *   http://www.opengl.org/registry/ABI/
+ */
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#include "action.h"
+#include "crosshair.h"
+#include "data.h"
+#include "draw.h"
+#include "error.h"
+#include "global.h"
+#include "mymem.h"
+#include "draw.h"
+#include "clip.h"
+
+#include "hid.h"
+#include "hidgl.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+
+triangle_buffer buffer;
+float global_depth = 0;
+
+void
+hidgl_init_triangle_array (triangle_buffer *buffer)
+{
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glVertexPointer (3, GL_FLOAT, 0, buffer->triangle_array);
+  buffer->triangle_count = 0;
+  buffer->coord_comp_count = 0;
+}
+
+void
+hidgl_flush_triangles (triangle_buffer *buffer)
+{
+  if (buffer->triangle_count == 0)
+    return;
+
+  glDrawArrays (GL_TRIANGLES, 0, buffer->triangle_count * 3);
+  buffer->triangle_count = 0;
+  buffer->coord_comp_count = 0;
+}
+
+void
+hidgl_ensure_triangle_space (triangle_buffer *buffer, int count)
+{
+  if (count > TRIANGLE_ARRAY_SIZE)
+    {
+      fprintf (stderr, "Not enough space in vertex buffer\n");
+      fprintf (stderr, "Requested %i triangles, %i available\n",
+                       count, TRIANGLE_ARRAY_SIZE);
+      exit (1);
+    }
+  if (count > TRIANGLE_ARRAY_SIZE - buffer->triangle_count)
+    hidgl_flush_triangles (buffer);
+}
+
+void
+hidgl_set_depth (float depth)
+{
+  global_depth = depth;
+}
+
+void
+hidgl_draw_grid (BoxType *drawn_area)
+{
+  static GLfloat *points = 0;
+  static int npoints = 0;
+  int x1, y1, x2, y2, n, i;
+  double x, y;
+
+  if (!Settings.DrawGrid)
+    return;
+
+  x1 = GRIDFIT_X (MAX (0, drawn_area->X1), PCB->Grid);
+  y1 = GRIDFIT_Y (MAX (0, drawn_area->Y1), PCB->Grid);
+  x2 = GRIDFIT_X (MIN (PCB->MaxWidth, drawn_area->X2), PCB->Grid);
+  y2 = GRIDFIT_Y (MIN (PCB->MaxHeight, drawn_area->Y2), PCB->Grid);
+
+  if (x1 > x2)
+    {
+      int tmp = x1;
+      x1 = x2;
+      x2 = tmp;
+    }
+
+  if (y1 > y2)
+    {
+      int tmp = y1;
+      y1 = y2;
+      y2 = tmp;
+    }
+
+  n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
+  if (n > npoints)
+    {
+      npoints = n + 10;
+      points = realloc (points, npoints * 3 * sizeof (GLfloat));
+    }
+
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glVertexPointer (3, GL_FLOAT, 0, points);
+
+  n = 0;
+  for (x = x1; x <= x2; x += PCB->Grid)
+    {
+      points[3 * n + 0] = x;
+      points[3 * n + 2] = global_depth;
+      n++;
+    }
+  for (y = y1; y <= y2; y += PCB->Grid)
+    {
+      for (i = 0; i < n; i++)
+        points[3 * i + 1] = y;
+      glDrawArrays (GL_POINTS, 0, n);
+    }
+
+  glDisableClientState (GL_VERTEX_ARRAY);
+}
+
+#define MAX_PIXELS_ARC_TO_CHORD 0.5
+#define MIN_SLICES 6
+int calc_slices (float pix_radius, float sweep_angle)
+{
+  float slices;
+
+  if (pix_radius <= MAX_PIXELS_ARC_TO_CHORD)
+    return MIN_SLICES;
+
+  slices = sweep_angle / acosf (1 - MAX_PIXELS_ARC_TO_CHORD / pix_radius) / 2.;
+  return (int)ceilf (slices);
+}
+
+#define MIN_TRIANGLES_PER_CAP 3
+#define MAX_TRIANGLES_PER_CAP 90
+static void draw_cap (double width, int x, int y, double angle, double scale)
+{
+  float last_capx, last_capy;
+  float capx, capy;
+  float radius = width / 2.;
+  int slices = calc_slices (radius / scale, M_PI);
+  int i;
+
+  if (slices < MIN_TRIANGLES_PER_CAP)
+    slices = MIN_TRIANGLES_PER_CAP;
+
+  if (slices > MAX_TRIANGLES_PER_CAP)
+    slices = MAX_TRIANGLES_PER_CAP;
+
+  hidgl_ensure_triangle_space (&buffer, slices);
+
+  last_capx =  radius * cosf (angle * M_PI / 180.) + x;
+  last_capy = -radius * sinf (angle * M_PI / 180.) + y;
+  for (i = 0; i < slices; i++) {
+    capx =  radius * cosf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + x;
+    capy = -radius * sinf (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / (float)slices) + y;
+    hidgl_add_triangle (&buffer, last_capx, last_capy, capx, capy, x, y);
+    last_capx = capx;
+    last_capy = capy;
+  }
+}
+
+void
+hidgl_draw_line (int cap, double width, int x1, int y1, int x2, int y2, double scale)
+{
+  double angle;
+  float deltax, deltay, length;
+  float wdx, wdy;
+  int circular_caps = 0;
+  int hairline = 0;
+
+  if (width == 0.0)
+    hairline = 1;
+
+  if (width < scale)
+    width = scale;
+
+  deltax = x2 - x1;
+  deltay = y2 - y1;
+
+  length = sqrt (deltax * deltax + deltay * deltay);
+
+  if (length == 0) {
+    /* Assume the orientation of the line is horizontal */
+    angle = 0;
+    wdx = -width / 2.;
+    wdy = 0;
+    length = 1.;
+    deltax = 1.;
+    deltay = 0.;
+  } else {
+    wdy = deltax * width / 2. / length;
+    wdx = -deltay * width / 2. / length;
+
+    if (deltay == 0.)
+      angle = (deltax < 0) ? 270. : 90.;
+    else
+      angle = 180. / M_PI * atanl (deltax / deltay);
+
+    if (deltay < 0)
+      angle += 180.;
+  }
+
+  switch (cap) {
+    case Trace_Cap:
+    case Round_Cap:
+      circular_caps = 1;
+      break;
+
+    case Square_Cap:
+    case Beveled_Cap:
+      x1 -= deltax * width / 2. / length;
+      y1 -= deltay * width / 2. / length;
+      x2 += deltax * width / 2. / length;
+      y2 += deltay * width / 2. / length;
+      break;
+  }
+
+  hidgl_ensure_triangle_space (&buffer, 2);
+  hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
+                               x2 - wdx, y2 - wdy,
+                               x2 + wdx, y2 + wdy);
+  hidgl_add_triangle (&buffer, x1 - wdx, y1 - wdy,
+                               x2 + wdx, y2 + wdy,
+                               x1 + wdx, y1 + wdy);
+
+  /* Don't bother capping hairlines */
+  if (circular_caps && !hairline)
+    {
+      draw_cap (width, x1, y1, angle, scale);
+      draw_cap (width, x2, y2, angle + 180., scale);
+    }
+}
+
+#define MIN_SLICES_PER_ARC 6
+#define MAX_SLICES_PER_ARC 360
+void
+hidgl_draw_arc (double width, int x, int y, int rx, int ry,
+                int start_angle, int delta_angle, double scale)
+{
+  float last_inner_x, last_inner_y;
+  float last_outer_x, last_outer_y;
+  float inner_x, inner_y;
+  float outer_x, outer_y;
+  float inner_r;
+  float outer_r;
+  float cos_ang, sin_ang;
+  float start_angle_rad;
+  float delta_angle_rad;
+  float angle_incr_rad;
+  int slices;
+  int i;
+  int hairline = 0;
+
+  if (width == 0.0)
+    hairline = 1;
+
+  if (width < scale)
+    width = scale;
+
+  inner_r = rx - width / 2.;
+  outer_r = rx + width / 2.;
+
+  if (delta_angle < 0) {
+    start_angle += delta_angle;
+    delta_angle = - delta_angle;
+  }
+
+  start_angle_rad = start_angle * M_PI / 180.;
+  delta_angle_rad = delta_angle * M_PI / 180.;
+
+  slices = calc_slices ((rx + width / 2.) / scale, delta_angle_rad);
+
+  if (slices < MIN_SLICES_PER_ARC)
+    slices = MIN_SLICES_PER_ARC;
+
+  if (slices > MAX_SLICES_PER_ARC)
+    slices = MAX_SLICES_PER_ARC;
+
+  hidgl_ensure_triangle_space (&buffer, 2 * slices);
+
+  angle_incr_rad = delta_angle_rad / (float)slices;
+
+  cos_ang = cosf (start_angle_rad);
+  sin_ang = sinf (start_angle_rad);
+  last_inner_x = -inner_r * cos_ang + x;  last_inner_y = inner_r * sin_ang + y;
+  last_outer_x = -outer_r * cos_ang + x;  last_outer_y = outer_r * sin_ang + y;
+  for (i = 1; i <= slices; i++) {
+    cos_ang = cosf (start_angle_rad + ((float)(i)) * angle_incr_rad);
+    sin_ang = sinf (start_angle_rad + ((float)(i)) * angle_incr_rad);
+    inner_x = -inner_r * cos_ang + x;  inner_y = inner_r * sin_ang + y;
+    outer_x = -outer_r * cos_ang + x;  outer_y = outer_r * sin_ang + y;
+    hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
+                                 last_outer_x, last_outer_y,
+                                 outer_x, outer_y);
+    hidgl_add_triangle (&buffer, last_inner_x, last_inner_y,
+                                 inner_x, inner_y,
+                                 outer_x, outer_y);
+    last_inner_x = inner_x;  last_inner_y = inner_y;
+    last_outer_x = outer_x;  last_outer_y = outer_y;
+  }
+
+  /* Don't bother capping hairlines */
+  if (hairline)
+    return;
+
+  draw_cap (width, x + rx * -cosf (start_angle_rad),
+                   y + rx *  sinf (start_angle_rad),
+                   start_angle, scale);
+  draw_cap (width, x + rx * -cosf (start_angle_rad + delta_angle_rad),
+                   y + rx *  sinf (start_angle_rad + delta_angle_rad),
+                   start_angle + delta_angle + 180., scale);
+}
+
+void
+hidgl_draw_rect (int x1, int y1, int x2, int y2)
+{
+  glBegin (GL_LINE_LOOP);
+  glVertex3f (x1, y1, global_depth);
+  glVertex3f (x1, y2, global_depth);
+  glVertex3f (x2, y2, global_depth);
+  glVertex3f (x2, y1, global_depth);
+  glEnd ();
+}
+
+
+void
+hidgl_fill_circle (int vx, int vy, int vr, double scale)
+{
+#define MIN_TRIANGLES_PER_CIRCLE 6
+#define MAX_TRIANGLES_PER_CIRCLE 360
+  float last_x, last_y;
+  float radius = vr;
+  int slices;
+  int i;
+
+  slices = calc_slices (vr / scale, 2 * M_PI);
+
+  if (slices < MIN_TRIANGLES_PER_CIRCLE)
+    slices = MIN_TRIANGLES_PER_CIRCLE;
+
+  if (slices > MAX_TRIANGLES_PER_CIRCLE)
+    slices = MAX_TRIANGLES_PER_CIRCLE;
+
+  hidgl_ensure_triangle_space (&buffer, slices);
+
+  last_x = vx + vr;
+  last_y = vy;
+
+  for (i = 0; i < slices; i++) {
+    float x, y;
+    x = radius * cosf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vx;
+    y = radius * sinf (((float)(i + 1)) * 2. * M_PI / (float)slices) + vy;
+    hidgl_add_triangle (&buffer, vx, vy, last_x, last_y, x, y);
+    last_x = x;
+    last_y = y;
+  }
+}
+
+#define MAX_COMBINED_MALLOCS 2500
+static void *combined_to_free [MAX_COMBINED_MALLOCS];
+static int combined_num_to_free = 0;
+
+static GLenum tessVertexType;
+static int stashed_vertices;
+static int triangle_comp_idx;
+
+
+static void
+myError (GLenum errno)
+{
+  printf ("gluTess error: %s\n", gluErrorString (errno));
+}
+
+static void
+myFreeCombined ()
+{
+  while (combined_num_to_free)
+    free (combined_to_free [-- combined_num_to_free]);
+}
+
+static void
+myCombine ( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **dataOut )
+{
+#define MAX_COMBINED_VERTICES 2500
+  static GLdouble combined_vertices [3 * MAX_COMBINED_VERTICES];
+  static int num_combined_vertices = 0;
+
+  GLdouble *new_vertex;
+
+  if (num_combined_vertices < MAX_COMBINED_VERTICES)
+    {
+      new_vertex = &combined_vertices [3 * num_combined_vertices];
+      num_combined_vertices ++;
+    }
+  else
+    {
+      new_vertex = malloc (3 * sizeof (GLdouble));
+
+      if (combined_num_to_free < MAX_COMBINED_MALLOCS)
+        combined_to_free [combined_num_to_free ++] = new_vertex;
+      else
+        printf ("myCombine leaking %lu bytes of memory\n", 3 * sizeof (GLdouble));
+    }
+
+  new_vertex[0] = coords[0];
+  new_vertex[1] = coords[1];
+  new_vertex[2] = coords[2];
+
+  *dataOut = new_vertex;
+}
+
+static void
+myBegin (GLenum type)
+{
+  tessVertexType = type;
+  stashed_vertices = 0;
+  triangle_comp_idx = 0;
+}
+
+static void
+myVertex (GLdouble *vertex_data)
+{
+  static GLfloat triangle_vertices [2 * 3];
+
+  if (tessVertexType == GL_TRIANGLE_STRIP ||
+      tessVertexType == GL_TRIANGLE_FAN)
+    {
+      if (stashed_vertices < 2)
+        {
+          triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
+          triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
+          stashed_vertices ++;
+        }
+      else
+        {
+          hidgl_ensure_triangle_space (&buffer, 1);
+          hidgl_add_triangle (&buffer,
+                              triangle_vertices [0], triangle_vertices [1],
+                              triangle_vertices [2], triangle_vertices [3],
+                              vertex_data [0], vertex_data [1]);
+
+          if (tessVertexType == GL_TRIANGLE_STRIP)
+            {
+              /* STRIP saves the last two vertices for re-use in the next triangle */
+              triangle_vertices [0] = triangle_vertices [2];
+              triangle_vertices [1] = triangle_vertices [3];
+            }
+          /* Both FAN and STRIP save the last vertex for re-use in the next triangle */
+          triangle_vertices [2] = vertex_data [0];
+          triangle_vertices [3] = vertex_data [1];
+        }
+    }
+  else if (tessVertexType == GL_TRIANGLES)
+    {
+      triangle_vertices [triangle_comp_idx ++] = vertex_data [0];
+      triangle_vertices [triangle_comp_idx ++] = vertex_data [1];
+      stashed_vertices ++;
+      if (stashed_vertices == 3)
+        {
+          hidgl_ensure_triangle_space (&buffer, 1);
+          hidgl_add_triangle (&buffer,
+                              triangle_vertices [0], triangle_vertices [1],
+                              triangle_vertices [2], triangle_vertices [3],
+                              triangle_vertices [4], triangle_vertices [5]);
+          triangle_comp_idx = 0;
+          stashed_vertices = 0;
+        }
+    }
+  else
+    printf ("Vertex recieved with unknown type\n");
+}
+
+void
+hidgl_fill_polygon (int n_coords, int *x, int *y)
+{
+  int i;
+  GLUtesselator *tobj;
+  GLdouble *vertices;
+
+  assert (n_coords > 0);
+
+  vertices = malloc (sizeof(GLdouble) * n_coords * 3);
+
+  tobj = gluNewTess ();
+  gluTessCallback(tobj, GLU_TESS_BEGIN, myBegin);
+  gluTessCallback(tobj, GLU_TESS_VERTEX, myVertex);
+  gluTessCallback(tobj, GLU_TESS_COMBINE, myCombine);
+  gluTessCallback(tobj, GLU_TESS_ERROR, myError);
+
+  gluTessBeginPolygon (tobj, NULL);
+  gluTessBeginContour (tobj);
+
+  for (i = 0; i < n_coords; i++)
+    {
+      vertices [0 + i * 3] = x[i];
+      vertices [1 + i * 3] = y[i];
+      vertices [2 + i * 3] = 0.;
+      gluTessVertex (tobj, &vertices [i * 3], &vertices [i * 3]);
+    }
+
+  gluTessEndContour (tobj);
+  gluTessEndPolygon (tobj);
+  gluDeleteTess (tobj);
+
+  myFreeCombined ();
+  free (vertices);
+}
+
+void
+hidgl_fill_rect (int x1, int y1, int x2, int y2)
+{
+  hidgl_ensure_triangle_space (&buffer, 2);
+  hidgl_add_triangle (&buffer, x1, y1, x1, y2, x2, y2);
+  hidgl_add_triangle (&buffer, x2, y1, x2, y2, x1, y1);
+}
diff --git a/src/hid/common/hidgl.h b/src/hid/common/hidgl.h
new file mode 100644
index 0000000..282b144
--- /dev/null
+++ b/src/hid/common/hidgl.h
@@ -0,0 +1,79 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2009-2011 PCB Contributors (See ChangeLog for details).
+ *
+ *  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 2 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __HIDGL_INCLUDED__
+#define __HIDGL_INCLUDED__
+
+#define TRIANGLE_ARRAY_SIZE 5461
+typedef struct {
+  GLfloat triangle_array [3 * 3 * TRIANGLE_ARRAY_SIZE];
+  unsigned int triangle_count;
+  unsigned int coord_comp_count;
+} triangle_buffer;
+
+extern triangle_buffer buffer;
+extern float global_depth;
+
+void hidgl_init_triangle_array (triangle_buffer *buffer);
+void hidgl_flush_triangles (triangle_buffer *buffer);
+void hidgl_ensure_triangle_space (triangle_buffer *buffer, int count);
+
+static inline void
+hidgl_add_triangle_3D (triangle_buffer *buffer,
+                       GLfloat x1, GLfloat y1, GLfloat z1,
+                       GLfloat x2, GLfloat y2, GLfloat z2,
+                       GLfloat x3, GLfloat y3, GLfloat z3)
+{
+  buffer->triangle_array [buffer->coord_comp_count++] = x1;
+  buffer->triangle_array [buffer->coord_comp_count++] = y1;
+  buffer->triangle_array [buffer->coord_comp_count++] = z1;
+  buffer->triangle_array [buffer->coord_comp_count++] = x2;
+  buffer->triangle_array [buffer->coord_comp_count++] = y2;
+  buffer->triangle_array [buffer->coord_comp_count++] = z2;
+  buffer->triangle_array [buffer->coord_comp_count++] = x3;
+  buffer->triangle_array [buffer->coord_comp_count++] = y3;
+  buffer->triangle_array [buffer->coord_comp_count++] = z3;
+  buffer->triangle_count++;
+}
+
+static inline void
+hidgl_add_triangle (triangle_buffer *buffer,
+                    GLfloat x1, GLfloat y1,
+                    GLfloat x2, GLfloat y2,
+                    GLfloat x3, GLfloat y3)
+{
+  hidgl_add_triangle_3D (buffer, x1, y1, global_depth,
+                                 x2, y2, global_depth,
+                                 x3, y3, global_depth);
+}
+
+void hidgl_draw_grid (BoxType *drawn_area);
+void hidgl_set_depth (float depth);
+void hidgl_draw_line (int cap, double width, int x1, int y1, int x2, int y2, double scale);
+void hidgl_draw_arc (double width, int vx, int vy, int vrx, int vry, int start_angle, int delta_angle, double scale);
+void hidgl_draw_rect (int x1, int y1, int x2, int y2);
+void hidgl_fill_circle (int vx, int vy, int vr, double scale);
+void hidgl_fill_polygon (int n_coords, int *x, int *y);
+void hidgl_fill_rect (int x1, int y1, int x2, int y2);
+
+
+#endif /* __HIDGL_INCLUDED__  */
diff --git a/src/hid/gtk/gtkhid-gl.c b/src/hid/gtk/gtkhid-gl.c
new file mode 100644
index 0000000..0923110
--- /dev/null
+++ b/src/hid/gtk/gtkhid-gl.c
@@ -0,0 +1,1159 @@
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include "crosshair.h"
+#include "clip.h"
+#include "../hidint.h"
+#include "gui.h"
+#include "gui-pinout-preview.h"
+
+/* The Linux OpenGL ABI 1.0 spec requires that we define
+ * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
+ * in order to get prototypes:
+ *   http://www.opengl.org/registry/ABI/
+ */
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/gl.h>
+#include <gtk/gtkgl.h>
+#include "hid/common/hidgl.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+RCSID ("$Id$");
+
+
+extern HID ghid_hid;
+
+static hidGC current_gc = NULL;
+
+/* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
+*/
+#define USE_GC(gc) if (!use_gc(gc)) return
+
+static int cur_mask = -1;
+
+typedef struct render_priv {
+  GdkGLConfig *glconfig;
+  bool trans_lines;
+  bool in_context;
+} render_priv;
+
+
+typedef struct hid_gc_struct
+{
+  HID *me_pointer;
+
+  gchar *colorname;
+  gint width;
+  gint cap, join;
+  gchar xor;
+  gchar erase;
+}
+hid_gc_struct;
+
+
+int
+ghid_set_layer (const char *name, int group, int empty)
+{
+  render_priv *priv = gport->render_priv;
+  int idx = group;
+  if (idx >= 0 && idx < max_group)
+    {
+      int n = PCB->LayerGroups.Number[group];
+      for (idx = 0; idx < n-1; idx ++)
+	{
+	  int ni = PCB->LayerGroups.Entries[group][idx];
+	  if (ni >= 0 && ni < max_copper_layer + 2
+	      && PCB->Data->Layer[ni].On)
+	    break;
+	}
+      idx = PCB->LayerGroups.Entries[group][idx];
+    }
+
+  if (idx >= 0 && idx < max_copper_layer + 2)
+    {
+      priv->trans_lines = false;
+      return PCB->Data->Layer[idx].On;
+    }
+  if (idx < 0)
+    {
+      switch (SL_TYPE (idx))
+	{
+	case SL_INVISIBLE:
+	  return PCB->InvisibleObjectsOn;
+	case SL_MASK:
+	  if (SL_MYSIDE (idx))
+	    return TEST_FLAG (SHOWMASKFLAG, PCB);
+	  return 0;
+	case SL_SILK:
+	  priv->trans_lines = false;
+	  if (SL_MYSIDE (idx))
+	    return PCB->ElementOn;
+	  return 0;
+	case SL_ASSY:
+	  return 0;
+	case SL_PDRILL:
+	case SL_UDRILL:
+	  return 1;
+	case SL_RATS:
+	  if (PCB->RatOn)
+	    priv->trans_lines = true;
+	  return PCB->RatOn;
+	}
+    }
+  return 0;
+}
+
+void
+ghid_destroy_gc (hidGC gc)
+{
+  g_free (gc);
+}
+
+hidGC
+ghid_make_gc (void)
+{
+  hidGC rv;
+
+  rv = g_new0 (hid_gc_struct, 1);
+  rv->me_pointer = &ghid_hid;
+  rv->colorname = Settings.BackgroundColor;
+  return rv;
+}
+
+static void
+ghid_draw_grid (BoxTypePtr drawn_area)
+{
+  if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
+    return;
+
+  if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
+    {
+      gport->grid_color.red ^= gport->bg_color.red;
+      gport->grid_color.green ^= gport->bg_color.green;
+      gport->grid_color.blue ^= gport->bg_color.blue;
+    }
+
+  glEnable (GL_COLOR_LOGIC_OP);
+  glLogicOp (GL_XOR);
+
+  glColor3f (gport->grid_color.red / 65535.,
+             gport->grid_color.green / 65535.,
+             gport->grid_color.blue / 65535.);
+
+  hidgl_draw_grid (drawn_area);
+
+  glDisable (GL_COLOR_LOGIC_OP);
+}
+
+static void
+ghid_draw_bg_image (void)
+{
+  static GLuint texture_handle = 0;
+
+  if (!ghidgui->bg_pixbuf)
+    return;
+
+  if (texture_handle == 0)
+    {
+      int width =             gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
+      int height =            gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
+      int rowstride =         gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
+      int bits_per_sample =   gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
+      int n_channels =        gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
+      unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
+
+      g_warn_if_fail (bits_per_sample == 8);
+      g_warn_if_fail (rowstride == width * n_channels);
+
+      glGenTextures (1, &texture_handle);
+      glBindTexture (GL_TEXTURE_2D, texture_handle);
+
+      /* XXX: We should proabbly determine what the maxmimum texture supported is,
+       *      and if our image is larger, shrink it down using GDK pixbuf routines
+       *      rather than having it fail below.
+       */
+
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
+                    (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
+    }
+
+  glBindTexture (GL_TEXTURE_2D, texture_handle);
+
+  glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+  glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+  glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+  glEnable (GL_TEXTURE_2D);
+
+  /* Render a quad with the background as a texture */
+
+  glBegin (GL_QUADS);
+  glTexCoord2d (0., 0.);
+  glVertex3i (0,             0,              0);
+  glTexCoord2d (1., 0.);
+  glVertex3i (PCB->MaxWidth, 0,              0);
+  glTexCoord2d (1., 1.);
+  glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
+  glTexCoord2d (0., 1.);
+  glVertex3i (0,             PCB->MaxHeight, 0);
+  glEnd ();
+
+  glDisable (GL_TEXTURE_2D);
+}
+
+void
+ghid_use_mask (int use_it)
+{
+  /* NOTE: We are assuming the stencil buffer bit plane is clear at the start
+   *       of a masked drawing operation.
+   *
+   *       For our current usage we know that it will start clean at the
+   *       beginning of the frame - and that the mask is only used at most
+   *       once during rendering (for the solder-mask layer).
+   */
+
+  if (use_it == cur_mask)
+    return;
+
+  hidgl_flush_triangles (&buffer);
+
+  switch (use_it)
+    {
+    case HID_MASK_BEFORE:
+      /* The HID asks not to receive this mask type, so warn if we get it */
+      g_return_if_reached ();
+
+    case HID_MASK_CLEAR:
+      /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
+      glColorMask (0, 0, 0, 0);                   /* Disable writting in color buffer */
+      glEnable (GL_STENCIL_TEST);                 /* Enable Stencil test              */
+      glStencilFunc (GL_ALWAYS, 1, 1);            /* Test always passes, value written 1 */
+      glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
+      break;
+
+    case HID_MASK_AFTER:
+      /* Drawing operations as masked to areas where the stencil buffer is '0' */
+      glColorMask (1, 1, 1, 1);                   /* Enable drawing of r, g, b & a */
+      glStencilFunc (GL_EQUAL, 0, 1);             /* Draw only where stencil buffer is 1 */
+      glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);    /* Stencil buffer read only */
+      break;
+
+    case HID_MASK_OFF:
+      /* Disable stenciling */
+      glDisable (GL_STENCIL_TEST);
+      break;
+    }
+  cur_mask = use_it;
+}
+
+
+  /* Config helper functions for when the user changes color preferences.
+     |  set_special colors used in the gtkhid.
+   */
+static void
+set_special_grid_color (void)
+{
+  if (!gport->colormap)
+    return;
+  gport->grid_color.red ^= gport->bg_color.red;
+  gport->grid_color.green ^= gport->bg_color.green;
+  gport->grid_color.blue ^= gport->bg_color.blue;
+}
+
+void
+ghid_set_special_colors (HID_Attribute * ha)
+{
+  if (!ha->name || !ha->value)
+    return;
+  if (!strcmp (ha->name, "background-color"))
+    {
+      ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
+      set_special_grid_color ();
+    }
+  else if (!strcmp (ha->name, "off-limit-color"))
+  {
+      ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
+    }
+  else if (!strcmp (ha->name, "grid-color"))
+    {
+      ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
+      set_special_grid_color ();
+    }
+}
+
+typedef struct
+{
+  int color_set;
+  GdkColor color;
+  int xor_set;
+  GdkColor xor_color;
+  double red;
+  double green;
+  double blue;
+} ColorCache;
+
+void
+ghid_set_color (hidGC gc, const char *name)
+{
+  render_priv *priv = gport->render_priv;
+  static void *cache = NULL;
+  static char *old_name = NULL;
+  hidval cval;
+  ColorCache *cc;
+  double alpha_mult = 1.0;
+  double r, g, b, a;
+  a = 1.0;
+
+  current_gc = gc;
+
+  if (old_name != NULL)
+    {
+      if (strcmp (name, old_name) == 0)
+        return;
+      free (old_name);
+    }
+
+  old_name = strdup (name);
+
+  if (name == NULL)
+    {
+      fprintf (stderr, "%s():  name = NULL, setting to magenta\n",
+               __FUNCTION__);
+      name = "magenta";
+    }
+
+  gc->colorname = (char *) name;
+
+  if (gport->colormap == NULL)
+    gport->colormap = gtk_widget_get_colormap (gport->top_window);
+  if (strcmp (name, "erase") == 0)
+    {
+      gc->erase = 1;
+      r = gport->bg_color.red   / 65535.;
+      g = gport->bg_color.green / 65535.;
+      b = gport->bg_color.blue  / 65535.;
+    }
+  else if (strcmp (name, "drill") == 0)
+    {
+      gc->erase = 0;
+      alpha_mult = 0.85;
+      r = gport->offlimits_color.red   / 65535.;
+      g = gport->offlimits_color.green / 65535.;
+      b = gport->offlimits_color.blue  / 65535.;
+    }
+  else
+    {
+      alpha_mult = 0.7;
+      if (hid_cache_color (0, name, &cval, &cache))
+        cc = (ColorCache *) cval.ptr;
+      else
+        {
+          cc = (ColorCache *) malloc (sizeof (ColorCache));
+          memset (cc, 0, sizeof (*cc));
+          cval.ptr = cc;
+          hid_cache_color (1, name, &cval, &cache);
+        }
+
+      if (!cc->color_set)
+        {
+          if (gdk_color_parse (name, &cc->color))
+            gdk_color_alloc (gport->colormap, &cc->color);
+          else
+            gdk_color_white (gport->colormap, &cc->color);
+          cc->red   = cc->color.red   / 65535.;
+          cc->green = cc->color.green / 65535.;
+          cc->blue  = cc->color.blue  / 65535.;
+          cc->color_set = 1;
+        }
+      if (gc->xor)
+        {
+          if (!cc->xor_set)
+            {
+              cc->xor_color.red = cc->color.red ^ gport->bg_color.red;
+              cc->xor_color.green = cc->color.green ^ gport->bg_color.green;
+              cc->xor_color.blue = cc->color.blue ^ gport->bg_color.blue;
+              gdk_color_alloc (gport->colormap, &cc->xor_color);
+              cc->red   = cc->color.red   / 65535.;
+              cc->green = cc->color.green / 65535.;
+              cc->blue  = cc->color.blue  / 65535.;
+              cc->xor_set = 1;
+            }
+        }
+      r = cc->red;
+      g = cc->green;
+      b = cc->blue;
+
+      gc->erase = 0;
+    }
+  if (1) {
+    double maxi, mult;
+    if (priv->trans_lines)
+      a = a * alpha_mult;
+    maxi = r;
+    if (g > maxi) maxi = g;
+    if (b > maxi) maxi = b;
+    mult = MIN (1 / alpha_mult, 1 / maxi);
+#if 1
+    r = r * mult;
+    g = g * mult;
+    b = b * mult;
+#endif
+  }
+
+  if(!priv->in_context)
+    return;
+
+  hidgl_flush_triangles (&buffer);
+  glColor4d (r, g, b, a);
+}
+
+void
+ghid_set_line_cap (hidGC gc, EndCapStyle style)
+{
+  gc->cap = style;
+}
+
+void
+ghid_set_line_width (hidGC gc, int width)
+{
+  gc->width = width;
+}
+
+
+void
+ghid_set_draw_xor (hidGC gc, int xor)
+{
+  /* NOT IMPLEMENTED */
+
+  /* Only presently called when setting up a crosshair GC.
+   * We manage our own drawing model for that anyway. */
+}
+
+void
+ghid_set_draw_faded (hidGC gc, int faded)
+{
+  printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
+}
+
+void
+ghid_set_line_cap_angle (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  printf ("ghid_set_line_cap_angle() -- not implemented\n");
+}
+
+static void
+ghid_invalidate_current_gc (void)
+{
+  current_gc = NULL;
+}
+
+static int
+use_gc (hidGC gc)
+{
+  if (gc->me_pointer != &ghid_hid)
+    {
+      fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
+      abort ();
+    }
+
+  if (current_gc == gc)
+    return 1;
+
+  current_gc = gc;
+
+  ghid_set_color (gc, gc->colorname);
+  return 1;
+}
+
+void
+ghid_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  USE_GC (gc);
+
+  hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->zoom);
+}
+
+void
+ghid_draw_arc (hidGC gc, int cx, int cy, int xradius, int yradius,
+                         int start_angle, int delta_angle)
+{
+  USE_GC (gc);
+
+  hidgl_draw_arc (gc->width, cx, cy, xradius, yradius,
+                  start_angle, delta_angle, gport->zoom);
+}
+
+void
+ghid_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  USE_GC (gc);
+
+  hidgl_draw_rect (x1, y1, x2, y2);
+}
+
+
+void
+ghid_fill_circle (hidGC gc, int cx, int cy, int radius)
+{
+  USE_GC (gc);
+
+  hidgl_fill_circle (cx, cy, radius, gport->zoom);
+}
+
+
+void
+ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
+{
+  USE_GC (gc);
+
+  hidgl_fill_polygon (n_coords, x, y);
+}
+
+void
+ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
+{
+  USE_GC (gc);
+
+  hidgl_fill_rect (x1, y1, x2, y2);
+}
+
+void
+ghid_invalidate_lr (int left, int right, int top, int bottom)
+{
+  ghid_invalidate_all ();
+}
+
+void
+ghid_invalidate_all ()
+{
+  ghid_draw_area_update (gport, NULL);
+}
+
+void
+ghid_notify_crosshair_change (bool changes_complete)
+{
+  /* We sometimes get called before the GUI is up */
+  if (gport->drawing_area == NULL)
+    return;
+
+  /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
+  ghid_invalidate_all ();
+}
+
+void
+ghid_notify_mark_change (bool changes_complete)
+{
+  /* We sometimes get called before the GUI is up */
+  if (gport->drawing_area == NULL)
+    return;
+
+  /* FIXME: We could just invalidate the bounds of the mark? */
+  ghid_invalidate_all ();
+}
+
+static void
+draw_right_cross (gint x, gint y)
+{
+  glVertex2i (x, 0);
+  glVertex2i (x, gport->height);
+  glVertex2i (0, y);
+  glVertex2i (gport->width, y);
+}
+
+static void
+draw_slanted_cross (gint x, gint y)
+{
+  gint x0, y0, x1, y1;
+
+  x0 = x + (gport->height - y);
+  x0 = MAX(0, MIN (x0, gport->width));
+  x1 = x - y;
+  x1 = MAX(0, MIN (x1, gport->width));
+  y0 = y + (gport->width - x);
+  y0 = MAX(0, MIN (y0, gport->height));
+  y1 = y - x;
+  y1 = MAX(0, MIN (y1, gport->height));
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+
+  x0 = x - (gport->height - y);
+  x0 = MAX(0, MIN (x0, gport->width));
+  x1 = x + y;
+  x1 = MAX(0, MIN (x1, gport->width));
+  y0 = y + x;
+  y0 = MAX(0, MIN (y0, gport->height));
+  y1 = y - (gport->width - x);
+  y1 = MAX(0, MIN (y1, gport->height));
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+}
+
+static void
+draw_dozen_cross (gint x, gint y)
+{
+  gint x0, y0, x1, y1;
+  gdouble tan60 = sqrt (3);
+
+  x0 = x + (gport->height - y) / tan60;
+  x0 = MAX(0, MIN (x0, gport->width));
+  x1 = x - y / tan60;
+  x1 = MAX(0, MIN (x1, gport->width));
+  y0 = y + (gport->width - x) * tan60;
+  y0 = MAX(0, MIN (y0, gport->height));
+  y1 = y - x * tan60;
+  y1 = MAX(0, MIN (y1, gport->height));
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+
+  x0 = x + (gport->height - y) * tan60;
+  x0 = MAX(0, MIN (x0, gport->width));
+  x1 = x - y * tan60;
+  x1 = MAX(0, MIN (x1, gport->width));
+  y0 = y + (gport->width - x) / tan60;
+  y0 = MAX(0, MIN (y0, gport->height));
+  y1 = y - x / tan60;
+  y1 = MAX(0, MIN (y1, gport->height));
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+
+  x0 = x - (gport->height - y) / tan60;
+  x0 = MAX(0, MIN (x0, gport->width));
+  x1 = x + y / tan60;
+  x1 = MAX(0, MIN (x1, gport->width));
+  y0 = y + x * tan60;
+  y0 = MAX(0, MIN (y0, gport->height));
+  y1 = y - (gport->width - x) * tan60;
+  y1 = MAX(0, MIN (y1, gport->height));
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+
+  x0 = x - (gport->height - y) * tan60;
+  x0 = MAX(0, MIN (x0, gport->width));
+  x1 = x + y * tan60;
+  x1 = MAX(0, MIN (x1, gport->width));
+  y0 = y + x / tan60;
+  y0 = MAX(0, MIN (y0, gport->height));
+  y1 = y - (gport->width - x) / tan60;
+  y1 = MAX(0, MIN (y1, gport->height));
+  glVertex2i (x0, y0);
+  glVertex2i (x1, y1);
+}
+
+static void
+draw_crosshair (gint x, gint y)
+{
+  static enum crosshair_shape prev = Basic_Crosshair_Shape;
+
+  draw_right_cross (x, y);
+  if (prev == Union_Jack_Crosshair_Shape)
+    draw_slanted_cross (x, y);
+  if (prev == Dozen_Crosshair_Shape)
+    draw_dozen_cross (x, y);
+  prev = Crosshair.shape;
+}
+
+#define VCW 16
+#define VCD 8
+
+void
+ghid_show_crosshair (gboolean paint_new_location)
+{
+  gint x, y;
+  gboolean draw_markers;
+  static int done_once = 0;
+  static GdkColor cross_color;
+
+  if (!paint_new_location)
+    return;
+
+  if (!done_once)
+    {
+      done_once = 1;
+      /* FIXME: when CrossColor changed from config */
+      ghid_map_color_string (Settings.CrossColor, &cross_color);
+    }
+  x = DRAW_X (gport->x_crosshair);
+  y = DRAW_Y (gport->y_crosshair);
+
+  glEnable (GL_COLOR_LOGIC_OP);
+  glLogicOp (GL_XOR);
+
+  hidgl_flush_triangles (&buffer);
+
+  glColor3f (cross_color.red / 65535.,
+             cross_color.green / 65535.,
+             cross_color.blue / 65535.);
+
+  if (x >= 0 && paint_new_location)
+    {
+      glBegin (GL_LINES);
+      draw_crosshair (x, y);
+      glEnd ();
+    }
+
+  draw_markers = ghidgui->auto_pan_on && have_crosshair_attachments ();
+  if (x >= 0 && paint_new_location && draw_markers)
+    {
+      glBegin (GL_QUADS);
+      glVertex2i (0,                  y - VCD);
+      glVertex2i (0,                  y - VCD + VCW);
+      glVertex2i (VCD,                y - VCD + VCW);
+      glVertex2i (VCD,                y - VCD);
+      glVertex2i (gport->width,       y - VCD);
+      glVertex2i (gport->width,       y - VCD + VCW);
+      glVertex2i (gport->width - VCD, y - VCD + VCW);
+      glVertex2i (gport->width - VCD, y - VCD);
+      glVertex2i (x - VCD,            0);
+      glVertex2i (x - VCD,            VCD);
+      glVertex2i (x - VCD + VCW,      VCD);
+      glVertex2i (x - VCD + VCW,      0);
+      glVertex2i (x - VCD,            gport->height - VCD);
+      glVertex2i (x - VCD,            gport->height);
+      glVertex2i (x - VCD + VCW,      gport->height);
+      glVertex2i (x - VCD + VCW,      gport->height - VCD);
+      glEnd ();
+    }
+
+  glDisable (GL_COLOR_LOGIC_OP);
+}
+
+void
+ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
+{
+  render_priv *priv;
+
+  port->render_priv = priv = g_new0 (render_priv, 1);
+
+  gtk_gl_init(argc, argv);
+
+  /* setup GL-context */
+  priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA    |
+                                              GDK_GL_MODE_STENCIL |
+                                              GDK_GL_MODE_DOUBLE);
+  if (!priv->glconfig)
+    {
+      printf ("Could not setup GL-context!\n");
+      return; /* Should we abort? */
+    }
+}
+
+void
+ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
+{
+  render_priv *priv = port->render_priv;
+
+  gtk_widget_set_gl_capability (widget,
+                                priv->glconfig,
+                                NULL,
+                                TRUE,
+                                GDK_GL_RGBA_TYPE);
+}
+
+void
+ghid_drawing_area_configure_hook (GHidPort *port)
+{
+}
+
+gboolean
+ghid_start_drawing (GHidPort *port)
+{
+  GtkWidget *widget = port->drawing_area;
+  GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
+
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
+    return FALSE;
+
+  port->render_priv->in_context = true;
+
+  return TRUE;
+}
+
+void
+ghid_end_drawing (GHidPort *port)
+{
+  GtkWidget *widget = port->drawing_area;
+  GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  port->render_priv->in_context = false;
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (pGlDrawable);
+}
+
+void
+ghid_screen_update (void)
+{
+}
+
+#define Z_NEAR 3.0
+gboolean
+ghid_drawing_area_expose_cb (GtkWidget *widget,
+                             GdkEventExpose *ev,
+                             GHidPort *port)
+{
+  BoxType region;
+
+  ghid_start_drawing (port);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glViewport (0, 0, widget->allocation.width, widget->allocation.height);
+
+  glEnable (GL_SCISSOR_TEST);
+  glScissor (ev->area.x,
+             widget->allocation.height - ev->area.height - ev->area.y,
+             ev->area.width, ev->area.height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glClearColor (port->offlimits_color.red / 65535.,
+                port->offlimits_color.green / 65535.,
+                port->offlimits_color.blue / 65535.,
+                1.);
+
+  glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+  region.X1 = MIN (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
+  region.X2 = MAX (Px (ev->area.x), Px (ev->area.x + ev->area.width + 1));
+  region.Y1 = MIN (Py (ev->area.y), Py (ev->area.y + ev->area.height + 1));
+  region.Y2 = MAX (Py (ev->area.y), Py (ev->area.y + ev->area.height + 1));
+
+  glColor3f (port->bg_color.red / 65535.,
+             port->bg_color.green / 65535.,
+             port->bg_color.blue / 65535.);
+
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / port->zoom,
+            (ghid_flip_y ? -1. : 1.) / port->zoom,
+            (ghid_flip_x == ghid_flip_y) ? 1. : -1.);
+  glTranslatef (ghid_flip_x ? port->view_x0 - PCB->MaxWidth  :
+                             -port->view_x0,
+                ghid_flip_y ? port->view_y0 - PCB->MaxHeight :
+                             -port->view_y0, 0);
+
+  glBegin (GL_QUADS);
+  glVertex3i (0,             0,              0);
+  glVertex3i (PCB->MaxWidth, 0,              0);
+  glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
+  glVertex3i (0,             PCB->MaxHeight, 0);
+  glEnd ();
+
+  ghid_draw_bg_image ();
+
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+  hid_expose_callback (&ghid_hid, &region, 0);
+  hidgl_flush_triangles (&buffer);
+
+  ghid_draw_grid (&region);
+
+  ghid_invalidate_current_gc ();
+
+  DrawAttached ();
+  DrawMark ();
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  ghid_show_crosshair (TRUE);
+
+  hidgl_flush_triangles (&buffer);
+
+  ghid_end_drawing (port);
+
+  return FALSE;
+}
+
+gboolean
+ghid_pinout_preview_expose (GtkWidget *widget,
+                            GdkEventExpose *ev)
+{
+  GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
+  GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
+  double save_zoom;
+  int da_w, da_h;
+  int save_left, save_top;
+  int save_width, save_height;
+  int save_view_width, save_view_height;
+  double xz, yz;
+
+  save_zoom = gport->zoom;
+  save_width = gport->width;
+  save_height = gport->height;
+  save_left = gport->view_x0;
+  save_top = gport->view_y0;
+  save_view_width = gport->view_width;
+  save_view_height = gport->view_height;
+
+  /* Setup zoom factor for drawing routines */
+
+  gdk_window_get_geometry (widget->window, 0, 0, &da_w, &da_h, 0);
+  xz = (double) pinout->x_max / da_w;
+  yz = (double) pinout->y_max / da_h;
+  if (xz > yz)
+    gport->zoom = xz;
+  else
+    gport->zoom = yz;
+
+  gport->width = da_w;
+  gport->height = da_h;
+  gport->view_width = da_w * gport->zoom;
+  gport->view_height = da_h * gport->zoom;
+  gport->view_x0 = (pinout->x_max - gport->view_width) / 2;
+  gport->view_y0 = (pinout->y_max - gport->view_height) / 2;
+
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
+    return FALSE;
+  }
+  gport->render_priv->in_context = true;
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glViewport (0, 0, widget->allocation.width, widget->allocation.height);
+
+  glEnable (GL_SCISSOR_TEST);
+  glScissor (ev->area.x,
+             widget->allocation.height - ev->area.height - ev->area.y,
+             ev->area.width, ev->area.height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glClearColor (gport->bg_color.red / 65535.,
+                gport->bg_color.green / 65535.,
+                gport->bg_color.blue / 65535.,
+                1.);
+
+  glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+  /* call the drawing routine */
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
+            (ghid_flip_y ? -1. : 1.) / gport->zoom, 1);
+  glTranslatef (ghid_flip_x ? gport->view_x0 - PCB->MaxWidth  :
+                             -gport->view_x0,
+                ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
+                             -gport->view_y0, 0);
+  hid_expose_callback (&ghid_hid, NULL, &pinout->element);
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  /* end drawing to current GL-context */
+  gport->render_priv->in_context = false;
+  gdk_gl_drawable_gl_end (pGlDrawable);
+
+  gport->zoom = save_zoom;
+  gport->width = save_width;
+  gport->height = save_height;
+  gport->view_x0 = save_left;
+  gport->view_y0 = save_top;
+  gport->view_width = save_view_width;
+  gport->view_height = save_view_height;
+
+  return FALSE;
+}
+
+
+GdkPixmap *
+ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
+{
+  GdkGLConfig *glconfig;
+  GdkPixmap *pixmap;
+  GdkGLPixmap *glpixmap;
+  GdkGLContext* glcontext;
+  GdkGLDrawable* gldrawable;
+  double save_zoom;
+  int save_left, save_top;
+  int save_width, save_height;
+  int save_view_width, save_view_height;
+  BoxType region;
+
+  save_zoom = gport->zoom;
+  save_width = gport->width;
+  save_height = gport->height;
+  save_left = gport->view_x0;
+  save_top = gport->view_y0;
+  save_view_width = gport->view_width;
+  save_view_height = gport->view_height;
+
+  /* Setup rendering context for drawing routines
+   */
+
+  glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB     |
+                                        GDK_GL_MODE_STENCIL |
+                                        GDK_GL_MODE_SINGLE);
+
+  pixmap = gdk_pixmap_new (NULL, width, height, depth);
+  glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
+  gldrawable = GDK_GL_DRAWABLE (glpixmap);
+  glcontext = gdk_gl_context_new (gldrawable, NULL, FALSE, GDK_GL_RGBA_TYPE);
+
+  /* Setup zoom factor for drawing routines */
+
+  gport->zoom = zoom;
+  gport->width = width;
+  gport->height = height;
+  gport->view_width = width * gport->zoom;
+  gport->view_height = height * gport->zoom;
+  gport->view_x0 = ghid_flip_x ? PCB->MaxWidth - cx : cx;
+  gport->view_x0 -= gport->view_height / 2;
+  gport->view_y0 = ghid_flip_y ? PCB->MaxHeight - cy : cy;
+  gport->view_y0 -= gport->view_width  / 2;
+
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
+    return NULL;
+  }
+  gport->render_priv->in_context = true;
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glViewport (0, 0, width, height);
+
+  glEnable (GL_SCISSOR_TEST);
+  glScissor (0, 0, width, height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, width, height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  glClearColor (gport->bg_color.red / 65535.,
+                gport->bg_color.green / 65535.,
+                gport->bg_color.blue / 65535.,
+                1.);
+  glClearStencil (0);
+  glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+  /* call the drawing routine */
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / gport->zoom,
+            (ghid_flip_y ? -1. : 1.) / gport->zoom, 1);
+  glTranslatef (ghid_flip_x ? gport->view_x0 - PCB->MaxWidth  :
+                             -gport->view_x0,
+                ghid_flip_y ? gport->view_y0 - PCB->MaxHeight :
+                             -gport->view_y0, 0);
+  region.X1 = MIN(Px(0), Px(gport->width + 1));
+  region.Y1 = MIN(Py(0), Py(gport->height + 1));
+  region.X2 = MAX(Px(0), Px(gport->width + 1));
+  region.Y2 = MAX(Py(0), Py(gport->height + 1));
+  hid_expose_callback (&ghid_hid, &region, NULL);
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  glFlush ();
+
+  /* end drawing to current GL-context */
+  gport->render_priv->in_context = false;
+  gdk_gl_drawable_gl_end (gldrawable);
+
+  gdk_pixmap_unset_gl_capability (pixmap);
+
+  g_object_unref (glconfig);
+  g_object_unref (glcontext);
+
+  gport->zoom = save_zoom;
+  gport->width = save_width;
+  gport->height = save_height;
+  gport->view_x0 = save_left;
+  gport->view_y0 = save_top;
+  gport->view_width = save_view_width;
+  gport->view_height = save_view_height;
+
+  return pixmap;
+}
+
+HID *
+ghid_request_debug_draw (void)
+{
+  GHidPort *port = gport;
+  GtkWidget *widget = port->drawing_area;
+
+  ghid_start_drawing (port);
+
+  glViewport (0, 0, widget->allocation.width, widget->allocation.height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, widget->allocation.width, widget->allocation.height, 0, 0, 100);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0f, 0.0f, -Z_NEAR);
+
+  hidgl_init_triangle_array (&buffer);
+  ghid_invalidate_current_gc ();
+
+  glPushMatrix ();
+  glScalef ((ghid_flip_x ? -1. : 1.) / port->zoom,
+            (ghid_flip_y ? -1. : 1.) / port->zoom,
+            (ghid_flip_x == ghid_flip_y) ? 1. : -1.);
+  glTranslatef (ghid_flip_x ? port->view_x0 - PCB->MaxWidth  :
+                             -port->view_x0,
+                ghid_flip_y ? port->view_y0 - PCB->MaxHeight :
+                             -port->view_y0, 0);
+
+  return &ghid_hid;
+}
+
+void
+ghid_flush_debug_draw (void)
+{
+  GtkWidget *widget = gport->drawing_area;
+  GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
+
+  hidgl_flush_triangles (&buffer);
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+}
+
+void
+ghid_finish_debug_draw (void)
+{
+  hidgl_flush_triangles (&buffer);
+  glPopMatrix ();
+
+  ghid_end_drawing (gport);
+}
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index d52d088..7a18906 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -470,7 +470,7 @@ void ghid_logv (const char *fmt, va_list args);
 /* gui-pinout-window.c */
 void ghid_pinout_window_show (GHidPort * out, ElementTypePtr Element);
 
-/* gtkhid-gdk.c */
+/* gtkhid-gdk.c AND gtkhid-gl.c */
 int ghid_set_layer (const char *name, int group, int empty);
 hidGC ghid_make_gc (void);
 void ghid_destroy_gc (hidGC);



_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs