Index: /trunk/Ohana/src/libkapa/include/kapa.h
===================================================================
--- /trunk/Ohana/src/libkapa/include/kapa.h	(revision 41155)
+++ /trunk/Ohana/src/libkapa/include/kapa.h	(revision 41156)
@@ -45,5 +45,7 @@
   KAPA_PLOT_BARS_OUTLINE =  4,
   KAPA_PLOT_BARS_OUTFILL =  5,
-  KAPA_PLOT_INVALID_MAX  =  6,
+  KAPA_PLOT_POLYGON      =  6,
+  KAPA_PLOT_POLYFILL     =  7,
+  KAPA_PLOT_INVALID_MAX  =  8,
 } KapaPlotStyle;
 
@@ -172,6 +174,8 @@
   int Nx, Ny, Nbyte;
   bDrawColor **pixels;
+  char **mask;
   png_color *palette;
   int Npalette;
+
   // current drawing values:
   int bWeight;
@@ -256,4 +260,8 @@
 int KapaGetImageData (int fd, KapaImageData *graphmode);
 int KapaSetToolbox (int fd, int location);
+int KapaSetSmoothSigma (int fd, float sigma);
+int KapaMemoryDump (int fd);
+int KapaMemoryDumpLines (int fd, int Nlines);
+int KapaMemoryDumpOnExit (int fd, int state);
 
 /* KapaColors */
@@ -272,4 +280,5 @@
 /* RotFont.c */
 void InitRotFonts PROTO((void));
+void FreeRotFonts PROTO((void));
 int SetRotFont PROTO((char *name, int size));
 char *GetRotFont PROTO((int *size));
@@ -292,4 +301,5 @@
 bDrawBuffer *bDrawBufferCreate (int Nx, int Ny, int Nbyte, png_color *palette, int Npalette);
 void bDrawBufferFree (bDrawBuffer *buffer);
+int bDrawMerge (bDrawBuffer *base, bDrawBuffer *layer);
 void bDrawSetBuffer (bDrawBuffer *buffer);
 void bDrawSetColor (bDrawBuffer *buffer, bDrawColor color);
@@ -312,4 +322,7 @@
 void bDrawTriOpen  (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3);
 void bDrawTriFill  (bDrawBuffer *buffer, double x1, double y1, double dx, double dy);
+void bDrawPolyFill (bDrawBuffer *buffer, double *x, double *y, int Npoints);
+
+void bDrawSmooth (bDrawBuffer *buffer, float sigma);
 
 /* bDrawRotFont.c */
Index: /trunk/Ohana/src/libkapa/src/KapaStyles.c
===================================================================
--- /trunk/Ohana/src/libkapa/src/KapaStyles.c	(revision 41155)
+++ /trunk/Ohana/src/libkapa/src/KapaStyles.c	(revision 41156)
@@ -54,4 +54,7 @@
   if (!strcasecmp (string,  "outline")) return KAPA_PLOT_BARS_OUTLINE;
   if (!strcasecmp (string,  "outfill")) return KAPA_PLOT_BARS_OUTFILL;
+
+  if (!strcasecmp (string,  "polygon"))   return KAPA_PLOT_POLYGON;
+  if (!strcasecmp (string,  "polyfill"))  return KAPA_PLOT_POLYFILL;
 
   if (strlen(string) > 2) {
Index: /trunk/Ohana/src/libkapa/src/KapaWindow.c
===================================================================
--- /trunk/Ohana/src/libkapa/src/KapaWindow.c	(revision 41155)
+++ /trunk/Ohana/src/libkapa/src/KapaWindow.c	(revision 41156)
@@ -455,2 +455,33 @@
 }
 
