1
0
Fork 0
LithOS3/lithos_c/lithos3/src/fontnew.c

251 lines
6.5 KiB
C

//-----------------------------------------------------------------------------
//
// Copyright © 2016 Project Golan
//
// See "LICENSE" for more information.
//
//-----------------------------------------------------------------------------
//
// Font creation.
//
//-----------------------------------------------------------------------------
#include "Lth.h"
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#define GenFontData() \
char const **base = Lth_HashMapFind(&rsrc->map, "Font.Base"); \
char const **casing = Lth_HashMapFind(&rsrc->map, "Font.Case"); \
char const **extraDir = Lth_HashMapFind(&rsrc->map, "Font.ExtraDir"); \
char const **glyphList = Lth_HashMapFind(&rsrc->map, "Font.Glyphs"); \
int const *height = Lth_HashMapFind(&rsrc->map, "Font.Height"); \
char const **prefix = Lth_HashMapFind(&rsrc->map, "Font.Prefix"); \
int const *spaceWidth = Lth_HashMapFind(&rsrc->map, "Font.SpaceWidth"); \
char const **suffix = Lth_HashMapFind(&rsrc->map, "Font.Suffix"); \
char const **typeStr = Lth_HashMapFind(&rsrc->map, "Font.Type");
#define FontError(err) \
if(1) \
{ \
fprintf(stderr, "%s: %s\n", __func__, err); \
longjmp(FontJmpBuf, FontJmpBufToken); \
} \
else ((void)0)
// Static Objects ------------------------------------------------------------|
static jmp_buf FontJmpBuf;
static int const FontJmpBufToken = 31;
// Static Functions ----------------------------------------------------------|
//
// FontValidate
//
static void FontValidate(Lth_ResourceMap *rsrc)
{
GenFontData();
if(!glyphList) FontError("Font definition must have a glyph list.");
if(!base && !extraDir) FontError("Font definition doesn't have a font.");
if(!height) FontError("Font definition doesn't have a height.");
}
//
// FontLoadGlyphs
//
static void FontLoadGlyphs(Lth_Font volatile *font, Lth_ResourceMap *rsrc,
int type)
{
char const **glyphList = Lth_HashMapFind(&rsrc->map, "Font.Glyphs");
wchar_t *tmpkey = Lth_wcsdup(L"Font.GlyphData. _ ");
wchar_t *keyl = wcschr(tmpkey, ' ');
wchar_t *keyr = wcsrchr(tmpkey, ' ');
__with(mbstate_t state; size_t i = 0; memset(&state, 0, sizeof(state));)
for(char const *sptr = *glyphList; *sptr; i++)
{
wchar_t wc;
int ret = mbrtowc(&wc, sptr, 4, &state);
if(ret <= 0) FontError("Error parsing Unicode sequence.");
Lth_Glyph glyph = { .ch = wc };
memmove(glyph.mb, sptr, ret);
(*keyl = wc);
int *x = (*keyr = 'x', Lth_HashMapFind(&rsrc->map, tmpkey));
int *y = (*keyr = 'y', Lth_HashMapFind(&rsrc->map, tmpkey));
int *w = (*keyr = 'w', Lth_HashMapFind(&rsrc->map, tmpkey));
int *h = (*keyr = 'h', Lth_HashMapFind(&rsrc->map, tmpkey));
_Accum *s = (*keyr = 's', Lth_HashMapFind(&rsrc->map, tmpkey));
if(x) glyph.x = *x;
if(y) glyph.y = *y;
if(w) glyph.w = *w;
if(h) glyph.h = *h;
if(s) glyph.s = *s;
if(wc > 0x7F)
{
ACS_BeginPrint();
ACS_PrintString(font->fnamePref);
switch(type)
{
case Lth_GT_Chara: Lth_PrintString(glyph.mb); break;
case Lth_GT_Codep: ACS_PrintHex(glyph.ch); break;
case Lth_GT_Digit: ACS_PrintInt(glyph.ch); break;
}
ACS_PrintString(font->fnameSuff);
glyph.fname = ACS_EndStrParam();
}
font->glyphV.data[i] = glyph;
font->glyphs.elem.data[i].keyhash = (size_t)wc;
font->glyphs.elem.data[i].value = &font->glyphV.data[i];
sptr += ret;
}
free(tmpkey);
Lth_HashMapBuild((Lth_HashMap *)&font->glyphs);
}
//
// FontSetup
//
static void FontSetup(Lth_Font volatile *font, Lth_ResourceMap *rsrc)
{
GenFontData();
int type;
if(typeStr)
if(Lth_stricmp(*typeStr, "Character") == 0) type = Lth_GT_Chara;
else if(Lth_stricmp(*typeStr, "Codepoint") == 0) type = Lth_GT_Codep;
else if(Lth_stricmp(*typeStr, "Digit") == 0) type = Lth_GT_Digit;
else FontError("Invalid Font.Type");
else
type = Lth_GT_Chara;
font->height = *height;
if(base)
font->baseName = Lth_strentdup(*base);
if(extraDir)
{
ACS_BeginPrint();
Lth_PrintString(*extraDir);
if((*extraDir)[strlen(*extraDir)] != '/')
ACS_PrintChar('/');
if(prefix)
Lth_PrintString(*prefix);
font->fnamePref = ACS_EndStrParam();
if(suffix) font->fnameSuff = Lth_strentdup(*suffix);
else font->fnameSuff = s".png";
}
if(spaceWidth) font->spaceWidth = *spaceWidth;
else font->spaceWidth = 4;
if(casing)
if(Lth_stricmp(*casing, "Both") == 0)
font->casing = Lth_Case_Both;
else if(Lth_stricmp(*casing, "UpperOnly") == 0)
font->casing = Lth_Case_Uppr;
else if(Lth_stricmp(*casing, "LowerOnly") == 0)
font->casing = Lth_Case_Lowr;
else
FontError("Invalid Font.Case");
else
font->casing = Lth_Case_Both;
font->glyphV.size = Lth_mbslen(*glyphList);
Lth_HashMapAlloc((Lth_HashMap *)&font->glyphs, font->glyphV.size);
Lth_VectorAlloc(Lth_Glyph, font->glyphV);
FontLoadGlyphs(font, rsrc, type);
}
//
// FontPrint
//
// [debug] Print characters out.
//
Lth_ScriptCall static void FontPrint(Lth_Font *font)
{
for(size_t i = 0; i < font->glyphs.elem.size; i++)
__with(Lth_Glyph *glyph = font->glyphs.elem.data[i].value;)
printf("glyph %X (%s)\t\tx: %i\ty: %i\tw: %i\n",
glyph->ch, glyph->mb, glyph->x, glyph->y, glyph->w);
}
// Extern Functions ----------------------------------------------------------|
//
// Lth_FontNew
//
Lth_ScriptCall Lth_Font *Lth_FontNew(char const *fname)
{
Lth_Font volatile *font = NULL;
Lth_ResourceMap *rsrc = NULL;
// Set up error handler.
if(setjmp(FontJmpBuf) == FontJmpBufToken)
{
if(font) Lth_FontDestroy((Lth_Font *)font);
if(rsrc) Lth_ResourceMapDestroy(rsrc);
return NULL;
}
rsrc = Lth_ManifestLoad_extern(fname);
if(rsrc == NULL)
FontError("Couldn't load resource manifest.");
FontValidate(rsrc);
font = calloc(1, sizeof(Lth_Font));
if(font == NULL)
FontError("Failed to allocate font.");
FontSetup(font, rsrc);
Lth_ResourceMapDestroy(rsrc);
return (Lth_Font *)font;
}
//
// Lth_FontDestroy
//
void Lth_FontDestroy(Lth_Font *font)
{
if(font == NULL) return;
Lth_HashMapDestroy(&font->glyphs);
free(font->glyphV.data);
free(font);
}
// EOF