Project

General

Profile

Statistics
| Revision:

root / proj / libs / graph / src / font.c @ 319

History | View | Annotate | Download (7.34 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 183 up20180642
static glyph_t* (glyph_ctor)(const char **xpm){
24
    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
            unsigned pos = x_ +y_*W;
75
            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
        ret->glyphs[i] = glyph_ctor((const char**)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
    int size;
141
    uint32_t color;
142 314 up20180642
    text_valign valign;
143
    text_halign halign;
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
void (text_set_size)  (text_t *p, unsigned 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 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 183 up20180642
180 188 up20180642
int (text_draw)(const text_t *p){
181
    if(p == NULL) return NULL_PTR;
182
    int ret = SUCCESS;
183
    // Get buffer with rescaled text
184
    uint8_t *alp_new_buf = NULL;
185
    uint16_t newH, newW;{
186
        const size_t len = strlen(p->txt);
187
        uint16_t W = 0, H = 0; {
188
            for(size_t i = 0; i < len; ++i){
189
                const glyph_t *g = p->fnt->glyphs[(size_t)p->txt[i]];
190
                if(g != NULL){ W += g->w; H = max(H, g->h); }
191
            }
192
        }
193
        uint8_t *alp_buf = malloc(W*H);
194
        if(alp_buf == NULL) return ALLOC_ERROR;{
195
            int16_t y = H;
196
            int16_t x = 0;
197
            for(size_t i = 0; i < len; ++i){
198
                const glyph_t *g = p->fnt->glyphs[(size_t)p->txt[i]];
199
                if(g != NULL){
200
                    if((ret = glyph_draw_to_alpha_buffer(g, x, y, alp_buf, W, H))) return ret;
201
                    x += g->w;
202
                }
203
            }
204
        }
205 183 up20180642
206 188 up20180642
        double factor = (double)p->size/(double)H;
207
208
        newH = H*factor;
209
        newW = W*factor;
210
        alp_new_buf = malloc(newW*newH);
211
        if(alp_new_buf == NULL) return ALLOC_ERROR;
212
213
        for(size_t newy = 0; newy < newH; ++newy){
214 298 up20180642
            size_t y = newy/factor;
215 188 up20180642
            for(size_t newx = 0; newx < newW; ++newx){
216 298 up20180642
                size_t x = newx/factor;
217 188 up20180642
                *(alp_new_buf+newx+newy*newW) = *(alp_buf+x+y*W);
218 183 up20180642
            }
219
        }
220 188 up20180642
        free(alp_buf);
221
    }
222
    // Get initial value of x
223
    int16_t initx;{
224
        switch(p->halign){
225
            case text_halign_left  : initx = p->x         ; break;
226
            case text_halign_center: initx = p->x - newW/2; break;
227
            case text_halign_right : initx = p->x - newW  ; break;
228
            default: return LOGIC_ERROR;
229 183 up20180642
        }
230
    }
231 188 up20180642
    // Get initial value of y
232
    int16_t inity;{
233
        switch(p->valign){
234
            case text_valign_top   : inity = p->y         ; break;
235
            case text_valign_center: inity = p->y - newH/2; break;
236
            case text_valign_bottom: inity = p->y - newH  ; break;
237
            default: return LOGIC_ERROR;
238 183 up20180642
        }
239
    }
240 188 up20180642
    // Draw text
241 307 up20180642
    for(int16_t x, y, newy = 0; newy < newH; ++newy){
242
        y = inity+newy;
243 188 up20180642
        for(int16_t newx = 0; newx < newW; ++newx){
244 307 up20180642
            x = initx+newx;
245
            if(!(0 <= x && x < graph_get_XRes() &&
246
                 0 <= y && y < graph_get_YRes())) continue;
247 188 up20180642
            uint8_t a = *(alp_new_buf+newx+newy*newW);
248 307 up20180642
            if(a < ALPHA_THRESHOLD) graph_set_pixel(x,y,p->color);
249 188 up20180642
        }
250
    }
251
    free(alp_new_buf);
252
    return SUCCESS;
253 183 up20180642
}