/* BDF simple reader and printer (ASCII Support only) include stdio.h stddef.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 *); #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; }; 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].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; } #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[*u].s]; x += f->g[*u].bx; y += f->g[*u].by; for (i = 0; i < f->g[*u].bh; i++) { for (j = 0; j < f->g[*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[*u].dx - f->g[*u].bx; y += f->g[*u].dy - f->g[*u].by; u++; } } #endif #endif