diff --git a/project/include/Font.h b/project/include/Font.h index a5deb2c5e..4f1172505 100644 --- a/project/include/Font.h +++ b/project/include/Font.h @@ -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, @@ -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); diff --git a/project/src/common/Font.cpp b/project/src/common/Font.cpp index d5c8affed..ef737cb9c 100644 --- a/project/src/common/Font.cpp +++ b/project/src/common/Font.cpp @@ -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]; @@ -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; } @@ -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) @@ -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; } @@ -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) diff --git a/project/src/common/FreeType.cpp b/project/src/common/FreeType.cpp index 7e32f92ac..09077317b 100644 --- a/project/src/common/FreeType.cpp +++ b/project/src/common/FreeType.cpp @@ -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 { @@ -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; @@ -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; @@ -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) { @@ -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) @@ -213,7 +232,6 @@ class FreeTypeFont : public FontFace outH = underlineY1; } - outAdvance = (mFace->glyph->advance.x); if (stroked) FT_Done_Glyph(glyph); @@ -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; @@ -257,15 +275,28 @@ class FreeTypeFont : public FontFace if (houtTarget.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=underlineY0 && r>= 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;x128 ? '#' : ' '; - buf[w] = '\0'; - printf("> %s\n", buf); + if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD) + { + char buf[1000]; + for(int x=0;x128 ? '#' : ' '; + buf[w] = '\0'; + printf("> %s\n", buf); + } */ - for(int x=0;x=underlineY0 && rGetGlyph( ch, a); + const Tile &tile = group.mFont->GetGlyph( ch, a); if (fontSurface!=tile.mSurface) { @@ -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++; @@ -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 (rightr = 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++; } diff --git a/samples/02-Text/Sample.hx b/samples/02-Text/Sample.hx index 92713a384..bd2fde0c0 100644 --- a/samples/02-Text/Sample.hx +++ b/samples/02-Text/Sample.hx @@ -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) { @@ -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; @@ -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; } } diff --git a/src/nme/text/TextField.hx b/src/nme/text/TextField.hx index 8e8bc44fc..eb9ea5dc1 100644 --- a/src/nme/text/TextField.hx +++ b/src/nme/text/TextField.hx @@ -43,12 +43,15 @@ class TextField extends InteractiveObject public var caretIndex(get, set):Int; public static var defaultAntiAliasType = AntiAliasType.NORMAL; + public static var defaultForceFreeType = false; public function new() { var handle = nme_text_field_create(); super(handle, "TextField"); antiAliasType = defaultAntiAliasType; + if (defaultForceFreeType) + forceFreeType = true; } public function appendText(newText:String):Void