diff --git a/text_rendering/font.c b/text_rendering/font.c index 076452b..575d34e 100644 --- a/text_rendering/font.c +++ b/text_rendering/font.c @@ -11,7 +11,6 @@ #include "stb_image_write.h" #include "util.h" -// generic cache type #include "generic_cache.h" static inline unsigned int hash(unsigned int code) { @@ -106,8 +105,8 @@ int font_free(struct font_atlas *atlas) } -// FIXME: when generating the sdf I only use the height, so to not encounter memory -// errors height and width must be equal +// TODO: time and take the median of the time it takes to generate the cache and +// the time it takes to draw the glyph const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code, int *updated) { int _u = 0; diff --git a/text_rendering/generic_cache.h b/text_rendering/generic_cache.h index 8640881..222426b 100644 --- a/text_rendering/generic_cache.h +++ b/text_rendering/generic_cache.h @@ -22,55 +22,53 @@ } -#define CACHE_DECL(cachename, type, hashfn, cmpfn) \ -HASH_DECL(cachename##table, unsigned int, void *, hashfn, cmpfn) \ -struct cachename { \ - struct cachename##table_ref *table; \ +#define CACHE_DECL(name, type, hashfn, cmpfn) \ +HASH_DECL(name##table, uint32_t, void *, hashfn, cmpfn) \ +struct name { \ + struct name##table_ref *table; \ type *array; \ uint64_t *bitmap; \ int cycles; \ }; \ \ \ -struct cachename cachename##_init(void) \ +struct name name##_init(void) \ { \ - struct cachename##table_ref *t = cachename##table_create(CACHE_SIZE); \ + struct name##table_ref *t = name##table_create(CACHE_SIZE); \ type *a = malloc(sizeof(type)*CACHE_SIZE); \ uint64_t *b = malloc(sizeof(uint64_t)*CACHE_BSIZE); \ CACHE_BRESET(b); \ - return (struct cachename){ .table = t, .array = a, .bitmap = b, 0}; \ + return (struct name){ .table = t, .array = a, .bitmap = b, 0}; \ } \ \ \ -void cachename##_free(struct cachename *cache) \ +void name##_free(struct name *cache) \ { \ if (cache) { \ - cachename##table_destroy(cache->table); \ + name##table_destroy(cache->table); \ free(cache->array); \ free(cache->bitmap); \ } \ } \ \ \ -const type * cachename##_search(struct cachename *cache, unsigned int code) \ +const type * name##_search(struct name *cache, uint32_t code) \ { \ - if (!cache) \ - return NULL; \ - struct cachename##table_entry *r; \ - r = cachename##table_search(cache->table, code); \ + if (!cache) return NULL; \ + struct name##table_entry *r; \ + r = name##table_search(cache->table, code); \ /* MISS */ \ - if (!r) \ + if (!r || !cmpfn(code, r->code)) \ return NULL; \ - /* HIT */ \ - CACHE_SET(cache, (type *)(r->data)-cache->array); \ + /* HIT, set as recently used */ \ + CACHE_SET(cache, (type *)(r->data)-(cache->array)); \ return (const type *)(r->data); \ } \ \ \ -int cachename##_get(struct cachename *cache) \ +int name##_get(struct name *cache) \ { \ - if (!cache) \ - return -1; \ + if (!cache) return -1; \ int x = 0; \ for (int b = 0; b < CACHE_BSIZE; b++) { \ if (cache->bitmap[b] == 0) x = 64; \ @@ -83,10 +81,9 @@ int cachename##_get(struct cachename *cache) \ } \ \ \ -const type * cachename##_insert(struct cachename *cache, const type *g, unsigned int code, int x) \ +const type * name##_insert(struct name *cache, const type *g, uint32_t code, int x)\ { \ - if (!cache) \ - return NULL; \ + if (!cache) return NULL; \ type *spot = NULL; \ /* x is the index to the cache array, it has to come from the user */ \ /* check if the spot is free */ \ @@ -95,8 +92,8 @@ const type * cachename##_insert(struct cachename *cache, const type *g, unsigned CACHE_SET(cache, x) \ spot = &(cache->array[x]); \ *spot = *g; \ - struct cachename##table_entry e = { .code = code, .data = spot}; \ - if (!cachename##table_insert(cache->table, &e)) \ + struct name##table_entry e = { .code = code, .data = spot}; \ + if (!name##table_insert(cache->table, &e)) \ return NULL; \ return spot; \ } \ diff --git a/text_rendering/generic_hash.h b/text_rendering/generic_hash.h index 639e7fc..50a83ec 100644 --- a/text_rendering/generic_hash.h +++ b/text_rendering/generic_hash.h @@ -3,35 +3,36 @@ #include #include +#include #define HASH_MAXSIZE 4096 // for fibonacci hashing, 2^{32,64}/ -#define HASH_RATIO32 (unsigned int)2654435769u -#define HASH_RATIO64 (unsigned long long int)11400714819322457583u +#define HASH_RATIO32 ((uint64_t)2654435769u) +#define HASH_RATIO64 ((uint64_t)11400714819322457583u) // salt for string hashing -#define HASH_STRSALT 0xbabb0cac +#define HASH_SALT ((uint64_t)0xbabb0cac) /* Ready-made compares */ -static inline int hash_cmp_u32(unsigned int a, unsigned int b) { return a == b; } -static inline int hash_cmp_u64(unsigned long long int a, unsigned long long int b) { return a == b; } +static inline int hash_cmp_u32(uint32_t a, uint32_t b) { return a == b; } +static inline int hash_cmp_u64(uint64_t a, uint64_t b) { return a == b; } static inline int hash_cmp_str(const char *a, const char *b) { return strcmp(a, b) == 0; } /* Ready-made hashes */ -static inline unsigned int hash_u64(unsigned long long int c) +static inline uint32_t hash_u64(uint64_t c) { - return (unsigned long long int)((unsigned long long int)(c*HASH_RATIO64)>>32); + return (uint64_t)((((uint64_t)c+HASH_SALT)*HASH_RATIO64)>>32); } -static inline unsigned int hash_u32(unsigned int c) +static inline uint32_t hash_u32(uint32_t c) { - return (unsigned int)((unsigned long long int)(c*HASH_RATIO32)>>32); + return (uint32_t)((((uint64_t)c<<31)*HASH_RATIO64)>>32); } -static inline unsigned int hash_str(const char *s) +static inline uint32_t hash_str(const char *s) { - unsigned int h = HASH_STRSALT; - const unsigned char *v = (const unsigned char *)(s); + uint32_t h = HASH_SALT; + const uint8_t *v = (const uint8_t *)(s); for (int x = *s; x; x--) { h += v[x-1]; h += h << 10; @@ -44,74 +45,75 @@ static inline unsigned int hash_str(const char *s) } -#define HASH_DECL(hashname, codetype, datatype, hashfn, cmpfn) \ -struct hashname##_entry { \ +#define HASH_DECL(htname, codetype, datatype, hashfn, cmpfn) \ +struct htname##_entry { \ codetype code; \ datatype data; \ }; \ \ -struct hashname##_ref { \ - unsigned int items, size; \ - struct hashname##_entry bucket[]; \ +struct htname##_ref { \ + uint32_t items, size, exp; \ + struct htname##_entry bucket[]; \ }; \ \ \ -struct hashname##_ref * hashname##_create(unsigned int size) \ +struct htname##_ref * htname##_create(uint32_t size) \ { \ if (!size || size > HASH_MAXSIZE) \ return NULL; \ /* round to the greater power of two */ \ /* FIXME: check for intger overflow here */ \ - size = 1<<__builtin_clz(size); \ + uint32_t exp = 32-__builtin_clz(size-1); \ + size = 1<<(exp); \ /* FIXME: check for intger overflow here */ \ - struct hashname##_ref *ht = malloc(sizeof(struct hashname##_ref)+sizeof(struct hashname##_entry)*size); \ + struct htname##_ref *ht = malloc(sizeof(struct htname##_ref)+sizeof(struct htname##_entry)*size); \ if (ht) { \ ht->items = 0; \ ht->size = size; \ - memset(ht->bucket, 0, sizeof(struct hashname##_entry)*size); \ + ht->exp = exp; \ + memset(ht->bucket, 0, sizeof(struct htname##_entry)*size); \ } \ return ht; \ } \ \ \ -void hashname##_destroy(struct hashname##_ref *ht) \ +void htname##_destroy(struct htname##_ref *ht) \ { \ - if (ht) \ - free(ht); \ + if (ht) free(ht); \ } \ \ \ -static struct hashname##_entry * hashname##lookup(struct hashname##_ref *ht, codetype code) \ +static uint32_t htname##_lookup(struct htname##_ref *ht, uint32_t hash, uint32_t idx) \ { \ - if (!ht) \ - return NULL; \ - /* fast modulo operation for power-of-2 size */ \ - unsigned int mask = ht->size - 1; \ - unsigned int i = hashfn(code); \ - for (unsigned int j = 1; ; i += j++) { \ - if (!ht->bucket[i&mask].code || cmpfn(ht->bucket[i].code, code)) \ - return &(ht->bucket[i&mask]); \ - } \ - return NULL; \ + if (!ht) return 0; \ + uint32_t mask = ht->size-1; \ + uint32_t step = (hash >> (32 - ht->exp)) | 1; \ + return (idx + step) & mask; \ } \ \ \ /* Find and return the element by code */ \ -struct hashname##_entry * hashname##_search(struct hashname##_ref *ht, codetype code) \ +struct htname##_entry * htname##_search(struct htname##_ref *ht, codetype code)\ { \ - if (!ht) \ - return NULL; \ - struct hashname##_entry *r = hashname##lookup(ht, code); \ - if (r && cmpfn(r->code, code)) \ - return r; \ + if (!ht) return NULL; \ + uint32_t h = hashfn(code); \ + for (uint32_t i=h, x=0; ; x++) { \ + i = htname##_lookup(ht, h, i); \ + if (x > (ht->size<<1) || \ + !ht->bucket[i].code || \ + cmpfn(ht->bucket[i].code, code) \ + ) { \ + return &(ht->bucket[i]); \ + } \ + } \ return NULL; \ } \ \ \ /* FIXME: this simply overrides the found item */ \ -struct hashname##_entry * hashname##_insert(struct hashname##_ref *ht, struct hashname##_entry *entry) \ +struct htname##_entry * htname##_insert(struct htname##_ref *ht, struct htname##_entry *entry) \ { \ - struct hashname##_entry *r = hashname##lookup(ht, entry->code); \ + struct htname##_entry *r = htname##_search(ht, entry->code); \ if (r) { \ if (!r->code) \ ht->items++; \ @@ -121,24 +123,26 @@ struct hashname##_entry * hashname##_insert(struct hashname##_ref *ht, struct ha } \ \ \ + +#if 0 /* returns the number of removed items */ \ -int hashname##_remove(struct hashname##_ref *ht, codetype code) \ +int htname##_remove(struct htname##_ref *ht, codetype code) \ { \ if (!ht) \ return -1; \ - unsigned int mask = ht->size - 1; \ - unsigned int s = hashfn(code)&mask, inc = 0; \ - struct hashname##_entry *r; \ + uint32_t mask = ht->size - 1; \ + uint32_t s = hashfn(code)&mask, inc = 0; \ + struct htname##_entry *r; \ /* Flag for removal */ \ - while (ht->items > 0 && (r = hashname##lookup(ht, code)) && r->code) { \ + while (ht->items > 0 && (r = htname##lookup(ht, code)) && r->code) { \ /* FIXME: this cast may not work */ \ r->code = (codetype)(-1); \ ht->items--; \ } \ /* Remove */ \ - for (unsigned int i = s; i < ht->items; i++) { \ + for (uint32_t i = s; i < ht->items; i++) { \ if (ht->bucket[i].code == (codetype)(-1)) { \ - ht->bucket[i] = (struct hashname##_entry){0}; \ + ht->bucket[i] = (struct htname##_entry){0}; \ inc++; \ } \ } \ @@ -146,3 +150,5 @@ int hashname##_remove(struct hashname##_ref *ht, codetype code) \ } \ #endif + +#endif diff --git a/text_rendering/main.c b/text_rendering/main.c index a819dee..f5550d9 100644 --- a/text_rendering/main.c +++ b/text_rendering/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "ren.h" @@ -10,7 +11,12 @@ //const char *str1 = "Ciao Mamma!\nprova: òçà°ù§|¬³¼$£ì\t"; const char *str1 = "ciao\tmamma"; -const char *str2 = "gmt"; +const char *str2 = "The quick brown fox jumps over the lazy dog\n" + "чащах юга жил бы цитрус? Да, но фальшивый экземпляр!\n" + "Pijamalı hasta, yağız şoföre çabucak güvendi\n" + "Pchnąć w tę łódź jeża lub ośm skrzyń fig\n" + "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン\n" + "Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa"; SDL_Window *win; @@ -19,20 +25,31 @@ void draw(void) static unsigned int frame = 0; printf("frame: %d\n", frame++); ren_clear(); - ren_render_box(10, 10, 400, 50, 0xffff0000); - if (ren_render_text(str1, 10, 10, 400, 50, 20)) - printf("text: %s\n", ren_strerror()); + //ren_render_box(10, 10, 400, 50, 0xffff0000); + //if (ren_render_text(str1, 10, 10, 400, 50, 20)) + // printf("text: %s\n", ren_strerror()); int w, h; - ren_get_text_box(str2, &w, &h, 40); - printf("box for: %s -> (%d, %d)\n", str2, w, h); - ren_render_box(200, 40, w, h, 0xffff0000); - ren_render_text(str2, 200, 40, 300, 300, 40); + ren_get_text_box(str2, &w, &h, 20); + //printf("box for: %s -> (%d, %d)\n", str2, w, h); + ren_render_box(0, 0, w, h, 0xffff0000); + ren_render_text(str2, 0, 0, w, h, 20); + + // fixme: this causes a bug + const char *s = "ciao mamma"; + ren_get_text_box(s, &w, &h, 12); + s = "stuff that was not in font size 12 -> чащаx"; + ren_render_box(0, 200, w, h, 0xff0000ff); + if (ren_render_text(s, 0, 200, 0xffff, 0xffff, 12)) + printf("BUG\n"); + SDL_GL_SwapWindow(win); } int main(void) { + setlocale(LC_ALL, "en_US.UTF-8"); + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); @@ -50,13 +67,6 @@ int main(void) return 1; } - - int w, h; - const char *s = "ciao mamma"; - ren_get_text_box(s, &w, &h, 12); - printf("box for: %s -> (%d, %d)\n", s, w, h); - - SDL_Event e; while(1) { SDL_WaitEvent(&e); diff --git a/text_rendering/ren.c b/text_rendering/ren.c index 53e12db..29022ba 100644 --- a/text_rendering/ren.c +++ b/text_rendering/ren.c @@ -314,7 +314,7 @@ static int update_font_texture(int idx) GL_RED, GL_UNSIGNED_BYTE, ren.fonts[idx].font->atlas)) - font_dump(ren.fonts[idx].font, "./atlas.png"); + //font_dump(ren.fonts[idx].font, "./atlas.png"); GL(glUseProgram(0)); return 0; } @@ -336,7 +336,7 @@ static int ren_load_font(int size, const char *path) if (font_load(f, path, size)) REN_RET(-1, REN_FONT) - font_dump(f, "./atlas.png"); + //font_dump(f, "./atlas.png"); // load font texture (atlas) ren.fonts[idx].texture = ren_texturer_rect( diff --git a/text_rendering/ren.h b/text_rendering/ren.h index 68fcd84..6219b34 100644 --- a/text_rendering/ren.h +++ b/text_rendering/ren.h @@ -4,7 +4,7 @@ #include -#define DEFAULT_FONT "/usr/share/fonts/TTF/DejaVuSansMono.ttf" +#define DEFAULT_FONT "/usr/share/fonts/TTF/FiraCode-Regular.ttf" #define FONT_VERSHADER "./font_vertshader.glsl" #define FONT_FRAGSHADER "./font_fragshader.glsl" #define BOX_VERSHADER "./box_vertshader.glsl"