+int KapaSetSmoothSigma (int fd, float sigma) {
+
+  KiiSendCommand (fd, 4, "SIGM");
+  KiiSendMessage (fd, "%4.1f ", sigma);
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
+int KapaMemoryDump (int fd) {
+
+  KiiSendCommand (fd, 4, "MEMD");
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
+int KapaMemoryDumpLines (int fd, int Nlines) {
+
+  KiiSendCommand (fd, 4, "MEML");
+  KiiSendMessage (fd, "%d ", Nlines);
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
+int KapaMemoryDumpOnExit (int fd, int state) {
+
+  KiiSendCommand (fd, 4, "MEMX");
+  KiiSendMessage (fd, "%d ", state);
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
Index: /trunk/Ohana/src/libkapa/src/RotFont.c
===================================================================
--- /trunk/Ohana/src/libkapa/src/RotFont.c	(revision 41155)
+++ /trunk/Ohana/src/libkapa/src/RotFont.c	(revision 41156)
@@ -32,4 +32,10 @@
   strncpy (currentname, RotFonts[DEFFONT].name, 63); currentname[63] = 0;
   currentsize = RotFonts[DEFFONT].size;
+}
+
+void FreeRotFonts (void) {
+  free (RotFonts);
+  RotFonts = FALSE;
+  RotFontInited = FALSE;
 }
 
Index: /trunk/Ohana/src/libkapa/src/bDrawFuncs.c
===================================================================
--- /trunk/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 41155)
+++ /trunk/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 41156)
@@ -1,14 +1,34 @@
 # include <kapa_internal.h>
 
-// move these to the bDrawBuffer type
-// static int bWeight;
-// static int bType;
-// static bDrawColor bColor;
-// static bDrawColor bColor_R;
-// static bDrawColor bColor_G;
-// static bDrawColor bColor_B;
-// static bDrawBuffer *bBuffer;
+// buffer->pixels carries the plot image
+// buffer->mask is 0 if the pixel is untouched, 1 if the pixel has data
 
 void bDrawCircleSingle (bDrawBuffer *buffer, double xc, double yc, double radius);
+
+int bDrawMerge (bDrawBuffer *base, bDrawBuffer *layer) {
+
+  // the two bDrawBuffers must match in size and depth
+
+  if (base->Nx != layer->Nx) return FALSE;
+  if (base->Ny != layer->Ny) return FALSE;
+  if (base->Nbyte != layer->Nbyte) return FALSE;
+
+  for (int j = 0; j < base->Ny; j++) {
+    for (int i = 0; i < base->Nx; i++) {
+
+      if (!layer->mask[j][i]) continue;
+      
+      // completely opaque top layer:
+      if (base->Nbyte == 1) {
+	base->pixels[j][i] = layer->pixels[j][i];
+      } else {
+	base->pixels[j][3*i+0] = layer->pixels[j][3*i+0];
+	base->pixels[j][3*i+1] = layer->pixels[j][3*i+1];
+	base->pixels[j][3*i+2] = layer->pixels[j][3*i+2];
+      }
+    }
+  }
+  return TRUE;
+}
 
 // create a drawing buffer with either 1 or 3 byte colors
@@ -35,6 +55,8 @@
 
   ALLOCATE (buffer[0].pixels, bDrawColor *, Ny);
+  ALLOCATE (buffer[0].mask, char *, Ny);
   for (i = 0; i < Ny; i++) {
     ALLOCATE (buffer[0].pixels[i], bDrawColor, Nbyte*Nx);
+    ALLOCATE (buffer[0].mask[i], char, Nx);
     for (j = 0; j < Nx; j++) {
       if (Nbyte == 1) {
@@ -45,4 +67,5 @@
 	buffer[0].pixels[i][3*j+2] = white_B;
       }
+      buffer[0].mask[i][j] = 0; // for now: 0 = no data, 1 = data
     }
   }
@@ -63,7 +86,9 @@
   for (i = 0; i < buffer[0].Ny; i++) {
     free (buffer[0].pixels[i]);
+    free (buffer[0].mask[i]);
   }
   free (buffer[0].pixels);
-  free (buffer[0].palette);
+  free (buffer[0].mask);
+  // free (buffer[0].palette);
   free (buffer);
   return;
@@ -121,11 +146,9 @@
     buffer[0].pixels[y][x] = buffer->bColor;
   } else {
-    // buffer[0].pixels[y][3*x+0] = buffer->bColor_R;
-    // buffer[0].pixels[y][3*x+1] = buffer->bColor_G;
-    // buffer[0].pixels[y][3*x+2] = buffer->bColor_B;
-    buffer[0].pixels[y][3*x+0] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[y][3*x+0] + alpha * buffer->bColor_R));
+    buffer[0].pixels[y][3*x+0] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[y][3*x+0] + alpha * buffer->bColor_R)); // was just buffer->bColor_R, etc
     buffer[0].pixels[y][3*x+1] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[y][3*x+1] + alpha * buffer->bColor_G));
     buffer[0].pixels[y][3*x+2] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[y][3*x+2] + alpha * buffer->bColor_B));
   }
