1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792 |
- //
- // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would be
- // appreciated but is not required.
- // 2. Altered source versions must be plainly marked as such, and must not be
- // misrepresented as being the original software.
- // 3. This notice may not be removed or altered from any source distribution.
- //
- #ifndef FONS_H
- #define FONS_H
- #define FONS_INVALID -1
- enum FONSflags {
- FONS_ZERO_TOPLEFT = 1,
- FONS_ZERO_BOTTOMLEFT = 2,
- };
- enum FONSalign {
- // Horizontal align
- FONS_ALIGN_LEFT = 1<<0, // Default
- FONS_ALIGN_CENTER = 1<<1,
- FONS_ALIGN_RIGHT = 1<<2,
- // Vertical align
- FONS_ALIGN_TOP = 1<<3,
- FONS_ALIGN_MIDDLE = 1<<4,
- FONS_ALIGN_BOTTOM = 1<<5,
- FONS_ALIGN_BASELINE = 1<<6, // Default
- };
- enum FONSglyphBitmap {
- FONS_GLYPH_BITMAP_OPTIONAL = 1,
- FONS_GLYPH_BITMAP_REQUIRED = 2,
- };
- enum FONSerrorCode {
- // Font atlas is full.
- FONS_ATLAS_FULL = 1,
- // Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
- FONS_SCRATCH_FULL = 2,
- // Calls to fonsPushState has created too large stack, if you need deep state stack bump up FONS_MAX_STATES.
- FONS_STATES_OVERFLOW = 3,
- // Trying to pop too many states fonsPopState().
- FONS_STATES_UNDERFLOW = 4,
- };
- struct FONSparams {
- int width, height;
- unsigned char flags;
- void* userPtr;
- int (*renderCreate)(void* uptr, int width, int height);
- int (*renderResize)(void* uptr, int width, int height);
- void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data);
- void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts);
- void (*renderDelete)(void* uptr);
- };
- typedef struct FONSparams FONSparams;
- struct FONSquad
- {
- float x0,y0,s0,t0;
- float x1,y1,s1,t1;
- };
- typedef struct FONSquad FONSquad;
- struct FONStextIter {
- float x, y, nextx, nexty, scale, spacing;
- unsigned int codepoint;
- short isize, iblur;
- struct FONSfont* font;
- int prevGlyphIndex;
- const char* str;
- const char* next;
- const char* end;
- unsigned int utf8state;
- int bitmapOption;
- };
- typedef struct FONStextIter FONStextIter;
- typedef struct FONScontext FONScontext;
- // Constructor and destructor.
- FONScontext* fonsCreateInternal(FONSparams* params);
- void fonsDeleteInternal(FONScontext* s);
- void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
- // Returns current atlas size.
- void fonsGetAtlasSize(FONScontext* s, int* width, int* height);
- // Expands the atlas size.
- int fonsExpandAtlas(FONScontext* s, int width, int height);
- // Resets the whole stash.
- int fonsResetAtlas(FONScontext* stash, int width, int height);
- // Add fonts
- int fonsAddFont(FONScontext* s, const char* name, const char* path, int fontIndex);
- int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData, int fontIndex);
- int fonsGetFontByName(FONScontext* s, const char* name);
- // State handling
- void fonsPushState(FONScontext* s);
- void fonsPopState(FONScontext* s);
- void fonsClearState(FONScontext* s);
- // State setting
- void fonsSetSize(FONScontext* s, float size);
- void fonsSetColor(FONScontext* s, unsigned int color);
- void fonsSetSpacing(FONScontext* s, float spacing);
- void fonsSetBlur(FONScontext* s, float blur);
- void fonsSetAlign(FONScontext* s, int align);
- void fonsSetFont(FONScontext* s, int font);
- // Draw text
- float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end);
- // Measure text
- float fonsTextBounds(FONScontext* s, float x, float y, const char* string, const char* end, float* bounds);
- void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
- void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);
- // Text iterator
- int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end, int bitmapOption);
- int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad);
- // Pull texture changes
- const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height);
- int fonsValidateTexture(FONScontext* s, int* dirty);
- // Draws the stash texture for debugging
- void fonsDrawDebug(FONScontext* s, float x, float y);
- #endif // FONTSTASH_H
- #ifdef FONTSTASH_IMPLEMENTATION
- #define FONS_NOTUSED(v) (void)sizeof(v)
- #ifdef FONS_USE_FREETYPE
- #include <ft2build.h>
- #include FT_FREETYPE_H
- #include FT_ADVANCES_H
- #include <math.h>
- struct FONSttFontImpl {
- FT_Face font;
- };
- typedef struct FONSttFontImpl FONSttFontImpl;
- #else
- #define STB_TRUETYPE_IMPLEMENTATION
- static void* fons__tmpalloc(size_t size, void* up);
- static void fons__tmpfree(void* ptr, void* up);
- #define STBTT_malloc(x,u) fons__tmpalloc(x,u)
- #define STBTT_free(x,u) fons__tmpfree(x,u)
- #include "stb_truetype.h"
- struct FONSttFontImpl {
- stbtt_fontinfo font;
- };
- typedef struct FONSttFontImpl FONSttFontImpl;
- #endif
- #ifndef FONS_SCRATCH_BUF_SIZE
- # define FONS_SCRATCH_BUF_SIZE 96000
- #endif
- #ifndef FONS_HASH_LUT_SIZE
- # define FONS_HASH_LUT_SIZE 256
- #endif
- #ifndef FONS_INIT_FONTS
- # define FONS_INIT_FONTS 4
- #endif
- #ifndef FONS_INIT_GLYPHS
- # define FONS_INIT_GLYPHS 256
- #endif
- #ifndef FONS_INIT_ATLAS_NODES
- # define FONS_INIT_ATLAS_NODES 256
- #endif
- #ifndef FONS_VERTEX_COUNT
- # define FONS_VERTEX_COUNT 1024
- #endif
- #ifndef FONS_MAX_STATES
- # define FONS_MAX_STATES 20
- #endif
- #ifndef FONS_MAX_FALLBACKS
- # define FONS_MAX_FALLBACKS 20
- #endif
- static unsigned int fons__hashint(unsigned int a)
- {
- a += ~(a<<15);
- a ^= (a>>10);
- a += (a<<3);
- a ^= (a>>6);
- a += ~(a<<11);
- a ^= (a>>16);
- return a;
- }
- static int fons__mini(int a, int b)
- {
- return a < b ? a : b;
- }
- static int fons__maxi(int a, int b)
- {
- return a > b ? a : b;
- }
- struct FONSglyph
- {
- unsigned int codepoint;
- int index;
- int next;
- short size, blur;
- short x0,y0,x1,y1;
- short xadv,xoff,yoff;
- };
- typedef struct FONSglyph FONSglyph;
- struct FONSfont
- {
- FONSttFontImpl font;
- char name[64];
- unsigned char* data;
- int dataSize;
- unsigned char freeData;
- float ascender;
- float descender;
- float lineh;
- FONSglyph* glyphs;
- int cglyphs;
- int nglyphs;
- int lut[FONS_HASH_LUT_SIZE];
- int fallbacks[FONS_MAX_FALLBACKS];
- int nfallbacks;
- };
- typedef struct FONSfont FONSfont;
- struct FONSstate
- {
- int font;
- int align;
- float size;
- unsigned int color;
- float blur;
- float spacing;
- };
- typedef struct FONSstate FONSstate;
- struct FONSatlasNode {
- short x, y, width;
- };
- typedef struct FONSatlasNode FONSatlasNode;
- struct FONSatlas
- {
- int width, height;
- FONSatlasNode* nodes;
- int nnodes;
- int cnodes;
- };
- typedef struct FONSatlas FONSatlas;
- struct FONScontext
- {
- FONSparams params;
- float itw,ith;
- unsigned char* texData;
- int dirtyRect[4];
- FONSfont** fonts;
- FONSatlas* atlas;
- int cfonts;
- int nfonts;
- float verts[FONS_VERTEX_COUNT*2];
- float tcoords[FONS_VERTEX_COUNT*2];
- unsigned int colors[FONS_VERTEX_COUNT];
- int nverts;
- unsigned char* scratch;
- int nscratch;
- FONSstate states[FONS_MAX_STATES];
- int nstates;
- void (*handleError)(void* uptr, int error, int val);
- void* errorUptr;
- #ifdef FONS_USE_FREETYPE
- FT_Library ftLibrary;
- #endif
- };
- #ifdef FONS_USE_FREETYPE
- int fons__tt_init(FONScontext *context)
- {
- FT_Error ftError;
- FONS_NOTUSED(context);
- ftError = FT_Init_FreeType(&context->ftLibrary);
- return ftError == 0;
- }
- int fons__tt_done(FONScontext *context)
- {
- FT_Error ftError;
- FONS_NOTUSED(context);
- ftError = FT_Done_FreeType(context->ftLibrary);
- return ftError == 0;
- }
- int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
- {
- FT_Error ftError;
- FONS_NOTUSED(context);
- ftError = FT_New_Memory_Face(context->ftLibrary, (const FT_Byte*)data, dataSize, fontIndex, &font->font);
- return ftError == 0;
- }
- void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
- {
- *ascent = font->font->ascender;
- *descent = font->font->descender;
- *lineGap = font->font->height - (*ascent - *descent);
- }
- float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
- {
- return size / font->font->units_per_EM;
- }
- int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
- {
- return FT_Get_Char_Index(font->font, codepoint);
- }
- int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
- int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
- {
- FT_Error ftError;
- FT_GlyphSlot ftGlyph;
- FT_Fixed advFixed;
- FONS_NOTUSED(scale);
- ftError = FT_Set_Pixel_Sizes(font->font, 0, size);
- if (ftError) return 0;
- ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT);
- if (ftError) return 0;
- ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
- if (ftError) return 0;
- ftGlyph = font->font->glyph;
- *advance = (int)advFixed;
- *lsb = (int)ftGlyph->metrics.horiBearingX;
- *x0 = ftGlyph->bitmap_left;
- *x1 = *x0 + ftGlyph->bitmap.width;
- *y0 = -ftGlyph->bitmap_top;
- *y1 = *y0 + ftGlyph->bitmap.rows;
- return 1;
- }
- void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
- float scaleX, float scaleY, int glyph)
- {
- FT_GlyphSlot ftGlyph = font->font->glyph;
- int ftGlyphOffset = 0;
- unsigned int x, y;
- FONS_NOTUSED(outWidth);
- FONS_NOTUSED(outHeight);
- FONS_NOTUSED(scaleX);
- FONS_NOTUSED(scaleY);
- FONS_NOTUSED(glyph); // glyph has already been loaded by fons__tt_buildGlyphBitmap
- for ( y = 0; y < ftGlyph->bitmap.rows; y++ ) {
- for ( x = 0; x < ftGlyph->bitmap.width; x++ ) {
- output[(y * outStride) + x] = ftGlyph->bitmap.buffer[ftGlyphOffset++];
- }
- }
- }
- int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
- {
- FT_Vector ftKerning;
- FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
- return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer
- }
- #else
- int fons__tt_init(FONScontext *context)
- {
- FONS_NOTUSED(context);
- return 1;
- }
- int fons__tt_done(FONScontext *context)
- {
- FONS_NOTUSED(context);
- return 1;
- }
- int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
- {
- int offset, stbError;
- FONS_NOTUSED(dataSize);
- font->font.userdata = context;
- offset = stbtt_GetFontOffsetForIndex(data, fontIndex);
- if (offset == -1) {
- stbError = 0;
- } else {
- stbError = stbtt_InitFont(&font->font, data, offset);
- }
- return stbError;
- }
- void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
- {
- stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap);
- }
- float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
- {
- return stbtt_ScaleForMappingEmToPixels(&font->font, size);
- }
- int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
- {
- return stbtt_FindGlyphIndex(&font->font, codepoint);
- }
- int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
- int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
- {
- FONS_NOTUSED(size);
- stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb);
- stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1);
- return 1;
- }
- void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
- float scaleX, float scaleY, int glyph)
- {
- stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph);
- }
- int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
- {
- return stbtt_GetGlyphKernAdvance(&font->font, glyph1, glyph2);
- }
- #endif
- #ifdef STB_TRUETYPE_IMPLEMENTATION
- static void* fons__tmpalloc(size_t size, void* up)
- {
- unsigned char* ptr;
- FONScontext* stash = (FONScontext*)up;
- // 16-byte align the returned pointer
- size = (size + 0xf) & ~0xf;
- if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) {
- if (stash->handleError)
- stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size);
- return NULL;
- }
- ptr = stash->scratch + stash->nscratch;
- stash->nscratch += (int)size;
- return ptr;
- }
- static void fons__tmpfree(void* ptr, void* up)
- {
- (void)ptr;
- (void)up;
- // empty
- }
- #endif // STB_TRUETYPE_IMPLEMENTATION
- // Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
- // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
- #define FONS_UTF8_ACCEPT 0
- #define FONS_UTF8_REJECT 12
- static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
- {
- static const unsigned char utf8d[] = {
- // The first part of the table maps bytes to character classes that
- // to reduce the size of the transition table and create bitmasks.
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
- // The second part is a transition table that maps a combination
- // of a state of the automaton and a character class to a state.
- 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
- 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
- 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
- 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
- 12,36,12,12,12,12,12,12,12,12,12,12,
- };
- unsigned int type = utf8d[byte];
- *codep = (*state != FONS_UTF8_ACCEPT) ?
- (byte & 0x3fu) | (*codep << 6) :
- (0xff >> type) & (byte);
- *state = utf8d[256 + *state + type];
- return *state;
- }
- // Atlas based on Skyline Bin Packer by Jukka Jylänki
- static void fons__deleteAtlas(FONSatlas* atlas)
- {
- if (atlas == NULL) return;
- if (atlas->nodes != NULL) free(atlas->nodes);
- free(atlas);
- }
- static FONSatlas* fons__allocAtlas(int w, int h, int nnodes)
- {
- FONSatlas* atlas = NULL;
- // Allocate memory for the font stash.
- atlas = (FONSatlas*)malloc(sizeof(FONSatlas));
- if (atlas == NULL) goto error;
- memset(atlas, 0, sizeof(FONSatlas));
- atlas->width = w;
- atlas->height = h;
- // Allocate space for skyline nodes
- atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes);
- if (atlas->nodes == NULL) goto error;
- memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes);
- atlas->nnodes = 0;
- atlas->cnodes = nnodes;
- // Init root node.
- atlas->nodes[0].x = 0;
- atlas->nodes[0].y = 0;
- atlas->nodes[0].width = (short)w;
- atlas->nnodes++;
- return atlas;
- error:
- if (atlas) fons__deleteAtlas(atlas);
- return NULL;
- }
- static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w)
- {
- int i;
- // Insert node
- if (atlas->nnodes+1 > atlas->cnodes) {
- atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2;
- atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes, sizeof(FONSatlasNode) * atlas->cnodes);
- if (atlas->nodes == NULL)
- return 0;
- }
- for (i = atlas->nnodes; i > idx; i--)
- atlas->nodes[i] = atlas->nodes[i-1];
- atlas->nodes[idx].x = (short)x;
- atlas->nodes[idx].y = (short)y;
- atlas->nodes[idx].width = (short)w;
- atlas->nnodes++;
- return 1;
- }
- static void fons__atlasRemoveNode(FONSatlas* atlas, int idx)
- {
- int i;
- if (atlas->nnodes == 0) return;
- for (i = idx; i < atlas->nnodes-1; i++)
- atlas->nodes[i] = atlas->nodes[i+1];
- atlas->nnodes--;
- }
- static void fons__atlasExpand(FONSatlas* atlas, int w, int h)
- {
- // Insert node for empty space
- if (w > atlas->width)
- fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
- atlas->width = w;
- atlas->height = h;
- }
- static void fons__atlasReset(FONSatlas* atlas, int w, int h)
- {
- atlas->width = w;
- atlas->height = h;
- atlas->nnodes = 0;
- // Init root node.
- atlas->nodes[0].x = 0;
- atlas->nodes[0].y = 0;
- atlas->nodes[0].width = (short)w;
- atlas->nnodes++;
- }
- static int fons__atlasAddSkylineLevel(FONSatlas* atlas, int idx, int x, int y, int w, int h)
- {
- int i;
- // Insert new node
- if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0)
- return 0;
- // Delete skyline segments that fall under the shadow of the new segment.
- for (i = idx+1; i < atlas->nnodes; i++) {
- if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
- int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
- atlas->nodes[i].x += (short)shrink;
- atlas->nodes[i].width -= (short)shrink;
- if (atlas->nodes[i].width <= 0) {
- fons__atlasRemoveNode(atlas, i);
- i--;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- // Merge same height skyline segments that are next to each other.
- for (i = 0; i < atlas->nnodes-1; i++) {
- if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
- atlas->nodes[i].width += atlas->nodes[i+1].width;
- fons__atlasRemoveNode(atlas, i+1);
- i--;
- }
- }
- return 1;
- }
- static int fons__atlasRectFits(FONSatlas* atlas, int i, int w, int h)
- {
- // Checks if there is enough space at the location of skyline span 'i',
- // and return the max height of all skyline spans under that at that location,
- // (think tetris block being dropped at that position). Or -1 if no space found.
- int x = atlas->nodes[i].x;
- int y = atlas->nodes[i].y;
- int spaceLeft;
- if (x + w > atlas->width)
- return -1;
- spaceLeft = w;
- while (spaceLeft > 0) {
- if (i == atlas->nnodes) return -1;
- y = fons__maxi(y, atlas->nodes[i].y);
- if (y + h > atlas->height) return -1;
- spaceLeft -= atlas->nodes[i].width;
- ++i;
- }
- return y;
- }
- static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
- {
- int besth = atlas->height, bestw = atlas->width, besti = -1;
- int bestx = -1, besty = -1, i;
- // Bottom left fit heuristic.
- for (i = 0; i < atlas->nnodes; i++) {
- int y = fons__atlasRectFits(atlas, i, rw, rh);
- if (y != -1) {
- if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) {
- besti = i;
- bestw = atlas->nodes[i].width;
- besth = y + rh;
- bestx = atlas->nodes[i].x;
- besty = y;
- }
- }
- }
- if (besti == -1)
- return 0;
- // Perform the actual packing.
- if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
- return 0;
- *rx = bestx;
- *ry = besty;
- return 1;
- }
- static void fons__addWhiteRect(FONScontext* stash, int w, int h)
- {
- int x, y, gx, gy;
- unsigned char* dst;
- if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
- return;
- // Rasterize
- dst = &stash->texData[gx + gy * stash->params.width];
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++)
- dst[x] = 0xff;
- dst += stash->params.width;
- }
- stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
- stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
- stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
- stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
- }
- FONScontext* fonsCreateInternal(FONSparams* params)
- {
- FONScontext* stash = NULL;
- // Allocate memory for the font stash.
- stash = (FONScontext*)malloc(sizeof(FONScontext));
- if (stash == NULL) goto error;
- memset(stash, 0, sizeof(FONScontext));
- stash->params = *params;
- // Allocate scratch buffer.
- stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
- if (stash->scratch == NULL) goto error;
- // Initialize implementation library
- if (!fons__tt_init(stash)) goto error;
- if (stash->params.renderCreate != NULL) {
- if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
- goto error;
- }
- stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
- if (stash->atlas == NULL) goto error;
- // Allocate space for fonts.
- stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS);
- if (stash->fonts == NULL) goto error;
- memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS);
- stash->cfonts = FONS_INIT_FONTS;
- stash->nfonts = 0;
- // Create texture for the cache.
- stash->itw = 1.0f/stash->params.width;
- stash->ith = 1.0f/stash->params.height;
- stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height);
- if (stash->texData == NULL) goto error;
- memset(stash->texData, 0, stash->params.width * stash->params.height);
- stash->dirtyRect[0] = stash->params.width;
- stash->dirtyRect[1] = stash->params.height;
- stash->dirtyRect[2] = 0;
- stash->dirtyRect[3] = 0;
- // Add white rect at 0,0 for debug drawing.
- fons__addWhiteRect(stash, 2,2);
- fonsPushState(stash);
- fonsClearState(stash);
- return stash;
- error:
- fonsDeleteInternal(stash);
- return NULL;
- }
- static FONSstate* fons__getState(FONScontext* stash)
- {
- return &stash->states[stash->nstates-1];
- }
- int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
- {
- FONSfont* baseFont = stash->fonts[base];
- if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
- baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
- return 1;
- }
- return 0;
- }
- void fonsResetFallbackFont(FONScontext* stash, int base)
- {
- int i;
- FONSfont* baseFont = stash->fonts[base];
- baseFont->nfallbacks = 0;
- baseFont->nglyphs = 0;
- for (i = 0; i < FONS_HASH_LUT_SIZE; i++)
- baseFont->lut[i] = -1;
- }
- void fonsSetSize(FONScontext* stash, float size)
- {
- fons__getState(stash)->size = size;
- }
- void fonsSetColor(FONScontext* stash, unsigned int color)
- {
- fons__getState(stash)->color = color;
- }
- void fonsSetSpacing(FONScontext* stash, float spacing)
- {
- fons__getState(stash)->spacing = spacing;
- }
- void fonsSetBlur(FONScontext* stash, float blur)
- {
- fons__getState(stash)->blur = blur;
- }
- void fonsSetAlign(FONScontext* stash, int align)
- {
- fons__getState(stash)->align = align;
- }
- void fonsSetFont(FONScontext* stash, int font)
- {
- fons__getState(stash)->font = font;
- }
- void fonsPushState(FONScontext* stash)
- {
- if (stash->nstates >= FONS_MAX_STATES) {
- if (stash->handleError)
- stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0);
- return;
- }
- if (stash->nstates > 0)
- memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate));
- stash->nstates++;
- }
- void fonsPopState(FONScontext* stash)
- {
- if (stash->nstates <= 1) {
- if (stash->handleError)
- stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0);
- return;
- }
- stash->nstates--;
- }
- void fonsClearState(FONScontext* stash)
- {
- FONSstate* state = fons__getState(stash);
- state->size = 12.0f;
- state->color = 0xffffffff;
- state->font = 0;
- state->blur = 0;
- state->spacing = 0;
- state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
- }
- static void fons__freeFont(FONSfont* font)
- {
- if (font == NULL) return;
- if (font->glyphs) free(font->glyphs);
- if (font->freeData && font->data) free(font->data);
- free(font);
- }
- static int fons__allocFont(FONScontext* stash)
- {
- FONSfont* font = NULL;
- if (stash->nfonts+1 > stash->cfonts) {
- stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2;
- stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts);
- if (stash->fonts == NULL)
- return -1;
- }
- font = (FONSfont*)malloc(sizeof(FONSfont));
- if (font == NULL) goto error;
- memset(font, 0, sizeof(FONSfont));
- font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS);
- if (font->glyphs == NULL) goto error;
- font->cglyphs = FONS_INIT_GLYPHS;
- font->nglyphs = 0;
- stash->fonts[stash->nfonts++] = font;
- return stash->nfonts-1;
- error:
- fons__freeFont(font);
- return FONS_INVALID;
- }
- int fonsAddFont(FONScontext* stash, const char* name, const char* path, int fontIndex)
- {
- FILE* fp = 0;
- int dataSize = 0;
- size_t readed;
- unsigned char* data = NULL;
- // Read in the font data.
- fp = fopen(path, "rb");
- if (fp == NULL) goto error;
- fseek(fp,0,SEEK_END);
- dataSize = (int)ftell(fp);
- fseek(fp,0,SEEK_SET);
- data = (unsigned char*)malloc(dataSize);
- if (data == NULL) goto error;
- readed = fread(data, 1, dataSize, fp);
- fclose(fp);
- fp = 0;
- if (readed != (size_t)dataSize) goto error;
- return fonsAddFontMem(stash, name, data, dataSize, 1, fontIndex);
- error:
- if (data) free(data);
- if (fp) fclose(fp);
- return FONS_INVALID;
- }
- int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData, int fontIndex)
- {
- int i, ascent, descent, fh, lineGap;
- FONSfont* font;
- int idx = fons__allocFont(stash);
- if (idx == FONS_INVALID)
- return FONS_INVALID;
- font = stash->fonts[idx];
- strncpy(font->name, name, sizeof(font->name));
- font->name[sizeof(font->name)-1] = '\0';
- // Init hash lookup.
- for (i = 0; i < FONS_HASH_LUT_SIZE; ++i)
- font->lut[i] = -1;
- // Read in the font data.
- font->dataSize = dataSize;
- font->data = data;
- font->freeData = (unsigned char)freeData;
- // Init font
- stash->nscratch = 0;
- if (!fons__tt_loadFont(stash, &font->font, data, dataSize, fontIndex)) goto error;
- // Store normalized line height. The real line height is got
- // by multiplying the lineh by font size.
- fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
- ascent += lineGap;
- fh = ascent - descent;
- font->ascender = (float)ascent / (float)fh;
- font->descender = (float)descent / (float)fh;
- font->lineh = font->ascender - font->descender;
- return idx;
- error:
- fons__freeFont(font);
- stash->nfonts--;
- return FONS_INVALID;
- }
- int fonsGetFontByName(FONScontext* s, const char* name)
- {
- int i;
- for (i = 0; i < s->nfonts; i++) {
- if (strcmp(s->fonts[i]->name, name) == 0)
- return i;
- }
- return FONS_INVALID;
- }
- static FONSglyph* fons__allocGlyph(FONSfont* font)
- {
- if (font->nglyphs+1 > font->cglyphs) {
- font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2;
- font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs);
- if (font->glyphs == NULL) return NULL;
- }
- font->nglyphs++;
- return &font->glyphs[font->nglyphs-1];
- }
- // Based on Exponential blur, Jani Huhtanen, 2006
- #define APREC 16
- #define ZPREC 7
- static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha)
- {
- int x, y;
- for (y = 0; y < h; y++) {
- int z = 0; // force zero border
- for (x = 1; x < w; x++) {
- z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
- dst[x] = (unsigned char)(z >> ZPREC);
- }
- dst[w-1] = 0; // force zero border
- z = 0;
- for (x = w-2; x >= 0; x--) {
- z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
- dst[x] = (unsigned char)(z >> ZPREC);
- }
- dst[0] = 0; // force zero border
- dst += dstStride;
- }
- }
- static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha)
- {
- int x, y;
- for (x = 0; x < w; x++) {
- int z = 0; // force zero border
- for (y = dstStride; y < h*dstStride; y += dstStride) {
- z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
- dst[y] = (unsigned char)(z >> ZPREC);
- }
- dst[(h-1)*dstStride] = 0; // force zero border
- z = 0;
- for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
- z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
- dst[y] = (unsigned char)(z >> ZPREC);
- }
- dst[0] = 0; // force zero border
- dst++;
- }
- }
- static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
- {
- int alpha;
- float sigma;
- (void)stash;
- if (blur < 1)
- return;
- // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
- sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
- alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
- fons__blurRows(dst, w, h, dstStride, alpha);
- fons__blurCols(dst, w, h, dstStride, alpha);
- fons__blurRows(dst, w, h, dstStride, alpha);
- fons__blurCols(dst, w, h, dstStride, alpha);
- // fons__blurrows(dst, w, h, dstStride, alpha);
- // fons__blurcols(dst, w, h, dstStride, alpha);
- }
- static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
- short isize, short iblur, int bitmapOption)
- {
- int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
- float scale;
- FONSglyph* glyph = NULL;
- unsigned int h;
- float size = isize/10.0f;
- int pad, added;
- unsigned char* bdst;
- unsigned char* dst;
- FONSfont* renderFont = font;
- if (isize < 2) return NULL;
- if (iblur > 20) iblur = 20;
- pad = iblur+2;
- // Reset allocator.
- stash->nscratch = 0;
- // Find code point and size.
- h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
- i = font->lut[h];
- while (i != -1) {
- if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur) {
- glyph = &font->glyphs[i];
- if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL || (glyph->x0 >= 0 && glyph->y0 >= 0)) {
- return glyph;
- }
- // At this point, glyph exists but the bitmap data is not yet created.
- break;
- }
- i = font->glyphs[i].next;
- }
- // Create a new glyph or rasterize bitmap data for a cached glyph.
- g = fons__tt_getGlyphIndex(&font->font, codepoint);
- // Try to find the glyph in fallback fonts.
- if (g == 0) {
- for (i = 0; i < font->nfallbacks; ++i) {
- FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
- int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
- if (fallbackIndex != 0) {
- g = fallbackIndex;
- renderFont = fallbackFont;
- break;
- }
- }
- // It is possible that we did not find a fallback glyph.
- // In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
- }
- scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
- fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
- gw = x1-x0 + pad*2;
- gh = y1-y0 + pad*2;
- // Determines the spot to draw glyph in the atlas.
- if (bitmapOption == FONS_GLYPH_BITMAP_REQUIRED) {
- // Find free spot for the rect in the atlas
- added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
- if (added == 0 && stash->handleError != NULL) {
- // Atlas is full, let the user to resize the atlas (or not), and try again.
- stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
- added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
- }
- if (added == 0) return NULL;
- } else {
- // Negative coordinate indicates there is no bitmap data created.
- gx = -1;
- gy = -1;
- }
- // Init glyph.
- if (glyph == NULL) {
- glyph = fons__allocGlyph(font);
- glyph->codepoint = codepoint;
- glyph->size = isize;
- glyph->blur = iblur;
- glyph->next = 0;
- // Insert char to hash lookup.
- glyph->next = font->lut[h];
- font->lut[h] = font->nglyphs-1;
- }
- glyph->index = g;
- glyph->x0 = (short)gx;
- glyph->y0 = (short)gy;
- glyph->x1 = (short)(glyph->x0+gw);
- glyph->y1 = (short)(glyph->y0+gh);
- glyph->xadv = (short)(scale * advance * 10.0f);
- glyph->xoff = (short)(x0 - pad);
- glyph->yoff = (short)(y0 - pad);
- if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL) {
- return glyph;
- }
- // Rasterize
- dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
- fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale, scale, g);
- // Make sure there is one pixel empty border.
- dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
- for (y = 0; y < gh; y++) {
- dst[y*stash->params.width] = 0;
- dst[gw-1 + y*stash->params.width] = 0;
- }
- for (x = 0; x < gw; x++) {
- dst[x] = 0;
- dst[x + (gh-1)*stash->params.width] = 0;
- }
- // Debug code to color the glyph background
- /* unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
- for (y = 0; y < gh; y++) {
- for (x = 0; x < gw; x++) {
- int a = (int)fdst[x+y*stash->params.width] + 20;
- if (a > 255) a = 255;
- fdst[x+y*stash->params.width] = a;
- }
- }*/
- // Blur
- if (iblur > 0) {
- stash->nscratch = 0;
- bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
- fons__blur(stash, bdst, gw, gh, stash->params.width, iblur);
- }
- stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
- stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
- stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
- stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
- return glyph;
- }
- static void fons__getQuad(FONScontext* stash, FONSfont* font,
- int prevGlyphIndex, FONSglyph* glyph,
- float scale, float spacing, float* x, float* y, FONSquad* q)
- {
- float rx,ry,xoff,yoff,x0,y0,x1,y1;
- if (prevGlyphIndex != -1) {
- float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
- *x += (int)(adv + spacing + 0.5f);
- }
- // Each glyph has 2px border to allow good interpolation,
- // one pixel to prevent leaking, and one to allow good interpolation for rendering.
- // Inset the texture region by one pixel for correct interpolation.
- xoff = (short)(glyph->xoff+1);
- yoff = (short)(glyph->yoff+1);
- x0 = (float)(glyph->x0+1);
- y0 = (float)(glyph->y0+1);
- x1 = (float)(glyph->x1-1);
- y1 = (float)(glyph->y1-1);
- if (stash->params.flags & FONS_ZERO_TOPLEFT) {
- rx = floorf(*x + xoff);
- ry = floorf(*y + yoff);
- q->x0 = rx;
- q->y0 = ry;
- q->x1 = rx + x1 - x0;
- q->y1 = ry + y1 - y0;
- q->s0 = x0 * stash->itw;
- q->t0 = y0 * stash->ith;
- q->s1 = x1 * stash->itw;
- q->t1 = y1 * stash->ith;
- } else {
- rx = floorf(*x + xoff);
- ry = floorf(*y - yoff);
- q->x0 = rx;
- q->y0 = ry;
- q->x1 = rx + x1 - x0;
- q->y1 = ry - y1 + y0;
- q->s0 = x0 * stash->itw;
- q->t0 = y0 * stash->ith;
- q->s1 = x1 * stash->itw;
- q->t1 = y1 * stash->ith;
- }
- *x += (int)(glyph->xadv / 10.0f + 0.5f);
- }
- static void fons__flush(FONScontext* stash)
- {
- // Flush texture
- if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
- if (stash->params.renderUpdate != NULL)
- stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
- // Reset dirty rect
- stash->dirtyRect[0] = stash->params.width;
- stash->dirtyRect[1] = stash->params.height;
- stash->dirtyRect[2] = 0;
- stash->dirtyRect[3] = 0;
- }
- // Flush triangles
- if (stash->nverts > 0) {
- if (stash->params.renderDraw != NULL)
- stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts);
- stash->nverts = 0;
- }
- }
- static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned int c)
- {
- stash->verts[stash->nverts*2+0] = x;
- stash->verts[stash->nverts*2+1] = y;
- stash->tcoords[stash->nverts*2+0] = s;
- stash->tcoords[stash->nverts*2+1] = t;
- stash->colors[stash->nverts] = c;
- stash->nverts++;
- }
- static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize)
- {
- if (stash->params.flags & FONS_ZERO_TOPLEFT) {
- if (align & FONS_ALIGN_TOP) {
- return font->ascender * (float)isize/10.0f;
- } else if (align & FONS_ALIGN_MIDDLE) {
- return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
- } else if (align & FONS_ALIGN_BASELINE) {
- return 0.0f;
- } else if (align & FONS_ALIGN_BOTTOM) {
- return font->descender * (float)isize/10.0f;
- }
- } else {
- if (align & FONS_ALIGN_TOP) {
- return -font->ascender * (float)isize/10.0f;
- } else if (align & FONS_ALIGN_MIDDLE) {
- return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
- } else if (align & FONS_ALIGN_BASELINE) {
- return 0.0f;
- } else if (align & FONS_ALIGN_BOTTOM) {
- return -font->descender * (float)isize/10.0f;
- }
- }
- return 0.0;
- }
- float fonsDrawText(FONScontext* stash,
- float x, float y,
- const char* str, const char* end)
- {
- FONSstate* state = fons__getState(stash);
- unsigned int codepoint;
- unsigned int utf8state = 0;
- FONSglyph* glyph = NULL;
- FONSquad q;
- int prevGlyphIndex = -1;
- short isize = (short)(state->size*10.0f);
- short iblur = (short)state->blur;
- float scale;
- FONSfont* font;
- float width;
- if (stash == NULL) return x;
- if (state->font < 0 || state->font >= stash->nfonts) return x;
- font = stash->fonts[state->font];
- if (font->data == NULL) return x;
- scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
- if (end == NULL)
- end = str + strlen(str);
- // Align horizontally
- if (state->align & FONS_ALIGN_LEFT) {
- // empty
- } else if (state->align & FONS_ALIGN_RIGHT) {
- width = fonsTextBounds(stash, x,y, str, end, NULL);
- x -= width;
- } else if (state->align & FONS_ALIGN_CENTER) {
- width = fonsTextBounds(stash, x,y, str, end, NULL);
- x -= width * 0.5f;
- }
- // Align vertically.
- y += fons__getVertAlign(stash, font, state->align, isize);
- for (; str != end; ++str) {
- if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
- continue;
- glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_REQUIRED);
- if (glyph != NULL) {
- fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
- if (stash->nverts+6 > FONS_VERTEX_COUNT)
- fons__flush(stash);
- fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
- fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
- fons__vertex(stash, q.x1, q.y0, q.s1, q.t0, state->color);
- fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
- fons__vertex(stash, q.x0, q.y1, q.s0, q.t1, state->color);
- fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
- }
- prevGlyphIndex = glyph != NULL ? glyph->index : -1;
- }
- fons__flush(stash);
- return x;
- }
- int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
- float x, float y, const char* str, const char* end, int bitmapOption)
- {
- FONSstate* state = fons__getState(stash);
- float width;
- memset(iter, 0, sizeof(*iter));
- if (stash == NULL) return 0;
- if (state->font < 0 || state->font >= stash->nfonts) return 0;
- iter->font = stash->fonts[state->font];
- if (iter->font->data == NULL) return 0;
- iter->isize = (short)(state->size*10.0f);
- iter->iblur = (short)state->blur;
- iter->scale = fons__tt_getPixelHeightScale(&iter->font->font, (float)iter->isize/10.0f);
- // Align horizontally
- if (state->align & FONS_ALIGN_LEFT) {
- // empty
- } else if (state->align & FONS_ALIGN_RIGHT) {
- width = fonsTextBounds(stash, x,y, str, end, NULL);
- x -= width;
- } else if (state->align & FONS_ALIGN_CENTER) {
- width = fonsTextBounds(stash, x,y, str, end, NULL);
- x -= width * 0.5f;
- }
- // Align vertically.
- y += fons__getVertAlign(stash, iter->font, state->align, iter->isize);
- if (end == NULL)
- end = str + strlen(str);
- iter->x = iter->nextx = x;
- iter->y = iter->nexty = y;
- iter->spacing = state->spacing;
- iter->str = str;
- iter->next = str;
- iter->end = end;
- iter->codepoint = 0;
- iter->prevGlyphIndex = -1;
- iter->bitmapOption = bitmapOption;
- return 1;
- }
- int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
- {
- FONSglyph* glyph = NULL;
- const char* str = iter->next;
- iter->str = iter->next;
- if (str == iter->end)
- return 0;
- for (; str != iter->end; str++) {
- if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str))
- continue;
- str++;
- // Get glyph and quad
- iter->x = iter->nextx;
- iter->y = iter->nexty;
- glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur, iter->bitmapOption);
- // If the iterator was initialized with FONS_GLYPH_BITMAP_OPTIONAL, then the UV coordinates of the quad will be invalid.
- if (glyph != NULL)
- fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
- iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1;
- break;
- }
- iter->next = str;
- return 1;
- }
- void fonsDrawDebug(FONScontext* stash, float x, float y)
- {
- int i;
- int w = stash->params.width;
- int h = stash->params.height;
- float u = w == 0 ? 0 : (1.0f / w);
- float v = h == 0 ? 0 : (1.0f / h);
- if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
- fons__flush(stash);
- // Draw background
- fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
- fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
- fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff);
- fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
- fons__vertex(stash, x+0, y+h, u, v, 0x0fffffff);
- fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
- // Draw texture
- fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
- fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
- fons__vertex(stash, x+w, y+0, 1, 0, 0xffffffff);
- fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
- fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff);
- fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
- // Drawbug draw atlas
- for (i = 0; i < stash->atlas->nnodes; i++) {
- FONSatlasNode* n = &stash->atlas->nodes[i];
- if (stash->nverts+6 > FONS_VERTEX_COUNT)
- fons__flush(stash);
- fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
- fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
- fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff);
- fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
- fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc00000ff);
- fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
- }
- fons__flush(stash);
- }
- float fonsTextBounds(FONScontext* stash,
- float x, float y,
- const char* str, const char* end,
- float* bounds)
- {
- FONSstate* state = fons__getState(stash);
- unsigned int codepoint;
- unsigned int utf8state = 0;
- FONSquad q;
- FONSglyph* glyph = NULL;
- int prevGlyphIndex = -1;
- short isize = (short)(state->size*10.0f);
- short iblur = (short)state->blur;
- float scale;
- FONSfont* font;
- float startx, advance;
- float minx, miny, maxx, maxy;
- if (stash == NULL) return 0;
- if (state->font < 0 || state->font >= stash->nfonts) return 0;
- font = stash->fonts[state->font];
- if (font->data == NULL) return 0;
- scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
- // Align vertically.
- y += fons__getVertAlign(stash, font, state->align, isize);
- minx = maxx = x;
- miny = maxy = y;
- startx = x;
- if (end == NULL)
- end = str + strlen(str);
- for (; str != end; ++str) {
- if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
- continue;
- glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL);
- if (glyph != NULL) {
- fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
- if (q.x0 < minx) minx = q.x0;
- if (q.x1 > maxx) maxx = q.x1;
- if (stash->params.flags & FONS_ZERO_TOPLEFT) {
- if (q.y0 < miny) miny = q.y0;
- if (q.y1 > maxy) maxy = q.y1;
- } else {
- if (q.y1 < miny) miny = q.y1;
- if (q.y0 > maxy) maxy = q.y0;
- }
- }
- prevGlyphIndex = glyph != NULL ? glyph->index : -1;
- }
- advance = x - startx;
- // Align horizontally
- if (state->align & FONS_ALIGN_LEFT) {
- // empty
- } else if (state->align & FONS_ALIGN_RIGHT) {
- minx -= advance;
- maxx -= advance;
- } else if (state->align & FONS_ALIGN_CENTER) {
- minx -= advance * 0.5f;
- maxx -= advance * 0.5f;
- }
- if (bounds) {
- bounds[0] = minx;
- bounds[1] = miny;
- bounds[2] = maxx;
- bounds[3] = maxy;
- }
- return advance;
- }
- void fonsVertMetrics(FONScontext* stash,
- float* ascender, float* descender, float* lineh)
- {
- FONSfont* font;
- FONSstate* state = fons__getState(stash);
- short isize;
- if (stash == NULL) return;
- if (state->font < 0 || state->font >= stash->nfonts) return;
- font = stash->fonts[state->font];
- isize = (short)(state->size*10.0f);
- if (font->data == NULL) return;
- if (ascender)
- *ascender = font->ascender*isize/10.0f;
- if (descender)
- *descender = font->descender*isize/10.0f;
- if (lineh)
- *lineh = font->lineh*isize/10.0f;
- }
- void fonsLineBounds(FONScontext* stash, float y, float* miny, float* maxy)
- {
- FONSfont* font;
- FONSstate* state = fons__getState(stash);
- short isize;
- if (stash == NULL) return;
- if (state->font < 0 || state->font >= stash->nfonts) return;
- font = stash->fonts[state->font];
- isize = (short)(state->size*10.0f);
- if (font->data == NULL) return;
- y += fons__getVertAlign(stash, font, state->align, isize);
- if (stash->params.flags & FONS_ZERO_TOPLEFT) {
- *miny = y - font->ascender * (float)isize/10.0f;
- *maxy = *miny + font->lineh*isize/10.0f;
- } else {
- *maxy = y + font->descender * (float)isize/10.0f;
- *miny = *maxy - font->lineh*isize/10.0f;
- }
- }
- const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height)
- {
- if (width != NULL)
- *width = stash->params.width;
- if (height != NULL)
- *height = stash->params.height;
- return stash->texData;
- }
- int fonsValidateTexture(FONScontext* stash, int* dirty)
- {
- if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
- dirty[0] = stash->dirtyRect[0];
- dirty[1] = stash->dirtyRect[1];
- dirty[2] = stash->dirtyRect[2];
- dirty[3] = stash->dirtyRect[3];
- // Reset dirty rect
- stash->dirtyRect[0] = stash->params.width;
- stash->dirtyRect[1] = stash->params.height;
- stash->dirtyRect[2] = 0;
- stash->dirtyRect[3] = 0;
- return 1;
- }
- return 0;
- }
- void fonsDeleteInternal(FONScontext* stash)
- {
- int i;
- if (stash == NULL) return;
- if (stash->params.renderDelete)
- stash->params.renderDelete(stash->params.userPtr);
- for (i = 0; i < stash->nfonts; ++i)
- fons__freeFont(stash->fonts[i]);
- if (stash->atlas) fons__deleteAtlas(stash->atlas);
- if (stash->fonts) free(stash->fonts);
- if (stash->texData) free(stash->texData);
- if (stash->scratch) free(stash->scratch);
- fons__tt_done(stash);
- free(stash);
- }
- void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
- {
- if (stash == NULL) return;
- stash->handleError = callback;
- stash->errorUptr = uptr;
- }
- void fonsGetAtlasSize(FONScontext* stash, int* width, int* height)
- {
- if (stash == NULL) return;
- *width = stash->params.width;
- *height = stash->params.height;
- }
- int fonsExpandAtlas(FONScontext* stash, int width, int height)
- {
- int i, maxy = 0;
- unsigned char* data = NULL;
- if (stash == NULL) return 0;
- width = fons__maxi(width, stash->params.width);
- height = fons__maxi(height, stash->params.height);
- if (width == stash->params.width && height == stash->params.height)
- return 1;
- // Flush pending glyphs.
- fons__flush(stash);
- // Create new texture
- if (stash->params.renderResize != NULL) {
- if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
- return 0;
- }
- // Copy old texture data over.
- data = (unsigned char*)malloc(width * height);
- if (data == NULL)
- return 0;
- for (i = 0; i < stash->params.height; i++) {
- unsigned char* dst = &data[i*width];
- unsigned char* src = &stash->texData[i*stash->params.width];
- memcpy(dst, src, stash->params.width);
- if (width > stash->params.width)
- memset(dst+stash->params.width, 0, width - stash->params.width);
- }
- if (height > stash->params.height)
- memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);
- free(stash->texData);
- stash->texData = data;
- // Increase atlas size
- fons__atlasExpand(stash->atlas, width, height);
- // Add existing data as dirty.
- for (i = 0; i < stash->atlas->nnodes; i++)
- maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
- stash->dirtyRect[0] = 0;
- stash->dirtyRect[1] = 0;
- stash->dirtyRect[2] = stash->params.width;
- stash->dirtyRect[3] = maxy;
- stash->params.width = width;
- stash->params.height = height;
- stash->itw = 1.0f/stash->params.width;
- stash->ith = 1.0f/stash->params.height;
- return 1;
- }
- int fonsResetAtlas(FONScontext* stash, int width, int height)
- {
- int i, j;
- if (stash == NULL) return 0;
- // Flush pending glyphs.
- fons__flush(stash);
- // Create new texture
- if (stash->params.renderResize != NULL) {
- if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
- return 0;
- }
- // Reset atlas
- fons__atlasReset(stash->atlas, width, height);
- // Clear texture data.
- stash->texData = (unsigned char*)realloc(stash->texData, width * height);
- if (stash->texData == NULL) return 0;
- memset(stash->texData, 0, width * height);
- // Reset dirty rect
- stash->dirtyRect[0] = width;
- stash->dirtyRect[1] = height;
- stash->dirtyRect[2] = 0;
- stash->dirtyRect[3] = 0;
- // Reset cached glyphs
- for (i = 0; i < stash->nfonts; i++) {
- FONSfont* font = stash->fonts[i];
- font->nglyphs = 0;
- for (j = 0; j < FONS_HASH_LUT_SIZE; j++)
- font->lut[j] = -1;
- }
- stash->params.width = width;
- stash->params.height = height;
- stash->itw = 1.0f/stash->params.width;
- stash->ith = 1.0f/stash->params.height;
- // Add white rect at 0,0 for debug drawing.
- fons__addWhiteRect(stash, 2,2);
- return 1;
- }
- #endif
|