something
This commit is contained in:
parent
4b6f76b6c8
commit
9136eaa54f
7
text_rendering/Makefile
Normal file
7
text_rendering/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
LDFLAGS = -lm -lgrapheme
|
||||
CFLAGS = -g -Wall -Wextra -pedantic
|
||||
SOURCE = main.c font.c cache.c hash.c util.c
|
||||
HEADER = font.h hash.h cache.h util.h
|
||||
|
||||
test: ${HEADER} ${SOURCE}
|
||||
gcc ${CFLAGS} ${LDFLAGS} ${SOURCE} -o test
|
BIN
text_rendering/atlas.png
Normal file
BIN
text_rendering/atlas.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 20 KiB |
@ -79,7 +79,7 @@ unsigned int cache_get(void)
|
||||
|
||||
|
||||
// inserts the font glyph into the cache
|
||||
const struct font_glyph * cache_insert(struct font_glyph *g, unsigned int x)
|
||||
const struct font_glyph * cache_insert(const struct font_glyph *g, unsigned int x)
|
||||
{
|
||||
struct font_glyph *spot = NULL;
|
||||
|
||||
|
@ -7,7 +7,7 @@ void cache_init(void);
|
||||
void cache_destroy(void);
|
||||
const struct font_glyph * cache_search(unsigned int code);
|
||||
unsigned int cache_get(void);
|
||||
const struct font_glyph * cache_insert(struct font_glyph *g, unsigned int idx);
|
||||
const struct font_glyph * cache_insert(const struct font_glyph *g, unsigned int idx);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STBTT_STATIC
|
||||
#define MSDF_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include <grapheme.h>
|
||||
#include <assert.h>
|
||||
@ -9,6 +10,7 @@
|
||||
#include "font.h"
|
||||
#include "msdf_c/stb_truetype.h"
|
||||
#include "msdf_c/msdf.h"
|
||||
#include "stb_image_write.h"
|
||||
#include "util.h"
|
||||
#include "cache.h"
|
||||
|
||||
@ -49,28 +51,39 @@ static inline void * _emalloc(size_t x, void *_) { (void)_; return emalloc(x); }
|
||||
static inline void _efree(void *x, void *_) { (void)_; efree(x); }
|
||||
|
||||
|
||||
struct font_atlas * font_init(void)
|
||||
{
|
||||
return emalloc(sizeof(struct font_atlas));
|
||||
}
|
||||
|
||||
|
||||
// loads a font into memory, storing all the ASCII characters in the atlas
|
||||
int font_load(struct font_atlas *atlas, const char *path, int height)
|
||||
int font_load(struct font_atlas *atlas, const char *path)
|
||||
{
|
||||
if (!atlas || !path)
|
||||
return -1;
|
||||
|
||||
int err;
|
||||
|
||||
dump_file(path, &(atlas->file), &(atlas->file_size));
|
||||
|
||||
stbtt_InitFont(&(atlas->priv.stb), atlas->file, 0);
|
||||
atlas->priv.scale = stbtt_ScaleForPixelHeight(&(atlas->priv.stb), height);
|
||||
int ascent, descent, linegap, baseline;
|
||||
int x0,y0,x1,y1;
|
||||
stbtt_GetFontVMetrics(&(atlas->priv.stb), &ascent, &descent, &linegap);
|
||||
stbtt_GetFontBoundingBox(&(atlas->priv.stb), &x0, &y0, &x1, &y1);
|
||||
err = stbtt_InitFont(&(atlas->priv.stb), atlas->file, 0);
|
||||
ERROR(err == 0, -1);
|
||||
|
||||
baseline = atlas->priv.scale * -y0;
|
||||
atlas->priv.scale = stbtt_ScaleForPixelHeight(&(atlas->priv.stb), glyph_h);
|
||||
//int ascent, descent, linegap, baseline;
|
||||
//int x0,y0,x1,y1;
|
||||
//stbtt_GetFontVMetrics(&(atlas->priv.stb), &ascent, &descent, &linegap);
|
||||
//stbtt_GetFontBoundingBox(&(atlas->priv.stb), &x0, &y0, &x1, &y1);
|
||||
//baseline = atlas->priv.scale * -y0;
|
||||
//atlas->glyph_max_w = (atlas->priv.scale*x1) - (atlas->priv.scale*x0);
|
||||
//atlas->glyph_max_h = (baseline+atlas->priv.scale*y1) - (baseline+atlas->priv.scale*y0);
|
||||
//atlas->atlas = emalloc(atlas->glyph_max_w*atlas->glyph_max_h*CACHE_SIZE);
|
||||
|
||||
atlas->atlas = ecalloc(CACHE_SIZE, BDEPTH*glyph_h*glyph_w);
|
||||
atlas->width = glyph_w*CACHE_SIZE;
|
||||
atlas->height = glyph_h*CACHE_SIZE;
|
||||
memset(atlas->atlas, 0, CACHE_SIZE*BDEPTH*glyph_h*glyph_w);
|
||||
atlas->width = glyph_w*CACHE_SIZE/2;
|
||||
atlas->height = glyph_h*CACHE_SIZE/2;
|
||||
|
||||
atlas->priv.ctx = (msdf_AllocCtx){_emalloc, _efree, NULL};
|
||||
|
||||
@ -84,36 +97,60 @@ int font_free(struct font_atlas *atlas)
|
||||
{
|
||||
efree(atlas->atlas);
|
||||
efree(atlas->file);
|
||||
efree(atlas);
|
||||
cache_destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: when generating the sdf I only use the height, so to not encounter memory
|
||||
// errors height and width must be equal
|
||||
static unsigned int insert(struct font_atlas *atlas)
|
||||
const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code)
|
||||
{
|
||||
unsigned char *a = atlas->atlas;
|
||||
msdf_Result res = atlas->priv.msdf;
|
||||
const struct font_glyph *r;
|
||||
if ((r = cache_search(code)) != NULL)
|
||||
return r;
|
||||
|
||||
// generate the sdf and put it into the cache
|
||||
// TODO: generate the whole block at once
|
||||
int idx = stbtt_FindGlyphIndex(&atlas->priv.stb, code);
|
||||
// FIXME: what happens if I change the range?
|
||||
int err;
|
||||
err = msdf_genGlyph(&atlas->priv.msdf,
|
||||
&atlas->priv.stb,
|
||||
idx,
|
||||
BORDER,
|
||||
atlas->priv.scale,
|
||||
2.0f/glyph_h,
|
||||
&atlas->priv.ctx);
|
||||
if (!err)
|
||||
return NULL;
|
||||
|
||||
|
||||
unsigned int spot = cache_get();
|
||||
unsigned int oy = (glyph_h * spot) / atlas->width;
|
||||
unsigned int ox = (glyph_h * spot) % atlas->height;
|
||||
unsigned int w = atlas->width;
|
||||
|
||||
// sum magic shit
|
||||
struct {unsigned char r,g,b;} *a = (void *)atlas->atlas;
|
||||
msdf_Result *res = &atlas->priv.msdf;
|
||||
float s = glyph_h;
|
||||
float tw = ((s * 0.7f) + s) / (s * 2.0f);
|
||||
float ta = tw - 0.5f;
|
||||
float ts = 0.5 - ta / 2;
|
||||
float te = ts + ta;
|
||||
|
||||
unsigned int spot = cache_get();
|
||||
unsigned int off = spot * glyph_h * glyph_w * BDEPTH;
|
||||
|
||||
#define NORMALIZE(x) x = x > ts ? (x > te ? 1.0f : (x-ts)/ta+0.0f) : (0.0f)
|
||||
|
||||
for (int y = 0; y < res.height; y++) {
|
||||
int yPos = res.width * 3 * y;
|
||||
for (int x = 0; x < res.width; x++) {
|
||||
for (int y = 0; y < res->height; y++) {
|
||||
int yPos = res->width * 3 * y;
|
||||
for (int x = 0; x < res->width; x++) {
|
||||
|
||||
int i = yPos + (x * 3);
|
||||
float r = res.rgb[i+0];
|
||||
float g = res.rgb[i+1];
|
||||
float b = res.rgb[i+2];
|
||||
float r = res->rgb[i+0];
|
||||
float g = res->rgb[i+1];
|
||||
float b = res->rgb[i+2];
|
||||
|
||||
r = (r + s) / (s * 2.0f);
|
||||
g = (g + s) / (s * 2.0f);
|
||||
@ -123,36 +160,31 @@ static unsigned int insert(struct font_atlas *atlas)
|
||||
NORMALIZE(g);
|
||||
NORMALIZE(b);
|
||||
|
||||
a[off + glyph_w*y + x + 0] = r * 255.0f; // (r > 0.5f) ? 255.0f : r * 255.0f;
|
||||
a[off + glyph_w*y + x + 0] = g * 255.0f; // (g > 0.5f) ? 255.0f : g * 255.0f;
|
||||
a[off + glyph_w*y + x + 0] = b * 255.0f; // (b > 0.5f) ? 255.0f : b * 255.0f;
|
||||
a[(oy+y)*w + (ox+x)].r = r * 255.0f; // (r > 0.5f) ? 255.0f : r * 255.0f;
|
||||
a[(oy+y)*w + (ox+x)].g = g * 255.0f; // (g > 0.5f) ? 255.0f : g * 255.0f;
|
||||
a[(oy+y)*w + (ox+x)].b = b * 255.0f; // (b > 0.5f) ? 255.0f : b * 255.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return spot;
|
||||
struct font_glyph g = {
|
||||
.codepoint = code,
|
||||
.u = ox,
|
||||
.v = oy,
|
||||
.w = res->width,
|
||||
.h = res->height,
|
||||
};
|
||||
return cache_insert(&g, spot);
|
||||
}
|
||||
|
||||
|
||||
struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code)
|
||||
void font_dump(const struct font_atlas *atlas, const char *path)
|
||||
{
|
||||
struct font_glyph *r;
|
||||
if ((r = cache_search(code)) != NULL)
|
||||
return r;
|
||||
|
||||
// generate the sdf and put it into the cache
|
||||
// TODO: generate the whole block at once
|
||||
int idx = stbtt_FindGlyphIndex(&atlas->priv.stb, code);
|
||||
// FIXME: what happens if I change the range?
|
||||
int s;
|
||||
s = msdf_genGlyph(&atlas->priv.msdf,
|
||||
&atlas->priv.stb,
|
||||
idx,
|
||||
BORDER,
|
||||
atlas->priv.scale,
|
||||
2.0f/glyph_h,
|
||||
&atlas->priv.ctx);
|
||||
if (!s)
|
||||
return NULL;
|
||||
unsigned int spot = insert(atlas);
|
||||
|
||||
stbi_write_png(
|
||||
path,
|
||||
//atlas->width,
|
||||
//atlas->height,
|
||||
128, 128,
|
||||
BDEPTH,
|
||||
atlas->atlas,
|
||||
BDEPTH*atlas->width);
|
||||
}
|
||||
|
@ -27,7 +27,10 @@ struct font_glyph {
|
||||
|
||||
struct font_atlas;
|
||||
|
||||
int font_load(struct font_atlas *atlas, const char *path, int height);
|
||||
struct font_atlas * font_init(void);
|
||||
int font_load(struct font_atlas *atlas, const char *path);
|
||||
int font_free(struct font_atlas *atlas);
|
||||
const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code);
|
||||
void font_dump(const struct font_atlas *atlas, const char *path);
|
||||
|
||||
#endif
|
||||
|
@ -4,32 +4,30 @@
|
||||
|
||||
#include "cache.h"
|
||||
#include "font.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
cache_init();
|
||||
int err;
|
||||
struct font_atlas *at = font_init();
|
||||
err = font_load(at, "./monospace.ttf");
|
||||
ERROR(err, -1, printf("failed to load font\n"));
|
||||
|
||||
struct font_glyph *g, b;
|
||||
b.codepoint = 'a';
|
||||
b.u = b.v = 10;
|
||||
b.w = b.h = 20;
|
||||
|
||||
g = cache_get('a');
|
||||
if (!g) printf("no element\n");
|
||||
g = cache_get(0xa3c0);
|
||||
if (!g) printf("not present\n");
|
||||
|
||||
const char *s = "κόσμε ciao mamma @à``²`²aas³³²";
|
||||
const char *s = "ciao mamma";
|
||||
const struct font_glyph *g;
|
||||
size_t ret, off;
|
||||
uint_least32_t cp;
|
||||
for (off = 0; (ret = grapheme_decode_utf8(s+off, SIZE_MAX, &cp)) > 0 && cp != 0; off += ret) {
|
||||
printf("%.*s (%d) -> %d\n", (int)ret, s+off, (int)ret, cp);
|
||||
b.codepoint = cp;
|
||||
if (cache_insert(&b)) printf("failed insert %d\n", b.codepoint);
|
||||
if ((g = cache_get(cp))) printf("got %d\n", g->codepoint);
|
||||
g = font_get_glyph_texture(at, cp);
|
||||
if (!g)
|
||||
printf("g is NULL\n");
|
||||
}
|
||||
|
||||
cache_destroy();
|
||||
font_dump(at, "./atlas.png");
|
||||
|
||||
font_free(at);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
BIN
text_rendering/monospace.ttf
Normal file
BIN
text_rendering/monospace.ttf
Normal file
Binary file not shown.
1724
text_rendering/stb_image_write.h
Normal file
1724
text_rendering/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -83,10 +83,13 @@ void dump_file(const char *path, unsigned char **buf, int *buf_len)
|
||||
if (!fp)
|
||||
err(EXIT_FAILURE, "Cannot open file %s", path);
|
||||
*buf_len = lseek(fileno(fp), 0, SEEK_END);
|
||||
rewind(fp);
|
||||
if (*buf_len == (off_t)-1)
|
||||
err(EXIT_FAILURE, "lseek() failed");
|
||||
*buf = emalloc(*buf_len);
|
||||
*buf_len = fread(*buf, 1, *buf_len, fp);
|
||||
int ret = fread(*buf, 1, *buf_len, fp);
|
||||
if (ret != *buf_len)
|
||||
err(EXIT_FAILURE, "fread() returned short %s", ferror(fp) ? "stream error" : feof(fp) ? "EOF reached" : "unknown error");
|
||||
if (fclose(fp))
|
||||
err(EXIT_FAILURE, "Error closing file");
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
#ifndef _UTIL_H
|
||||
#define _UTIL_H
|
||||
|
||||
|
||||
#define ERROR(expr, ret, ...) if (expr) { __VA_ARGS__; return ret; }
|
||||
|
||||
|
||||
void * emalloc(unsigned long int size);
|
||||
void * ecalloc(unsigned long int nmemb, unsigned long int size);
|
||||
void efree(void *ptr);
|
||||
|
Loading…
Reference in New Issue
Block a user