[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

gEDA-dev: Faster PCB + GL



This attempt uses an array of triangle primatives for lines, line caps
and filled circles. These are flushed if the colour changes, the
triangle array fills up, and after rendering completes.

It achieves 18fps, nearly full screen (1400x1050), with my complex board
(after polygons are removed). It reaches about 4fps with the polygons
(which are quite extensive / complex in this design)

To do this (beat the 2fps or so throughput limited by PCB's no-holes
dicer), it caches the no-holes polygon contours. Its not perfect yet
though, certain polygon operations won't update the cached outlines. I
haven't tried the hell-board, but I strongly suspect it will improve its
rendering speed (although not the "bootup" time).

It still leaks the memory fed to GL (if the combine callback for
polygons is called), but that shouldn't be as bad as before.

One of my speed gotchas (in the previous implementation too) was
computing how many slices to draw for a filled circle using the radius
in internal units, not pixels - resulting in a huge number of vertices.
Fixing this, the previous implementation reached 4fps (no polygons) 
-- 

Peter Clifton

Electrical Engineering Division,
Engineering Department,
University of Cambridge,
9, JJ Thomson Avenue,
Cambridge
CB3 0FA

Tel: +44 (0)7729 980173 - (No signal in the lab!)
Index: configure.ac
===================================================================
RCS file: /cvsroot/pcb/pcb/configure.ac,v
retrieving revision 1.103
diff -U3 -p -r1.103 configure.ac
--- configure.ac	28 Apr 2008 17:10:13 -0000	1.103
+++ configure.ac	21 Jun 2008 22:07:28 -0000
@@ -494,6 +494,16 @@ Please review the following errors:
 $GLIB_PKG_ERRORS])]
 	)
 	GLIB_VERSION=`$PKG_CONFIG glib-2.0 --modversion`
+
+
+# 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`
 	;;
 
       nelma|png )
@@ -696,8 +706,8 @@ fi
 AC_MSG_RESULT([no])
 ])
 
-CFLAGS="$CFLAGS $X_CFLAGS $DBUS_CFLAGS $GTK_CFLAGS"
-LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GTK_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS"
+CFLAGS="$CFLAGS $X_CFLAGS $DBUS_CFLAGS $GTK_CFLAGS $GTKGLEXT_CFLAGS"
+LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GTK_LIBS $GTKGLEXT_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS -lglut"
 
 
 # if we have gcc then add -Wall
Index: src/create.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/create.c,v
retrieving revision 1.42
diff -U3 -p -r1.42 create.c
--- src/create.c	2 May 2007 03:17:58 -0000	1.42
+++ src/create.c	21 Jun 2008 22:07:54 -0000
@@ -600,6 +600,7 @@ CreateNewPolygon (LayerTypePtr Layer, Fl
   polygon->Flags = Flags;
   polygon->ID = ID++;
   polygon->Clipped = NULL;
+  polygon->NoHoles = NULL;
   return (polygon);
 }
 
Index: src/crosshair.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/crosshair.c,v
retrieving revision 1.36
diff -U3 -p -r1.36 crosshair.c
--- src/crosshair.c	13 Apr 2008 16:06:39 -0000	1.36
+++ src/crosshair.c	21 Jun 2008 22:07:55 -0000
@@ -83,7 +83,7 @@ static void XORDrawMoveOrCopyObject (voi
 static void XORDrawAttachedLine (LocationType, LocationType, LocationType,
 				 LocationType, BDimension);
 static void XORDrawAttachedArc (BDimension);
-static void DrawAttached (Boolean);
+/*static*/ void DrawAttached (Boolean);
 
 /* ---------------------------------------------------------------------------
  * creates a tmp polygon with coordinates converted to screen system
@@ -184,8 +184,7 @@ XORDrawAttachedLine (LocationType x1, Lo
     {
       LocationType angle = atan2 ((float) dx, (float) dy) * 57.295779;
       gui->draw_line (Crosshair.GC, x1 - ox, y1 - oy, x2 - ox, y2 - oy);
-      gui->draw_arc (Crosshair.GC,
-		     x1, y1, thick / 2, thick / 2, angle - 180, 180);
+      gui->draw_arc (Crosshair.GC, x1, y1, thick / 2, thick / 2, angle - 180, 180);
       gui->draw_arc (Crosshair.GC, x2, y2, thick / 2, thick / 2, angle, 180);
     }
 }
@@ -575,7 +574,7 @@ XORDrawMoveOrCopyObject (void)
 /* ---------------------------------------------------------------------------
  * draws additional stuff that follows the crosshair
  */
-static void
+/*static*/ void
 DrawAttached (Boolean BlockToo)
 {
   BDimension s;
@@ -746,7 +745,7 @@ HideCrosshair (Boolean BlockToo)
   CrosshairStack[CrosshairStackLocation] = Crosshair.On;
   CrosshairStackLocation++;
 
-  CrosshairOff (BlockToo);
+//  CrosshairOff (BlockToo);
 }
 
 /* ---------------------------------------------------------------------------
@@ -766,11 +765,11 @@ RestoreCrosshair (Boolean BlockToo)
 
   if (CrosshairStack[CrosshairStackLocation])
     {
-      CrosshairOn (BlockToo);
+//      CrosshairOn (BlockToo);
     }
   else
     {
-      CrosshairOff (BlockToo);
+//      CrosshairOff (BlockToo);
     }
 }
 
@@ -782,6 +781,7 @@ FitCrosshairIntoGrid (LocationType X, Lo
 {
   LocationType x2, y2, x0, y0;
   void *ptr1, *ptr2, *ptr3;
+  float nearest, sq_dist;
   int ans;
 
   x0 = 0;
@@ -791,41 +791,6 @@ FitCrosshairIntoGrid (LocationType X, Lo
   Crosshair.X = MIN (Crosshair.MaxX, MAX (Crosshair.MinX, X));
   Crosshair.Y = MIN (Crosshair.MaxY, MAX (Crosshair.MinY, Y));
 
-  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
-    {
-      ans =
-	SearchScreen (Crosshair.X, Crosshair.Y,
-		      PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
-      if (ans == NO_TYPE && !PCB->RatDraw)
-	ans =
-	  SearchScreen (Crosshair.X, Crosshair.Y, VIA_TYPE | LINEPOINT_TYPE,
-			&ptr1, &ptr2, &ptr3);
-      if (ans == NO_TYPE && !PCB->RatDraw)
-	ans =
-	  SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptr1, &ptr2,
-			&ptr3);
-    }
-  else
-    ans = NO_TYPE;
-
-  /* avoid self-snapping */
-  if (Settings.Mode == MOVE_MODE)
-    {
-      switch (Crosshair.AttachedObject.Type)
-	{
-	case ELEMENT_TYPE:
-	  if ((ans & (PAD_TYPE | PIN_TYPE)) &&
-	      ptr1 == Crosshair.AttachedObject.Ptr1)
-	    ans = NO_TYPE;
-	  break;
-	case VIA_TYPE:
-	  /* just avoid snapping to any other vias */
-	  if (ans & PIN_TYPES)
-	    ans = NO_TYPE;
-	  break;
-	}
-    }
-
   if (PCB->RatDraw)
     {
       x0 = -600;
@@ -875,82 +840,133 @@ FitCrosshairIntoGrid (LocationType X, Lo
 	}
 
     }
+
+  nearest = -1;
+
+  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  /* Avoid self-snapping when moving */
+  if (Settings.Mode == MOVE_MODE &&
+      Crosshair.AttachedObject.Type == ELEMENT_TYPE)
+    {
+      if ((ans & (PAD_TYPE | PIN_TYPE)) &&
+           ptr1 == Crosshair.AttachedObject.Ptr1)
+        ans = NO_TYPE;
+    }
+
   if (ans & PAD_TYPE)
     {
       PadTypePtr pad = (PadTypePtr) ptr2;
       LocationType px, py;
-      if (SQUARE (pad->Point1.X - Crosshair.X) +
-	  SQUARE (pad->Point1.Y - Crosshair.Y) <
-	  SQUARE (pad->Point2.X - Crosshair.X) + SQUARE (pad->Point2.Y -
-							 Crosshair.Y))
-	{
-	  px = pad->Point1.X;
-	  py = pad->Point1.Y;
-	}
-      else
-	{
-	  px = pad->Point2.X;
-	  py = pad->Point2.Y;
-	}
+      px = (pad->Point1.X + pad->Point2.X) / 2;
+      py = (pad->Point1.Y + pad->Point2.Y) / 2;
 
-      if (!gui->shift_is_pressed()
-	  || (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
-	      SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y)))
-	{
-	  x0 = px;
-	  y0 = py;
-	}
+      sq_dist = SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y);
+
+      if (!gui->shift_is_pressed() ||
+          SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)
+        {
+          x0 = px;
+          y0 = py;
+          nearest = sq_dist;
+        }
+    }
+  else if (ans & PIN_TYPE)
+    {
+      PinTypePtr pin = (PinTypePtr) ptr2;
+      sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pin->X;
+          y0 = pin->Y;
+          nearest = sq_dist;
+        }
     }
 
-  else if (ans & (PIN_TYPE | VIA_TYPE))
+  if (TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                VIA_TYPE | LINEPOINT_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  /* Avoid snapping vias to any other vias */
+  if (Settings.Mode == MOVE_MODE &&
+      Crosshair.AttachedObject.Type == VIA_TYPE)
+    {
+        if (ans & PIN_TYPES)
+          ans = NO_TYPE;
+    }
+
+  if (ans & VIA_TYPE)
     {
       PinTypePtr pin = (PinTypePtr) ptr2;
-      if (!gui->shift_is_pressed()
-	  || (SQUARE (x0 - Crosshair.X) +
-	      SQUARE (y0 - Crosshair.Y) >
-	      SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y)))
-	{
-	  x0 = pin->X;
-	  y0 = pin->Y;
-	}
+      sq_dist = SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pin->X;
+          y0 = pin->Y;
+          nearest = sq_dist;
+        }
     }
   else if (ans & LINEPOINT_TYPE)
     {
       PointTypePtr pnt = (PointTypePtr) ptr3;
-      if (((x0 - Crosshair.X) * (x0 - Crosshair.X) +
-	   (y0 - Crosshair.Y) * (y0 - Crosshair.Y)) >
-	  ((pnt->X - Crosshair.X) * (pnt->X - Crosshair.X) +
-	   (pnt->Y - Crosshair.Y) * (pnt->Y - Crosshair.Y)))
-	{
-	  x0 = pnt->X;
-	  y0 = pnt->Y;
-	}
+      sq_dist = SQUARE (pnt->X - Crosshair.X) + SQUARE (pnt->Y - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist))
+        {
+          x0 = pnt->X;
+          y0 = pnt->Y;
+          nearest = sq_dist;
+        }
     }
