diff --git a/lime/graphics/Font.hx b/lime/graphics/Font.hx index 672e9a35d..38f125e84 100644 --- a/lime/graphics/Font.hx +++ b/lime/graphics/Font.hx @@ -27,6 +27,10 @@ typedef GlyphData = { @:autoBuild(lime.Assets.embedFont()) class Font { + + public var image:Image; + public var glyphRects:StringMap; + #if js private static var __canvas:CanvasElement; @@ -52,9 +56,54 @@ class Font { } - public function loadGlyphData (size:Int, glyphs:String="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "):GlyphData { + public function createImage ():Image { - var glyphRects = new StringMap(); + glyphRects = new StringMap(); + + #if (cpp || neko) + + var data = lime_font_create_image (handle); + + if (data == null) { + + return null; + + } else { + + for (glyph in cast (data.glyphs, Array)) { + + glyphRects.set (glyph.char, { + x: glyph.x, + y: glyph.y, + xOffset: glyph.xOffset, + yOffset: glyph.yOffset, + advance: glyph.advance, + width: glyph.width, + height: glyph.height, + }); + + } + + glyphRects = data.glyphRects; + return new Image (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp); + + } + + #end + + } + + public function loadRange (size:Int, start:Int, end:Int) { + + #if (cpp || neko) + + lime_font_load_range (handle, size, start, end); + + #end + + } + + public function loadGlyphs (size:Int, glyphs:String="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. ") { #if js @@ -212,34 +261,6 @@ class Font { #elseif (cpp || neko) lime_font_load_glyphs (handle, size, glyphs); - var data = lime_font_create_image (handle); - - if (data == null) { - - return null; - - } else { - - for (glyph in cast (data.glyphs, Array)) { - - glyphRects.set (glyph.char, { - x: glyph.x, - y: glyph.y, - xOffset: glyph.xOffset, - yOffset: glyph.yOffset, - advance: glyph.advance, - width: glyph.width, - height: glyph.height, - }); - - } - - return { - glyphs: glyphRects, - image: new Image (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp) - }; - - } #end @@ -248,6 +269,7 @@ class Font { #if (cpp || neko) private static var lime_font_load = System.load ("lime", "lime_font_load", 1); private static var lime_font_load_glyphs = System.load ("lime", "lime_font_load_glyphs", 3); + private static var lime_font_load_range = System.load ("lime", "lime_font_load_range", 4); private static var lime_font_create_image = System.load ("lime", "lime_font_create_image", 1); #end diff --git a/lime/graphics/Text.hx b/lime/graphics/Text.hx index 855e678a5..01880eca3 100644 --- a/lime/graphics/Text.hx +++ b/lime/graphics/Text.hx @@ -174,11 +174,11 @@ class Text { } - public function fromString (font:Font, text:String) { + public function fromString (font:Font, size:Int, text:String) { #if (cpp || neko) - return lime_text_from_string (handle, font.handle, text); + return lime_text_from_string (handle, font.handle, size, text); #end @@ -186,7 +186,7 @@ class Text { #if (cpp || neko) private static var lime_text_create = System.load ("lime", "lime_text_create", 3); - private static var lime_text_from_string = System.load ("lime", "lime_text_from_string", 3); + private static var lime_text_from_string = System.load ("lime", "lime_text_from_string", 4); #end } diff --git a/project/include/graphics/Font.h b/project/include/graphics/Font.h index 0b90deb28..b504223b5 100644 --- a/project/include/graphics/Font.h +++ b/project/include/graphics/Font.h @@ -17,6 +17,7 @@ namespace lime { typedef struct { unsigned long codepoint; + unsigned int size; FT_UInt index; FT_Pos height; @@ -29,13 +30,16 @@ namespace lime { public: Font (const char *fontFace); - void LoadGlyphs (int size, const char *glyphs); - value createImage (Image *image); + void LoadGlyphs (size_t size, const char *glyphs); + void LoadRange (size_t size, unsigned long start, unsigned long end); + value renderToImage (Image *image); FT_Face face; private: + bool InsertCodepoint (unsigned long codepoint, size_t size); + std::list glyphList; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 2088c8172..b46d84c46 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include @@ -168,13 +167,25 @@ namespace lime { } + value lime_font_load_range (value fontHandle, value size, value start, value end) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)(intptr_t)val_float (fontHandle); + font->LoadRange (val_int (size), val_int (start), val_int (end)); + #endif + + return alloc_null (); + + } + + value lime_font_create_image (value fontHandle) { #ifdef LIME_FREETYPE Image image; Font *font = (Font*)(intptr_t)val_float (fontHandle); value data = alloc_empty_object (); - alloc_field (data, val_id ("glyphs"), font->createImage (&image)); + alloc_field (data, val_id ("glyphs"), font->renderToImage (&image)); alloc_field (data, val_id ("image"), image.Value ()); return data; #else @@ -207,7 +218,7 @@ namespace lime { } - value lime_text_from_string (value textHandle, value fontHandle, value textString) { + value lime_text_from_string (value textHandle, value fontHandle, value size, value textString) { #if defined(LIME_FREETYPE) && defined(LIME_HARFBUZZ) Image image; @@ -368,9 +379,10 @@ namespace lime { DEFINE_PRIM (lime_image_load, 1); DEFINE_PRIM (lime_font_load, 1); DEFINE_PRIM (lime_font_load_glyphs, 3); + DEFINE_PRIM (lime_font_load_range, 4); DEFINE_PRIM (lime_font_create_image, 1); DEFINE_PRIM (lime_text_create, 3); - DEFINE_PRIM (lime_text_from_string, 3); + DEFINE_PRIM (lime_text_from_string, 4); DEFINE_PRIM (lime_key_event_manager_register, 2); DEFINE_PRIM (lime_lzma_encode, 1); DEFINE_PRIM (lime_lzma_decode, 1); @@ -395,4 +407,4 @@ extern "C" int lime_register_prims () { return 0; -} \ No newline at end of file +} diff --git a/project/src/graphics/Font.cpp b/project/src/graphics/Font.cpp index e37ccce40..ffaf06b60 100644 --- a/project/src/graphics/Font.cpp +++ b/project/src/graphics/Font.cpp @@ -134,7 +134,7 @@ namespace lime { bool CompareGlyphCodepoint (const GlyphInfo &a, const GlyphInfo &b) { - return a.codepoint < b.codepoint; + return a.codepoint < b.codepoint || a.size < b.size; } @@ -188,8 +188,59 @@ namespace lime { } + bool Font::InsertCodepoint (unsigned long codepoint, size_t size) { - void Font::LoadGlyphs (int size, const char *glyphs) { + GlyphInfo info; + info.codepoint = codepoint; + + // search for duplicates, if any + std::list::iterator first = glyphList.begin (); + first = std::lower_bound (first, glyphList.end (), info, CompareGlyphCodepoint); + + // skip duplicates unless they are different sizes + if (codepoint < (*first).codepoint || + (codepoint == (*first).codepoint && size != (*first).size)) { + + info.size = size; + info.index = FT_Get_Char_Index (face, codepoint); + + if (FT_Load_Glyph (face, info.index, FT_LOAD_DEFAULT) != 0) return false; + info.height = face->glyph->metrics.height; + + glyphList.insert (first, info); + + return true; + } + + return false; + + } + + void Font::LoadRange (size_t size, unsigned long start, unsigned long end) { + + size_t hdpi = 72; + size_t vdpi = 72; + size_t hres = 100; + FT_Matrix matrix = { + (int)((1.0/hres) * 0x10000L), + (int)((0.0) * 0x10000L), + (int)((0.0) * 0x10000L), + (int)((1.0) * 0x10000L) + }; + + FT_Set_Char_Size (face, 0, (int)(size*64), (int)(hdpi * hres), vdpi); + FT_Set_Transform (face, &matrix, NULL); + + for (unsigned long codepoint = start; codepoint < end; codepoint++) { + + InsertCodepoint (codepoint, size); + + } + + } + + + void Font::LoadGlyphs (size_t size, const char *glyphs) { size_t hdpi = 72; size_t vdpi = 72; @@ -207,29 +258,13 @@ namespace lime { char *g = (char*)glyphs; while (*g != 0) { - GlyphInfo info; - bool found = false; - info.codepoint = readNextChar(g); - - std::list::iterator first = glyphList.begin (); - first = std::lower_bound (first, glyphList.end (), info, CompareGlyphCodepoint); - - if (info.codepoint < (*first).codepoint) { - - info.index = FT_Get_Char_Index (face, info.codepoint); - - if (FT_Load_Glyph (face, info.index, FT_LOAD_DEFAULT) != 0) continue; - info.height = face->glyph->metrics.height; - - glyphList.insert (first, info); - - } + InsertCodepoint (readNextChar(g), size); } } - value Font::createImage (Image *image) { + value Font::renderToImage (Image *image) { if (!init) { @@ -254,8 +289,22 @@ namespace lime { value rects = alloc_array (glyphList.size()); int rectsIndex = 0; + size_t hdpi = 72; + size_t vdpi = 72; + size_t hres = 100; + FT_Matrix matrix = { + (int)((1.0/hres) * 0x10000L), + (int)((0.0) * 0x10000L), + (int)((0.0) * 0x10000L), + (int)((1.0) * 0x10000L) + }; + for (std::list::iterator it = glyphList.begin(); it != glyphList.end(); it++) { + // recalculate the character size for each glyph since it will vary + FT_Set_Char_Size (face, 0, (int)((*it).size*64), (int)(hdpi * hres), vdpi); + FT_Set_Transform (face, &matrix, NULL); + FT_Load_Glyph (face, (*it).index, FT_LOAD_DEFAULT); if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL) != 0) continue; diff --git a/samples/TextRendering/Source/Main.hx b/samples/TextRendering/Source/Main.hx index d3f4d35fe..8535ca92b 100644 --- a/samples/TextRendering/Source/Main.hx +++ b/samples/TextRendering/Source/Main.hx @@ -30,21 +30,23 @@ class Main extends Application { var text:Text; var font = new Font ("assets/amiri-regular.ttf"); + font.loadRange (16, 32, 128); + font.loadGlyphs (32, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ."); + font.loadGlyphs (32, "صِفخَلقخودكَمثلالشمسإذبَزَغت—يحظىالضَجيعُبهانَلاءَمِعطار "); + var image = font.createImage (); text = new Text (RightToLeft, ScriptArabic, "ar"); - text.fromString (font, "صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ"); - var data = font.loadGlyphData (16, "صِفخَلقخودكَمثلالشمسإذبَزَغت—يحظىالضَجيعُبهانَلاءَمِعطار "); - var image = data.image; + text.fromString (font, 32, "صِف خَلقَ خَودِ كَمِثلِ الشَمسِ إِذ بَزَغَت — يَحظى الضَجيعُ بِها نَجلاءَ مِعطارِ"); text = new Text (LeftToRight, ScriptLatin, "en"); - var data = font.loadGlyphData (32, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ."); - text.fromString (font, "The quick brown fox jumps over the lazy dog."); + text.fromString (font, 16, "The quick brown fox jumps over the lazy dog."); font = new Font ("assets/fireflysung.ttf"); - text = new Text (TopToBottom, ScriptHan, "ch"); - text.fromString (font, "懶惰的姜貓"); + font.loadGlyphs (32, "懶惰的姜貓"); + // var image = font.createImage (); - var chinese = font.loadGlyphData (64, "懶惰的姜貓"); + text = new Text (TopToBottom, ScriptHan, "ch"); + text.fromString (font, 32, "懶惰的姜貓"); switch (context) {