shithub: puzzles

Download patch

ref: 9cd182ffa92e97609d562883a1c8e74949963ba0
parent: ef6e78c6ac804a197cfc6002c5866885321626c5
author: Simon Tatham <anakin@pobox.com>
date: Sat May 29 11:43:46 EDT 2010

Patch from Mark Wooding to introduce a draw_thick_line() function in
the drawing API, for use by Loopy. It's optional: drawing.c will
construct an acceptable alternative using a filled polygon if the
front end doesn't provide it.

Net and Netslide previously had static functions called
draw_thick_line(), whose claim to the name is less justified and so
they've been renamed.

[originally from svn r8962]

--- a/drawing.c
+++ b/drawing.c
@@ -87,6 +87,34 @@
     dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour);
 }
 
+void draw_thick_line(drawing *dr, float thickness,
+		     float x1, float y1, float x2, float y2, int colour)
+{
+    if (dr->api->draw_thick_line) {
+	dr->api->draw_thick_line(dr->handle, thickness,
+				 x1, y1, x2, y2, colour);
+    } else {
+	/* We'll fake it up with a filled polygon.  The tweak to the
+	 * thickness empirically compensates for rounding errors, because
+	 * polygon rendering uses integer coordinates.
+	 */
+	float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
+	float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2);
+	float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2);
+	int p[8];
+
+	p[0] = x1 - tvhaty;
+	p[1] = y1 + tvhatx;
+	p[2] = x2 - tvhaty;
+	p[3] = y2 + tvhatx;
+	p[4] = x2 + tvhaty;
+	p[5] = y2 - tvhatx;
+	p[6] = x1 + tvhaty;
+	p[7] = y1 - tvhatx;
+	dr->api->draw_polygon(dr->handle, p, 4, colour, colour);
+    }
+}
+
 void draw_polygon(drawing *dr, int *coords, int npoints,
                   int fillcolour, int outlinecolour)
 {
--- a/gtk.c
+++ b/gtk.c
@@ -40,6 +40,8 @@
 # define USE_CAIRO
 #endif
 
+/* #undef USE_CAIRO */
+/* #define NO_THICK_LINE */
 #ifdef DEBUGGING
 static FILE *debug_fp = NULL;
 
@@ -297,6 +299,18 @@
     cairo_stroke(fe->cr);
 }
 
+static void do_draw_thick_line(frontend *fe, float thickness,
+			       float x1, float y1, float x2, float y2)
+{
+    cairo_save(fe->cr);
+    cairo_set_line_width(fe->cr, thickness);
+    cairo_new_path(fe->cr);
+    cairo_move_to(fe->cr, x1, y1);
+    cairo_line_to(fe->cr, x2, y2);
+    cairo_stroke(fe->cr);
+    cairo_restore(fe->cr);
+}
+
 static void do_draw_poly(frontend *fe, int *coords, int npoints,
 			 int fillcolour, int outlinecolour)
 {
@@ -518,6 +532,25 @@
     gdk_draw_line(fe->pixmap, fe->gc, x1, y1, x2, y2);
 }
 
+static void do_draw_thick_line(frontend *fe, float thickness,
+			       float x1, float y1, float x2, float y2)
+{
+    GdkGCValues save;
+
+    gdk_gc_get_values(fe->gc, &save);
+    gdk_gc_set_line_attributes(fe->gc,
+			       thickness,
+			       GDK_LINE_SOLID,
+			       GDK_CAP_BUTT,
+			       GDK_JOIN_BEVEL);
+    gdk_draw_line(fe->pixmap, fe->gc, x1, y1, x2, y2);
+    gdk_gc_set_line_attributes(fe->gc,
+			       save.line_width,
+			       save.line_style,
+			       save.cap_style,
+			       save.join_style);
+}
+
 static void do_draw_poly(frontend *fe, int *coords, int npoints,
 			 int fillcolour, int outlinecolour)
 {
@@ -850,6 +883,14 @@
     do_draw_line(fe, x1, y1, x2, y2);
 }
 
+void gtk_draw_thick_line(void *handle, float thickness,
+			 float x1, float y1, float x2, float y2, int colour)
+{
+    frontend *fe = (frontend *)handle;
+    set_colour(fe, colour);
+    do_draw_thick_line(fe, thickness, x1, y1, x2, y2);
+}
+
 void gtk_draw_poly(void *handle, int *coords, int npoints,
 		   int fillcolour, int outlinecolour)
 {
@@ -954,6 +995,11 @@
     gtk_text_fallback,
 #else
     NULL,
+#endif
+#ifdef NO_THICK_LINE
+    NULL,
+#else
+    gtk_draw_thick_line,
 #endif
 };
 
