some tests
This commit is contained in:
parent
f8e2c0b70c
commit
574a1f23dc
10
test/test_bittype.c3
Normal file
10
test/test_bittype.c3
Normal file
@ -0,0 +1,10 @@
|
||||
import std::io;
|
||||
import std::collections::bitset;
|
||||
|
||||
def Bits = bitset::BitSet(<128>);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
Bits b;
|
||||
io::printn($typeof(b.data[0]).sizeof);
|
||||
}
|
14
test/test_custom_hash.c3
Normal file
14
test/test_custom_hash.c3
Normal file
@ -0,0 +1,14 @@
|
||||
import std::collections::map;
|
||||
|
||||
def Codepoint = uint;
|
||||
fn uint Codepoint.hash(Codepoint code) => code < 128 ? code : ((uint)code).hash();
|
||||
def CodeMap = map::HashMap(<Codepoint, Codepoint>);
|
||||
|
||||
|
||||
fn int main()
|
||||
{
|
||||
CodeMap m;
|
||||
m.new_init();
|
||||
m.free();
|
||||
return 0;
|
||||
}
|
226
test/ugui_font.c3
Normal file
226
test/ugui_font.c3
Normal file
@ -0,0 +1,226 @@
|
||||
module ugui;
|
||||
|
||||
import cache;
|
||||
//#include <grapheme.h>
|
||||
//#include <assert.h>
|
||||
|
||||
//#include "stb_truetype.h"
|
||||
//#include "stbimage_write.h"
|
||||
|
||||
// unicode code point, different type for a different hash
|
||||
def Codepoint = uint;
|
||||
|
||||
/* width and height of a glyph contain the kering advance
|
||||
* (u,v)
|
||||
* +-------------*---+ -
|
||||
* | ^ | | ^
|
||||
* | |oy | | |
|
||||
* | v | | |
|
||||
* | .ii. | | |
|
||||
* | @@@@@@. |<->| |
|
||||
* | V@Mio@@o |adv| |h
|
||||
* | :i. V@V | | |
|
||||
* | :oM@@M | | |
|
||||
* | :@@@MM@M | | |
|
||||
* | @@o o@M | | |
|
||||
* |<->:@@. M@M | | |
|
||||
* |ox @@@o@@@@ | | |
|
||||
* | :M@@V:@@.| | v
|
||||
* +-------------*---+ -
|
||||
* |<------------->|
|
||||
* w
|
||||
*/
|
||||
struct Glyph {
|
||||
Codepoint code;
|
||||
uint u, v;
|
||||
ushort w, h, a, x, y;
|
||||
}
|
||||
|
||||
def GlyphCache = cache::Cache(<Codepoint, Glyph, 1024>);
|
||||
|
||||
// identity map the ASCII range
|
||||
fn uint Codepoint.hash(Codepoint code) => code < 128 ? code : ((uint)code).hash();
|
||||
|
||||
struct FontAtlas {
|
||||
uint width, height;
|
||||
char* atlas;
|
||||
uint glyph_max_w, glyph_max_h;
|
||||
int size;
|
||||
int file_size;
|
||||
char *file;
|
||||
void *priv;
|
||||
}
|
||||
|
||||
|
||||
macro is_utf8(char c) => c & 0x80;
|
||||
const uint BDEPTH = 1;
|
||||
const uint BORDER = 4;
|
||||
|
||||
// FIXME: as of now only monospaced fonts look decent since no
|
||||
// kerning information is stored
|
||||
|
||||
struct Priv @private {
|
||||
stbtt_fontinfo stb;
|
||||
float scale;
|
||||
int baseline;
|
||||
unsigned char *bitmap;
|
||||
struct cache c;
|
||||
}
|
||||
//#define PRIV(x) ((struct priv *)x->priv)
|
||||
|
||||
|
||||
struct font_atlas * font_init(void)
|
||||
{
|
||||
struct font_atlas *p = emalloc(sizeof(struct font_atlas));
|
||||
memset(p, 0, sizeof(struct font_atlas));
|
||||
p->priv = emalloc(sizeof(struct priv));
|
||||
memset(p->priv, 0, sizeof(struct priv));
|
||||
PRIV(p)->c = cache_init();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// loads a font into memory, storing all the ASCII characters in the atlas, each font
|
||||
// atlas structure holds glyphs of a specific size in pixels
|
||||
// NOTE: size includes ascend and descend (so 12 does not mean that 'A' is 12px tall)
|
||||
int font_load(struct font_atlas *atlas, const char *path, int size)
|
||||
{
|
||||
if (!atlas || !path)
|
||||
return -1;
|
||||
|
||||
int err;
|
||||
|
||||
dump_file(path, &(atlas->file), &(atlas->file_size));
|
||||
|
||||
err = stbtt_InitFont(&(PRIV(atlas)->stb), (unsigned char *)atlas->file, 0);
|
||||
if (err == 0) return -1;
|
||||
|
||||
int ascent, descent, linegap, baseline;
|
||||
int x0,y0,x1,y1;
|
||||
float scale;
|
||||
stbtt_GetFontVMetrics(&(PRIV(atlas)->stb), &ascent, &descent, &linegap);
|
||||
stbtt_GetFontBoundingBox(&(PRIV(atlas)->stb), &x0, &y0, &x1, &y1);
|
||||
scale = stbtt_ScaleForPixelHeight(&(PRIV(atlas)->stb), size);
|
||||
baseline = scale * -y0;
|
||||
atlas->glyph_max_w = (scale*x1) - (scale*x0);
|
||||
atlas->glyph_max_h = (baseline+scale*y1) - (baseline+scale*y0);
|
||||
atlas->atlas = emalloc(CACHE_SIZE*BDEPTH*atlas->glyph_max_w*atlas->glyph_max_h);
|
||||
memset(atlas->atlas, 0, CACHE_SIZE*BDEPTH*atlas->glyph_max_w*atlas->glyph_max_h);
|
||||
PRIV(atlas)->baseline = atlas->glyph_max_h - baseline;
|
||||
PRIV(atlas)->scale = scale;
|
||||
PRIV(atlas)->bitmap = emalloc(BDEPTH*atlas->glyph_max_w*atlas->glyph_max_h);
|
||||
// FIXME: make this a square atlas
|
||||
atlas->width = atlas->glyph_max_w*CACHE_SIZE/4;
|
||||
atlas->height = atlas->glyph_max_h*4;
|
||||
atlas->size = size;
|
||||
|
||||
// preallocate all ascii characters
|
||||
for (char c = ' '; c <= '~'; c++) {
|
||||
if (!font_get_glyph_texture(atlas, c, NULL))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int font_free(struct font_atlas *atlas)
|
||||
{
|
||||
efree(atlas->atlas);
|
||||
efree(atlas->file);
|
||||
efree(PRIV(atlas)->bitmap);
|
||||
cache_free(&PRIV(atlas)->c);
|
||||
efree(atlas->priv);
|
||||
efree(atlas);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
if (!updated) updated = &_u;
|
||||
|
||||
const struct font_glyph *r;
|
||||
if ((r = cache_search(&PRIV(atlas)->c, code)) != NULL) {
|
||||
*updated = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
*updated = 1;
|
||||
// generate the sdf and put it into the cache
|
||||
// TODO: generate the whole block at once
|
||||
int idx = stbtt_FindGlyphIndex(&PRIV(atlas)->stb, code);
|
||||
int x0,y0,x1,y1,gw,gh,l,off_x,off_y,adv,base;
|
||||
base = atlas->glyph_max_h - PRIV(atlas)->baseline;
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(
|
||||
&PRIV(atlas)->stb,
|
||||
idx,
|
||||
PRIV(atlas)->scale,
|
||||
PRIV(atlas)->scale,
|
||||
0,0,
|
||||
&x0,&y0,
|
||||
&x1, &y1);
|
||||
gw = x1 - x0;
|
||||
gh = y1 - y0;
|
||||
stbtt_GetGlyphHMetrics(&PRIV(atlas)->stb, idx, &adv, &l);
|
||||
adv *= PRIV(atlas)->scale;
|
||||
off_x = PRIV(atlas)->scale*l;
|
||||
off_y = atlas->glyph_max_h+y0;
|
||||
stbtt_MakeGlyphBitmapSubpixel(
|
||||
&PRIV(atlas)->stb,
|
||||
PRIV(atlas)->bitmap,
|
||||
atlas->glyph_max_w,
|
||||
atlas->glyph_max_h,
|
||||
atlas->glyph_max_w,
|
||||
PRIV(atlas)->scale,
|
||||
PRIV(atlas)->scale,
|
||||
0, 0,
|
||||
idx);
|
||||
|
||||
// TODO: bounds check usign atlas height
|
||||
// TODO: clear spot area in the atlas before writing on it
|
||||
unsigned int spot = cache_get_free_spot(&PRIV(atlas)->c);
|
||||
unsigned int ty = ((atlas->glyph_max_w * spot) / atlas->width) * atlas->glyph_max_h;
|
||||
unsigned int tx = (atlas->glyph_max_w * spot) % atlas->width;
|
||||
unsigned int w = atlas->width;
|
||||
|
||||
unsigned char *a = (void *)atlas->atlas;
|
||||
|
||||
//printf("max:%d %d spot:%d : %d %d %d %d\n", atlas->glyph_max_w, atlas->glyph_max_h, spot, tx, ty, off_x, off_y);
|
||||
|
||||
for (int y = 0; y < gh; y++) {
|
||||
for (int x = 0; x < gw; x++) {
|
||||
int c, r;
|
||||
r = (ty+y)*w;
|
||||
c = tx+x;
|
||||
a[r+c] = PRIV(atlas)->bitmap[y*atlas->glyph_max_w+x];
|
||||
}
|
||||
}
|
||||
|
||||
struct font_glyph g = {
|
||||
.codepoint = code,
|
||||
.u = tx,
|
||||
.v = ty,
|
||||
.w = gw,
|
||||
.h = gh,
|
||||
.x = off_x,
|
||||
.y = off_y-base,
|
||||
.a = adv,
|
||||
};
|
||||
return cache_insert_at(&PRIV(atlas)->c, &g, g.codepoint, spot);
|
||||
}
|
||||
|
||||
|
||||
void font_dump(const struct font_atlas *atlas, const char *path)
|
||||
{
|
||||
stbi_write_png(
|
||||
path,
|
||||
atlas->width,
|
||||
atlas->height,
|
||||
BDEPTH,
|
||||
atlas->atlas,
|
||||
BDEPTH*atlas->width);
|
||||
}
|
Loading…
Reference in New Issue
Block a user