-  else if (ans & ELEMENT_TYPE)
+
+
+  if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
+    ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                ELEMENT_TYPE, &ptr1, &ptr2, &ptr3);
+  else
+    ans = NO_TYPE;
+
+  if (ans & ELEMENT_TYPE)
     {
       ElementTypePtr el = (ElementTypePtr) ptr1;
-      if (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
-	  SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y))
-	{
-	  x0 = el->MarkX;
-	  y0 = el->MarkY;
-	}
+      sq_dist = SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y);
+      if ((nearest == -1 || sq_dist < nearest) &&
+//          (!gui->shift_is_pressed() ||
+           SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) > sq_dist)
+        {
+          x0 = el->MarkX;
+          y0 = el->MarkY;
+          nearest = sq_dist;
+        }
     }
+
   if (x0 >= 0 && y0 >= 0)
     {
       Crosshair.X = x0;
       Crosshair.Y = y0;
     }
+
   if (Settings.Mode == ARROW_MODE)
     {
-	ans =
-	  SearchScreen (Crosshair.X, Crosshair.Y, LINEPOINT_TYPE,
-			&ptr1, &ptr2, &ptr3);
-	if (ans == NO_TYPE)
-	  hid_action("PointCursor");
-	else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2))
-	  hid_actionl("PointCursor","True", NULL);
+      ans = SearchScreenGridSlop (Crosshair.X, Crosshair.Y,
+                                  LINEPOINT_TYPE, &ptr1, &ptr2, &ptr3);
+      if (ans == NO_TYPE)
+        hid_action("PointCursor");
+      else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2))
+        hid_actionl("PointCursor","True", NULL);
     }
+
   if (Settings.Mode == LINE_MODE
       && Crosshair.AttachedLine.State != STATE_FIRST
       && TEST_FLAG (AUTODRCFLAG, PCB))
Index: src/draw.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/draw.c,v
retrieving revision 1.87
diff -U3 -p -r1.87 draw.c
--- src/draw.c	10 Dec 2007 03:29:55 -0000	1.87
+++ src/draw.c	21 Jun 2008 22:07:57 -0000
@@ -355,7 +355,7 @@ static int
 lowvia_callback (const BoxType * b, void *cl)
 {
   PinTypePtr via = (PinTypePtr) b;
-  if (!via->Mask)
+//  if (!via->Mask)
     DrawPlainVia (via, False);
   return 1;
 }
@@ -473,25 +473,9 @@ DrawEverything (BoxTypePtr drawn_area)
     }
   if (TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->gui)
     return;
-
   /* draw vias below silk */
   if (PCB->ViaOn && gui->gui)
     r_search (PCB->Data->via_tree, drawn_area, NULL, lowvia_callback, NULL);
-  /* Draw the solder mask if turned on */
-  if (gui->set_layer ("componentmask", SL (MASK, TOP)))
-    {
-      int save_swap = SWAP_IDENT;
-      SWAP_IDENT = 0;
-      DrawMask (drawn_area);
-      SWAP_IDENT = save_swap;
-    }
-  if (gui->set_layer ("soldermask", SL (MASK, BOTTOM)))
-    {
-      int save_swap = SWAP_IDENT;
-      SWAP_IDENT = 1;
-      DrawMask (drawn_area);
-      SWAP_IDENT = save_swap;
-    }
   /* Draw pins, pads, vias below silk */
   if (gui->gui)
     DrawTop (drawn_area);
@@ -520,6 +504,21 @@ DrawEverything (BoxTypePtr drawn_area)
 		    &plated);
 	}
     }
+  /* Draw the solder mask if turned on */
+  if (gui->set_layer ("componentmask", SL (MASK, TOP)))
+    {
+      int save_swap = SWAP_IDENT;
+      SWAP_IDENT = 0;
+      DrawMask (drawn_area);
+      SWAP_IDENT = save_swap;
+    }
+  if (gui->set_layer ("soldermask", SL (MASK, BOTTOM)))
+    {
+      int save_swap = SWAP_IDENT;
+      SWAP_IDENT = 1;
+      DrawMask (drawn_area);
+      SWAP_IDENT = save_swap;
+    }
   /* Draw top silkscreen */
   if (gui->set_layer ("topsilk", SL (SILK, TOP)))
     DrawSilk (0, COMPONENT_LAYER, drawn_area);
@@ -532,7 +531,7 @@ DrawEverything (BoxTypePtr drawn_area)
 	r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback,
 		  NULL);
       /* Draw rat lines on top */
-      if (PCB->RatOn)
+      if (PCB->RatOn && gui->set_layer ("rats", SL (RATS, 0)))
 	DrawRats(drawn_area);
     }
 
@@ -625,7 +624,7 @@ static int
 via_callback (const BoxType * b, void *cl)
 {
   PinTypePtr via = (PinTypePtr) b;
-  if (via->Mask)
+//  if (via->Mask)
     DrawPlainVia (via, False);
   return 1;
 }
@@ -2113,8 +2112,16 @@ DrawPlainPolygon (LayerTypePtr Layer, Po
       if (!Gathering)
 	PolygonHoles (clip_box, Layer, Polygon, thin_callback);
     }
-  else if (Polygon->Clipped)
+  else if (Polygon->NoHoles)//(Polygon->Clipped)
     {
+      PolygonType poly;
+      poly.Clipped = Polygon->NoHoles;
+      do {
+        DrawPolygonLowLevel (&poly);
+//        printf ("Drawing no-holes portion of polygon\n");
+        poly.Clipped = poly.Clipped->f;
+      } while (poly.Clipped != Polygon->NoHoles);
+#if 0
       NoHolesPolygonDicer (Polygon, DrawPolygonLowLevel, clip_box);
       /* draw other parts of the polygon if fullpoly flag is set */
       if (TEST_FLAG (FULLPOLYFLAG, Polygon))
@@ -2127,6 +2134,7 @@ DrawPlainPolygon (LayerTypePtr Layer, Po
 	      NoHolesPolygonDicer (&poly, DrawPolygonLowLevel, clip_box);
 	    }
 	}
+#endif
     }
   /* if the gui has the dicer flag set then it won't draw missing poly outlines */
   if (TEST_FLAG (CHECKPLANESFLAG, PCB) && Polygon->Clipped && !Gathering
Index: src/global.h
===================================================================
RCS file: /cvsroot/pcb/pcb/src/global.h,v
retrieving revision 1.56
diff -U3 -p -r1.56 global.h
--- src/global.h	6 Aug 2007 04:31:00 -0000	1.56
+++ src/global.h	21 Jun 2008 22:07:58 -0000
@@ -204,6 +204,7 @@ typedef struct			/* holds information ab
   Cardinal PointN,		/* number of points in polygon */
     PointMax;			/* max number from malloc() */
   POLYAREA *Clipped;		/* the clipped region of this polygon */
+  POLYAREA *NoHoles;		/* the polygon broken into hole-less regions */
   PointTypePtr Points;		/* data */
 } PolygonType, *PolygonTypePtr;
 
Index: src/hid.h
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid.h,v
retrieving revision 1.22
diff -U3 -p -r1.22 hid.h
--- src/hid.h	13 Apr 2008 14:15:37 -0000	1.22
+++ src/hid.h	21 Jun 2008 22:07:58 -0000
@@ -194,6 +194,7 @@ extern "C"
 #define SL_INVISIBLE	0x0060
 #define SL_FAB		0x0070
 #define SL_ASSY		0x0080
+#define SL_RATS		0x0090
 /* Callers should use this.  */
 #define SL(type,side) (~0xfff | SL_##type | SL_##side##_SIDE)
 
Index: src/polygon.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/polygon.c,v
retrieving revision 1.59
diff -U3 -p -r1.59 polygon.c
--- src/polygon.c	2 Dec 2007 09:35:40 -0000	1.59
+++ src/polygon.c	21 Jun 2008 22:07:59 -0000
@@ -109,7 +109,7 @@ biggest (POLYAREA * p)
           big = n->contours->area;
         }
     }
-  while ((n = n->f) != p);
+  while ((n = n->f) != p); /* TODO: Decipher this line ... is it pointless? Is it just "n=p"? */
   assert (top);
   if (top == p)
     return p;
@@ -170,6 +170,54 @@ original_poly (PolygonType * p)
   return biggest (np);
 }
 
+static void
+add_noholes_polyarea (PolygonType *noholes_poly, void *user_data)
+{
+  PolygonType *poly = user_data;
+  PLINE *pline;//, last;
+  POLYAREA *new_area;
+
+  new_area = malloc (sizeof (POLYAREA) * 1);
+
+  /* Allocate a new PLINE, COPY the PLINE from the passed polygon */
+  poly_CopyContour (&pline, noholes_poly->Clipped->contours);
+  new_area->contours = pline;
+
+  /* Link the new POLYAREA into the NoHoles linked list POLYAREA */
+
+  if (poly->NoHoles)
+    {
+      new_area->f = poly->NoHoles;
+      new_area->b = poly->NoHoles->b;
+      poly->NoHoles->b->f = new_area;
+      poly->NoHoles->b = new_area;
+    }
+  else
+    {
+      new_area->f = new_area;
+      new_area->b = new_area;
+    }
+
+  poly->NoHoles = new_area;
+
+}
+
+static void
+compute_noholes (PolygonType *poly)
+{
+  /* TODO: IS THIS RIGHT? */
+  if (poly->NoHoles)
+    {
+      poly_Free (&poly->NoHoles);
+//      printf ("Just leaked in compute_noholes\n");
+    }
+  poly->NoHoles = NULL;
+  if (poly->Clipped)
+    NoHolesPolygonDicer (poly, add_noholes_polyarea, poly, NULL);
+  else
+    printf ("Fubar, compute_noholes caught poly->Clipped = NULL\n");
+}
+
 static int
 ClipOriginal (PolygonType * poly)
 {
@@ -183,10 +231,13 @@ ClipOriginal (PolygonType * poly)
       fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", r);
       poly_Free (&result);
       poly->Clipped = NULL;
+      if (poly->NoHoles) printf ("Just leaked in ClipOriginal\n");
+      poly->NoHoles = NULL;
       return 0;
     }
   poly->Clipped = biggest (result);
   assert (!poly->Clipped || poly_Valid (poly->Clipped));