+  buffer[0].mask[y][x] = 1;
   return;
 }
@@ -150,37 +173,51 @@
 void bDrawRectOpen (bDrawBuffer *buffer, double x1, double y1, double x2, double y2) {
 
-  int X1, Y1, X2, Y2;
-
   if (x1 > x2) SWAP (x1, x2);
   if (y1 > y2) SWAP (y1, y2);
 
+  int X1 = MIN (MAX (ROUND (x1), 0), buffer[0].Nx - 1);
+  int X2 = MIN (MAX (ROUND (x2), 1), buffer[0].Nx - 1);
+
+  int Y1 = MIN (MAX (ROUND (y1), 0), buffer[0].Ny - 1);
+  int Y2 = MIN (MAX (ROUND (y2), 1), buffer[0].Ny - 1);
+
+  int dNs = -0.5*(buffer->bWeight - 1); 
+  /* 0, 0, 0, -1, -1, -2, -2 */
+
+  int dNe = +0.5*buffer->bWeight + 1; 
+  /* 1, 1, 2, 2, 2, 3, 3 */
+
+  for (int dN = dNs; dN < dNe; dN ++) {
+    // line on the bottom needs to run longer for the negative dN values
+    bDrawLineHorizontal (buffer, X1 + dN, X2 + 1 - dN, Y1 + dN);
+
+    // line on the top needs to run longer for the positive dN values
+    bDrawLineHorizontal (buffer, X1 + dN, X2 + 1 - dN, Y2 - dN);
+
+    // line on the left needs to run longer for the negative dN values
+    bDrawLineVertical   (buffer, X1 + dN, Y1 + dN, Y2 - dN);
+
+    // line on the right needs to run longer for the positive dN values
+    bDrawLineVertical   (buffer, X2 - dN, Y1 + dN, Y2 - dN);
+  }
+  return;
+}
+
+void bDrawRectFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2) {
+
+  int i;
+  int X1, Y1, X2, Y2;
+
+  if (x1 > x2) SWAP (x1, x2);
+  if (y1 > y2) SWAP (y1, y2);
+
   X1 = MIN (MAX (ROUND (x1), 0), buffer[0].Nx - 1);
   X2 = MIN (MAX (ROUND (x2), 1), buffer[0].Nx - 1);
 
   Y1 = MIN (MAX (ROUND (y1), 0), buffer[0].Ny - 1);
-  Y2 = MIN (MAX (ROUND (y2), 1), buffer[0].Ny - 1);
-
-  bDrawLineHorizontal (buffer, X1, X2 + 1, Y1);
-  bDrawLineHorizontal (buffer, X1, X2 + 1, Y2);
-  bDrawLineVertical   (buffer, X1, Y1, Y2);
-  bDrawLineVertical   (buffer, X2, Y1, Y2);
-  return;
-}
-
-void bDrawRectFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2) {
-
-  int i;
-  int X1, Y1, X2, Y2;
-
-  if (x1 > x2) SWAP (x1, x2);
-  if (y1 > y2) SWAP (y1, y2);
-
-  X1 = MIN (MAX (ROUND (x1), 0), buffer[0].Nx - 1);
-  X2 = MIN (MAX (ROUND (x2), 1), buffer[0].Nx - 1);
-
-  Y1 = MIN (MAX (ROUND (y1), 0), buffer[0].Ny - 1);
   Y2 = MIN (MAX (ROUND (y2), 0), buffer[0].Ny - 1);
 
   for (i = Y1; i < Y2; i++) {
+    // this should be a line of width 1 or we duplicate pixels
     bDrawLineHorizontal (buffer, X1, X2, i);
   } 
@@ -235,4 +272,5 @@
 // use the Bresenham line drawing technique
 // integer-only Bresenham line-draw version which is fast
+// bresenham assumes x1 < x2 and (y2 - y1) < (x2 - x1)
 void bDrawLineBresen (bDrawBuffer *buffer, int X1, int Y1, int X2, int Y2, int swapcoords) {
 
@@ -299,8 +337,6 @@
       buffer[0].pixels[Y][3*i+1] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[Y][3*i+1] + alpha * buffer->bColor_G));
       buffer[0].pixels[Y][3*i+2] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[Y][3*i+2] + alpha * buffer->bColor_B));
