331 lines
6.5 KiB
C
331 lines
6.5 KiB
C
//-----------------------------------------------------------------------------
|
||
//
|
||
// Copyright © 2016 Project Golan
|
||
//
|
||
// See "LICENSE" for more information.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// Font rendering.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
#include "Lth.h"
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "Lth_stdfix.h"
|
||
|
||
#define FontCheckASCII(rst) if((rst)->asciiPrint) FontRenderAPr((rst))
|
||
|
||
|
||
// Type Definitions ----------------------------------------------------------|
|
||
|
||
typedef struct FontRenderState
|
||
{
|
||
Lth_Context *ctx;
|
||
Lth_Font *font;
|
||
bool asciiPrint;
|
||
_Accum ax, ay;
|
||
int x, y;
|
||
int tmpx;
|
||
int origx, origy;
|
||
} FontRenderState;
|
||
|
||
|
||
// Static Objects ------------------------------------------------------------|
|
||
|
||
static Lth_Glyph FontReplacementGlyph = {
|
||
.fname = s"lithos_gfx/ReplacementCharacter.png",
|
||
.ch = 0xFFFD,
|
||
.mb = u8"<EFBFBD>",
|
||
.w = 32,
|
||
.h = 32,
|
||
.s = -1
|
||
};
|
||
|
||
|
||
// Static Functions ----------------------------------------------------------|
|
||
|
||
//
|
||
// ASCII Character
|
||
// Advance Line
|
||
// ASCII Print
|
||
// Advance Space
|
||
// Advance Tabulator
|
||
// Character
|
||
// Finish
|
||
// Glyph
|
||
// Return Line
|
||
// Wide Character
|
||
//
|
||
static void FontRenderACh(FontRenderState *rst, Lth_Glyph *glyph);
|
||
static void FontRenderALn(FontRenderState *rst);
|
||
static void FontRenderAPr(FontRenderState *rst);
|
||
static void FontRenderASp(FontRenderState *rst, int amt);
|
||
static void FontRenderATa(FontRenderState *rst);
|
||
static void FontRenderChr(FontRenderState *rst, wchar_t wc);
|
||
static void FontRenderFin(FontRenderState *rst);
|
||
static void FontRenderGly(FontRenderState *rst, Lth_Glyph *glyph);
|
||
static void FontRenderRLn(FontRenderState *rst);
|
||
static void FontRenderWCh(FontRenderState *rst, wchar_t wc, bool noascii);
|
||
|
||
//
|
||
// FontRenderACh
|
||
//
|
||
static void FontRenderACh(FontRenderState *rst, Lth_Glyph *glyph)
|
||
{
|
||
if(!rst->asciiPrint)
|
||
{
|
||
Lth_HudMessageBegin();
|
||
rst->asciiPrint = true;
|
||
}
|
||
|
||
rst->tmpx += glyph->w;
|
||
ACS_PrintChar(glyph->ch);
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("ASCII_CHAR[%c] ", glyph->ch);
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// FontRenderALn
|
||
//
|
||
static void FontRenderALn(FontRenderState *rst)
|
||
{
|
||
FontCheckASCII(rst);
|
||
|
||
rst->y += rst->font->height;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("NEWLINE ");
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// FontRenderAPr
|
||
//
|
||
static void FontRenderAPr(FontRenderState *rst)
|
||
{
|
||
rst->asciiPrint = false;
|
||
|
||
if(rst->font->baseName)
|
||
{
|
||
_Accum x = rst->x + rst->ax;
|
||
_Accum y = rst->y + rst->ay;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("ASCII_PRINT[%.2k, %.2k] ", x, y);
|
||
#endif
|
||
|
||
ACS_SetFont(rst->font->baseName);
|
||
Lth_HudMessageEnd(rst->ctx, x, y);
|
||
|
||
rst->x += rst->tmpx;
|
||
rst->tmpx = 0;
|
||
}
|
||
else
|
||
{
|
||
__str s = ACS_EndStrParam();
|
||
int len = ACS_StrLen(s);
|
||
|
||
for(int i = 0; i < len; i++)
|
||
FontRenderWCh(rst, s[i], true);
|
||
}
|
||
}
|
||
|
||
//
|
||
// FontRenderASp
|
||
//
|
||
static void FontRenderASp(FontRenderState *rst, int amt)
|
||
{
|
||
FontCheckASCII(rst);
|
||
|
||
rst->x += rst->font->spaceWidth * amt;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("SPACE[%i] ", amt);
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// FontRenderATa
|
||
//
|
||
static void FontRenderATa(FontRenderState *rst)
|
||
{
|
||
FontCheckASCII(rst);
|
||
|
||
int tabw = rst->font->spaceWidth * 8;
|
||
rst->x = Lth_ceilk(rst->x / (_Accum)tabw) * tabw;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("TABULATOR ");
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// FontRenderChr
|
||
//
|
||
static void FontRenderChr(FontRenderState *rst, wchar_t wc)
|
||
{
|
||
switch(wc)
|
||
{
|
||
case L' ': FontRenderASp(rst, 1); break;
|
||
case 0x3000: FontRenderASp(rst, 2); break;
|
||
case L'\t': FontRenderATa(rst); break;
|
||
case L'\n': FontRenderALn(rst);
|
||
case L'\r': FontRenderRLn(rst); break;
|
||
default: FontRenderWCh(rst, wc, false); break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// FontRenderFin
|
||
//
|
||
static void FontRenderFin(FontRenderState *rst)
|
||
{
|
||
FontCheckASCII(rst);
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("DONE\n");
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// FontRenderGly
|
||
//
|
||
static void FontRenderGly(FontRenderState *rst, Lth_Glyph *glyph)
|
||
{
|
||
FontCheckASCII(rst);
|
||
|
||
_Accum w = glyph->w;
|
||
|
||
_Accum scale = 0;
|
||
|
||
if(glyph->s != 0)
|
||
{
|
||
if(glyph->s < 0) scale = rst->font->height / (_Accum)glyph->h;
|
||
else scale = glyph->s;
|
||
|
||
w *= scale;
|
||
}
|
||
|
||
if(scale)
|
||
Lth_ContextScale(rst->ctx, scale);
|
||
|
||
_Accum x = (rst->x + glyph->x) + rst->ax;
|
||
_Accum y = (rst->y + glyph->y) + rst->ax;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("GLYPH[%s][%.2k, %.2k] ", glyph->mb, x, y);
|
||
#endif
|
||
|
||
Lth_DrawSprite(rst->ctx, glyph->fname, x, y);
|
||
|
||
if(scale)
|
||
Lth_ContextScale(rst->ctx, 1);
|
||
|
||
rst->x += w;
|
||
}
|
||
|
||
//
|
||
// FontRenderRLn
|
||
//
|
||
static void FontRenderRLn(FontRenderState *rst)
|
||
{
|
||
FontCheckASCII(rst);
|
||
|
||
rst->x = rst->origx;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("RET_LINE ");
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// FontRenderWCh
|
||
//
|
||
static void FontRenderWCh(FontRenderState *rst, wchar_t wc, bool noascii)
|
||
{
|
||
switch(rst->font->casing)
|
||
{
|
||
case Lth_Case_Both: default: break;
|
||
case Lth_Case_Uppr: if(wc >= L'a' && wc <= L'z') wc -= 0x20; break;
|
||
case Lth_Case_Lowr: if(wc >= L'A' && wc <= L'Z') wc += 0x20; break;
|
||
}
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("CH ");
|
||
#endif
|
||
|
||
Lth_Glyph *glyph = Lth_HashMapFind(&rst->font->glyphs, wc);
|
||
if(glyph == NULL) glyph = &FontReplacementGlyph;
|
||
|
||
if(glyph->ch > 0x7F || noascii) FontRenderGly(rst, glyph);
|
||
else FontRenderACh(rst, glyph);
|
||
}
|
||
|
||
|
||
// Extern Functions ----------------------------------------------------------|
|
||
|
||
//
|
||
// Lth_FontRunPlain
|
||
//
|
||
void Lth_FontRunPlain(Lth_Context *ctx, Lth_Font *font, int x, int y,
|
||
int ax, int ay)
|
||
{
|
||
if(font == NULL)
|
||
{
|
||
ACS_EndStrParam();
|
||
return;
|
||
}
|
||
|
||
FontRenderState rst = {
|
||
.ctx = ctx,
|
||
.font = font,
|
||
.x = x, .y = y,
|
||
.origx = x, .origy = y
|
||
};
|
||
|
||
switch(ax)
|
||
{
|
||
default: case Lth_AX_Lef: rst.ax = 0.1k; break;
|
||
case Lth_AX_Rig: rst.ax = 0.2k; break;
|
||
case Lth_AX_Cen: rst.ax = 0.0k; break;
|
||
}
|
||
|
||
switch(ay)
|
||
{
|
||
default: case Lth_AY_Top: rst.ay = 0.1k; break;
|
||
case Lth_AY_Bot: rst.ay = 0.2k; break;
|
||
case Lth_AY_Cen: rst.ay = 0.0k; break;
|
||
}
|
||
|
||
char *str = Lth_strdup_str(ACS_EndStrParam());
|
||
|
||
Lth_WithMbState()
|
||
for(char const *sptr = str; *sptr;)
|
||
{
|
||
wchar_t wc;
|
||
int ret = mbrtowc(&wc, sptr, 4, &state);
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("%i: ", ret);
|
||
#endif
|
||
|
||
if(ret > 0) FontRenderChr(&rst, wc), sptr += ret;
|
||
else FontRenderGly(&rst, &FontReplacementGlyph), sptr += -ret;
|
||
|
||
#if Lth_DEBUG_FONTRUN
|
||
printf("\n");
|
||
#endif
|
||
}
|
||
|
||
FontRenderFin(&rst);
|
||
|
||
free(str);
|
||
}
|
||
|
||
// EOF
|