|
|
drawille.c - ploot - simple plotting tools |
|
|
 |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
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 } |
|