root / proj / libs / graph / src / font.c @ 332
History | View | Annotate | Download (7.48 KB)
1 |
#include <lcom/lcf.h> |
---|---|
2 |
|
3 |
#include "font.h" |
4 |
|
5 |
#include "xpm_utils.h" |
6 |
#include "graph.h" |
7 |
#include "utils.h" |
8 |
#include "errors.h" |
9 |
#include <assert.h> |
10 |
|
11 |
/**
|
12 |
* @brief Text glyph. Represents a letter that can be drawn.
|
13 |
*/
|
14 |
typedef struct { |
15 |
uint16_t w, h; |
16 |
uint8_t *map; |
17 |
} glyph_t; |
18 |
/**
|
19 |
* @brief Construct glyph.
|
20 |
* @param xpm XPM describing the glyph
|
21 |
* @return Pointer to created glyph
|
22 |
*/
|
23 |
static glyph_t* (glyph_ctor)(const char *const *xpm){ |
24 |
if(xpm == NULL) return NULL; |
25 |
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 |
ret->map = NULL;
|
30 |
uint8_t *map = xpm_load((xpm_map_t)xpm, type, &img); |
31 |
if(map == NULL){ |
32 |
free(ret); |
33 |
return NULL; |
34 |
} |
35 |
ret->w = img.width; |
36 |
ret->h = img.height; |
37 |
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 |
return ret;
|
46 |
} |
47 |
/**
|
48 |
* @brief Destruct glyph.
|
49 |
* @param p Pointer to glyph to be destroyed
|
50 |
*/
|
51 |
static void (glyph_dtor)(glyph_t *p){ |
52 |
if(p == NULL) return; |
53 |
free(p->map); |
54 |
free(p); |
55 |
} |
56 |
/**
|
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 |
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 |
uint8_t a = *(p->map + w + h*p->w); |
73 |
int16_t x_ = x+w, y_ = y-p->h+h; |
74 |
int32_t pos = x_ +y_*W; |
75 |
if(0 <= pos && pos < W*H) alp_buf[pos] = a; |
76 |
} |
77 |
} |
78 |
return SUCCESS;
|
79 |
} |
80 |
|
81 |
/// FONT
|
82 |
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 |
int good = false; |
97 |
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 |
ret->glyphs[i] = glyph_ctor((const char *const *)xpm); |
102 |
if(ret->glyphs[i] != NULL) good = true; |
103 |
} |
104 |
if(good) return ret; |
105 |
else{
|
106 |
//font_dtor(ret);
|
107 |
return NULL; |
108 |
} |
109 |
} |
110 |
void (font_dtor)(font_t *p){
|
111 |
if(p == NULL) return; |
112 |
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 |
static font_t *consolas = NULL; |
119 |
static font_t *default_font = NULL; |
120 |
|
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 |
const font_t* font_get_default(void){ return default_font; } |
128 |
const font_t* font_get_consolas(void){ return consolas; } |
129 |
void (font_free)(void){ |
130 |
font_dtor(consolas); |
131 |
consolas = NULL;
|
132 |
default_font = NULL;
|
133 |
} |
134 |
|
135 |
/// TEXT
|
136 |
struct text{
|
137 |
const font_t *fnt;
|
138 |
char *txt;
|
139 |
int16_t x, y; |
140 |
uint16_t size; |
141 |
text_valign valign; |
142 |
text_halign halign; |
143 |
uint32_t color; |
144 |
}; |
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 |
text_set_string(ret, txt); |
152 |
ret->x = 0;
|
153 |
ret->y = 0;
|
154 |
ret->size = 25;
|
155 |
ret->color = GRAPH_BLACK; |
156 |
ret->valign = text_valign_top; |
157 |
ret->halign = text_halign_left; |
158 |
return ret;
|
159 |
} |
160 |
void (text_dtor)(text_t *p){
|
161 |
if(p == NULL) return; |
162 |
free(p->txt); |
163 |
free(p); |
164 |
} |
165 |
void (text_set_string) (text_t *p, const char *txt){ |
166 |
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 |
const char* (text_get_string)(const text_t *p){return p->txt; } |
172 |
void (text_set_pos) (text_t *p, int16_t x, int16_t y){ p->x = x; p->y = y; }
|
173 |
void (text_set_size) (text_t *p, uint16_t size ){ p->size = size ; }
|
174 |
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 |
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 |
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 |
if(g != NULL){ W += g->w; H = umax16(H, g->h); } |
190 |
} |
191 |
} |
192 |
uint8_t *alp_buf = malloc(W*H); |
193 |
if(alp_buf == NULL) return ALLOC_ERROR;{ |
194 |
int16_t y = (int16_t)H; |
195 |
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 |
|
205 |
double factor = (double)p->size/(double)H; |
206 |
|
207 |
newH = (uint16_t)(H*factor); |
208 |
newW = (uint16_t)(W*factor); |
209 |
alp_new_buf = malloc(newW*newH); |
210 |
if(alp_new_buf == NULL) return ALLOC_ERROR; |
211 |
|
212 |
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 |
*(alp_new_buf+newx+newy*newW) = *(alp_buf+x+y*W); |
217 |
} |
218 |
} |
219 |
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 |
//default: return LOGIC_ERROR;
|
228 |
} |
229 |
} |
230 |
// 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 |
//default: return LOGIC_ERROR;
|
237 |
} |
238 |
} |
239 |
// Draw text
|
240 |
for(int16_t x, y, newy = 0; newy < newH; ++newy){ |
241 |
y = inity+newy; |
242 |
for(int16_t newx = 0; newx < newW; ++newx){ |
243 |
x = initx+newx; |
244 |
if(!(0 <= x && x < graph_get_XRes() && |
245 |
0 <= y && y < graph_get_YRes())) continue; |
246 |
uint8_t a = *(alp_new_buf+newx+newy*newW); |
247 |
if(a < ALPHA_THRESHOLD) graph_set_pixel((uint16_t)x,(uint16_t)y,p->color);
|
248 |
} |
249 |
} |
250 |
free(alp_new_buf); |
251 |
return SUCCESS;
|
252 |
} |