Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (7.5 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
#include "text.h"
137

    
138
struct text{
139
    const font_t *fnt;
140
    char *txt;
141
    int16_t x, y;
142
    uint16_t size;
143
    text_valign valign;
144
    text_halign halign;
145
    uint32_t color;
146
};
147
text_t* (text_ctor)(const font_t *fnt, const char *txt){
148
    if(fnt == NULL) return NULL;
149
    text_t *ret = malloc(sizeof(text_t));
150
    if(ret == NULL) return NULL;
151
    ret->fnt = fnt;
152
    ret->txt = NULL;
153
    text_set_string(ret, txt);
154
    ret->x = 0;
155
    ret->y = 0;
156
    ret->size = 25;
157
    ret->color = GRAPH_BLACK;
158
    ret->valign = text_valign_top;
159
    ret->halign = text_halign_left;
160
    return ret;
161
}
162
void (text_dtor)(text_t *p){
163
    if(p == NULL) return;
164
    free(p->txt);
165
    free(p);
166
}
167
void (text_set_string) (text_t *p, const char *txt){
168
    size_t sz = strlen(txt);
169
    p->txt = realloc(p->txt, (sz+1)*sizeof(char));
170
    if(p->txt == NULL) return;
171
    strcpy(p->txt, txt);
172
}
173
const char* (text_get_string)(const text_t *p){return p->txt; }
174
void (text_set_pos)   (text_t *p, int16_t x, int16_t y){ p->x = x; p->y = y; }
175
void (text_set_size)  (text_t *p, uint16_t size       ){ p->size = size    ; }
176
void (text_set_color) (text_t *p, uint32_t color      ){ p->color = color  ; }
177
void (text_set_valign)(text_t *p, text_valign valign  ){ p->valign = valign; }
178
void (text_set_halign)(text_t *p, text_halign halign  ){ p->halign = halign; }
179
int16_t (text_get_x)  (const text_t *p){ return p->x; }
180
int16_t (text_get_y)  (const text_t *p){ return p->y; }
181
int (text_draw)(const text_t *p){
182
    if(p == NULL) return NULL_PTR;
183
    int ret = SUCCESS;
184
    // Get buffer with rescaled text
185
    uint8_t *alp_new_buf = NULL;
186
    uint16_t newH, newW;{
187
        const size_t len = strlen(p->txt);
188
        uint16_t W = 0, H = 0; {
189
            for(size_t i = 0; i < len; ++i){
190
                const glyph_t *g = p->fnt->glyphs[(size_t)p->txt[i]];
191
                if(g != NULL){ W += g->w; H = max_u16(H, g->h); }
192
            }
193
        }
194
        uint8_t *alp_buf = malloc(W*H);
195
        if(alp_buf == NULL) return ALLOC_ERROR;{
196
            int16_t y = (int16_t)H;
197
            int16_t x = 0;
198
            for(size_t i = 0; i < len; ++i){
199
                const glyph_t *g = p->fnt->glyphs[(size_t)p->txt[i]];
200
                if(g != NULL){
201
                    if((ret = glyph_draw_to_alpha_buffer(g, x, y, alp_buf, W, H))) return ret;
202
                    x += g->w;
203
                }
204
            }
205
        }
206

    
207
        double factor = (double)p->size/(double)H;
208

    
209
        newH = (uint16_t)(H*factor);
210
        newW = (uint16_t)(W*factor);
211
        alp_new_buf = malloc(newW*newH);
212
        if(alp_new_buf == NULL) return ALLOC_ERROR;
213

    
214
        for(uint16_t newy = 0; newy < newH; ++newy){
215
            uint16_t y = (uint16_t)(newy/factor);
216
            for(uint16_t newx = 0; newx < newW; ++newx){
217
                uint16_t x = (uint16_t)(newx/factor);
218
                *(alp_new_buf+newx+newy*newW) = *(alp_buf+x+y*W);
219
            }
220
        }
221
        free(alp_buf);
222
    }
223
    // Get initial value of x
224
    int16_t initx;{
225
        switch(p->halign){
226
            case text_halign_left  : initx = p->x         ; break;
227
            case text_halign_center: initx = p->x - newW/2; break;
228
            case text_halign_right : initx = p->x - newW  ; break;
229
            //default: return LOGIC_ERROR;
230
        }
231
    }
232
    // Get initial value of y
233
    int16_t inity;{
234
        switch(p->valign){
235
            case text_valign_top   : inity = p->y         ; break;
236
            case text_valign_center: inity = p->y - newH/2; break;
237
            case text_valign_bottom: inity = p->y - newH  ; break;
238
            //default: return LOGIC_ERROR;
239
        }
240
    }
241
    // Draw text
242
    for(int16_t x, y, newy = 0; newy < newH; ++newy){
243
        y = inity+newy;
244
        for(int16_t newx = 0; newx < newW; ++newx){
245
            x = initx+newx;
246
            if(!(0 <= x && x < graph_get_XRes() &&
247
                 0 <= y && y < graph_get_YRes())) continue;
248
            uint8_t a = *(alp_new_buf+newx+newy*newW);
249
            if(a < ALPHA_THRESHOLD) graph_set_pixel((uint16_t)x,(uint16_t)y,p->color);
250
        }
251
    }
252
    free(alp_new_buf);
253
    return SUCCESS;
254
}