Skip to content

Commit

Permalink
Add freetype LCD fonts. Tweak the font gamma settings. Add TextField.…
Browse files Browse the repository at this point in the history
…defaultForceFreeType
  • Loading branch information
hughsando committed Mar 29, 2024
1 parent c74fec0 commit 4e2aeba
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 49 deletions.
4 changes: 2 additions & 2 deletions project/include/Font.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class FontFace
virtual ~FontFace() { };

static FontFace *CreateNative(const TextFormat &inFormat,double inScale, AntiAliasType aaType);
static FontFace *CreateFreeType(const TextFormat &inFormat,double inScale,FontBuffer inBytes, const std::string &inCombinedName);
static FontFace *CreateFreeType(const TextFormat &inFormat,double inScale,AntiAliasType aaType,FontBuffer inBytes, const std::string &inCombinedName);
static FontFace *CreateCFFIFont(const TextFormat &inFormat,double inScale);

virtual bool GetGlyphInfo(int inChar, int &outW, int &outH, int &outAdvance,
Expand Down Expand Up @@ -213,7 +213,7 @@ class Font : public Object

Font *IncRef() { Object::IncRef(); return this; }

Tile GetGlyph(int inCharacter,int &outAdvance6);
const Tile &GetGlyph(int inCharacter,int &outAdvance6);

void UpdateMetrics(TextLineMetrics &ioMetrics);

Expand Down
10 changes: 5 additions & 5 deletions project/src/common/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ Font::~Font()



Tile Font::GetGlyph(int inCharacter,int &outAdvance)
const Tile &Font::GetGlyph(int inCharacter,int &outAdvance)
{
bool use_default = false;
Glyph &glyph = inCharacter < 128 ? mGlyph[inCharacter] : mExtendedGlyph[inCharacter];
Expand All @@ -201,7 +201,7 @@ Tile Font::GetGlyph(int inCharacter,int &outAdvance)
}
else
{
Tile result = GetGlyph('?',outAdvance);
const Tile &result = GetGlyph('?',outAdvance);
glyph = mGlyph['?'];
return result;
}
Expand Down Expand Up @@ -242,7 +242,7 @@ Tile Font::GetGlyph(int inCharacter,int &outAdvance)
mCurrentSheet = -1;
}
// Now fill rect...
Tile tile = mSheets[glyph.sheet]->GetTile(glyph.tile);
const Tile &tile = mSheets[glyph.sheet]->GetTile(glyph.tile);
// SharpenText(bitmap);
RenderTarget target = tile.mSurface->BeginRender(tile.mRect);
if (use_default)
Expand Down Expand Up @@ -517,7 +517,7 @@ Font *Font::Create(TextFormat &inFormat,double inScale,bool inNative,AntiAliasTy

if (bytes)
{
face = FontFace::CreateFreeType(inFormat,inScale,bytes,pass==0 ? seekName : "");
face = FontFace::CreateFreeType(inFormat,inScale,aaType,bytes,pass==0 ? seekName : "");
if (face)
break;
}
Expand All @@ -532,7 +532,7 @@ Font *Font::Create(TextFormat &inFormat,double inScale,bool inNative,AntiAliasTy
#endif

if (!face)
face = FontFace::CreateFreeType(inFormat,inScale,NULL,"");
face = FontFace::CreateFreeType(inFormat,inScale,aaType,NULL,"");

#ifndef HX_WINRT
if (!native && !face)
Expand Down
92 changes: 65 additions & 27 deletions project/src/common/FreeType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,22 @@

#include "ByteArray.h"

#define NME_FREETYPE_FLAGS (FT_LOAD_FORCE_AUTOHINT|FT_LOAD_DEFAULT)
#ifdef EMSCRIPTEN
// There is a bug on the proto-types of AF_WritingSystemClass this might need fixing
#define NME_FREETYPE_NORMAL_FLAGS (FT_LOAD_DEFAULT)
#else
#define NME_FREETYPE_NORMAL_FLAGS (FT_LOAD_FORCE_AUTOHINT|FT_LOAD_DEFAULT)
#endif



#define NME_OUTLINE_END_SQUARE 0x10
#define NME_OUTLINE_EDGE_BEVEL 0x20
#define NME_OUTLINE_EDGE_MITER 0x40

static unsigned char sGammaLUT[256];
static bool sGammaLUTInit = false;

namespace nme
{

Expand All @@ -69,14 +79,15 @@ class FreeTypeFont : public FontFace
bool stroked;
int pad;
FT_Stroker stroker;
AntiAliasType aaType;

public:
// inOutline in 64th of a pixel...
// inOutlineMiter in 16.16 format
FreeTypeFont(FT_Face inFace, int inPixelHeight,
FreeTypeFont(FT_Face inFace, int inPixelHeight, AntiAliasType inAaType,
int inOutline, int inOutlineFlags, unsigned int inOutlineMiter,
int inTransform, void* inBuffer) :
mFace(inFace), mPixelHeight(inPixelHeight),
mFace(inFace), mPixelHeight(inPixelHeight), aaType(inAaType),
mTransform(inTransform), mBuffer(inBuffer)
{
stroked = inOutline>0;
Expand Down Expand Up @@ -105,19 +116,14 @@ class FreeTypeFont : public FontFace
if (mBuffer) free(mBuffer);
}

PixelFormat getImageFormat() const { return aaType==aaAdvancedLcd ? pfRGB : pfAlpha; }

bool LoadBitmap(int inChar,bool andRender=true)
{
int idx = FT_Get_Char_Index( mFace, inChar );

int renderFlags = FT_LOAD_DEFAULT;
#ifndef EMSCRIPTEN
// There is a bug on the proto-types of AF_WritingSystemClass this might need fixing
//if (!(mTransform & (ffItalic|ffBold) ))
renderFlags |= FT_LOAD_FORCE_AUTOHINT;
#endif


int err = FT_Load_Glyph( mFace, idx, renderFlags );
int loadFlags = aaType==aaNormal ? NME_FREETYPE_NORMAL_FLAGS : FT_LOAD_DEFAULT;
int err = FT_Load_Glyph( mFace, idx, loadFlags );
if (err)
return false;

Expand Down Expand Up @@ -150,13 +156,18 @@ class FreeTypeFont : public FontFace


FT_Render_Mode mode = FT_RENDER_MODE_NORMAL;
if (aaType==aaAdvancedLcd)
mode = FT_RENDER_MODE_LCD;
// mode = FT_RENDER_MODE_MONO;
//if (mFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
if (andRender)
{
err = FT_Render_Glyph( mFace->glyph, mode );
if (err)
{
printf("could not render\n");
return false;
}

if (mTransform & ffBold)
{
Expand Down Expand Up @@ -194,15 +205,23 @@ class FreeTypeFont : public FontFace
bitmap = &glyph_bitmap->bitmap;
outOx = glyph_bitmap->left;
outOy = -glyph_bitmap->top;
outAdvance = (glyph->advance.x);
}
else
{
outOx = mFace->glyph->bitmap_left;
outOy = -mFace->glyph->bitmap_top;
outAdvance = (mFace->glyph->advance.x);

FT_Bitmap *bitmap = &mFace->glyph->bitmap;
//if (aaType==aaAdvancedLcd)
// printf(" %c] %dx%d + %d, -> adv=%d \n", inChar, bitmap->width, bitmap->rows, outOx, outAdvance>>6);
}


outW = bitmap->width;
if (aaType==aaAdvancedLcd)
outW = (outW+2)/3;
outH = bitmap->rows;

if (mTransform & ffUnderline)
Expand All @@ -213,7 +232,6 @@ class FreeTypeFont : public FontFace
outH = underlineY1;
}

outAdvance = (mFace->glyph->advance.x);

if (stroked)
FT_Done_Glyph(glyph);
Expand All @@ -239,7 +257,7 @@ class FreeTypeFont : public FontFace
{
FT_Get_Glyph(mFace->glyph, &glyph);
FT_Glyph_StrokeBorder(&glyph, stroker, false, false);
FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
FT_Glyph_To_Bitmap( &glyph, aaType==aaAdvancedLcd ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_NORMAL, 0, 1 );

FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)glyph;
bitmap = &glyph_bitmap->bitmap;
Expand All @@ -257,15 +275,28 @@ class FreeTypeFont : public FontFace
if (h<underlineY1)
h = underlineY1;

if (w>outTarget.mRect.w || h>outTarget.mRect.h)
int bpp = aaType==aaAdvancedLcd ? 3 : 1;
if (w/bpp>outTarget.mRect.w || h>outTarget.mRect.h)
{
printf(" too big %d %d\n", outTarget.mRect.w, outTarget.mRect.h);
return;
}

const unsigned char *lut = nullptr;
if ( (bitmap->pixel_mode==FT_PIXEL_MODE_GRAY || bitmap->pixel_mode == FT_PIXEL_MODE_LCD) && aaType!=aaNormal )
{
if (!sGammaLUTInit)
{
for(int i=0;i<256;i++)
sGammaLUT[i] = pow(i/255.0,1.25)*255 + 0.5;
sGammaLUTInit = true;
}
lut = sGammaLUT;
}

for(int r=0;r<h;r++)
{
uint8 *dest = (uint8 *)outTarget.Row(r + outTarget.mRect.y) + outTarget.mRect.x;
uint8 *dest = (uint8 *)outTarget.Row(r + outTarget.mRect.y) + outTarget.mRect.x*bpp;

int underline = (r>=underlineY0 && r<underlineY1) ? 0xff : 0;

Expand All @@ -287,18 +318,25 @@ class FreeTypeFont : public FontFace
bit >>= 1;
}
}
else if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY)
else if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY || bitmap->pixel_mode == FT_PIXEL_MODE_LCD )
{
/*
char buf[1000];
for(int x=0;x<w;x++)
buf[x] = row[x]>128 ? '#' : ' ';
buf[w] = '\0';
printf("> %s\n", buf);
if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD)
{
char buf[1000];
for(int x=0;x<w;x++)
buf[x] = row[x]>128 ? '#' : ' ';
buf[w] = '\0';
printf("> %s\n", buf);
}
*/

for(int x=0;x<w;x++)
*dest ++ = *row++;// | underline;
if (lut)
for(int x=0;x<w;x++)
*dest ++ = lut[*row++];
else
for(int x=0;x<w;x++)
*dest ++ = *row++;// | underline;
}
}
else if (r>=underlineY0 && r<underlineY1)
Expand Down Expand Up @@ -730,7 +768,7 @@ std::string ToAssetName(const std::string &inPath)
#endif
}