--- a/loopy.c
+++ b/loopy.c
@@ -3543,21 +3543,10 @@
 	    if (draw_faint_lines)
 		draw_line(dr, x1, y1, x2, y2, line_colour);
 	} else {
-            /* (dx, dy) points roughly from (x1, y1) to (x2, y2).
-             * The line is then "fattened" in a (roughly) perpendicular
-             * direction to create a thin rectangle. */
-            int dx = (x1 > x2) ? -1 : ((x1 < x2) ? 1 : 0);
-            int dy = (y1 > y2) ? -1 : ((y1 < y2) ? 1 : 0);
-            int points[8];
-	    points[0] = x1 + dy;
-	    points[1] = y1 - dx;
-	    points[2] = x1 - dy;
-	    points[3] = y1 + dx;
-	    points[4] = x2 - dy;
-	    points[5] = y2 + dx;
-	    points[6] = x2 + dy;
-	    points[7] = y2 - dx;
-            draw_polygon(dr, points, 4, line_colour, line_colour);
+	    draw_thick_line(dr, 3.0,
+			    x1 + 0.5, y1 + 0.5,
+			    x2 + 0.5, y2 + 0.5,
+			    line_colour);
         }
         if (ds->started) {
             /* Draw dots at ends of the line */
--- a/net.c
+++ b/net.c
@@ -2377,8 +2377,8 @@
     return ret;
 }
 
-static void draw_thick_line(drawing *dr, int x1, int y1, int x2, int y2,
-                            int colour)
+static void draw_filled_line(drawing *dr, int x1, int y1, int x2, int y2,
+			     int colour)
 {
     draw_line(dr, x1-1, y1, x2-1, y2, COL_WIRE);
     draw_line(dr, x1+1, y1, x2+1, y2, COL_WIRE);
@@ -2514,9 +2514,9 @@
             ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir);
             ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir);
             MATMUL(tx, ty, matrix, ex, ey);
-            draw_thick_line(dr, bx+(int)cx, by+(int)cy,
-			    bx+(int)(cx+tx), by+(int)(cy+ty),
-                            COL_WIRE);
+            draw_filled_line(dr, bx+(int)cx, by+(int)cy,
+			     bx+(int)(cx+tx), by+(int)(cy+ty),
+			     COL_WIRE);
         }
     }
     for (dir = 1; dir < 0x10; dir <<= 1) {
--- a/netslide.c
+++ b/netslide.c
@@ -1307,8 +1307,8 @@
     return ret;
 }
 
-static void draw_thick_line(drawing *dr, int x1, int y1, int x2, int y2,
-                            int colour)
+static void draw_filled_line(drawing *dr, int x1, int y1, int x2, int y2,
+			     int colour)
 {
     draw_line(dr, x1-1, y1, x2-1, y2, COL_WIRE);
     draw_line(dr, x1+1, y1, x2+1, y2, COL_WIRE);
@@ -1420,9 +1420,9 @@
         if (tile & dir) {
             ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir);
             ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir);
-            draw_thick_line(dr, bx+(int)cx, by+(int)cy,
-			    bx+(int)(cx+ex), by+(int)(cy+ey),
-                            COL_WIRE);
+            draw_filled_line(dr, bx+(int)cx, by+(int)cy,
+			     bx+(int)(cx+ex), by+(int)(cy+ey),
+			     COL_WIRE);
         }
     }
     for (dir = 1; dir < 0x10; dir <<= 1) {
--- a/nullfe.c
+++ b/nullfe.c
@@ -13,6 +13,8 @@
                int align, int colour, char *text) {}
 void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) {}
 void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) {}
+void draw_thick_line(drawing *dr, float thickness,
+		     float x1, float y1, float x2, float y2, int colour) {}
 void draw_polygon(drawing *dr, int *coords, int npoints,
                   int fillcolour, int outlinecolour) {}
 void draw_circle(drawing *dr, int cx, int cy, int radius,
--- a/puzzles.h
+++ b/puzzles.h
@@ -184,6 +184,8 @@
                   int fillcolour, int outlinecolour);
 void draw_circle(drawing *dr, int cx, int cy, int radius,
                  int fillcolour, int outlinecolour);
+void draw_thick_line(drawing *dr, float thickness,
+		     float x1, float y1, float x2, float y2, int colour);
 void clip(drawing *dr, int x, int y, int w, int h);
 void unclip(drawing *dr);
 void start_draw(drawing *dr);
@@ -519,6 +521,9 @@
     void (*line_dotted)(void *handle, int dotted);
     char *(*text_fallback)(void *handle, const char *const *strings,
 			   int nstrings);
+    void (*draw_thick_line)(void *handle, float thickness,
+			    float x1, float y1, float x2, float y2,
+			    int colour);
 };
 
 /*