+//  compute_noholes (poly);
   return 1;
 }
 
@@ -480,10 +531,13 @@ Subtract (POLYAREA * np1, PolygonType * 
       fprintf (stderr, "Error while clipping PBO_SUB: %d\n", x);
       poly_Free (&merged);
       p->Clipped = NULL;
+      if (p->NoHoles) printf ("Just leaked in Subtract\n");
+      p->NoHoles = NULL;
       return -1;
     }
   p->Clipped = biggest (merged);
   assert (!p->Clipped || poly_Valid (p->Clipped));
+//  compute_noholes (p);
   if (!p->Clipped)
     Message ("Polygon cleared out of existence near (%d, %d)\n",
              (p->BoundingBox.X1 + p->BoundingBox.X2) / 2,
@@ -770,10 +824,13 @@ Unsubtract (POLYAREA * np1, PolygonType 
       fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x);
       poly_Free (&merged);
       p->Clipped = NULL;
+      if (p->NoHoles) printf ("Just leaked in Unsubtract\n");
+      p->NoHoles = NULL;
       return 0;
     }
   p->Clipped = biggest (merged);
   assert (!p->Clipped || poly_Valid (p->Clipped));
+//  compute_noholes (p);
   return ClipOriginal (p);
 }
 
@@ -871,11 +928,18 @@ InitClip (DataTypePtr Data, LayerTypePtr
   if (p->Clipped)
     poly_Free (&p->Clipped);
   p->Clipped = original_poly (p);
+  if (p->NoHoles)
+    {
+      poly_Free (&p->NoHoles);
+//      printf ("Just leaked in InitClip\n");
+    }
+  p->NoHoles = NULL;
   if (!p->Clipped)
     return 0;
   assert (poly_Valid (p->Clipped));
   if (TEST_FLAG (CLEARPOLYFLAG, p))
     clearPoly (Data, layer, p, NULL, 0);
+  compute_noholes (p);
   return 1;
 }
 
@@ -1337,7 +1401,7 @@ IsRectangleInPolygon (LocationType X1, L
 }
 
 static void