-      // buffer[0].pixels[Y][3*i+0] = buffer->bColor_R;
-      // buffer[0].pixels[Y][3*i+1] = buffer->bColor_G;
-      // buffer[0].pixels[Y][3*i+2] = buffer->bColor_B;
-    }
+    }
+    buffer[0].mask[Y][i] = 1;
   }
   return;
@@ -326,8 +362,6 @@
       buffer[0].pixels[i][3*X+1] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[i][3*X+1] + alpha * buffer->bColor_G));
       buffer[0].pixels[i][3*X+2] = MAX (0x00, MIN(0xff, beta * buffer[0].pixels[i][3*X+2] + alpha * buffer->bColor_B));
-      // buffer[0].pixels[i][3*X+0] = buffer->bColor_R;
-      // buffer[0].pixels[i][3*X+1] = buffer->bColor_G;
-      // buffer[0].pixels[i][3*X+2] = buffer->bColor_B;
-    }
+    }
+    buffer[0].mask[i][X] = 1;
   }
   return;
@@ -384,4 +418,148 @@
  
   return;
+}
+
+# define BOT_LEFT 0
+# define BOT_RGHT 1
+# define TOP_LEFT 2
+# define TOP_RGHT 3
+
+// I should probably look up an appropriate recipe for this 
+// source code for XDrawPolyFill?
+
+int GetNextSeqNumber (int seq, int Npoint, int Clockwise, int LeftSide);
+int bDrawFillBetweenSegments (bDrawBuffer *buffer, int *x, int *y, int ystart);
+
+void bDrawPolyFill (bDrawBuffer *buffer, double *x, double *y, int Npoints) {
+
+  // The coord list which is passed in (x,y) must be in order around the contour
+  for (int i = 0; i < Npoints; i++) {
+    fprintf (stderr, "%d : %f,%f\n", i, x[i], y[i]);
+  }
+
+  // First, find the lowest point and start at that sequence number
+  int iMin = 0;
+  double yMin = y[iMin];
+  for (int i = 1; i < Npoints; i++) {
+    if (y[i] < yMin) { iMin = i; yMin = y[iMin]; }
+  }
+
+  // we generate two line segments and will fill between them
+  int xval[4];
+  int yval[4];
+
+  // the starting point is a vertex
+  xval[BOT_LEFT] = x[iMin];  yval[BOT_LEFT] = y[iMin];
+  xval[BOT_RGHT] = x[iMin];  yval[BOT_RGHT] = y[iMin];
+
+  // get iNext, iPrev assuming ClockWise, then test
+  int isCW = TRUE;
+  int iNextLeft = GetNextSeqNumber (iMin, Npoints, isCW, TRUE); // TRUE => left-side
+  int iNextRght = GetNextSeqNumber (iMin, Npoints, isCW, FALSE); 
+
+  // if this is true, the points are not clockwise
+  if (x[iNextLeft] > x[iNextRght]) {
+    isCW = FALSE;
+    int tmp = iNextLeft;
+    iNextLeft = iNextRght;
+    iNextRght = tmp;
+  }
+
+  int iTL = iNextLeft; // sequence number of the top,left point
+  int iTR = iNextRght; // sequence number of the top,right point
+  xval[TOP_LEFT] = x[iTL]; yval[TOP_LEFT] = y[iTL];
+  xval[TOP_RGHT] = x[iTR]; yval[TOP_RGHT] = y[iTR];
+
+  // we need to track the starting row, start at the bottom
+  int ystart = yval[BOT_LEFT];
+
+  while (TRUE) {
+    int isLeft = bDrawFillBetweenSegments (buffer, xval, yval, ystart);
+
+    // the last pair of segments in the sequence end at the same top point:
+    if (iTL == iTR) break;
+
+    // after one pass, if isLeft is true, then cycle the points on the left
+    // segment, otherwise cycle the right segment:
+
+    if (isLeft) {
+      iTL = GetNextSeqNumber (iTL, Npoints, isCW, TRUE);
+      xval[BOT_LEFT] = xval[TOP_LEFT]; yval[BOT_LEFT] = yval[TOP_LEFT];
+      xval[TOP_LEFT] = x[iTL];         yval[TOP_LEFT] = y[iTL];
+      ystart = yval[BOT_LEFT];
+    } else {
+      iTR = GetNextSeqNumber (iTR, Npoints, isCW, FALSE);
+      xval[BOT_RGHT] = xval[TOP_RGHT]; yval[BOT_RGHT] = yval[TOP_RGHT];
+      xval[TOP_RGHT] = x[iTR];         yval[TOP_RGHT] = y[iTR];
+      ystart = yval[BOT_RGHT];
+    }
+  }
+  return;
+}
+
+// we have two line segments defined by x[],y[].  
+
+// [0],[1] is the left-side segment
+// [2],[3] is the right-side segment
+
+// Fill the region between the two segments until 
+// the lower of the two y coordinates y[1], y[3]
+
+// return which of y[1] or y[3] was the ending row
+
+int bDrawFillBetweenSegments (bDrawBuffer *buffer, int *x, int *y, int ystart) {
+
+  int dY_L = y[TOP_LEFT] - y[BOT_LEFT];
+  int dX_L = x[TOP_LEFT] - x[BOT_LEFT];
+
+  int dY_R = y[TOP_RGHT] - y[BOT_RGHT];
+  int dX_R = x[TOP_RGHT] - x[BOT_RGHT];
+    
+  double Slope_L = (dY_L == 0) ? NAN : dX_L / (double) dY_L;
+  double Slope_R = (dY_R == 0) ? NAN : dX_R / (double) dY_R;
+
+  // stop at whichever comes first
+  // XXX not sure if I need to use < or <= here:
+  // with <=, the value of Y after the loop will be one too high.
+  int Y; 
+  for (Y = ystart; (Y < y[TOP_LEFT]) && (Y < y[TOP_RGHT]); Y++) {
+
+    // calculating X_L, X_R based on the slope and current y point
+    int X_L = (dY_L == 0) ? x[BOT_LEFT] : (Y - y[BOT_LEFT]) * Slope_L + x[BOT_LEFT];
+    int X_R = (dY_R == 0) ? x[BOT_RGHT] : (Y - y[BOT_RGHT]) * Slope_R + x[BOT_RGHT];
+      
+    // draw horizontal line from X_L to X_R at Y
+    bDrawLineHorizontal (buffer, X_L, X_R, Y);
+  }
+
+  if (Y == y[TOP_LEFT]) {
+    return TRUE; // TRUE is LEFT SIDE
+  } else {
+    return FALSE;
+  }
+}
+
+int GetNextSeqNumber (int seq, int Npoints, int Clockwise, int LeftSide) {
+
+  int iNext;
+
+  if (Clockwise) {
+    if (LeftSide) {
+      // next point is next in sequence
+      iNext = (seq < Npoints - 1) ? seq + 1 : 0;
+    } else {
+      // next point is prev in sequence
+      iNext = (seq > 0) ? seq - 1 : Npoints - 1;
+    }
+  } else {
+    if (LeftSide) {
+      // next point is prev in sequence
+      iNext = (seq > 0) ? seq - 1 : Npoints - 1;
+    } else {
+      // next point is next in sequence
+      iNext = (seq < Npoints - 1) ? seq + 1 : 0;
+    }
+  }
+  return iNext;
 }
 