FT_Face FindFont(const std::string &inFontName, unsigned int inFlags, FontBuffer inBuffer, void** pBuffer)
FT_Face FindFont(const std::string &inFontName,unsigned int inFlags, FontBuffer inBuffer, void** pBuffer)
{
std::string fname = inFontName;

Expand Down Expand Up @@ -765,7 +803,7 @@ FT_Face FindFont(const std::string &inFontName, unsigned int inFlags, FontBuffer

extern const char *RemapFontName(const char *inName);

FontFace *FontFace::CreateFreeType(const TextFormat &inFormat,double inScale,FontBuffer inBytes, const std::string &inCombinedName)
FontFace *FontFace::CreateFreeType(const TextFormat &inFormat,double inScale, AntiAliasType aaType, FontBuffer inBytes, const std::string &inCombinedName)
{
if (!sgLibrary)
FT_Init_FreeType( &sgLibrary );
Expand Down Expand Up @@ -827,7 +865,7 @@ FontFace *FontFace::CreateFreeType(const TextFormat &inFormat,double inScale,Fon
if ( inFormat.underline )
transform |= ffUnderline;

return new FreeTypeFont(face,height,scaledOutline,inFormat.outlineFlags.Get(),miter8d8<<8,transform,pBuffer);
return new FreeTypeFont(face,height,aaType,scaledOutline,inFormat.outlineFlags.Get(),miter8d8<<8,transform,pBuffer);
}


Expand Down
5 changes: 3 additions & 2 deletions project/src/common/TextField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1885,7 +1885,7 @@ void TextField::Render( const RenderTarget &inTarget, const RenderState &inState


int a;
Tile tile = group.mFont->GetGlyph( ch, a);
const Tile &tile = group.mFont->GetGlyph( ch, a);

if (fontSurface!=tile.mSurface)
{
Expand Down Expand Up @@ -2208,6 +2208,7 @@ void TextField::Layout(const Matrix &inMatrix, const RenderTarget *inTarget)
int advance6 = 0;
int ch = g.mString[cid];
mCharPos.push_back( UserPoint(charX,charY) );
//printf(" %c : %f\n", ch, charX );
line.mChars++;
char_count++;
cid++;
Expand Down Expand Up @@ -2249,7 +2250,7 @@ void TextField::Layout(const Matrix &inMatrix, const RenderTarget *inTarget)
double right = charX;
if (g.mFont)
{
Tile tile = g.mFont->GetGlyph( ch, advance6 );
const Tile &tile = g.mFont->GetGlyph( ch, advance6 );
charX += advance6*font6ToLocalX;
right += (tile.mRect.w+tile.mOx)*fontToLocal;
if (right<charX)
Expand Down
13 changes: 10 additions & 3 deletions project/src/opengl/OpenGLContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,16 @@ class OGLContext : public HardwareRenderer
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR);
break;
case bmComponentAlpha:
glBlendFunc(0x88F9/*GL_SRC1_COLOR*/, 0x88FA /*GL_ONE_MINUS_SRC1_COLOR*/ );
//glBlendFunc( GL_ONE, GL_ZERO);
break;
if (hasDrawBufferBlend)
{
glBlendFunc(0x88F9/*GL_SRC1_COLOR*/, 0x88FA /*GL_ONE_MINUS_SRC1_COLOR*/ );
//glBlendFunc( GL_ONE, GL_ZERO);
break;
}
else
{
// Fallthough
}
default:
glBlendFunc(premAlpha ? GL_ONE : GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
Expand Down
6 changes: 3 additions & 3 deletions project/src/windows/GDIFont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ class GDIFont : public FontFace
RGB *dest = (RGB *)outTarget.Row(y + outTarget.mRect.y) + outTarget.mRect.x;
for(int x=0;x<outTarget.mRect.w;x++)
{
dest->r = src->r;
dest->g = src->g;
dest->b = src->b;
dest->r = sGammaLUT[src->r];
dest->g = sGammaLUT[src->g];
dest->b = sGammaLUT[src->b];
dest++;
src++;
}
Expand Down
21 changes: 14 additions & 7 deletions samples/02-Text/Sample.hx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Sample extends Sprite

TextField.defaultAntiAliasType = stage.hasHardwareLcdFonts ?
AntiAliasType.ADVANCED_LCD : AntiAliasType.ADVANCED;
TextField.defaultForceFreeType = true;

for(side in 0...2)
{
Expand Down Expand Up @@ -77,7 +78,11 @@ class Sample extends Sprite
input.multiline = true;
input.width = 240;
input.height = 300;
input.text = "Input";
input.text = "Input\n" +
"This app tests font rendering. The LCD (Sub pixel) rendering on hardware requires " +
"an extension that libAngle does not support on windows.\n" +
"You can rebuild with \"neko build.n ndll-windows-m64 -DNME_NO_ANGLE\" or add " +
"the flag to your static links to increase the chances of finding hardware support.";
input.border = true;
input.borderColor = 0x000000;
input.background = true;
Expand All @@ -95,23 +100,25 @@ class Sample extends Sprite
tf.antiAliasType = AntiAliasType.ADVANCED_LCD;
addChild(tf);

for(side in 0...2)
for(side in 0...3)
for(cab in 0...2)
for(aa in 0...3)
{
var tf = new nme.text.TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.background = true;
tf.backgroundColor = side==0 ? 0xe0e0e0 : 0x202020;
tf.backgroundColor = side!=1 ? 0xe0e0e0 : 0x202020;
tf.border = true;
tf.borderColor = side==0 ? 0x000000 : 0x0000ff;
tf.borderColor = side!=1 ? 0x000000 : 0x0000ff;
tf.antiAliasType = aa;
tf.textColor = side==0 ? 0x000000 : 0xffffff;
tf.text = "Utf1 Lorem Ipsum " + cabText[cab] + " " + aaText[aa];
tf.textColor = side!=1 ? 0x000000 : 0xffffff;
tf.forceFreeType = side==2;
var freeT = side==2 ? "FreeType " : "";
tf.text = "Utf1 Lorem Ipsum " + freeT + cabText[cab] + " " + aaText[aa];
tf.cacheAsBitmap = cab==0;

addChild(tf);
tf.x = 20 + side*300;
tf.x = 20 + side*230;
tf.y = 360 + aa*24 + cab*24*3;
}
}
Expand Down
Loading

0 comments on commit 4e2aeba

Please sign in to comment.