root / proj / libs / graph / src / font.c @ 327
History | View | Annotate | Download (7.48 KB)
1 | 182 | up20180642 | #include <lcom/lcf.h> |
---|---|---|---|
2 | |||
3 | #include "font.h" |
||
4 | |||
5 | 183 | up20180642 | #include "xpm_utils.h" |
6 | #include "graph.h" |
||
7 | #include "utils.h" |
||
8 | #include "errors.h" |
||
9 | 188 | up20180642 | #include <assert.h> |
10 | 183 | up20180642 | |
11 | 319 | up20180642 | /**
|
12 | * @brief Text glyph. Represents a letter that can be drawn.
|
||
13 | */
|
||
14 | 317 | up20180642 | typedef struct { |
15 | 182 | up20180642 | uint16_t w, h; |
16 | uint8_t *map; |
||
17 | 317 | up20180642 | } glyph_t; |
18 | 319 | up20180642 | /**
|
19 | * @brief Construct glyph.
|
||
20 | * @param xpm XPM describing the glyph
|
||
21 | * @return Pointer to created glyph
|
||
22 | */
|
||
23 | 323 | up20180642 | static glyph_t* (glyph_ctor)(const char *const *xpm){ |
24 | 183 | up20180642 | if(xpm == NULL) return NULL; |
25 | 182 | up20180642 | glyph_t *ret = malloc(sizeof(glyph_t));
|
26 | if(ret == NULL) return NULL; |
||
27 | enum xpm_image_type type = XPM_8_8_8_8;
|
||
28 | xpm_image_t img; |
||
29 | 213 | up20180642 | ret->map = NULL;
|
30 | uint8_t *map = xpm_load((xpm_map_t)xpm, type, &img); |
||
31 | if(map == NULL){ |
||
32 | 182 | up20180642 | free(ret); |
33 | return NULL; |
||
34 | } |
||
35 | ret->w = img.width; |
||
36 | ret->h = img.height; |
||
37 | 213 | up20180642 | ret->map = malloc(ret->w*ret->h*sizeof(uint8_t));
|
38 | if(ret->map == NULL){ |
||
39 | free(ret); |
||
40 | return NULL; |
||
41 | } |
||
42 | for(unsigned i = 0; i < ret->w*ret->h; ++i){ |
||
43 | ret->map[i] = map[4*i+3]; |
||
44 | } |
||
45 | 182 | up20180642 | return ret;
|
46 | } |
||
47 | 319 | up20180642 | /**
|
48 | * @brief Destruct glyph.
|
||
49 | * @param p Pointer to glyph to be destroyed
|
||
50 | */
|
||
51 | 183 | up20180642 | static void (glyph_dtor)(glyph_t *p){ |
52 | 182 | up20180642 | if(p == NULL) return; |
53 | free(p->map); |
||
54 | free(p); |
||
55 | } |
||
56 | 319 | up20180642 | /**
|
57 | * @brief Draw glyph to an alpha-buffer.
|
||
58 | *
|
||
59 | * An alpha-buffer is an array of uint8_t that represents transparencies.
|
||
60 | * It proves fit as a tool for drawing text.
|
||
61 | * @param p Pointer to glyph to be drawn
|
||
62 | * @param x X-position to draw the glyph
|
||
63 | * @param y Y-position to draw the glyph
|
||
64 | * @param alp_buf Alpha-buffer to which the glyph will be drawn
|
||
65 | * @param W Width of the alpha-buffer
|
||
66 | * @param H Height of the alpha-buffer
|
||
67 | */
|
||
68 | 183 | up20180642 | static int (glyph_draw_to_alpha_buffer)(const glyph_t *p, int16_t x, int16_t y, uint8_t *alp_buf, uint16_t W, uint16_t H){ |
69 | if(p == NULL) return NULL_PTR; |
||
70 | for(int16_t h = 0; h < p->h; ++h){ |
||
71 | for(int16_t w = 0; w < p->w; ++w){ |
||
72 | 213 | up20180642 | uint8_t a = *(p->map + w + h*p->w); |
73 | 208 | up20180642 | int16_t x_ = x+w, y_ = y-p->h+h; |
74 | 323 | up20180642 | int32_t pos = x_ +y_*W; |
75 | if(0 <= pos && pos < W*H) alp_buf[pos] = a; |
||
76 | 183 | up20180642 | } |
77 | } |
||
78 | return SUCCESS;
|
||
79 | } |
||
80 | |||
81 | 314 | up20180642 | /// FONT
|
82 | 183 | up20180642 | struct font{
|
83 | size_t nchars; |
||
84 | glyph_t **glyphs; |
||
85 | }; |
||
86 | font_t* (font_ctor)(const char *s){ |
||
87 | font_t *ret = malloc(sizeof(font_t));
|
||
88 | if(ret == NULL) return NULL; |
||
89 | ret->nchars = 128;
|
||
90 | ret->glyphs = malloc(ret->nchars*sizeof(glyph_t*));
|
||
91 | if(ret->glyphs == NULL){ |
||
92 | free(ret->glyphs); |
||
93 | free(ret); |
||
94 | return NULL; |
||
95 | } |
||
96 | 192 | up20180642 | int good = false; |
97 | 183 | up20180642 | char filepath[1024]; |
98 | for(size_t i = 0; i < ret->nchars; ++i){ |
||
99 | sprintf(filepath, "%s/ascii%03d.xpm2", s, i);
|
||
100 | char **xpm = xpm_load_xpm2(filepath);
|
||
101 | 323 | up20180642 | ret->glyphs[i] = glyph_ctor((const char *const *)xpm); |
102 | 192 | up20180642 | if(ret->glyphs[i] != NULL) good = true; |
103 | 183 | up20180642 | } |
104 | 192 | up20180642 | if(good) return ret; |
105 | else{
|
||
106 | //font_dtor(ret);
|
||
107 | return NULL; |
||
108 | } |
||
109 | 183 | up20180642 | } |
110 | 319 | up20180642 | void (font_dtor)(font_t *p){
|
111 | if(p == NULL) return; |
||
112 | 183 | up20180642 | for(size_t i = 0; i < p->nchars; ++i) |
113 | glyph_dtor(p->glyphs[i]); |
||
114 | free(p->glyphs); |
||
115 | free(p); |
||
116 | } |
||
117 | |||
118 | 314 | up20180642 | static font_t *consolas = NULL; |
119 | static font_t *default_font = NULL; |
||
120 | 313 | up20180642 | |
121 | int (font_init)(void){ |
||
122 | consolas = font_ctor("/home/lcom/labs/proj/media/font/Consolas/xpm2");
|
||
123 | if(consolas == NULL) return NULL_PTR; |
||
124 | default_font = consolas; |
||
125 | return SUCCESS;
|
||
126 | } |
||
127 | 314 | up20180642 | const font_t* font_get_default(void){ return default_font; } |
128 | const font_t* font_get_consolas(void){ return consolas; } |
||
129 | 319 | up20180642 | void (font_free)(void){ |
130 | font_dtor(consolas); |
||
131 | 313 | up20180642 | consolas = NULL;
|
132 | default_font = NULL;
|
||
133 | } |
||
134 | |||
135 | 314 | up20180642 | /// TEXT
|
136 | 183 | up20180642 | struct text{
|
137 | const font_t *fnt;
|
||
138 | char *txt;
|
||
139 | int16_t x, y; |
||
140 | 323 | up20180642 | uint16_t size; |
141 | 314 | up20180642 | text_valign valign; |
142 | text_halign halign; |
||
143 | 323 | up20180642 | uint32_t color; |
144 | 183 | up20180642 | }; |
145 | text_t* (text_ctor)(const font_t *fnt, const char *txt){ |
||
146 | if(fnt == NULL) return NULL; |
||
147 | text_t *ret = malloc(sizeof(text_t));
|
||
148 | if(ret == NULL) return NULL; |
||
149 | ret->fnt = fnt; |
||
150 | ret->txt = NULL;
|
||
151 | 314 | up20180642 | text_set_string(ret, txt); |
152 | 183 | up20180642 | ret->x = 0;
|
153 | ret->y = 0;
|
||
154 | 188 | up20180642 | ret->size = 25;
|
155 | 253 | up20180642 | ret->color = GRAPH_BLACK; |
156 | 188 | up20180642 | ret->valign = text_valign_top; |
157 | ret->halign = text_halign_left; |
||
158 | 183 | up20180642 | return ret;
|
159 | } |
||
160 | void (text_dtor)(text_t *p){
|
||
161 | if(p == NULL) return; |
||
162 | free(p->txt); |
||
163 | free(p); |
||
164 | } |
||
165 | 314 | up20180642 | void (text_set_string) (text_t *p, const char *txt){ |
166 | 183 | up20180642 | size_t sz = strlen(txt); |
167 | p->txt = realloc(p->txt, (sz+1)*sizeof(char)); |
||
168 | if(p->txt == NULL) return; |
||
169 | strcpy(p->txt, txt); |
||
170 | } |
||
171 | 319 | up20180642 | const char* (text_get_string)(const text_t *p){return p->txt; } |
172 | 314 | up20180642 | void (text_set_pos) (text_t *p, int16_t x, int16_t y){ p->x = x; p->y = y; }
|
173 | 323 | up20180642 | void (text_set_size) (text_t *p, uint16_t size ){ p->size = size ; }
|
174 | 314 | up20180642 | void (text_set_color) (text_t *p, uint32_t color ){ p->color = color ; }
|
175 | void (text_set_valign)(text_t *p, text_valign valign ){ p->valign = valign; }
|
||
176 | void (text_set_halign)(text_t *p, text_halign halign ){ p->halign = halign; }
|
||
177 | 297 | up20180642 | int16_t (text_get_x) (const text_t *p){ return p->x; } |
178 | int16_t (text_get_y) (const text_t *p){ return p->y; } |
||
179 | 188 | up20180642 | int (text_draw)(const text_t *p){ |
180 | if(p == NULL) return NULL_PTR; |
||
181 | int ret = SUCCESS;
|
||
182 | // Get buffer with rescaled text
|
||
183 | uint8_t *alp_new_buf = NULL;
|
||
184 | uint16_t newH, newW;{ |
||
185 | const size_t len = strlen(p->txt);
|
||
186 | uint16_t W = 0, H = 0; { |
||
187 | for(size_t i = 0; i < len; ++i){ |
||
188 | const glyph_t *g = p->fnt->glyphs[(size_t)p->txt[i]];
|
||
189 | 323 | up20180642 | if(g != NULL){ W += g->w; H = umax16(H, g->h); } |
190 | 188 | up20180642 | } |
191 | } |
||
192 | uint8_t *alp_buf = malloc(W*H); |
||
193 | if(alp_buf == NULL) return ALLOC_ERROR;{ |
||
194 | 323 | up20180642 | int16_t y = (int16_t)H; |
195 | 188 | up20180642 | int16_t x = 0;
|
196 | for(size_t i = 0; i < len; ++i){ |
||
197 | const glyph_t *g = p->fnt->glyphs[(size_t)p->txt[i]];
|
||
198 | if(g != NULL){ |
||
199 | if((ret = glyph_draw_to_alpha_buffer(g, x, y, alp_buf, W, H))) return ret; |
||
200 | x += g->w; |
||
201 | } |
||
202 | } |
||
203 | } |
||
204 | 183 | up20180642 | |
205 | 188 | up20180642 | double factor = (double)p->size/(double)H; |
206 | |||
207 | 323 | up20180642 | newH = (uint16_t)(H*factor); |
208 | newW = (uint16_t)(W*factor); |
||
209 | 188 | up20180642 | alp_new_buf = malloc(newW*newH); |
210 | if(alp_new_buf == NULL) return ALLOC_ERROR; |
||
211 | |||
212 | 323 | up20180642 | for(uint16_t newy = 0; newy < newH; ++newy){ |
213 | uint16_t y = (uint16_t)(newy/factor); |
||
214 | for(uint16_t newx = 0; newx < newW; ++newx){ |
||
215 | uint16_t x = (uint16_t)(newx/factor); |
||
216 | 188 | up20180642 | *(alp_new_buf+newx+newy*newW) = *(alp_buf+x+y*W); |
217 | 183 | up20180642 | } |
218 | } |
||
219 | 188 | up20180642 | free(alp_buf); |
220 | } |
||
221 | // Get initial value of x
|
||
222 | int16_t initx;{ |
||
223 | switch(p->halign){
|
||
224 | case text_halign_left : initx = p->x ; break; |
||
225 | case text_halign_center: initx = p->x - newW/2; break; |
||
226 | case text_halign_right : initx = p->x - newW ; break; |
||
227 | 323 | up20180642 | //default: return LOGIC_ERROR;
|
228 | 183 | up20180642 | } |
229 | } |
||
230 | 188 | up20180642 | // Get initial value of y
|
231 | int16_t inity;{ |
||
232 | switch(p->valign){
|
||
233 | case text_valign_top : inity = p->y ; break; |
||
234 | case text_valign_center: inity = p->y - newH/2; break; |
||
235 | case text_valign_bottom: inity = p->y - newH ; break; |
||
236 | 323 | up20180642 | //default: return LOGIC_ERROR;
|
237 | 183 | up20180642 | } |
238 | } |
||
239 | 188 | up20180642 | // Draw text
|
240 | 307 | up20180642 | for(int16_t x, y, newy = 0; newy < newH; ++newy){ |
241 | y = inity+newy; |
||
242 | 188 | up20180642 | for(int16_t newx = 0; newx < newW; ++newx){ |
243 | 307 | up20180642 | x = initx+newx; |
244 | if(!(0 <= x && x < graph_get_XRes() && |
||
245 | 0 <= y && y < graph_get_YRes())) continue; |
||
246 | 188 | up20180642 | uint8_t a = *(alp_new_buf+newx+newy*newW); |
247 | 323 | up20180642 | if(a < ALPHA_THRESHOLD) graph_set_pixel((uint16_t)x,(uint16_t)y,p->color);
|
248 | 188 | up20180642 | } |
249 | } |
||
250 | free(alp_new_buf); |
||
251 | return SUCCESS;
|
||
252 | 183 | up20180642 | } |