URI: 
       tdrawille.c - ploot - simple plotting tools
  HTML git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
       ---
       tdrawille.c (3892B)
       ---
            1 #include "drawille.h"
            2 
            3 #include <stdint.h>
            4 #include <stdio.h>
            5 #include <stdlib.h>
            6 #include <string.h>
            7 #include <math.h>
            8 
            9 #include "font.h"
           10 
           11 #include "log.h" /* XXX */
           12 
           13 /*
           14  * Terminal-based plotting using drawille character, aka drawille.
           15  */
           16 
           17 /* parameters used to draw a line */
           18 struct line {
           19         int x0, y0, x1, y1;                /* point of the line */
           20         int dx, dy, sx, sy, err;        /* parameters for the algorythm */
           21 };
           22 
           23 /*
           24  * Turn on the bit at position (row, col) of a single cell.  The
           25  * pattern is not linear (1-4-2-5-3-6-7-8), because it matches the
           26  * drawille pattern.
           27  */
           28 static void
           29 drawille_cell_dot(uint8_t *cell, int row, int col)
           30 {
           31         uint8_t flags[4][2] = {
           32                 { 0x01, 0x08 },
           33                 { 0x02, 0x10 },
           34                 { 0x04, 0x20 },
           35                 { 0x40, 0x80 },
           36         };
           37 
           38         *cell |= flags[row][col];
           39 }
           40 
           41 static size_t
           42 drawille_cell_utf(uint8_t cell, char *utf)
           43 {
           44         long rune;
           45 
           46         rune = 10240 + cell;
           47         utf[0] = (char)(0xe0 | (0x0f & (rune >> 12)));        /* 1110xxxx */
           48         utf[1] = (char)(0x80 | (0x3f & (rune >> 6)));        /* 10xxxxxx */
           49         utf[2] = (char)(0x80 | (0x3f & (rune)));        /* 10xxxxxx */
           50         return 3;
           51 }
           52 
           53 static uint8_t
           54 drawille_get(struct drawille *drw, int row, int col)
           55 {
           56         return drw->buf[row * drw->col + col];
           57 }
           58 
           59 size_t
           60 drawille_put_row(FILE *fp, struct drawille *drw, int row)
           61 {
           62         char txt[] = "xxx";
           63         size_t n;
           64 
           65         n = 0;
           66         for (int col = 0; col < drw->col; col++) {
           67                 drawille_cell_utf(drawille_get(drw, row, col), txt);
           68                 n += fputs(txt, fp);
           69         }
           70         return n;
           71 }
           72 
           73 /*
           74  * Coordinates are passed as (x, y), but the canvas stores bits as
           75  * (row, col).  Conversion is made by this function.
           76  */
           77 void
           78 drawille_dot(struct drawille *drw, int x, int y)
           79 {
           80         if (x < 0 || x / 2 >= drw->col || y < 0 || y / 4 >= drw->row)
           81                 return;
           82         drawille_cell_dot(drw->buf + (drw->row - y / 4 - 1) * drw->col + (x / 2),
           83             3 - y % 4,
           84             x % 2);
           85 }
           86 
           87 struct drawille *
           88 drawille_new(int row, int col)
           89 {
           90         struct drawille *drw;
           91 
           92         if ((drw = calloc(sizeof(struct drawille) + row * col, 1)) == NULL)
           93                 return NULL;
           94         drw->row = row;
           95         drw->col = col;
           96         return drw;
           97 }
           98 
           99 static void
          100 drawille_line_init(struct line *l, int x0, int y0, int x1, int y1)
          101 {
          102         l->x0 = x0;
          103         l->y0 = y0;
          104         l->x1 = x1;
          105         l->y1 = y1;
          106         l->sx = x0 < x1 ? 1 : -1;
          107         l->sy = y0 < y1 ? 1 : -1;
          108         l->dx = abs(x1 - x0);
          109         l->dy = abs(y1 - y0);
          110         l->err = (l->dx > l->dy ? l->dx : -l->dy) / 2;
          111 }
          112 
          113 static int
          114 drawille_line_next(struct line *l)
          115 {
          116         int e;
          117 
          118         if (l->x0 == l->x1 && l->y0 == l->y1)
          119                 return 0;
          120 
          121         e = l->err;
          122         if (e > -l->dx) {
          123                 l->x0 += l->sx;
          124                 l->err -= l->dy;
          125         }
          126         if (e < l->dy) {
          127                 l->y0 += l->sy;
          128                 l->err += l->dx;
          129         }
          130         return 1;
          131 }
          132 
          133 void
          134 drawille_line(struct drawille *drw, int x0, int y0, int x1, int y1)
          135 {
          136         struct line l;
          137 
          138         drawille_line_init(&l, x0, y0, x1, y1);
          139         do {
          140                 drawille_dot(drw, l.x0, l.y0);
          141         } while (drawille_line_next(&l));
          142 }
          143 
          144 void
          145 drawille_histogram_dot(struct drawille *drw, int x, int y, int zero)
          146 {
          147         int sign;
          148 
          149         sign = (y > zero) ? (+1) : (-1);
          150         for (; y != zero; y -= sign)
          151                 drawille_dot(drw, x, y);
          152         drawille_dot(drw, x, y);
          153 }
          154 
          155 void
          156 drawille_histogram_line(struct drawille *drw, int x0, int y0, int x1, int y1, int zero)
          157 {
          158         struct line l;
          159 
          160         drawille_line_init(&l, x0, y0, x1, y1);
          161         do {
          162                 drawille_histogram_dot(drw, l.x0, l.y0, zero);
          163         } while (drawille_line_next(&l));
          164 }
          165 
          166 static int
          167 drawille_text_glyph(struct drawille *drw, int x, int y, struct font *font, char c)
          168 {
          169         int width;
          170         char *glyph;
          171 
          172         if ((unsigned)c > 127)
          173                 glyph = font->glyph[0];
          174         else
          175                 glyph = font->glyph[(unsigned)c];
          176 
          177         width = strlen(glyph) / font->height;
          178 
          179         for (int ix = 0; ix < width; ix++)
          180         for (int iy = 0; iy < font->height; iy++) {
          181                 if (glyph[ix + (font->height - 1) * width - iy * width] == 3)
          182                         drawille_dot(drw, x + ix, y + iy);
          183         }
          184 
          185         return width;
          186 }
          187 
          188 char *
          189 drawille_text(struct drawille *drw, int x, int y, struct font *font, char *s)
          190 {
          191         if (drw->row*4 < font->height)
          192                 return NULL;
          193         for (; *s != '\0' && x < drw->col * 2; s++, x++)
          194                 x += drawille_text_glyph(drw, x, y, font, *s);
          195         return s;
          196 }