ffff
This commit is contained in:
parent
7552d2fa2a
commit
4b6f76b6c8
@ -6,6 +6,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cache.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -49,7 +50,7 @@ void cache_destroy(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct font_glyph * cache_get(unsigned int code)
|
const struct font_glyph * cache_search(unsigned int code)
|
||||||
{
|
{
|
||||||
struct hm_entry *r = hm_search(hash_table, code);
|
struct hm_entry *r = hm_search(hash_table, code);
|
||||||
|
|
||||||
@ -63,21 +64,28 @@ struct font_glyph * cache_get(unsigned int code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int cache_insert(struct font_glyph *g)
|
// return the first free spot into the cache
|
||||||
|
unsigned int cache_get(void)
|
||||||
{
|
{
|
||||||
struct font_glyph *spot = NULL;
|
|
||||||
uint32_t x = 0;
|
uint32_t x = 0;
|
||||||
// find an open spot in the cache
|
// find an open spot in the cache
|
||||||
// TODO: use __builtin_clz to speed this up
|
// TODO: use __builtin_clz to speed this up
|
||||||
for (; x < CACHE_SIZE; x++) {
|
for (; x < CACHE_SIZE; x++) {
|
||||||
// printf("test: %d\n", x);
|
|
||||||
if (!B_TEST(x))
|
if (!B_TEST(x))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// inserts the font glyph into the cache
|
||||||
|
const struct font_glyph * cache_insert(struct font_glyph *g, unsigned int x)
|
||||||
|
{
|
||||||
|
struct font_glyph *spot = NULL;
|
||||||
|
|
||||||
// allocation in cache failed
|
// allocation in cache failed
|
||||||
if (B_TEST(x))
|
if (B_TEST(x))
|
||||||
return -1;
|
return NULL;
|
||||||
|
|
||||||
set_bit(x);
|
set_bit(x);
|
||||||
spot = &cache_array[x];
|
spot = &cache_array[x];
|
||||||
@ -100,7 +108,7 @@ int cache_insert(struct font_glyph *g)
|
|||||||
|
|
||||||
struct hm_entry e = { .code = g->codepoint, .data = spot};
|
struct hm_entry e = { .code = g->codepoint, .data = spot};
|
||||||
if (!hm_insert(hash_table, &e))
|
if (!hm_insert(hash_table, &e))
|
||||||
return -1;
|
return NULL;
|
||||||
|
|
||||||
return 0;
|
return spot;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#ifndef _CACHE_H
|
#ifndef _CACHE_H
|
||||||
#define _CACHE_H
|
#define _CACHE_H
|
||||||
|
|
||||||
|
#define CACHE_SIZE 512
|
||||||
|
|
||||||
void cache_init(void);
|
void cache_init(void);
|
||||||
void cache_destroy(void);
|
void cache_destroy(void);
|
||||||
struct font_glyph * cache_get(unsigned int code);
|
const struct font_glyph * cache_search(unsigned int code);
|
||||||
int cache_insert(struct font_glyph *g);
|
unsigned int cache_get(void);
|
||||||
|
const struct font_glyph * cache_insert(struct font_glyph *g, unsigned int idx);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
#define _POSIX_C_SOURCE 200809l
|
#define _POSIX_C_SOURCE 200809l
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
#define STBTT_STATIC
|
#define STBTT_STATIC
|
||||||
|
#define MSDF_IMPLEMENTATION
|
||||||
|
|
||||||
#include <grapheme.h>
|
#include <grapheme.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "font.h"
|
||||||
#include "msdf_c/stb_truetype.h"
|
#include "msdf_c/stb_truetype.h"
|
||||||
#include "msdf_c/msdf.h"
|
#include "msdf_c/msdf.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "font.h"
|
#include "cache.h"
|
||||||
|
|
||||||
|
|
||||||
#define UTF8(c) (c&0x80)
|
#define UTF8(c) (c&0x80)
|
||||||
|
#define BDEPTH 3
|
||||||
|
#define BORDER 4
|
||||||
|
|
||||||
// Generates a cached atlas of font glyphs encoded usign a signed distance field
|
// Generates a cached atlas of font glyphs encoded usign a signed distance field
|
||||||
// https://www.youtube.com/watch?v=1b5hIMqz_wM
|
// https://www.youtube.com/watch?v=1b5hIMqz_wM
|
||||||
@ -21,13 +25,16 @@
|
|||||||
|
|
||||||
|
|
||||||
struct font_atlas {
|
struct font_atlas {
|
||||||
unsigned int glyphs;
|
unsigned int glyphs, width, height;
|
||||||
unsigned char *atlas;
|
unsigned char *atlas;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
stbtt_fontinfo info;
|
stbtt_fontinfo stb;
|
||||||
|
msdf_AllocCtx ctx;
|
||||||
|
msdf_Result msdf;
|
||||||
float scale;
|
float scale;
|
||||||
} stb;
|
} priv;
|
||||||
|
|
||||||
int file_size;
|
int file_size;
|
||||||
unsigned char *file;
|
unsigned char *file;
|
||||||
};
|
};
|
||||||
@ -37,34 +44,115 @@ const unsigned int glyph_w = 32;
|
|||||||
const unsigned int glyph_h = 32;
|
const unsigned int glyph_h = 32;
|
||||||
|
|
||||||
|
|
||||||
|
// only useful for msdf_c
|
||||||
|
static inline void * _emalloc(size_t x, void *_) { (void)_; return emalloc(x); }
|
||||||
|
static inline void _efree(void *x, void *_) { (void)_; efree(x); }
|
||||||
|
|
||||||
|
|
||||||
// loads a font into memory, storing all the ASCII characters in the atlas
|
// loads a font into memory, storing all the ASCII characters in the atlas
|
||||||
int load_font(struct font_atlas *atlas, const char *path, int height)
|
int font_load(struct font_atlas *atlas, const char *path, int height)
|
||||||
{
|
{
|
||||||
if (!atlas || !path)
|
if (!atlas || !path)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dump_file(path, &(atlas->file), &(atlas->file_size));
|
dump_file(path, &(atlas->file), &(atlas->file_size));
|
||||||
|
|
||||||
stbtt_InitFont(&(atlas->stb.info), atlas->file, 0);
|
stbtt_InitFont(&(atlas->priv.stb), atlas->file, 0);
|
||||||
atlas->stb.scale = stbtt_ScaleForPixelHeight(&(atlas->stb.info), height);
|
atlas->priv.scale = stbtt_ScaleForPixelHeight(&(atlas->priv.stb), height);
|
||||||
int ascent, descent, linegap, baseline;
|
int ascent, descent, linegap, baseline;
|
||||||
int x0,y0,x1,y1;
|
int x0,y0,x1,y1;
|
||||||
stbtt_GetFontVMetrics(&(atlas->stb.info), &ascent, &descent, &linegap);
|
stbtt_GetFontVMetrics(&(atlas->priv.stb), &ascent, &descent, &linegap);
|
||||||
stbtt_GetFontBoundingBox(&(atlas->stb.info), &x0, &y0, &x1, &y1);
|
stbtt_GetFontBoundingBox(&(atlas->priv.stb), &x0, &y0, &x1, &y1);
|
||||||
|
|
||||||
baseline = atlas->stb.scale * -y0;
|
baseline = atlas->priv.scale * -y0;
|
||||||
//atlas->glyph_max_w = (atlas->stb.scale*x1) - (atlas->stb.scale*x0);
|
//atlas->glyph_max_w = (atlas->priv.scale*x1) - (atlas->priv.scale*x0);
|
||||||
//atlas->glyph_max_h = (baseline+atlas->stb.scale*y1) - (baseline+atlas->stb.scale*y0);
|
//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 = emalloc(atlas->glyph_max_w*atlas->glyph_max_h*CACHE_SIZE);
|
||||||
atlas->atlas
|
atlas->atlas = ecalloc(CACHE_SIZE, BDEPTH*glyph_h*glyph_w);
|
||||||
|
atlas->width = glyph_w*CACHE_SIZE;
|
||||||
|
atlas->height = glyph_h*CACHE_SIZE;
|
||||||
|
|
||||||
|
atlas->priv.ctx = (msdf_AllocCtx){_emalloc, _efree, NULL};
|
||||||
|
|
||||||
|
cache_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int free_font(struct font_atlas *atlas)
|
int font_free(struct font_atlas *atlas)
|
||||||
{
|
{
|
||||||
efree(atlas->atlas);
|
efree(atlas->atlas);
|
||||||
efree(atlas->file);
|
efree(atlas->file);
|
||||||
return 0;
|
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)
|
||||||
|
{
|
||||||
|
unsigned char *a = 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++) {
|
||||||
|
|
||||||
|
int i = yPos + (x * 3);
|
||||||
|
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);
|
||||||
|
b = (b + s) / (s * 2.0f);
|
||||||
|
|
||||||
|
NORMALIZE(r);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return spot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#ifndef _FONT_H
|
#ifndef _FONT_H
|
||||||
#define _FONT_H
|
#define _FONT_H
|
||||||
|
|
||||||
#define CACHE_SIZE 512
|
|
||||||
|
|
||||||
/* width and height of a glyph contain the kering advance
|
/* width and height of a glyph contain the kering advance
|
||||||
* (u,v)
|
* (u,v)
|
||||||
@ -28,13 +27,7 @@ struct font_glyph {
|
|||||||
|
|
||||||
struct font_atlas;
|
struct font_atlas;
|
||||||
|
|
||||||
int load_font(struct font_atlas *atlas, const char *path, int height);
|
int font_load(struct font_atlas *atlas, const char *path, int height);
|
||||||
int free_font(struct font_atlas *atlas);
|
int font_free(struct font_atlas *atlas);
|
||||||
|
|
||||||
void cache_init(void);
|
|
||||||
void cache_destroy(void);
|
|
||||||
struct font_glyph * cache_get(unsigned int code);
|
|
||||||
int cache_insert(struct font_glyph *g);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.19)
|
|
||||||
project(engine)
|
|
||||||
|
|
||||||
add_definitions(-DSAMPLE_ROOT="${PROJECT_SOURCE_DIR}/sample")
|
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
|
||||||
|
|
||||||
add_executable(msdf_sample sample/sample.c)
|
|
@ -1,22 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2023 Peter Jakobs
|
|
||||||
Copyright (c) 2018 exezin
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
Loading…
Reference in New Issue
Block a user