tdrawille.c - ploot - simple plotting tools | |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65… | |
Log | |
Files | |
Refs | |
Tags | |
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))); /* 1110xxx… | |
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 +… | |
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)) == NU… | |
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, in… | |
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 *fon… | |
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] … | |
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, cha… | |
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 } |