mirror of
https://github.com/nishiowo/nishbox
synced 2025-04-21 20:24:39 +00:00
179 lines
4.9 KiB
C
179 lines
4.9 KiB
C
#define GF_EXPOSE_FONT
|
|
|
|
#include <gf_pre.h>
|
|
|
|
/* External library */
|
|
|
|
/* Interface */
|
|
#include <gf_font.h>
|
|
|
|
/* Engine */
|
|
#include <gf_log.h>
|
|
#include <gf_texture.h>
|
|
|
|
/* Standard */
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
gf_font_glyph_t* gf_font_get(gf_font_t* font, int code) {
|
|
int i;
|
|
if(code < 0x20) return NULL;
|
|
for(i = 0; i < font->count; i++) {
|
|
if(font->glyph[i] != NULL && font->glyph[i]->code == code) {
|
|
return font->glyph[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#define gf_stat _stat
|
|
#else
|
|
#define gf_stat stat
|
|
#endif
|
|
|
|
GF_DECLARE_TYPE(font_store, {
|
|
int glyph_index;
|
|
int line_index;
|
|
unsigned char* buffer;
|
|
});
|
|
|
|
/**
|
|
* This is a private method to parse BDF line
|
|
*/
|
|
void gf_font_parse_line(gf_draw_t* draw, const char* path, gf_font_store_t* store, gf_font_t* font, char* line) {
|
|
int i;
|
|
char* args[32];
|
|
int argc = 0;
|
|
int incr = 0;
|
|
int dq = 0;
|
|
for(i = 0;; i++) {
|
|
if((dq == 0 && line[i] == ' ') || line[i] == 0) {
|
|
char oldc = line[i];
|
|
line[i] = 0;
|
|
|
|
args[argc] = line + incr;
|
|
if(args[argc][0] == '"') args[argc]++;
|
|
if(args[argc][strlen(args[argc]) - 1] == '"') args[argc][strlen(args[argc]) - 1] = 0;
|
|
|
|
argc++;
|
|
|
|
incr = i + 1;
|
|
|
|
if(oldc == 0) break;
|
|
} else if(line[i] == '"') {
|
|
dq = 1 - dq;
|
|
}
|
|
}
|
|
if(store->line_index != -1 && store->line_index < font->glyph[store->glyph_index]->bbox.height) {
|
|
int wid = font->glyph[store->glyph_index]->bbox.width;
|
|
unsigned char* linebuf = store->buffer + store->line_index * wid * 4;
|
|
for(i = 0; line[i] != 0; i++) {
|
|
int n = 0;
|
|
int j;
|
|
if('0' <= line[i] && line[i] <= '9') {
|
|
n = line[i] - '0';
|
|
} else if('a' <= line[i] && line[i] <= 'f') {
|
|
n = 10 + line[i] - 'a';
|
|
} else if('A' <= line[i] && line[i] <= 'F') {
|
|
n = 10 + line[i] - 'A';
|
|
}
|
|
for(j = 0; j < (wid > 4 ? 4 : wid); j++) {
|
|
if((n >> 3) & 1) {
|
|
memset(linebuf + 16 * i + 4 * j, 255, 4);
|
|
}
|
|
n = n << 1;
|
|
}
|
|
wid -= 4;
|
|
}
|
|
store->line_index++;
|
|
} else if(argc > 0 && strcmp(args[0], "STARTCHAR") == 0) {
|
|
font->glyph[store->glyph_index] = malloc(sizeof(**font->glyph));
|
|
memset(font->glyph[store->glyph_index], 0, sizeof(**font->glyph));
|
|
} else if(argc > 0 && strcmp(args[0], "ENDCHAR") == 0) {
|
|
font->glyph[store->glyph_index]->texture = gf_texture_create(draw, font->glyph[store->glyph_index]->bbox.width, font->glyph[store->glyph_index]->bbox.height, store->buffer);
|
|
free(store->buffer);
|
|
store->glyph_index++;
|
|
store->line_index = -1;
|
|
} else if(argc > 0 && strcmp(args[0], "BITMAP") == 0) {
|
|
store->line_index = 0;
|
|
} else if(argc == 2) {
|
|
if(strcmp(args[0], "COPYRIGHT") == 0) {
|
|
gf_log_function(NULL, "%s: %s", path, args[1]);
|
|
} else if(strcmp(args[0], "NOTICE") == 0) {
|
|
gf_log_function(NULL, "%s: %s", path, args[1]);
|
|
} else if(strcmp(args[0], "FOUNDRY") == 0) {
|
|
gf_log_function(NULL, "%s: Made by %s", path, args[1]);
|
|
} else if(strcmp(args[0], "CHARS") == 0) {
|
|
int j;
|
|
gf_log_function(NULL, "%s: %s characters", path, args[1]);
|
|
font->count = atoi(args[1]);
|
|
font->glyph = malloc(font->count * sizeof(*font->glyph));
|
|
for(j = 0; j < font->count; j++) font->glyph[j] = NULL;
|
|
} else if(strcmp(args[0], "ENCODING") == 0) {
|
|
font->glyph[store->glyph_index]->code = atoi(args[1]);
|
|
}
|
|
} else if(argc == 3) {
|
|
if(strcmp(args[0], "DWIDTH") == 0) {
|
|
font->glyph[store->glyph_index]->dwidth[0] = atoi(args[1]);
|
|
font->glyph[store->glyph_index]->dwidth[1] = atoi(args[2]);
|
|
}
|
|
} else if(argc == 5) {
|
|
if(strcmp(args[0], "FONTBOUNDINGBOX") == 0) {
|
|
font->bbox.width = atoi(args[1]);
|
|
font->bbox.height = atoi(args[2]);
|
|
font->bbox.x = atoi(args[3]);
|
|
font->bbox.y = atoi(args[4]);
|
|
} else if(strcmp(args[0], "BBX") == 0) {
|
|
font->glyph[store->glyph_index]->bbox.width = atoi(args[1]);
|
|
font->glyph[store->glyph_index]->bbox.height = atoi(args[2]);
|
|
font->glyph[store->glyph_index]->bbox.x = atoi(args[3]);
|
|
font->glyph[store->glyph_index]->bbox.y = atoi(args[4]);
|
|
|
|
store->buffer = malloc(atoi(args[1]) * atoi(args[2]) * 4);
|
|
memset(store->buffer, 0, atoi(args[1]) * atoi(args[2]) * 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
gf_font_t* gf_font_create(gf_draw_t* draw, const char* path) {
|
|
gf_font_t* font = malloc(sizeof(*font));
|
|
struct gf_stat s;
|
|
char* buf;
|
|
FILE* f;
|
|
int i = 0;
|
|
int incr = 0;
|
|
gf_font_store_t store;
|
|
store.line_index = -1;
|
|
store.glyph_index = 0;
|
|
memset(font, 0, sizeof(*font));
|
|
if(gf_stat(path, &s) != 0) {
|
|
free(font);
|
|
return NULL;
|
|
}
|
|
gf_log_function(NULL, "%s: %lu bytes", path, (unsigned long)s.st_size);
|
|
buf = malloc(s.st_size + 1);
|
|
buf[s.st_size] = 0;
|
|
f = fopen(path, "r");
|
|
fread(buf, s.st_size, 1, f);
|
|
fclose(f);
|
|
|
|
for(i = 0;; i++) {
|
|
if(buf[i] == 0 || buf[i] == '\n') {
|
|
char oldc = buf[i];
|
|
char* line = buf + incr;
|
|
buf[i] = 0;
|
|
incr = i + 1;
|
|
|
|
gf_font_parse_line(draw, path, &store, font, line);
|
|
|
|
if(oldc == 0) break;
|
|
}
|
|
}
|
|
|
|
free(buf);
|
|
return font;
|
|
}
|