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