-r_NoHolesPolygonDicer (PLINE * p, void (*emit) (PolygonTypePtr))
+r_NoHolesPolygonDicer (PLINE * p, void (*emit) (PolygonTypePtr, void *), void *user_data)
 {
   POLYAREA *pa;
 
@@ -1345,6 +1409,7 @@ r_NoHolesPolygonDicer (PLINE * p, void (
   pa->b = pa->f = pa;
   pa->contours = p;
   if (!p->next)                 /* no holes */
+//  if (1)
     {
       PolygonType poly;
       PointType pts[4];
@@ -1355,6 +1420,7 @@ r_NoHolesPolygonDicer (PLINE * p, void (
       poly.BoundingBox.Y2 = p->ymax;
       poly.PointN = poly.PointMax = 4;
       poly.Clipped = pa;
+      poly.NoHoles = NULL;
       poly.Points = pts;
       pts[0].X = pts[0].X2 = p->xmin;
       pts[0].Y = pts[0].Y2 = p->ymin;
@@ -1365,7 +1431,7 @@ r_NoHolesPolygonDicer (PLINE * p, void (
       pts[3].X = pts[3].X2 = p->xmin;
       pts[3].Y = pts[3].Y2 = p->ymax;
       poly.Flags = MakeFlags (CLEARPOLYFLAG);
-      emit (&poly);
+      emit (&poly, user_data);
       poly_Free (&pa);
       return;
     }
@@ -1385,7 +1451,7 @@ r_NoHolesPolygonDicer (PLINE * p, void (
           do
             {
               PLINE *pl = x->contours;
-              r_NoHolesPolygonDicer (pl, emit);
+              r_NoHolesPolygonDicer (pl, emit, user_data);
               y = x->f;
               /* the pline was already freed by its use int he recursive dicer */
               free (x);
@@ -1399,7 +1465,7 @@ r_NoHolesPolygonDicer (PLINE * p, void (
           do
             {
               PLINE *pl = x->contours;
-              r_NoHolesPolygonDicer (pl, emit);
+              r_NoHolesPolygonDicer (pl, emit, user_data);
               y = x->f;
               free (x);
             }
@@ -1409,8 +1475,8 @@ r_NoHolesPolygonDicer (PLINE * p, void (
 }
 
 void
-NoHolesPolygonDicer (PolygonTypePtr p, void (*emit) (PolygonTypePtr),
-                     const BoxType * clip)
+NoHolesPolygonDicer (PolygonTypePtr p, void (*emit) (PolygonTypePtr, void *),
+                     void *user_data, const BoxType * clip)
 {
   POLYAREA *save, *ans;
 
@@ -1435,7 +1501,7 @@ NoHolesPolygonDicer (PolygonTypePtr p, v
   do
     {
       POLYAREA *prev;
-      r_NoHolesPolygonDicer (save->contours, emit);
+      r_NoHolesPolygonDicer (save->contours, emit, user_data);
       /* go to next poly (could be one because of clip) */
       prev = save;
       save = prev->f;
@@ -1468,6 +1534,8 @@ MorphPolygon (LayerTypePtr layer, Polygo
    * we do this dirty work.
    */
   poly->Clipped = NULL;
+  if (poly->NoHoles) printf ("Just leaked in MorpyPolygon\n");
+  poly->NoHoles = NULL;
   flags = poly->Flags;
   RemovePolygon (layer, poly);
   inhibit = True;
@@ -1494,6 +1562,7 @@ MorphPolygon (LayerTypePtr layer, Polygo
           new->Clipped = p;
           p = p->f;             /* go to next pline */
           new->Clipped->b = new->Clipped->f = new->Clipped;     /* unlink from others */
+//          compute_noholes (new);
           r_insert_entry (layer->polygon_tree, (BoxType *) new, 0);
           DrawPolygon (layer, new, 0);
         }
Index: src/polygon.h
===================================================================
RCS file: /cvsroot/pcb/pcb/src/polygon.h,v
retrieving revision 1.13
diff -U3 -p -r1.13 polygon.h
--- src/polygon.h	16 Nov 2006 03:01:21 -0000	1.13
+++ src/polygon.h	21 Jun 2008 22:07:59 -0000
@@ -60,5 +60,5 @@ Boolean IsRectangleInPolygon (LocationTy
 			      LocationType, PolygonTypePtr);
 Boolean isects (POLYAREA *, PolygonTypePtr, Boolean);
 Boolean MorphPolygon (LayerTypePtr, PolygonTypePtr);
-void NoHolesPolygonDicer (PolygonTypePtr p, void (*emit) (PolygonTypePtr), const BoxType *clip);
+void NoHolesPolygonDicer (PolygonTypePtr p, void (*emit) (PolygonTypePtr, void *), void *user_data, const BoxType *clip);
 #endif
Index: src/polygon1.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/polygon1.c,v
retrieving revision 1.16
diff -U3 -p -r1.16 polygon1.c
--- src/polygon1.c	11 Jan 2008 20:32:47 -0000	1.16
+++ src/polygon1.c	21 Jun 2008 22:08:01 -0000
@@ -2106,6 +2106,12 @@ poly_CopyContour (PLINE ** dst, PLINE * 
       poly_InclVertex ((*dst)->head.prev, newnode);
     }
   (*dst)->tree = make_edge_tree (*dst);
+
+  {
+    static int count = 0;
+    count ++;
+//    printf ("Counting poly_CopyContour %i\n", count);
+  }
   return TRUE;
 }
 
Index: src/search.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/search.c,v
retrieving revision 1.36
diff -U3 -p -r1.36 search.c
--- src/search.c	23 Nov 2007 06:09:18 -0000	1.36
+++ src/search.c	21 Jun 2008 22:08:01 -0000
@@ -322,6 +322,7 @@ struct arc_info
   ArcTypePtr *Arc, *Dummy;
   jmp_buf env;
   int locked;
+  int smallest_radius;
 };
 
 static int
@@ -329,16 +330,24 @@ arc_callback (const BoxType * box, void 
 {
   struct arc_info *i = (struct arc_info *) cl;
   ArcTypePtr a = (ArcTypePtr) box;
+  int found_radius;
 
   if (TEST_FLAG (i->locked, a))
     return 0;
 
   if (!IsPointOnArc (PosX, PosY, SearchRadius, a))
     return 0;
-  *i->Arc = a;
-  *i->Dummy = a;
-  longjmp (i->env, 1);
-  return 1;			/* never reached */
+
+  found_radius = ClosestArcPoint (PosX, PosY, a);
+
+  if (i->smallest_radius == -1 || found_radius < i->smallest_radius)
+    {
+      i->smallest_radius = found_radius;
+      *i->Arc = a;
+      *i->Dummy = a;
+    }
+//  longjmp (i->env, 1);
+  return 1;//			/* never reached */
 }
 
 
@@ -351,14 +360,18 @@ SearchArcByLocation (int locked, LayerTy
   info.Arc = Arc;
   info.Dummy = Dummy;
   info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
+  info.smallest_radius = -1;
 
   *Layer = SearchLayer;
-  if (setjmp (info.env) == 0)
-    {
+//  if (setjmp (info.env) == 0)
+//    {
       r_search (SearchLayer->arc_tree, &SearchBox, NULL, arc_callback, &info);
-      return False;
-    }
-  return (True);
+//      return False;
+//    }
+  if (info.smallest_radius > -1)
+    return True;
+  else
+    return False;
 }
 
 static int
@@ -492,7 +505,9 @@ SearchLinePointByLocation (int locked, L
   info.locked = (locked & LOCKED_TYPE) ? 0 : LOCKFLAG;
   if (r_search
       (SearchLayer->line_tree, &SearchBox, NULL, linepoint_callback, &info))
+  {
     return True;
+  }
   return False;
 }
 
@@ -1001,6 +1016,11 @@ IsPointInBox (LocationType X, LocationTy
   return IsPointInPad (X, Y, Radius, &pad);
 }
 
+int ClosestArcPoint (float X, float Y, ArcTypePtr Arc)
+{
+  return 0;
+}
+
 Boolean
 IsPointOnArc (float X, float Y, float Radius, ArcTypePtr Arc)
 {
@@ -1548,3 +1568,17 @@ SearchScreen (LocationType X, LocationTy
 				X, Y, SLOP * pixel_slop);
   return (ans);
 }
+
+/* ---------------------------------------------------------------------------
+ * searches the cursor position for the type 
+ */
+int
+SearchScreenGridSlop (LocationType X, LocationType Y, int Type, void **Result1,
+	      void **Result2, void **Result3)
+{
+  int ans;
+
+  ans = SearchObjectByLocation (Type, Result1, Result2, Result3,
+				X, Y, PCB->Grid / 2);
+  return (ans);
+}
Index: src/search.h
===================================================================
RCS file: /cvsroot/pcb/pcb/src/search.h,v
retrieving revision 1.12
diff -U3 -p -r1.12 search.h
--- src/search.h	23 Nov 2007 06:09:19 -0000	1.12
+++ src/search.h	21 Jun 2008 22:08:01 -0000
@@ -73,6 +73,7 @@
  */
 Boolean IsPointOnLine (float, float, float, LineTypePtr);
 Boolean IsPointOnPin (float, float, float, PinTypePtr);
+int ClosestArcPoint (float, float, ArcTypePtr);
 Boolean IsPointOnArc (float, float, float, ArcTypePtr);
 Boolean IsPointOnLineEnd (LocationType, LocationType, RatTypePtr);
 Boolean IsLineInRectangle (LocationType, LocationType, LocationType,
@@ -85,6 +86,7 @@ Boolean IsPointInBox (LocationType, Loca
 int SearchObjectByLocation (int, void **, void **, void **, LocationType,
 			    LocationType, BDimension);
 int SearchScreen (LocationType, LocationType, int, void **, void **, void **);
+int SearchScreenGridSlop (LocationType, LocationType, int, void **, void **, void **);
 int SearchObjectByID (DataTypePtr, void **, void **, void **, int, int);
 ElementTypePtr SearchElementByName (DataTypePtr, char *);
 
Index: src/hid/batch/batch.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/batch/batch.c,v
retrieving revision 1.11
diff -U3 -p -r1.11 batch.c
--- src/hid/batch/batch.c	13 Apr 2008 14:15:38 -0000	1.11
+++ src/hid/batch/batch.c	21 Jun 2008 22:08:12 -0000
@@ -329,6 +329,33 @@ batch_stop_timer (hidval timer)
 {
 }
 
+hidval
+batch_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
+    hidval user_data)
+{
+  hidval ret;
+  ret.ptr = NULL;
+  return ret;
+}
+
+void
+batch_unwatch_file (hidval data)
+{
+}
+
+static hidval
+batch_add_block_hook (void (*func) (hidval data), hidval user_data )
+{
+  hidval ret;
+  ret.ptr = NULL;
+  return ret;
+}
+
+static void
+batch_stop_block_hook (hidval mlpoll)
+{
+}
+
 static void
 batch_log (const char *fmt, ...)
 {
@@ -454,6 +481,10 @@ HID batch_gui = {
   batch_set_crosshair,
   batch_add_timer,
   batch_stop_timer,
+  batch_watch_file,
+  batch_unwatch_file,
+  batch_add_block_hook,
+  batch_stop_block_hook,
   batch_log,
   batch_logv,
   batch_confirm_dialog,
Index: src/hid/common/hidinit.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/common/hidinit.c,v
retrieving revision 1.19
diff -U3 -p -r1.19 hidinit.c
--- src/hid/common/hidinit.c	20 Apr 2007 11:31:14 -0000	1.19
+++ src/hid/common/hidinit.c	21 Jun 2008 22:08:14 -0000
@@ -609,7 +609,7 @@ hid_load_settings ()
   hid_load_settings_1 (Concat ("pcb.settings", NULL));
 }
 
-#define HASH_SIZE 32
+#define HASH_SIZE 31
 
 typedef struct ecache
 {
@@ -636,7 +636,7 @@ copy_color (int set, hidval * cval, hidv
 int
 hid_cache_color (int set, const char *name, hidval * val, void **vcache)
 {
-  int hash;
+  unsigned long hash;
   const char *cp;
   ccache *cache;
   ecache *e;
@@ -651,14 +651,22 @@ hid_cache_color (int set, const char *na
       return 1;
     }
 
+  /* djb2: this algorithm (k=33) was first reported by dan bernstein many
+   * years ago in comp.lang.c. another version of this algorithm (now favored
+   * by bernstein) uses xor: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic
+   * of number 33 (why it works better than many other constants, prime or
+   * not) has never been adequately explained.
+   */
+  hash = 5381;
   for (cp = name, hash = 0; *cp; cp++)
-    hash += (*cp) & 0xff;
+    hash = ((hash << 5) + hash) + (*cp & 0xff); /* hash * 33 + c */
   hash %= HASH_SIZE;
 
   for (e = cache->colors[hash]; e; e = e->next)
     if (strcmp (e->name, name) == 0)
       {
 	copy_color (set, &(e->val), val);
+        cache->lru = e;
 	return 1;
       }
   if (!set)
@@ -670,6 +678,8 @@ hid_cache_color (int set, const char *na
   e->name = strdup (name);
   memcpy (&(e->val), val, sizeof (hidval));
 
+  cache->lru = e;
+
   return 1;
 }
 
Index: src/hid/gerber/gerber.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/gerber/gerber.c,v
retrieving revision 1.33
diff -U3 -p -r1.33 gerber.c
--- src/hid/gerber/gerber.c	13 Apr 2008 14:15:38 -0000	1.33
+++ src/hid/gerber/gerber.c	21 Jun 2008 22:08:16 -0000
@@ -462,10 +462,17 @@ gerber_set_layer (const char *name, int 
 	      int ap = findApertureCode (pending_drills[i].diam, ROUND);
 	      fprintf (f, "T%02d\015\012", ap);
 	    }
+#ifdef EDG_ARE_BROKEN
+	  fprintf (f, "X%06ldY%06ld\015\012",
+		   100 * gerberX (PCB, pending_drills[i].x), 100 * gerberY (PCB,
+								pending_drills
+								[i].y));
+#else
 	  fprintf (f, "X%06ldY%06ld\015\012",
 		   gerberX (PCB, pending_drills[i].x), gerberY (PCB,
 								pending_drills
 								[i].y));
+#endif
 	}
       free (pending_drills);
       n_pending_drills = max_pending_drills = 0;
Index: src/hid/gtk/gtkhid-main.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/gtk/gtkhid-main.c,v
retrieving revision 1.56
diff -U3 -p -r1.56 gtkhid-main.c
--- src/hid/gtk/gtkhid-main.c	13 Apr 2008 15:29:20 -0000	1.56
+++ src/hid/gtk/gtkhid-main.c	21 Jun 2008 22:08:18 -0000
@@ -32,26 +32,81 @@
 #include <gdk/gdkx.h>
 #endif
 
+#include <gtk/gtkgl.h>
+#include <GL/glut.h>
+
 #ifdef HAVE_LIBDMALLOC
 #include <dmalloc.h>
 #endif
 
+#define PIXELS_PER_CIRCLINE 5.
 
 RCSID ("$Id: gtkhid-main.c,v 1.56 2008/04/13 15:29:20 petercjclifton Exp $");
 
 
 extern HID ghid_hid;
 
+#define TRIANGLE_ARRAY_SIZE 5000
+static GLfloat triangle_array [2 * 3 * TRIANGLE_ARRAY_SIZE];
+static unsigned int triangle_count;
+static int coord_comp_count;
+
+void
+ghid_init_triangle_array (void)
+{
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glVertexPointer (2, GL_FLOAT, 0, &triangle_array);
+  triangle_count = 0;
+  coord_comp_count = 0;
+}
+
+void
+ghid_flush_triangles ()
+{
+  if (triangle_count == 0)
+    return;
+
+//  printf ("Flushing %i triangles\n", triangle_count);
+  glDrawArrays (GL_TRIANGLES, 0, triangle_count * 3);
+  triangle_count = 0;
+  coord_comp_count = 0;
+}
+
+static void
+ensure_triangle_space (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 - triangle_count)
+    ghid_flush_triangles ();
+}
+
+static inline void
+add_triangle (GLfloat x1, GLfloat y1,
+              GLfloat x2, GLfloat y2,
+              GLfloat x3, GLfloat y3)
+{
+  triangle_array [coord_comp_count++] = x1;
+  triangle_array [coord_comp_count++] = y1;
+  triangle_array [coord_comp_count++] = x2;
+  triangle_array [coord_comp_count++] = y2;
+  triangle_array [coord_comp_count++] = x3;
+  triangle_array [coord_comp_count++] = y3;
+  triangle_count++;
+}
 
 static void zoom_to (double factor, int x, int y);
 static void zoom_by (double factor, int x, int y);
 
 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
 */
-#define USE_GC(gc) if (!use_gc(gc)) return
+#define USE_GC(gc)
 
 static int cur_mask = -1;
-static int mask_seq = 0;
 
 int ghid_flip_x = 0, ghid_flip_y = 0;
 
@@ -379,7 +434,7 @@ zoom_by (double factor, int x, int y)
 
 /* ------------------------------------------------------------ */
 
-static void
+/*static*/ void
 draw_grid ()
 {
   static GdkPoint *points = 0;
@@ -387,6 +442,8 @@ draw_grid ()
   int x1, y1, x2, y2, n, i;
   double x, y;
 
+  return;
+
   if (!Settings.DrawGrid)
     return;
   if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
@@ -474,105 +531,76 @@ ghid_invalidate_lr (int left, int right,
 static void
 ghid_draw_bg_image(void)
 {
-	static GdkPixbuf	*pixbuf;
-	GdkInterpType	interp_type;
-	gint	x, y, w, h, w_src, h_src;
-	static gint	w_scaled, h_scaled;
-
-	if (!ghidgui->bg_pixbuf)
-		return;
-
-	w = PCB->MaxWidth / gport->zoom;
-	h = PCB->MaxHeight / gport->zoom;
-	x = gport->view_x0 / gport->zoom;
-	y = gport->view_y0 / gport->zoom;
-
-	if (w_scaled != w || h_scaled != h)
-		{
-		if (pixbuf)
-			g_object_unref(G_OBJECT(pixbuf));
-
-		w_src = gdk_pixbuf_get_width(ghidgui->bg_pixbuf);
-		h_src = gdk_pixbuf_get_height(ghidgui->bg_pixbuf);
-		if (w > w_src && h > h_src)
-			interp_type = GDK_INTERP_NEAREST;
-		else
-			interp_type = GDK_INTERP_BILINEAR;
-
-		pixbuf = gdk_pixbuf_scale_simple(ghidgui->bg_pixbuf, w, h, interp_type);
-		w_scaled = w;
-		h_scaled = h;
-		}
-	if (pixbuf)
-		gdk_pixbuf_render_to_drawable(pixbuf, gport->drawable, gport->bg_gc,
-            x, y, 0, 0,
-            w - x, h - y, GDK_RGB_DITHER_NORMAL, 0, 0);
-	}
+  static GdkPixbuf *pixbuf = NULL;
+  static gint vw_scaled, vh_scaled, x_cached, y_cached;
+  GdkInterpType interp_type;
+  gint x, y, vw, vh, w, h, w_src, h_src;
+  int bits_per_sample;
+  gboolean has_alpha;
 
-void
-ghid_invalidate_all ()
-{
-  int eleft, eright, etop, ebottom;
-  BoxType region;
+  if (!ghidgui->bg_pixbuf)
+    return;
 
-  if (!gport->pixmap)
+  w = PCB->MaxWidth / gport->zoom;
+  h = PCB->MaxHeight / gport->zoom;
+  x = gport->view_x0 / gport->zoom;
+  y = gport->view_y0 / gport->zoom;
+  vw = gport->view_width / gport->zoom;
+  vh = gport->view_height / gport->zoom;
+
+  if (pixbuf == NULL || vw_scaled != vw || vh_scaled != vh)
+    {
+      if (pixbuf != NULL)
+        g_object_unref(G_OBJECT(pixbuf));
+
+      bits_per_sample = gdk_pixbuf_get_bits_per_sample(ghidgui->bg_pixbuf);
+      has_alpha = gdk_pixbuf_get_has_alpha (ghidgui->bg_pixbuf);
+      pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+                              has_alpha,
+                              bits_per_sample,
+                              vw, vh);
+    }
+
+  if (pixbuf == NULL)
     return;
 
-  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));
-
-  eleft = Vx (0);
-  eright = Vx (PCB->MaxWidth);
-  etop = Vy (0);
-  ebottom = Vy (PCB->MaxHeight);
-  if (eleft > eright)
-    {
-      int tmp = eleft;
-      eleft = eright;
-      eright = tmp;
-    }
-  if (etop > ebottom)
-    {
-      int tmp = etop;
-      etop = ebottom;
-      ebottom = tmp;
-    }
-
-  if (eleft > 0)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, 0, 0, eleft, gport->height);
-  else
-    eleft = 0;
-  if (eright < gport->width)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, eright, 0, gport->width - eright, gport->height);
-  else
-    eright = gport->width;
-  if (etop > 0)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, eleft, 0, eright - eleft + 1, etop);
-  else
-    etop = 0;
-  if (ebottom < gport->height)
-    gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
-			1, eleft, ebottom, eright - eleft + 1,
-			gport->height - ebottom);
-  else
-    ebottom = gport->height;
+  if (vw_scaled != vw || vh_scaled != vh ||
+       x_cached != x  ||  y_cached != y)
+    {
+      w_src = gdk_pixbuf_get_width(ghidgui->bg_pixbuf);
+      h_src = gdk_pixbuf_get_height(ghidgui->bg_pixbuf);
 
-  gdk_draw_rectangle (gport->drawable, gport->bg_gc, 1,
-		      eleft, etop, eright - eleft + 1, ebottom - etop + 1);
+      if (w > w_src && h > h_src)
+        interp_type = GDK_INTERP_NEAREST;
+      else
+        interp_type = GDK_INTERP_BILINEAR;
 
-  ghid_draw_bg_image();
+      gdk_pixbuf_scale(ghidgui->bg_pixbuf, pixbuf,
+                       0, 0, vw, vh,
+                       (double) -x,
+                       (double) -y,
+                       (double) w / w_src,
+                       (double) h / h_src,
+                       interp_type);
+
+      x_cached = x;
+      y_cached = y;
+      vw_scaled = vw;
+      vh_scaled = vh;
+    }
+
+  if (pixbuf != NULL)
+    gdk_draw_pixbuf(gport->drawable, gport->bg_gc, pixbuf,
+                    0, 0, 0, 0, vw, vh, GDK_RGB_DITHER_NORMAL, 0, 0);
+}
 
-  hid_expose_callback (&ghid_hid, &region, 0);
-  draw_grid ();
+void
+ghid_invalidate_all ()
+{
   if (ghidgui->need_restore_crosshair)
     RestoreCrosshair (FALSE);
   ghidgui->need_restore_crosshair = FALSE;
-  ghid_screen_update ();
+  gdk_window_invalidate_rect (gport->drawing_area->window, NULL, 1);
 }
 
 
@@ -581,10 +609,13 @@ ghid_set_layer (const char *name, int gr
 {
   int idx = (group >= 0
 	     && group <
+//  ghid_flush_triangles();
 	     max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
 
-  if (idx >= 0 && idx < max_layer + 2)
+  if (idx >= 0 && idx < max_layer + 2) {
+    gport->trans_lines = TRUE;
     return /*pinout ? 1 : */ PCB->Data->Layer[idx].On;
+  }
   if (idx < 0)
     {
       switch (SL_TYPE (idx))
@@ -596,11 +627,15 @@ ghid_set_layer (const char *name, int gr
 	    return TEST_FLAG (SHOWMASKFLAG, PCB);
 	  return 0;
 	case SL_SILK:
+          gport->trans_lines = FALSE;
 	  if (SL_MYSIDE (idx) /*|| pinout */ )
 	    return PCB->ElementOn;
 	  return 0;
 	case SL_ASSY:
 	  return 0;
+	case SL_RATS:
+	  gport->trans_lines = TRUE;
+	  return 1;
 	case SL_PDRILL:
 	case SL_UDRILL:
 	  return 1;
@@ -609,55 +644,39 @@ ghid_set_layer (const char *name, int gr
   return 0;
 }
 
-#define WHICH_GC(gc) (cur_mask == HID_MASK_CLEAR ? gport->mask_gc : (gc)->gc)
-
 void
 ghid_use_mask (int use_it)
 {
-  static int mask_seq_id = 0;
-  GdkColor color;
-
-  if (!gport->pixmap)
-    return;
   if (use_it == cur_mask)
     return;
+
   switch (use_it)
     {
-    case HID_MASK_OFF:
-      gport->drawable = gport->pixmap;
-      mask_seq = 0;
-      break;
-
     case HID_MASK_BEFORE:
-      printf ("gtk doesn't support mask_before!\n");
-      abort ();
+      /* Write '1' to the stencil buffer where the solder-mask is 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_CLEAR:
-      if (!gport->mask)
-	gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
-      gport->drawable = gport->mask;
-      mask_seq = 0;
-      if (!gport->mask_gc)
-	{
-	  gport->mask_gc = gdk_gc_new (gport->drawable);
-	}
-      color.pixel = 1;
-      gdk_gc_set_foreground (gport->mask_gc, &color);
-      gdk_draw_rectangle (gport->drawable, gport->mask_gc, TRUE, 0, 0,
-			  gport->width, gport->height);
-      color.pixel = 0;
-      gdk_gc_set_foreground (gport->mask_gc, &color);
+      /* Drawing operations clear the stencil buffer to '0' */
+      glStencilFunc (GL_ALWAYS, 0, 1);            // Test always passes, value written 0
+      glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); // Stencil pass => replace stencil value (with 0)
       break;
 
     case HID_MASK_AFTER:
-      mask_seq_id++;
-      if (!mask_seq_id)
-	mask_seq_id = 1;
-      mask_seq = mask_seq_id;
-
-      gport->drawable = gport->pixmap;
+      /* Drawing operations as masked to areas where the stencil buffer is '1' */
+      glColorMask (1, 1, 1, 1);                   // Enable drawing of r, g, b & a
+      glStencilFunc (GL_EQUAL, 1, 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);                // Disable Stencil test
+      break;
     }
   cur_mask = use_it;
 }
@@ -674,6 +693,9 @@ typedef struct
   GdkColor color;
   int xor_set;
   GdkColor xor_color;
+  double red;
+  double green;
+  double blue;
 } ColorCache;
 
 
@@ -716,11 +738,115 @@ ghid_set_special_colors (HID_Attribute *
     }
 }
 
+static void *cache = 0;
+
+void
+ghid_gl_set_color (hidGC gc, const char *name)
+{
+  static char *old_name = NULL;
+  hidval cval;
+  ColorCache *cc;
+  double alpha_mult = 1.0;
+  double r, g, b, a;
+  a = 1.0;
+
+  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 == 0)
+    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;
+        }
+      r = cc->red;
+      g = cc->green;
+      b = cc->blue;
+      if (gc->xor)
+        {
+          if (!cc->xor_set)
+            {
+              cc->xor_set = 1;
+            }
+        }
+
+      gc->erase = 0;
+    }
+  if (1) {
+    double maxi, mult;
+    if (gport->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
+  }
+
+  ghid_flush_triangles ();
+  glColor4d (r, g, b, a);
+}
+
 void
 ghid_set_color (hidGC gc, const char *name)
 {
-  static void *cache = 0;
   hidval cval;
+  ghid_gl_set_color (gc, name);
 
   if (name == NULL)
     {
@@ -764,6 +890,9 @@ ghid_set_color (hidGC gc, const char *na
 	    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)
@@ -774,6 +903,9 @@ ghid_set_color (hidGC gc, const char *na
 	      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;
 	    }
 	  gdk_gc_set_foreground (gc->gc, &cc->xor_color);
@@ -790,7 +922,6 @@ ghid_set_color (hidGC gc, const char *na
 void
 ghid_set_line_cap (hidGC gc, EndCapStyle style)
 {
-
   switch (style)
     {
     case Trace_Cap:
@@ -804,31 +935,18 @@ ghid_set_line_cap (hidGC gc, EndCapStyle
       gc->join = GDK_JOIN_MITER;
       break;
     }
-  if (gc->gc)
-    gdk_gc_set_line_attributes (WHICH_GC (gc),
-				Vz (gc->width), GDK_LINE_SOLID,
-				gc->cap, gc->join);
 }
 
 void
 ghid_set_line_width (hidGC gc, int width)
 {
-
   gc->width = width;
-  if (gc->gc)
-    gdk_gc_set_line_attributes (WHICH_GC (gc),
-				Vz (gc->width), GDK_LINE_SOLID,
-				gc->cap, gc->join);
 }
 
 void
 ghid_set_draw_xor (hidGC gc, int xor)
 {
-  gc->xor = xor;
-  if (!gc->gc)
-    return;
-  gdk_gc_set_function (gc->gc, xor ? GDK_XOR : GDK_COPY);
-  ghid_set_color (gc, gc->colorname);
+  /* NOT IMPLEMENTED */
 }
 
 void
@@ -843,56 +961,139 @@ ghid_set_line_cap_angle (hidGC gc, int x
   printf ("ghid_set_line_cap_angle() -- not implemented\n");
 }
 
-static int
-use_gc (hidGC gc)
+#ifndef CALLBACK
+#define CALLBACK
+#endif
+
+void CALLBACK errorCallback(GLenum errorCode)
 {
-  if (!gport->pixmap)
-    return 0;
-  if (!gc->gc)
-    {
-      gc->gc = gdk_gc_new (gport->top_window->window);
-      ghid_set_color (gc, gc->colorname);
-      ghid_set_line_width (gc, gc->width);
-      ghid_set_line_cap (gc, gc->cap);
-      ghid_set_draw_xor (gc, gc->xor);
-    }
-  if (gc->mask_seq != mask_seq)
-    {
-      if (mask_seq)
-	gdk_gc_set_clip_mask (gc->gc, gport->mask);
-      else
-	gdk_gc_set_clip_mask (gc->gc, NULL);
-      gc->mask_seq = mask_seq;
-    }
-  gport->u_gc = WHICH_GC (gc);
-  return 1;
+   const GLubyte *estring;
+
+   estring = gluErrorString(errorCode);
+   fprintf(stderr, "Quadric Error: %s\n", estring);
+   exit(0);
 }
 
+
 void
 ghid_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
 {
+#define TRIANGLES_PER_CAP 15
   double dx1, dy1, dx2, dy2;
+  double width, angle;
+  float deltax, deltay, length;
+  float wdx, wdy;
+  int slices;
+  int circular_caps = 0;
 
-  dx1 = Vx ((double)x1);
-  dy1 = Vy ((double)y1);
-  dx2 = Vx ((double)x2);
-  dy2 = Vy ((double)y2);
-
+#if 0
+  if (! ClipLine (0, 0, gport->width, gport->height,
   if (! ClipLine (0, 0, gport->width, gport->height,
-		  &dx1, &dy1, &dx2, &dy2, gc->width / gport->zoom))
+                  &dx1, &dy1, &dx2, &dy2, gc->width / gport->zoom))
     return;
+#endif
 
-  USE_GC (gc);
-  gdk_draw_line (gport->drawable, gport->u_gc, dx1, dy1, dx2, dy2);
+  dx1 = Vx (x1);
+  dy1 = Vy (y1);
+  dx2 = Vx (x2);
+  dy2 = Vy (y2);
+
+  width = Vz (gc->width);
+
+  if (width == 0.0)
+    width = 1.0;
+
+  deltax = dx2 - dx1;
+  deltay = dy2 - dy1;
+
+  length = sqrt (deltax * deltax + deltay * deltay);
+
+  if (length == 0) {
+    angle = 0;
+    wdx = -width / 2;
+    wdy = 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.;
+  }
+
+  slices = M_PI * width / PIXELS_PER_CIRCLINE;
+
+  if (slices < 2)
+    slices = 2;
+
+//  slices = TRIANGLES_PER_CAP;
+
+  switch (gc->cap) {
+    case Trace_Cap:
+    case Round_Cap:
+      circular_caps = 1;
+      break;
+
+    case Square_Cap:
+    case Beveled_Cap:
+      dx1 -= deltax * width / 2 / length;
+      dy1 -= deltay * width / 2 / length;
+      dx2 += deltax * width / 2 / length;
+      dy2 += deltay * width / 2 / length;
+      break;
+  }
+
+  ensure_triangle_space (2);
+  add_triangle (dx1 - wdx, dy1 - wdy, dx2 - wdx, dy2 - wdy, dx2 + wdx, dy2 + wdy);
+  add_triangle (dx1 - wdx, dy1 - wdy, dx2 + wdx, dy2 + wdy, dx1 + wdx, dy1 + wdy);
+
+  if (circular_caps) {
+    int i;
+    float last_capx, last_capy;
+
+    ensure_triangle_space (2 * slices);
+
+    last_capx = ((float)width) / 2. * cos (angle * M_PI / 180.) + dx1;
+    last_capy = -((float)width) / 2. * sin (angle * M_PI / 180.) + dy1;
+    for (i = 0; i < slices; i++) {
+      float capx, capy;
+      capx = ((float)width) / 2. * cos (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / slices) + dx1;
+      capy = -((float)width) / 2. * sin (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / slices) + dy1;
+      add_triangle (last_capx, last_capy, capx, capy, dx1, dy1);
+      last_capx = capx;
+      last_capy = capy;
+    }
+    last_capx = -((float)width) / 2. * cos (angle * M_PI / 180.) + dx2;
+    last_capy = ((float)width) / 2. * sin (angle * M_PI / 180.) + dy2;
+    for (i = 0; i < slices; i++) {
+      float capx, capy;
+      capx = -((float)width) / 2. * cos (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / slices) + dx2;
+      capy = ((float)width) / 2. * sin (angle * M_PI / 180. + ((float)(i + 1)) * M_PI / slices) + dy2;
+      add_triangle (last_capx, last_capy, capx, capy, dx2, dy2);
+      last_capx = capx;
+      last_capy = capy;
+    }
+  }
 }
 
 void
 ghid_draw_arc (hidGC gc, int cx, int cy,
-	       int xradius, int yradius, int start_angle, int delta_angle)
+               int xradius, int yradius, int start_angle, int delta_angle)
 {
   gint vrx, vry;
-  gint w, h, radius;
-  
+  gint w, h, radius, slices;
+  double width;
+  GLUquadricObj *qobj;
+
+  width = Vz (gc->width);
+
+  if (width == 0.0)
+    width = 1.0;
+
   w = gport->width * gport->zoom;
   h = gport->height * gport->zoom;
   radius = (xradius > yradius) ? xradius : yradius;
@@ -901,12 +1102,11 @@ ghid_draw_arc (hidGC gc, int cx, int cy,
       || SIDE_Y (cy) < gport->view_y0 - radius 
       || SIDE_Y (cy) > gport->view_y0 + h + radius)
     return;
-  
+
   USE_GC (gc);
   vrx = Vz (xradius);
   vry = Vz (yradius);
 
-
   /* make sure we fall in the -180 to +180 range */
   start_angle = (start_angle + 360 + 180) % 360 - 180;
   if (ghid_flip_x)
@@ -917,12 +1117,47 @@ ghid_draw_arc (hidGC gc, int cx, int cy,
   if (ghid_flip_y)
     {
       start_angle = - start_angle;
-      delta_angle = - delta_angle;					
+      delta_angle = - delta_angle;
     }
 
-  gdk_draw_arc (gport->drawable, gport->u_gc, 0,
-		Vx (cx) - vrx, Vy (cy) - vry,
-		vrx * 2, vry * 2, (start_angle + 180) * 64, delta_angle * 64);
+  if (delta_angle < 0) {
+    start_angle += delta_angle;
+    delta_angle = - delta_angle;
+  }
+
+  slices = M_PI * (vrx + width / 2.) / PIXELS_PER_CIRCLINE;
+
+  if (slices < 2)
+    slices = 2;
+
+  qobj = gluNewQuadric ();
+  gluQuadricCallback (qobj, GLU_ERROR, errorCallback);
+  gluQuadricDrawStyle (qobj, GLU_FILL); /* smooth shaded */
+  gluQuadricNormals (qobj, GLU_SMOOTH);
+
+  glPushMatrix ();
+  glTranslatef (Vx (cx), Vy (cy), 0.0);
+  gluPartialDisk (qobj, vrx - width / 2, vrx + width / 2, slices, 1, 270 + start_angle, delta_angle);
+  glPopMatrix ();
+
+  slices = M_PI * width / PIXELS_PER_CIRCLINE;
+
+  if (slices < 2)
+    slices = 2;
+
+  glPushMatrix ();
+  glTranslatef (Vx (cx) + vrx * -cos (M_PI / 180. * start_angle),
+                Vy (cy) + vrx *  sin (M_PI / 180. * start_angle), 0.0);
+  gluPartialDisk (qobj, 0, width / 2, slices, 1, start_angle + 90., 180);
+  glPopMatrix ();
+
+  glPushMatrix ();
+  glTranslatef (Vx (cx) + vrx * -cos (M_PI / 180. * (start_angle + delta_angle)),
+                Vy (cy) + vrx *  sin (M_PI / 180. * (start_angle + delta_angle)), 0.0);
+  gluPartialDisk (qobj, 0, width / 2, slices, 1, start_angle + delta_angle + 270., 180);
+  glPopMatrix ();
+
+  gluDeleteQuadric (qobj);
 }
 
 void
@@ -949,19 +1184,24 @@ ghid_draw_rect (hidGC gc, int x1, int y1
   x2 = Vx (x2);
   y2 = Vy (y2);
 
-  if (x1 > x2) { gint xt = x1; x1 = x2; x2 = xt; }
-  if (y1 > y2) { gint yt = y1; y1 = y2; y2 = yt; }
-
   USE_GC (gc);
-  gdk_draw_rectangle (gport->drawable, gport->u_gc, FALSE,
-		      x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+
+  glBegin (GL_LINE_LOOP);
+  glVertex2f (x1, y1);
+  glVertex2f (x1, y2);
+  glVertex2f (x2, y2);
+  glVertex2f (x2, y1);
+  glEnd ();
 }
 
 
 void
 ghid_fill_circle (hidGC gc, int cx, int cy, int radius)
 {
-  gint w, h, vr;
+#define TRIANGLES_PER_CIRCLE 30
+  gint w, h, vx, vy, vr;
+  float last_x, last_y, slices;
+  int i;
 
   w = gport->width * gport->zoom;
   h = gport->height * gport->zoom;
@@ -972,38 +1212,129 @@ ghid_fill_circle (hidGC gc, int cx, int 
     return;
 
   USE_GC (gc);
+  vx = Vx (cx);
+  vy = Vy (cy);
   vr = Vz (radius);
-  gdk_draw_arc (gport->drawable, gport->u_gc, TRUE,
-		Vx (cx) - vr, Vy (cy) - vr,
-		vr * 2, vr * 2, 0, 360 * 64);
+
+  slices = M_PI * 2 * vr / PIXELS_PER_CIRCLINE;
+
+  if (slices < 2)
+    slices = 2;
+
+//  slices = TRIANGLES_PER_CIRCLE;
+
+  ensure_triangle_space (slices);
+
+  last_x = vx + vr;
+  last_y = vy;
+
+  for (i = 0; i < slices; i++) {
+    float x, y;
+    x = ((float)vr) * cos (((float)(i + 1)) * 2. * M_PI / slices) + vx;
+    y = ((float)vr) * sin (((float)(i + 1)) * 2. * M_PI / slices) + vy;
+    add_triangle (vx, vy, last_x, last_y, x, y);
+    last_x = x;
+    last_y = y;
+  }
+
+//  ghid_flush_triangles ();
+}
+
+void
+myError (GLenum errno)
+{
+  printf ("gluTess error: %s\n", gluErrorString (errno));
+}
+
+/* TODO: Structure for storing pointers for combined memory,
+ *       so we can free it.
+ */
+
+void
+myFreeCombined ()
+{
+
+}
+
+void
+myCombine ( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **dataOut )
+{
+  GLdouble *new_vertex;
+
+  new_vertex = malloc (3 * sizeof (GLdouble));
+  new_vertex[0] = coords[0];
+  new_vertex[1] = coords[1];
+  new_vertex[2] = coords[2];
+
+  *dataOut = new_vertex;
 }
 
 void
 ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
 {
-  static GdkPoint *points = 0;
-  static int npoints = 0;
   int i;
-  USE_GC (gc);
 
-  if (npoints < n_coords)
+#if 0
+  static int count = 0;
+  static int vcount = 0;
+  count ++;
+  vcount += n_coords;
+  printf ("fill_polygon count = %i, total vertices %i\n", count, vcount);
+#endif
+
+#if 0
+  /* IF WE COULD GAURANTEE CONVEX POLYGONS... */
+  glBegin (GL_POLYGON);
+
+  for (i = 0; i < n_coords; i++)
     {
-      npoints = n_coords + 1;
-      points = MyRealloc (points,
-			  npoints * sizeof (GdkPoint), (char *) __FUNCTION__);
+      glVertex2f (Vx(x[i]), Vy(y[i]));
     }
+  glEnd ();
+#endif
+
+#if 1
+  GLUtesselator *tobj;
+  GLdouble *vertices;
+
+  USE_GC (gc);
+
+  g_assert (n_coords > 0);
+
+  vertices = malloc (sizeof(GLdouble) * n_coords * 3);
+
+  tobj = gluNewTess ();
+  gluTessCallback(tobj, GLU_TESS_BEGIN, glBegin);
+  gluTessCallback(tobj, GLU_TESS_VERTEX, glVertex3dv);
+  gluTessCallback(tobj, GLU_TESS_END, glEnd);
+  gluTessCallback(tobj, GLU_TESS_COMBINE, myCombine);
+  gluTessCallback(tobj, GLU_TESS_ERROR, myError);
+
+  gluTessBeginPolygon (tobj, NULL);
+  gluTessBeginContour (tobj);
+
   for (i = 0; i < n_coords; i++)
     {
-      points[i].x = Vx (x[i]);
-      points[i].y = Vy (y[i]);
+      vertices [0 + i * 3] = Vx (x[i]);
+      vertices [1 + i * 3] = Vy (y[i]);
+      vertices [2 + i * 3] = 0.;
+      gluTessVertex (tobj, &vertices [i * 3], &vertices [i * 3]);
     }
-  gdk_draw_polygon (gport->drawable, gport->u_gc, 1, points, n_coords);
+
+  gluTessEndContour (tobj);
+  gluTessEndPolygon (tobj);
+  gluDeleteTess (tobj);
+
+  myFreeCombined ();
+  free (vertices);
+#endif
 }
 
 void
 ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
 {
-  gint w, h, lw, xx, yy;
+#if 1
+  gint w, h, lw;
 
   lw = gc->width;
   w = gport->width * gport->zoom;
@@ -1023,21 +1354,15 @@ ghid_fill_rect (hidGC gc, int x1, int y1
   y1 = Vy (y1);
   x2 = Vx (x2);
   y2 = Vy (y2);
-  if (x2 < x1)
-    {
-      xx = x1;
-      x1 = x2;
-      x2 = xx;
-    }
-  if (y2 < y1)
-    {
-      yy = y1;
-      y1 = y2;
-      y2 = yy;
-    }
+
   USE_GC (gc);
-  gdk_draw_rectangle (gport->drawable, gport->u_gc, TRUE,
-                      x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+  glBegin (GL_QUADS);
+  glVertex2f (x1, y1);
+  glVertex2f (x1, y2);
+  glVertex2f (x2, y2);
+  glVertex2f (x2, y1);
+  glEnd ();
+#endif
 }
 
 void
@@ -1527,7 +1852,7 @@ HID ghid_hid = {
   1,				/* gui */
   0,				/* printer */
   0,				/* exporter */
-  0,				/* poly before */
+  1,				/* poly before */
   1,				/* poly after */
   0,				/* poly dicer */
 
@@ -2160,11 +2485,14 @@ Benchmark (int argc, char **argv, int x,
   region.X2 = PCB->MaxWidth;
   region.Y2 = PCB->MaxHeight;
 
+  
+
   gdk_display_sync (display);
   time (&start);
   do
     {
-      hid_expose_callback (&ghid_hid, &region, 0);
+      gdk_window_invalidate_rect (gport->drawing_area->window, NULL, 1);
+      gdk_window_process_updates (gport->drawing_area->window, FALSE);
       gdk_display_sync (display);
       time (&end);
       i++;
Index: src/hid/gtk/gui-output-events.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/gtk/gui-output-events.c,v
retrieving revision 1.26
diff -U3 -p -r1.26 gui-output-events.c
--- src/hid/gtk/gui-output-events.c	13 Apr 2008 16:06:39 -0000	1.26
+++ src/hid/gtk/gui-output-events.c	21 Jun 2008 22:08:18 -0000
@@ -300,63 +300,103 @@ ghid_show_crosshair (gboolean show)
   static GdkGC *xor_gc;
   static GdkColor cross_color;
 
-  if (gport->x_crosshair < 0 || ghidgui->creating || !gport->has_entered)
+  if (gport->x_crosshair < 0 || ghidgui->creating) {// || !gport->has_entered) {
+    printf ("Returning\n");
     return;
+  }
 
   if (!xor_gc)
     {
-      xor_gc = gdk_gc_new (ghid_port.drawing_area->window);
-      gdk_gc_copy (xor_gc, ghid_port.drawing_area->style->white_gc);
-      gdk_gc_set_function (xor_gc, GDK_XOR);
+      xor_gc = (GdkGC *)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);
 
-  gdk_gc_set_foreground (xor_gc, &cross_color);
+  glEnable (GL_COLOR_LOGIC_OP);
+  glLogicOp (GL_XOR);
+
+  glColor3f (cross_color.red / 65535.,
+             cross_color.green / 65535.,
+             cross_color.blue / 65535.);
+
+  glBegin (GL_LINES);
 
   if (x_prev >= 0)
     {
-      gdk_draw_line (gport->drawing_area->window, xor_gc,
-		     x_prev, 0, x_prev, gport->height);
-      gdk_draw_line (gport->drawing_area->window, xor_gc,
-		     0, y_prev, gport->width, y_prev);
-      if (ghidgui->auto_pan_on && have_crosshair_attachments ())
-	{
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      0, y_prev - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      gport->width - VCD, y_prev - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x_prev - VCD, 0, VCW, VCD);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x_prev - VCD, gport->height - VCD, VCW, VCD);
-	}
+      glVertex2i (x_prev, 0);
+      glVertex2i (x_prev, gport->height);
+      glVertex2i (0, y_prev);
+      glVertex2i (gport->width, y_prev);
+    }
+
+  if (x >= 0 && show)
+    {
+      glVertex2i (x, 0);
+      glVertex2i (x, gport->height);
+      glVertex2i (0, y);
+      glVertex2i (gport->width, y);
+    }
+
+  glEnd ();
+
+  if (ghidgui->auto_pan_on && have_crosshair_attachments ())
+    {
+      glBegin (GL_QUADS);
+
+      if (x_prev >= 0)
+        {
+          glVertex2i (0,                  y_prev - VCD);
+          glVertex2i (0,                  y_prev - VCD + VCW);
+          glVertex2i (VCD,                y_prev - VCD + VCW);
+          glVertex2i (VCD,                y_prev - VCD);
+          glVertex2i (gport->width,       y_prev - VCD);
+          glVertex2i (gport->width,       y_prev - VCD + VCW);
+          glVertex2i (gport->width - VCD, y_prev - VCD + VCW);
+          glVertex2i (gport->width - VCD, y_prev - VCD);
+          glVertex2i (x_prev - VCD,       0);
+          glVertex2i (x_prev - VCD,       VCD);
+          glVertex2i (x_prev - VCD + VCW, VCD);
+          glVertex2i (x_prev - VCD + VCW, 0);
+          glVertex2i (x_prev - VCD,       gport->height - VCD);
+          glVertex2i (x_prev - VCD,       gport->height);
+          glVertex2i (x_prev - VCD + VCW, gport->height);
+          glVertex2i (x_prev - VCD + VCW, gport->height - VCD);
+        }
+
+      if (x >= 0 && show)
+        {
+          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 ();
     }
 
   if (x >= 0 && show)
     {
-      gdk_draw_line (gport->drawing_area->window, xor_gc,
-		     x, 0, x, gport->height);
-      gdk_draw_line (gport->drawing_area->window, xor_gc,
-		     0, y, gport->width, y);
-      if (ghidgui->auto_pan_on && have_crosshair_attachments ())
-	{
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      0, y - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      gport->width - VCD, y - VCD, VCD, VCW);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x - VCD, 0, VCW, VCD);
-	  gdk_draw_rectangle (gport->drawing_area->window, xor_gc, TRUE,
-			      x - VCD, gport->height - VCD, VCW, VCD);
-	}
       x_prev = x;
       y_prev = y;
     }
   else
     x_prev = y_prev = -1;
+
+  glDisable (GL_COLOR_LOGIC_OP);
 }
 
 static gboolean
@@ -746,37 +786,129 @@ ghid_port_drawing_area_configure_event_c
       first_time_done = TRUE;
       PCBChanged (0, NULL, 0, 0);
     }
-  if (gport->mask)
-    {
-      gdk_pixmap_unref (gport->mask);
-      gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
-    }
+//  if (gport->mask)
+//    {
+//      gdk_pixmap_unref (gport->mask);
+//      gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
+//    }
   ghid_port_ranges_scale (FALSE);
   ghid_invalidate_all ();
   RestoreCrosshair (TRUE);
   return 0;
 }
 
+static inline int
+Px (int x)
+{
+  int rv = x * gport->zoom + gport->view_x0;
+  if (ghid_flip_x)
+    rv = PCB->MaxWidth - (x * gport->zoom + gport->view_x0);
+  return  rv;
+}
+
+static inline int
+Py (int y)
+{
+  int rv = y * gport->zoom + gport->view_y0;
+  if (ghid_flip_y)
+    rv = PCB->MaxHeight - (y * gport->zoom + gport->view_y0);
+  return  rv;
+}
+
+static inline int
+Vx (int x)
+{
+  int rv;
+  if (ghid_flip_x) 
+    rv = (PCB->MaxWidth - x - gport->view_x0) / gport->zoom + 0.5;
+  else
+    rv = (x - gport->view_x0) / gport->zoom + 0.5;
+  return rv;
+}
+
+static inline int
+Vy (int y)
+{
+  int rv;
+  if (ghid_flip_y)
+    rv = (PCB->MaxHeight - y - gport->view_y0) / gport->zoom + 0.5;
+  else
+    rv = (y - gport->view_y0) / gport->zoom + 0.5;
+  return rv;
+}
 
 void
 ghid_screen_update (void)
 {
-
+#if 0
   ghid_show_crosshair (FALSE);
   gdk_draw_drawable (gport->drawing_area->window, gport->bg_gc, gport->pixmap,
 		     0, 0, 0, 0, gport->width, gport->height);
   ghid_show_crosshair (TRUE);
+#endif
 }
 
+void DrawAttached (Boolean);
+void draw_grid ();
+
+#define Z_NEAR 3.0
+#define FOVY_2 20.0
 gboolean
 ghid_port_drawing_area_expose_event_cb (GtkWidget * widget,
 					GdkEventExpose * ev, GHidPort * port)
 {
+  BoxType region;
+  extern HID ghid_hid;
+  GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
+  GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
+
   ghid_show_crosshair (FALSE);
-  gdk_draw_drawable (widget->window, port->bg_gc, port->pixmap,
-		     ev->area.x, ev->area.y, ev->area.x, ev->area.y,
-		     ev->area.width, ev->area.height);
+
+  /* make GL-context "current" */
+  if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
+    return FALSE;
+  }
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  glViewport (0, 0, ev->area.width, ev->area.height);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, ev->area.width, ev->area.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);// | GL_DEPTH_BUFFER_BIT);
+
+  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));
+
+  ghid_init_triangle_array ();
+  hid_expose_callback (&ghid_hid, &region, 0);
+  ghid_flush_triangles ();
+
+  draw_grid ();
+  DrawAttached (TRUE);
   ghid_show_crosshair (TRUE);
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (pGlDrawable);
+
   return FALSE;
 }
 
@@ -789,6 +921,13 @@ ghid_port_window_motion_cb (GtkWidget * 
   static gint x_prev = -1, y_prev = -1;
   gboolean moved;
   GdkModifierType state;
+  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;
+  }
 
   state = (GdkModifierType) (ev->state);
   mk = ghid_modifier_keys_state (&state);
@@ -808,9 +947,18 @@ ghid_port_window_motion_cb (GtkWidget * 
     }
   x_prev = y_prev = -1;
   moved = ghid_note_event_location (ev);
+
   ghid_show_crosshair (TRUE);
   if (moved && have_crosshair_attachments ())
     ghid_draw_area_update (gport, NULL);
+
+  if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
+    gdk_gl_drawable_swap_buffers (pGlDrawable);
+  else
+    glFlush ();
+
+  /* end drawing to current GL-context */
+  gdk_gl_drawable_gl_end (pGlDrawable);
   return FALSE;
 }
 
@@ -964,18 +1112,18 @@ ghid_port_window_mouse_scroll_cb (GtkWid
 
   state = (GdkModifierType) (ev->state);
   mk = ghid_modifier_keys_state (&state);
+
   if (mk == NONE_PRESSED)
+    dy = ghid_port.height * gport->zoom / 40;
+  else if (mk == SHIFT_PRESSED)
+    dx = ghid_port.width * gport->zoom / 40;
+  else if (mk == CONTROL_PRESSED)
     {
       zoom_factor = (ev->direction == GDK_SCROLL_UP) ? 0.8 : 1.25;
       ghid_port_ranges_zoom (gport->zoom * zoom_factor);
       return TRUE;
     }
 
-  if (mk == SHIFT_PRESSED)
-    dy = ghid_port.height * gport->zoom / 40;
-  else
-    dx = ghid_port.width * gport->zoom / 40;
-
   if (ev->direction == GDK_SCROLL_UP)
     {
       dx = -dx;
Index: src/hid/gtk/gui-top-window.c
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/gtk/gui-top-window.c,v
retrieving revision 1.54
diff -U3 -p -r1.54 gui-top-window.c
--- src/hid/gtk/gui-top-window.c	31 Jan 2008 01:23:09 -0000	1.54
+++ src/hid/gtk/gui-top-window.c	21 Jun 2008 22:08:20 -0000
@@ -2295,6 +2295,11 @@ ghid_build_pcb_top_window (void)
   gtk_box_pack_start (GTK_BOX (hbox), viewport, TRUE, TRUE, 0);
 
   gport->drawing_area = gtk_drawing_area_new ();
+  gtk_widget_set_gl_capability (gport->drawing_area,
+                                gport->glconfig,
+                                NULL,
+                                TRUE,
+                                GDK_GL_RGBA_TYPE);
 
   gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK
 			 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
@@ -2657,11 +2662,23 @@ ghid_parse_arguments (int *argc, char **
   gtk_disable_setlocale ();
 
   gtk_init (argc, argv);
+  gtk_gl_init(argc, argv);
 
   gport = &ghid_port;
   gport->zoom = 300.0;
   pixel_slop = 300;
 
+  /* setup GL-context */
+  gport->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB   |
+                                               GDK_GL_MODE_ALPHA |
+                                               GDK_GL_MODE_STENCIL |
+//                                               GDK_GL_MODE_DEPTH |
+                                               GDK_GL_MODE_DOUBLE);
+  if (!gport->glconfig) {
+    printf("Could not setup GL-context!\n");
+    return; /* Should we abort? */
+  }
+
   ghid_config_files_read (argc, argv);
 
   Settings.AutoPlace = 0;
Index: src/hid/gtk/gui.h
===================================================================
RCS file: /cvsroot/pcb/pcb/src/hid/gtk/gui.h,v
retrieving revision 1.25
diff -U3 -p -r1.25 gui.h
--- src/hid/gtk/gui.h	13 Apr 2008 14:15:38 -0000	1.25
+++ src/hid/gtk/gui.h	21 Jun 2008 22:08:20 -0000
@@ -35,6 +35,10 @@
 
 #include <gtk/gtk.h>
 
+#include <gtk/gtkgl.h>
+#include <GL/glu.h>
+//#include <GL/glut.h>
+
 /* Internationalization support.
 */
 #if defined (ENABLE_NLS)
@@ -197,6 +201,10 @@ typedef struct
   GdkDrawable *drawable;	/* Current drawable for drawing routines */
   gint width, height;
 
+  GdkGLConfig *glconfig;
+
+  gint trans_lines;
+
   GdkGC *bg_gc, *offlimits_gc, *mask_gc, *u_gc, *grid_gc;
 
   GdkColor bg_color, offlimits_color, grid_color;
@@ -510,6 +518,8 @@ void ghid_logv (const char *fmt, va_list
 void ghid_pinout_window_show (GHidPort * out, ElementTypePtr Element);
 
 /* gtkhid-main.c */
+void ghid_init_triangle_array ();
+void ghid_flush_triangles ();
 void ghid_invalidate_all ();
 void ghid_get_coords (const char *msg, int *x, int *y);
 gint PCBChanged (int argc, char **argv, int x, int y);


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