6633064d829943c30ee0fa1c8824c33d4746b9fd
braney
  Tue Apr 2 15:35:53 2013 -0700
add simple anti-aliasing to graphics line primitive
diff --git src/lib/memgfx.c src/lib/memgfx.c
index 13099fa..dd7c880 100644
--- src/lib/memgfx.c
+++ src/lib/memgfx.c
@@ -390,30 +390,141 @@
 switch(mg->writeMode)
     {
     case MG_WRITE_MODE_NORMAL:
         {
         mgDrawBoxNormal(mg,x,y, width, height, color);
         }
         break;
     case MG_WRITE_MODE_MULTIPLY:
         {
         mgDrawBoxMultiply(mg,x,y, width, height, color);
         }
         break;
     }
 }
 
+
+inline void mixDot(struct memGfx *img, int x, int y,  float frac, Color col)
+/* Puts a single dot on the image, mixing it with what is already there
+ * based on the frac argument. */
+{
+Color *pt = _mgPixAdr(img,x,y);
+float invFrac = 1 - frac;
+
+int r = COLOR_32_RED(*pt) * invFrac + COLOR_32_RED(col) * frac;
+int g = COLOR_32_GREEN(*pt) * invFrac + COLOR_32_GREEN(col) * frac;
+int b = COLOR_32_BLUE(*pt) * invFrac + COLOR_32_BLUE(col) * frac;
+mgPutDot(img,x,y,MAKECOLOR_32(r,g,b));
+}
+ 
+#define fraction(X) (((double)(X))-(double)(int)(X))
+#define invFraction(X) (1.0-fraction(X))
+
+void mgAliasLine( struct memGfx *mg, unsigned int x1, unsigned int y1,
+  unsigned int x2, unsigned int y2, Color color)
+/* Draw an antialiased line using the Wu algorithm. */
+{
+double dx = (double)x2 - (double)x1;
+double dy = (double)y2 - (double)y1;
+
+// figure out what quadrant we're in
+if ( fabs(dx) > fabs(dy) ) 
+    {
+    if ( x2 < x1 ) 
+	{
+	// swap start and end points
+	int tmp = x2;
+	x2 = x1;
+	x1 = tmp;
+
+	tmp = y2;
+	y2 = y1;
+	y1 = tmp;
+	}
+
+    double gradient = dy / dx;
+    double xend = round(x1);
+    double yend = y1 + gradient*(xend - x1);
+    double xgap = invFraction(x1 + 0.5);
+    int xpxl1 = xend;
+    int ypxl1 = (int)yend;
+    mixDot(mg, xpxl1, ypxl1, invFraction(yend)*xgap, color);
+    mixDot(mg, xpxl1, ypxl1+1, fraction(yend)*xgap, color);
+
+    double intery = yend + gradient;
+
+    xend = round(x2);
+    yend = y2 + gradient*(xend - x2);
+    xgap = fraction(x2+0.5);
+    int xpxl2 = xend;
+    int ypxl2 = (int)yend;
+    mixDot(mg, xpxl2, ypxl2, invFraction(yend) * xgap, color);
+    mixDot(mg, xpxl2, ypxl2 + 1, fraction(yend) * xgap, color);
+
+    int x;
+    for(x=xpxl1+1; x <= (xpxl2-1); x++) 
+	{
+	mixDot(mg, x, (int)intery, invFraction(intery), color);
+	mixDot(mg, x, (int)intery + 1, fraction(intery), color);
+	intery += gradient;
+	}
+    } 
+else  // ( fabs(dx) <= fabs(dy) ) 
+    {    
+    if ( y2 < y1 ) 
+	{
+	// swap start and end points
+	int tmp = x2;
+	x2 = x1;
+	x1 = tmp;
+
+	tmp = y2;
+	y2 = y1;
+	y1 = tmp;
+	}
+
+    double gradient = dx / dy;
+    double yend = rint(y1);
+    double xend = x1 + gradient*(yend - y1);
+    double ygap = invFraction(y1 + 0.5);
+    int ypxl1 = yend;
+    int xpxl1 = (int)xend;
+    mixDot(mg, xpxl1, ypxl1, invFraction(xend)*ygap, color);
+    mixDot(mg, xpxl1, ypxl1+1, fraction(xend)*ygap, color);
+    double interx = xend + gradient;
+
+    yend = rint(y2);
+    xend = x2 + gradient*(yend - y2);
+    ygap = fraction(y2+0.5);
+    int ypxl2 = yend;
+    int xpxl2 = (int)xend;
+    mixDot(mg, xpxl2, ypxl2, invFraction(xend) * ygap, color);
+    mixDot(mg, xpxl2, ypxl2 + 1, fraction(xend) * ygap, color);
+
+    int y;
+    for(y=ypxl1+1; y <= (ypxl2-1); y++) 
+	{
+	mixDot(mg, (int)interx, y, invFraction(interx), color);
+	mixDot(mg, (int)interx + 1, y, fraction(interx), color);
+	interx += gradient;
+	}
+    }
+}
+#undef fraction
+#undef invFraction
+
+
 void mgBrezy(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color,
 	int yBase, boolean fillFromBase)
 /* Brezenham line algorithm.  Optionally fill in under line. */
 {
 if (x1 == x2)
     {
     int y,height;
     if (y1 > y2)
 	{
 	y = y2;
 	height = y1-y2+1;
 	}
     else
         {
 	y = y1;
@@ -509,33 +620,37 @@
 	    else
 		mgPutDot(mg,x1,y1,color);
 	    duty_cycle += delta_x;
 	    y1+=incy;
 	    if (duty_cycle > 0)
 		{
 		duty_cycle -= delta_y;	  /* update duty cycle */
 		x1 += 1;
 		}
 	    }
 	}
     }
 }
 
 void mgDrawLine(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color)
-/* Draw a line from one point to another. */
+/* Draw a line from one point to another. Draws it antialiased if
+ * it's not horizontal or vertical. */
 {
+if ((x1 == x2) || (y1 == y2))
 mgBrezy(mg, x1, y1, x2, y2, color, 0, FALSE);
+else
+    mgAliasLine(mg, x1, y1, x2, y2, color);
 }
 
 void mgFillUnder(struct memGfx *mg, int x1, int y1, int x2, int y2, 
 	int bottom, Color color)
 /* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
  * it's top, a horizontal line at bottom as it's bottom, and
  * vertical lines from the bottom to y1 on the left and bottom to
  * y2 on the right. */
 {
 mgBrezy(mg, x1, y1, x2, y2, color, bottom, TRUE);
 }
 
 void mgPutSeg(struct memGfx *mg, int x, int y, int width, Color *dots)
 /* Put a series of dots starting at x, y and going to right width pixels. */
 {