@@ -585,4 +763,5 @@
   if (x == 0) {
     if (decrementY) {
+      // this should must be a line or width 1 or we duplicate pixels
       bDrawLineHorizontal (buffer, Xc    , Xc + 1, Yc + y);
       bDrawLineHorizontal (buffer, Xc    , Xc + 1, Yc - y);
@@ -590,4 +769,5 @@
 
     // center line 
+    // this should must be a line or width 1 or we duplicate pixels
     bDrawLineHorizontal (buffer, Xc - y, Xc + y + 1, Yc    );
     return;
@@ -595,4 +775,5 @@
 
   if (x == y) {
+    // this should must be a line or width 1 or we duplicate pixels
     bDrawLineHorizontal (buffer, Xc - x, Xc + x + 1, Yc + y);
     bDrawLineHorizontal (buffer, Xc - x, Xc + x + 1, Yc - y);
@@ -602,4 +783,5 @@
   // only draw these two lines if we decrement y
   if (decrementY) {
+    // this must be a line or width 1 or we duplicate pixels
     bDrawLineHorizontal (buffer, Xc - x, Xc + x + 1, Yc + y);
     bDrawLineHorizontal (buffer, Xc - x, Xc + x + 1, Yc - y);
@@ -607,4 +789,5 @@
 
   // always draw these two lines:
+  // this must be a line or width 1 or we duplicate pixels
   bDrawLineHorizontal (buffer, Xc - y, Xc + y + 1, Yc + x);
   bDrawLineHorizontal (buffer, Xc - y, Xc + y + 1, Yc - x);
@@ -648,5 +831,110 @@
 }
 
+// run a smoothing kernel on each channel for anti-aliasing
+// XXX I need to consider the mask as well
+void bDrawSmooth (bDrawBuffer *buffer, float sigma) {
+
+  // generate a temp buffer for storage of the smoothed result
+  int Nx = buffer[0].Nx;
+  int Ny = buffer[0].Ny;
+  ALLOCATE_PTR (temp, bDrawColor, Nx*Ny);
+
+  //* build a 1D gaussian 
+  int Nsigma = 2;
+  int Ns = (int) (Nsigma*sigma + 0.5);
+  int Ngauss = 2*Ns + 1;
+  ALLOCATE_PTR (gaussnorm, float, Ngauss);
+  float *gauss = &gaussnorm[Ns];
+  for (int i = -Ns; i < Ns + 1; i++) {
+    gauss[i] = exp ((i*i)/(-2*sigma*sigma));
+  }
+
+  // NOTE XXX: need to handle Nbyte = 1 or 3
+  int Nchannel = 3;
+
+  // we need to smooth the 3 channels independently, do this as three passes
+  for (int ch = 0; ch < Nchannel; ch++) {
+
+    // smooth in X direction 
+    for (int j = 0; j < Ny; j++) {
+      bDrawColor *vi = (bDrawColor *) &buffer[0].pixels[j][ch];
+      bDrawColor *vo = &temp[j*Nx];
+      for (int i = 0; i < Nx; i++, vo++, vi += Nchannel) {
+	float g = 0.0, s = 0.0;
+	for (int n = -Ns; n <= Ns; n++) {
+	  if (i+n < 0) continue;
+	  if (i+n >= Nx) continue;
+	  s += gauss[n]*vi[Nchannel*n];
+	  g += gauss[n];
+	}
+	*vo = s / g;
+      }
+    }
+
+    // NOTE: output maps back into original image
+    // careful on the counting
+
+    /* smooth in Y direction */
+    for (int i = 0; i < Nx; i++) {
+      bDrawColor *vi = &temp[i];
+      for (int j = 0; j < Ny; j++) {
+	float g = 0.0, s = 0.0;
+	for (int n = -Ns; n <= Ns; n++) {
+	  if (j+n < 0) continue;
+	  if (j+n >= Ny) continue;
+	  s += gauss[n]*vi[(n+j)*Nx]; // vi is a single-index array, so this is stepping by rows
+	  g += gauss[n];
+	}
+	buffer[0].pixels[j][Nchannel*i + ch] = s / g;
+      }
+    }
+  }
+
+  // smooth the mask
+  ALLOCATE_PTR (temp_mask, float, Nx*Ny);
+
+  // smooth in X direction 
+  for (int j = 0; j < Ny; j++) {
+    char *vi = (char *) &buffer[0].mask[j][0];
+    float *vo = &temp_mask[j*Nx];
+    for (int i = 0; i < Nx; i++, vo++, vi++) {
+  	float g = 0.0, s = 0.0;
+  	for (int n = -Ns; n <= Ns; n++) {
+  	  if (i+n < 0) continue;
+  	  if (i+n >= Nx) continue;
+  	  s += gauss[n]*vi[n];
+  	  g += gauss[n];
+  	}
+  	*vo = s / g;
+    }
+  }
+
+  // NOTE: output maps back into original image
+  // careful on the counting
+
+  /* smooth in Y direction */
+  for (int i = 0; i < Nx; i++) {
+    float *vi = &temp_mask[i];
+    for (int j = 0; j < Ny; j++) {
+  	float g = 0.0, s = 0.0;
+  	for (int n = -Ns; n <= Ns; n++) {
+  	  if (j+n < 0) continue;
+  	  if (j+n >= Ny) continue;
+  	  s += gauss[n]*vi[(n+j)*Nx]; // vi is a single-index array, so this is stepping by rows
+  	  g += gauss[n];
+  	}
+  	buffer[0].mask[j][i] = (s / g > 0.05) ? 1 : 0;
+    }
+  }
+
+  free (temp);
+  free (temp_mask);
+  free (gaussnorm);
+
+  return;
+}
+
 /* 
+NOTES on Bresenham-style circles:
 the discriminant of inside or outside the circle is:
 
