+ sfree(ui);
+}
+
+void coord_round(float x, float y, int *xr, int *yr)
+{
+ float xs, ys, xv, yv, dx, dy, dist;
+
+ /*
+ * Find the nearest square-centre.
+ */
+ xs = (float)floor(x) + 0.5F;
+ ys = (float)floor(y) + 0.5F;
+
+ /*
+ * And find the nearest grid vertex.
+ */
+ xv = (float)floor(x + 0.5F);
+ yv = (float)floor(y + 0.5F);
+
+ /*
+ * We allocate clicks in parts of the grid square to either
+ * corners, edges or square centres, as follows:
+ *
+ * +--+--------+--+
+ * | | | |
+ * +--+ +--+
+ * | `. ,' |
+ * | +--+ |
+ * | | | |
+ * | +--+ |
+ * | ,' `. |
+ * +--+ +--+
+ * | | | |
+ * +--+--------+--+
+ *
+ * (Not to scale!)
+ *
+ * In other words: we measure the square distance (i.e.
+ * max(dx,dy)) from the click to the nearest corner, and if
+ * it's within CORNER_TOLERANCE then we return a corner click.
+ * We measure the square distance from the click to the nearest
+ * centre, and if that's within CENTRE_TOLERANCE we return a
+ * centre click. Failing that, we find which of the two edge
+ * centres is nearer to the click and return that edge.
+ */
+
+ /*
+ * Check for corner click.
+ */
+ dx = (float)fabs(x - xv);
+ dy = (float)fabs(y - yv);
+ dist = (dx > dy ? dx : dy);
+ if (dist < CORNER_TOLERANCE) {
+ *xr = 2 * (int)xv;
+ *yr = 2 * (int)yv;
+ } else {
+ /*
+ * Check for centre click.
+ */
+ dx = (float)fabs(x - xs);
+ dy = (float)fabs(y - ys);
+ dist = (dx > dy ? dx : dy);
+ if (dist < CENTRE_TOLERANCE) {
+ *xr = 1 + 2 * (int)xs;
+ *yr = 1 + 2 * (int)ys;
+ } else {
+ /*
+ * Failing both of those, see which edge we're closer to.
+ * Conveniently, this is simply done by testing the relative
+ * magnitude of dx and dy (which are currently distances from
+ * the square centre).
+ */
+ if (dx > dy) {
+ /* Vertical edge: x-coord of corner,
+ * y-coord of square centre. */
+ *xr = 2 * (int)xv;
+ *yr = 1 + 2 * (int)ys;
+ } else {
+ /* Horizontal edge: x-coord of square centre,
+ * y-coord of corner. */
+ *xr = 1 + 2 * (int)xs;
+ *yr = 2 * (int)yv;
+ }
+ }
+ }
+}
+
+static void ui_draw_rect(game_state *state, game_ui *ui,
+ unsigned char *hedge, unsigned char *vedge, int c)
+{
+ int x1, x2, y1, y2, x, y, t;
+
+ x1 = ui->drag_start_x;
+ x2 = ui->drag_end_x;
+ if (x2 < x1) { t = x1; x1 = x2; x2 = t; }
+
+ y1 = ui->drag_start_y;
+ y2 = ui->drag_end_y;
+ if (y2 < y1) { t = y1; y1 = y2; y2 = t; }
+
+ x1 = x1 / 2; /* rounds down */
+ x2 = (x2+1) / 2; /* rounds up */
+ y1 = y1 / 2; /* rounds down */
+ y2 = (y2+1) / 2; /* rounds up */
+
+ /*
+ * Draw horizontal edges of rectangles.
+ */
+ for (x = x1; x < x2; x++)
+ for (y = y1; y <= y2; y++)
+ if (HRANGE(state,x,y)) {
+ int val = index(state,hedge,x,y);
+ if (y == y1 || y == y2)
+ val = c;
+ else if (c == 1)
+ val = 0;
+ index(state,hedge,x,y) = val;
+ }
+
+ /*
+ * Draw vertical edges of rectangles.
+ */
+ for (y = y1; y < y2; y++)
+ for (x = x1; x <= x2; x++)
+ if (VRANGE(state,x,y)) {
+ int val = index(state,vedge,x,y);
+ if (x == x1 || x == x2)
+ val = c;
+ else if (c == 1)
+ val = 0;
+ index(state,vedge,x,y) = val;
+ }