/* BDF simple reader and printer (ASCII Support only) include stdio.h stdlib.h string.h Should define SBDF_IMPLEMENTATION in only one .c file */ typedef struct SBDF_Font SBDF_Font; SBDF_Font* SBDF_FontLoad(const char *); void SBDF_FontDestroy(SBDF_Font *); void SBDF_GetSize(const SBDF_Font *, const char *, int *, int *, int *, int *); #ifdef SBDF_USESDL void SBDF_SDLPrint(const SDL_Renderer *, const SBDF_Font *, const char *, int, int); #endif #ifdef SBDF_IMPLEMENTATION struct SBDF_Glyph { int dx, dy; int bx, by, bw, bh; size_t s; }; struct SBDF_Font { struct SBDF_Glyph g[256]; unsigned char *data; }; static struct SBDF_Font* SBDF_FontInit(size_t sz) { struct SBDF_Font *res; int i; res = malloc(sizeof(*res)); if (res == NULL) return NULL; res->data = malloc(sz); if (res->data == NULL) { free(res); return NULL; } for (i = 0; i < 256; i++) { res->g[i].dx = 0; res->g[i].dy = 0; res->g[i].bx = 0; res->g[i].by = 0; res->g[i].bw = 0; res->g[i].bh = 0; res->g[i].s = -1; } return res; } void SBDF_FontDestroy(struct SBDF_Font *f) { if (f == NULL) return; free(f->data); free(f); } #define SBDF_NULL 0x00000 #define SBDF_PROPS 0x00010 #define SBDF_CHARS 0x00100 #define SBDF_GLYPH 0x01100 struct SBDF_Font* SBDF_FontLoad(const char *path) { FILE *f; int cnt, rd, tp; struct SBDF_Glyph g; size_t sz; char line[2049]; char word[2049]; char *v; unsigned char val; int state; struct SBDF_Font *res; res = NULL; f = fopen(path, "r"); if (f == NULL) goto SBDF_FontLoad_defer; state = SBDF_NULL; rd = cnt = sz = 0; while (fgets(line, 2049, f)) { if ((state&SBDF_CHARS) == 0) { sscanf(line, "%s", word); if (state == SBDF_PROPS) { if (strcmp(word, "ENDPROPERTIES") == 0) state = SBDF_NULL; } else { if (strcmp(word, "STARTPROPERTIES") == 0) state = SBDF_PROPS; else if (strcmp(word, "CHARS") == 0) state = SBDF_CHARS; } continue; } else { sscanf(line, "%s", word); if (cnt) { --cnt; continue; } if (strcmp(word, "ENCODING") == 0) { sscanf(line, "%*s %d", &tp); rd = (tp > -1 && tp < 256); continue; } if (strcmp(word, "DWIDTH") == 0) { sscanf(line, "%*s %d %d", &g.dx, &g.dy); continue; } if (strcmp(word, "BBX") == 0) { sscanf(line, "%*s %d %d %d %d", &g.bw, &g.bh, &g.bx, &g.by); if (rd) { sz += (g.bw+7) / 8 * g.bh; } continue; } if (strcmp(word, "BITMAP") == 0) { cnt = g.bh; continue; } } } fclose(f); res = SBDF_FontInit(sz); if (res == NULL) goto SBDF_FontLoad_defer; f = fopen(path, "r"); if (f == NULL) goto SBDF_FontLoad_defer; state = SBDF_NULL; rd = cnt = sz = 0; while (fgets(line, 2049, f)) { if ((state&SBDF_CHARS) == 0) { sscanf(line, "%s", word); if (state == SBDF_PROPS) { if (strcmp(word, "ENDPROPERTIES") == 0) state = SBDF_NULL; } else { if (strcmp(word, "STARTPROPERTIES") == 0) state = SBDF_PROPS; else if (strcmp(word, "CHARS") == 0) state = SBDF_CHARS; } continue; } else { sscanf(line, "%s", word); if (cnt) { --cnt; if (rd) { v = word; while (v[0] != '\0') { if (v[0] <= '9') val = (unsigned char)16*(v[0] - '0'); else val = (unsigned char)16*(v[0] - 'A' + 10); if (v[1] <= '9') val += (unsigned char)(v[1] - '0'); else val += (unsigned char)(v[1] - 'A' + 10); res->data[sz] = val; sz++; v += 2; } } continue; } if (strcmp(word, "ENCODING") == 0) { sscanf(line, "%*s %d", &tp); rd = (tp > -1 && tp < 256); continue; } if (strcmp(word, "DWIDTH") == 0) { sscanf(line, "%*s %d %d", &g.dx, &g.dy); continue; } if (strcmp(word, "BBX") == 0) { sscanf(line, "%*s %d %d %d %d", &g.bw, &g.bh, &g.bx, &g.by); continue; } if (strcmp(word, "BITMAP") == 0) { cnt = g.bh; if (rd) { g.s = sz; res->g[tp] = g; } continue; } } } return res; SBDF_FontLoad_defer: if (f != NULL) fclose(f); SBDF_FontDestroy(res); return NULL; } void SBDF_GetSize(const struct SBDF_Font *f, const char *text, int *tx, int *ty, int *w, int *h) { char *u; int minw, minh, maxw, maxh, x, y; x = y = minw = minh = maxw = maxh = 0; u = text; while (*u != '\0') { x += f->g[(unsigned char)*u].bx; y += f->g[(unsigned char)*u].by; minw = (minw < x) ? minw : x; minh = (minh < y) ? minh : y; maxw = (maxw > x + f->g[(unsigned char)*u].bw) ? maxw : (x + f->g[(unsigned char)*u].bw); maxh = (maxh > y + f->g[(unsigned char)*u].bh) ? maxh : (y + f->g[(unsigned char)*u].bh); x += f->g[(unsigned char)*u].dx - f->g[(unsigned char)*u].bx; y += f->g[(unsigned char)*u].dy - f->g[(unsigned char)*u].by; u++; } if (tx != NULL) *tx = minw; if (ty != NULL) *ty = minh; if (w != NULL) *w = maxw; if (h != NULL) *h = maxh; } #ifdef SBDF_USESDL void SBDF_SDLPrint(const SDL_Renderer *r, const struct SBDF_Font *f, const char *text, int x, int y) { char *u; unsigned char *v; int i, j; u = text; while (*u != '\0') { v = &f->data[f->g[(unsigned char)*u].s]; x += f->g[(unsigned char)*u].bx; y -= f->g[(unsigned char)*u].by + f->g[(unsigned char)*u].bh; for (i = 0; i < f->g[(unsigned char)*u].bh; i++) { for (j = 0; j < f->g[(unsigned char)*u].bw; j++) { if (v[j/8]>>(7-(j%8))&1) SDL_RenderDrawPoint(r, x+j, y+i); } v += (j + 7) / 8; } x += f->g[(unsigned char)*u].dx - f->g[(unsigned char)*u].bx; y += f->g[(unsigned char)*u].dy + f->g[(unsigned char)*u].by + f->g[(unsigned char)*u].bh; u++; } } #endif #endif