Pārlūkot izejas kodu

Add a minimal freetype extension.

mingodad 9 gadi atpakaļ
vecāks
revīzija
c44eae7e3e
2 mainītis faili ar 491 papildinājumiem un 0 dzēšanām
  1. 416 0
      SquiLu-ext/sq_freetype.cpp
  2. 75 0
      SquiLu/samples/test-freetype.nut

+ 416 - 0
SquiLu-ext/sq_freetype.cpp

@@ -0,0 +1,416 @@
+#ifdef SQ_USE_FREETYPE
+
+#include <string.h>
+#include <stdio.h>
+
+#include "squirrel.h"
+#include "sqstdblobimpl.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "dynamic_library.h"
+
+/*SquiLu
+
+local library_functions = [
+    ["FT_Error", "FT_Init_FreeType", "FT_Library *library"],
+    ["FT_Error", "FT_New_Face", "FT_Library library, const char*  filepathname, FT_Long face_index, FT_Face *aface"],
+    ["FT_Error", "FT_New_Memory_Face", "FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface"],
+    ["FT_Error", "FT_Done_Face", "FT_Face face"],
+    ["FT_Error", "FT_Set_Char_Size", "FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution"],
+    ["FT_Error", "FT_Load_Glyph", "FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags"],
+    ["FT_Error", "FT_Load_Char", "FT_Face face, FT_ULong  char_code, FT_Int32 load_flags"],
+    ["FT_Error", "FT_Get_Glyph_Name", "FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max"],
+    ["const char*", "FT_Get_Postscript_Name", "FT_Face face"],
+    ["FT_Error", "FT_Select_Charmap", "FT_Face face, FT_Encoding  encoding"],
+    ["FT_Error", "FT_Set_Charmap", "FT_Face face, FT_CharMap  charmap"],
+    ["FT_Int", "FT_Get_Charmap_Index", "FT_CharMap  charmap"],
+    ["FT_UInt", "FT_Get_Char_Index", "FT_Face face, FT_ULong  charcode"],
+    ["FT_ULong", "FT_Get_First_Char", "FT_Face face, FT_UInt  *agindex"],
+    ["FT_ULong", "FT_Get_Next_Char", "FT_Face face, FT_ULong   char_code, FT_UInt  *agindex"],
+    ["FT_UInt", "FT_Get_Name_Index", "FT_Face face, FT_String*  glyph_name"],
+
+    //next entry should be the last one
+    //to make valid the test made on load_library function
+    ["FT_Error", "FT_Done_FreeType", "FT_Library library"],
+];
+
+function write_library_functions_declaration(){
+    foreach(k,v in library_functions) {
+        putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
+        putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
+    }
+}
+
+function write_library_functions_load(){
+    foreach(k,v in library_functions){
+        putsnl("dl" + v[1] + " = (" + v[1] + "_t) libdyn.dlsym(\"" + v[1] + "\");");
+        putsnl("if(!dl" + v[1] + ") return false;");
+    }
+}
+
+function write_library_functions_static_defines(){
+    foreach(k,v in library_functions){
+        putsnl("#define dl" + v[1] + " " + v[1]);
+    }
+}
+SquiLu*/
+
+static DynamicLibrary libdyn;
+
+//@write_library_functions_declaration();
+// generated-code:begin
+typedef FT_Error (*FT_Init_FreeType_t)(FT_Library *library);
+static FT_Init_FreeType_t dlFT_Init_FreeType = 0;
+typedef FT_Error (*FT_New_Face_t)(FT_Library library, const char*  filepathname, FT_Long face_index, FT_Face *aface);
+static FT_New_Face_t dlFT_New_Face = 0;
+typedef FT_Error (*FT_New_Memory_Face_t)(FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface);
+static FT_New_Memory_Face_t dlFT_New_Memory_Face = 0;
+typedef FT_Error (*FT_Done_Face_t)(FT_Face face);
+static FT_Done_Face_t dlFT_Done_Face = 0;
+typedef FT_Error (*FT_Set_Char_Size_t)(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution);
+static FT_Set_Char_Size_t dlFT_Set_Char_Size = 0;
+typedef FT_Error (*FT_Load_Glyph_t)(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags);
+static FT_Load_Glyph_t dlFT_Load_Glyph = 0;
+typedef FT_Error (*FT_Load_Char_t)(FT_Face face, FT_ULong  char_code, FT_Int32 load_flags);
+static FT_Load_Char_t dlFT_Load_Char = 0;
+typedef FT_Error (*FT_Get_Glyph_Name_t)(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max);
+static FT_Get_Glyph_Name_t dlFT_Get_Glyph_Name = 0;
+typedef const char* (*FT_Get_Postscript_Name_t)(FT_Face face);
+static FT_Get_Postscript_Name_t dlFT_Get_Postscript_Name = 0;
+typedef FT_Error (*FT_Select_Charmap_t)(FT_Face face, FT_Encoding  encoding);
+static FT_Select_Charmap_t dlFT_Select_Charmap = 0;
+typedef FT_Error (*FT_Set_Charmap_t)(FT_Face face, FT_CharMap  charmap);
+static FT_Set_Charmap_t dlFT_Set_Charmap = 0;
+typedef FT_Int (*FT_Get_Charmap_Index_t)(FT_CharMap  charmap);
+static FT_Get_Charmap_Index_t dlFT_Get_Charmap_Index = 0;
+typedef FT_UInt (*FT_Get_Char_Index_t)(FT_Face face, FT_ULong  charcode);
+static FT_Get_Char_Index_t dlFT_Get_Char_Index = 0;
+typedef FT_ULong (*FT_Get_First_Char_t)(FT_Face face, FT_UInt  *agindex);
+static FT_Get_First_Char_t dlFT_Get_First_Char = 0;
+typedef FT_ULong (*FT_Get_Next_Char_t)(FT_Face face, FT_ULong   char_code, FT_UInt  *agindex);
+static FT_Get_Next_Char_t dlFT_Get_Next_Char = 0;
+typedef FT_UInt (*FT_Get_Name_Index_t)(FT_Face face, FT_String*  glyph_name);
+static FT_Get_Name_Index_t dlFT_Get_Name_Index = 0;
+typedef FT_Error (*FT_Done_FreeType_t)(FT_Library library);
+static FT_Done_FreeType_t dlFT_Done_FreeType = 0;
+// generated-code:end
+
+static const char *dynamicLibName = DYNLIB_FOR_OS(libfreetype);
+
+static bool load_library(const char *libname)
+{
+    if(dlFT_Done_FreeType) return true;
+    if(libdyn.open(libname))
+    {
+        //@write_library_functions_load();
+// generated-code:begin
+dlFT_Init_FreeType = (FT_Init_FreeType_t) libdyn.dlsym("FT_Init_FreeType");
+if(!dlFT_Init_FreeType) return false;
+dlFT_New_Face = (FT_New_Face_t) libdyn.dlsym("FT_New_Face");
+if(!dlFT_New_Face) return false;
+dlFT_New_Memory_Face = (FT_New_Memory_Face_t) libdyn.dlsym("FT_New_Memory_Face");
+if(!dlFT_New_Memory_Face) return false;
+dlFT_Done_Face = (FT_Done_Face_t) libdyn.dlsym("FT_Done_Face");
+if(!dlFT_Done_Face) return false;
+dlFT_Set_Char_Size = (FT_Set_Char_Size_t) libdyn.dlsym("FT_Set_Char_Size");
+if(!dlFT_Set_Char_Size) return false;
+dlFT_Load_Glyph = (FT_Load_Glyph_t) libdyn.dlsym("FT_Load_Glyph");
+if(!dlFT_Load_Glyph) return false;
+dlFT_Load_Char = (FT_Load_Char_t) libdyn.dlsym("FT_Load_Char");
+if(!dlFT_Load_Char) return false;
+dlFT_Get_Glyph_Name = (FT_Get_Glyph_Name_t) libdyn.dlsym("FT_Get_Glyph_Name");
+if(!dlFT_Get_Glyph_Name) return false;
+dlFT_Get_Postscript_Name = (FT_Get_Postscript_Name_t) libdyn.dlsym("FT_Get_Postscript_Name");
+if(!dlFT_Get_Postscript_Name) return false;
+dlFT_Select_Charmap = (FT_Select_Charmap_t) libdyn.dlsym("FT_Select_Charmap");
+if(!dlFT_Select_Charmap) return false;
+dlFT_Set_Charmap = (FT_Set_Charmap_t) libdyn.dlsym("FT_Set_Charmap");
+if(!dlFT_Set_Charmap) return false;
+dlFT_Get_Charmap_Index = (FT_Get_Charmap_Index_t) libdyn.dlsym("FT_Get_Charmap_Index");
+if(!dlFT_Get_Charmap_Index) return false;
+dlFT_Get_Char_Index = (FT_Get_Char_Index_t) libdyn.dlsym("FT_Get_Char_Index");
+if(!dlFT_Get_Char_Index) return false;
+dlFT_Get_First_Char = (FT_Get_First_Char_t) libdyn.dlsym("FT_Get_First_Char");
+if(!dlFT_Get_First_Char) return false;
+dlFT_Get_Next_Char = (FT_Get_Next_Char_t) libdyn.dlsym("FT_Get_Next_Char");
+if(!dlFT_Get_Next_Char) return false;
+dlFT_Get_Name_Index = (FT_Get_Name_Index_t) libdyn.dlsym("FT_Get_Name_Index");
+if(!dlFT_Get_Name_Index) return false;
+dlFT_Done_FreeType = (FT_Done_FreeType_t) libdyn.dlsym("FT_Done_FreeType");
+if(!dlFT_Done_FreeType) return false;
+// generated-code:end
+        return true;
+    }
+    return false;
+}
+
+#undef KLASS_VAR
+#define KLASS_VAR(Klass, Var) Klass Var
+
+static const SQChar Freetype_Tag[]   = _SC("sqFreetype");
+#define GET_freetype_INSTANCE_AT(idx, self) SQ_GET_INSTANCE2(v, idx, self, FT_Library, Freetype_Tag) \
+	if(self == NULL) return sq_throwerror(v, _SC("sqfreetype object already closed"));
+#define GET_freetype_INSTANCE() GET_freetype_INSTANCE_AT(1, self)
+
+
+static SQRESULT sq_freetype_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
+{
+	FT_Library self = ((FT_Library)p);
+	if(self)
+    {
+        dlFT_Done_FreeType(self);
+    }
+	return 1;
+}
+
+static SQRESULT sq_freetype_constructor(HSQUIRRELVM v)
+{
+    if(!load_library(dynamicLibName)) return sq_throwerror(v, _SC("Failed to load libfreetype !"));
+    FT_Library library;
+	FT_Error error = dlFT_Init_FreeType( &library );
+	if(error)
+    {
+        return sq_throwerror(v,_SC("Failed to initialize FreeType library"));
+    }
+
+	sq_setinstanceup(v,1,library);
+	sq_setreleasehook(v,1,sq_freetype_releasehook);
+	return 0;
+}
+
+static SQRESULT sq_freetype_loadlib(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    SQ_GET_STRING(v, 2, libname);
+    sq_pushbool(v, load_library(libname));
+	return 1;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_freetype_##name,nparams,tycheck}
+static SQRegFunction sq_freetype_methods[] =
+{
+	_DECL_FUNC(constructor,1,_SC(".")),
+    _DECL_FUNC(loadlib,2,_SC(".s")),
+    {0,0}
+};
+#undef _DECL_FUNC
+
+static const SQChar FreetypeFace_Tag[]   = _SC("sqFreetypeFace");
+#define GET_freetype_face_INSTANCE_AT(idx, self) SQ_GET_INSTANCE2(v, idx, self, FT_Face, FreetypeFace_Tag) \
+	if(self == NULL) return sq_throwerror(v, _SC("sqFreetypeFace object already closed"));
+#define GET_freetype_face_INSTANCE() GET_freetype_face_INSTANCE_AT(1, self)
+
+static SQRESULT sq_freetype_face_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
+{
+	FT_Face self = ((FT_Face)p);
+	if(self)
+    {
+        FT_Done_Face(self);
+    }
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_constructor(HSQUIRRELVM v)
+{
+    if(!load_library(dynamicLibName)) return sq_throwerror(v, _SC("Failed to load libpcre !"));
+	SQ_FUNC_VARS(v);
+	GET_freetype_INSTANCE_AT(2, library);
+	SQ_GET_STRING(v, 3, fname);
+	SQ_OPT_INTEGER(v, 4, face_index, 0);
+	SQ_OPT_BOOL(v, 5, isMemory, SQFalse);
+
+	FT_Face face;
+	FT_Error error;
+	if(isMemory) error = dlFT_New_Memory_Face(library, (const FT_Byte*)fname, fname_size, face_index, &face);
+	else error = dlFT_New_Face(library, (const char*)fname, face_index, &face);
+
+	if(error)
+    {
+        return sq_throwerror(v,_SC("Could not create freetype face"));
+    }
+
+	sq_setinstanceup(v,1,face);
+	sq_setreleasehook(v,1,sq_freetype_face_releasehook);
+	return 0;
+}
+
+static SQRESULT sq_freetype_face_set_char_size(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS(v);
+    GET_freetype_face_INSTANCE();
+    SQ_GET_INTEGER(v, 2, char_width);
+    SQ_GET_INTEGER(v, 3, char_height);
+    SQ_OPT_INTEGER(v, 4, horz_resolution, 0);
+    SQ_OPT_INTEGER(v, 5, vert_resolution, 0);
+    sq_pushinteger(v, dlFT_Set_Char_Size(self, char_width, char_height, horz_resolution, vert_resolution));
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_load_char(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS(v);
+    GET_freetype_face_INSTANCE();
+    SQ_GET_INTEGER(v, 2, char_idx);
+    SQ_OPT_INTEGER(v, 3, load_flags, FT_LOAD_RENDER);
+    FT_GlyphSlot slot = self->glyph;
+    FT_Error error = dlFT_Load_Char(self, char_idx, load_flags);
+    if(error) sq_pushinteger(v, error);
+    else sq_pushstring(v, (const SQChar*)slot->bitmap.buffer,
+                       slot->bitmap.pitch * slot->bitmap.rows * sizeof (unsigned char));
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_load_glyph(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS(v);
+    GET_freetype_face_INSTANCE();
+    SQ_GET_INTEGER(v, 2, glyph_idx);
+    SQ_OPT_INTEGER(v, 3, load_flags, FT_LOAD_RENDER);
+    FT_GlyphSlot slot = self->glyph;
+    FT_Error error = dlFT_Load_Glyph(self, glyph_idx, load_flags);
+    if(error) sq_pushinteger(v, error);
+    else sq_pushstring(v, (const SQChar*)slot->bitmap.buffer,
+                       slot->bitmap.pitch * slot->bitmap.rows * sizeof (unsigned char));
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_char_index(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    SQ_GET_INTEGER(v, 2, glyph_idx);
+    sq_pushinteger(v, dlFT_Get_Char_Index(self, glyph_idx));
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_first_char(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    FT_UInt agindex;
+    FT_ULong charcode = dlFT_Get_First_Char(self, &agindex);
+    sq_newarray(v, 2);
+    sq_pushinteger(v, charcode);
+    sq_arrayset(v, -2, 0);
+    sq_pushinteger(v, agindex);
+    sq_arrayset(v, -2, 1);
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_next_char(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    SQ_GET_INTEGER(v, 2, char_idx);
+    FT_UInt agindex;
+    FT_ULong charcode = dlFT_Get_Next_Char(self, char_idx, &agindex);
+    sq_newarray(v, 2);
+    sq_pushinteger(v, charcode);
+    sq_arrayset(v, -2, 0);
+    sq_pushinteger(v, agindex);
+    sq_arrayset(v, -2, 1);
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_name_index(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    SQ_GET_STRING(v, 2, char_name);
+    FT_UInt gindex = dlFT_Get_Name_Index(self, (FT_String*)char_name);
+    sq_pushinteger(v, gindex);
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_glyph_name(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    if(FT_HAS_GLYPH_NAMES(self))
+    {
+        SQ_GET_INTEGER(v, 2, glyph_idx);
+        SQInteger buf_size = 254;
+        SQChar *buf = sq_getscratchpad(v, buf_size);
+        FT_Error error = dlFT_Get_Glyph_Name(self, glyph_idx, buf, buf_size);
+        if(error) sq_pushinteger(v, error);
+        else sq_pushstring(v, buf, buf_size);
+    }
+    else sq_pushnull(v);
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_postscript_name(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    const char *pname = dlFT_Get_Postscript_Name(self);
+    if(pname) sq_pushstring(v, pname, -1);
+    else sq_pushnull(v);
+	return 1;
+}
+
+static SQRESULT sq_freetype_face_get_num_glyphs(HSQUIRRELVM v)
+{
+	SQ_FUNC_VARS_NO_TOP(v);
+    GET_freetype_face_INSTANCE();
+    sq_pushinteger(v, self->num_glyphs);
+	return 1;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_freetype_face_##name,nparams,tycheck}
+static SQRegFunction sq_freetype_face_methods[] =
+{
+	_DECL_FUNC(constructor,-3,_SC(".xsnb")),
+    _DECL_FUNC(set_char_size,-3,_SC(".iiii")),
+    _DECL_FUNC(get_num_glyphs,1,_SC("x")),
+    _DECL_FUNC(load_char,-2,_SC("xi")),
+    _DECL_FUNC(load_glyph,-2,_SC("xi")),
+    _DECL_FUNC(first_char,1,_SC("x")),
+    _DECL_FUNC(next_char,2,_SC("xi")),
+    _DECL_FUNC(char_index,2,_SC("xi")),
+    _DECL_FUNC(name_index,2,_SC("xs")),
+    _DECL_FUNC(glyph_name,2,_SC("xi")),
+    _DECL_FUNC(postscript_name,1,_SC("x")),
+    {0,0}
+};
+#undef _DECL_FUNC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SQRESULT sqext_register_freetype(HSQUIRRELVM v)
+{
+    sq_pushstring(v, Freetype_Tag,-1);
+    sq_newclass(v,SQFalse);
+    sq_settypetag(v,-1,(void*)Freetype_Tag);
+    sq_insert_reg_funcs(v, sq_freetype_methods);
+
+    /*
+	//add constants
+	KeyIntPtrType KeyIntPtr;
+	for (KeyIntPtr = sqfreetype_constants; KeyIntPtr->Str; KeyIntPtr++) {
+		sq_pushstring(v, KeyIntPtr->Str, -1);    //first the key
+		sq_pushinteger(v, KeyIntPtr->Val);       //then the value
+		sq_newslot(v, -3, SQFalse);              //store then
+	}
+	*/
+
+    sq_newslot(v,-3,SQTrue);
+
+    sq_pushstring(v, FreetypeFace_Tag,-1);
+    sq_newclass(v,SQFalse);
+    sq_settypetag(v,-1,(void*)FreetypeFace_Tag);
+    sq_insert_reg_funcs(v, sq_freetype_face_methods);
+    sq_newslot(v,-3,SQTrue);
+
+    return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SQ_USE_FREETYPE

+ 75 - 0
SquiLu/samples/test-freetype.nut

@@ -0,0 +1,75 @@
+//print(sqFreetype.loadlib("/usr/lib/x86_64-linux-gnu/libfreetype.so"));
+auto ft_library = new sqFreetype();
+//print(ft_library);
+
+auto function getFontGlyps(ft_library, font_fname, isMemory=false, max_glyphs=256)
+{
+	auto face = new sqFreetypeFace(ft_library, font_fname, 0, isMemory);
+	//print(face);
+	auto face_num_glyps = face.get_num_glyphs();
+	if(face_num_glyps > max_glyphs) face_num_glyps = max_glyphs;
+	//auto font_size = 64*12;
+	auto font_size = 32*12;
+	face.set_char_size(font_size, font_size);
+	auto glyphs = array(face_num_glyps);
+	for(auto i=0; i < face_num_glyps; ++i)
+	{
+		glyphs[i] = face.load_char(i);
+	}
+	return [face, glyphs];
+}
+
+auto function crossMatch(font1_glyphs, font2_glyphs)
+{
+	auto face1 = font1_glyphs[0];
+	auto glyphs1 = font1_glyphs[1];
+
+	auto face2 = font2_glyphs[0];
+	auto glyphs2 = font2_glyphs[1];
+
+	auto first_char = face2.first_char();
+	print(glyphs1.len(), glyphs2.len(), first_char[0], first_char[1], face2.postscript_name());
+
+	for(auto n0=0, len0=glyphs1.len(); n0 < len0; ++n0)
+	{
+		auto glyph1 = glyphs1[n0];
+		for(auto n2=0, len2=glyphs2.len(); n2 < len2; ++n2)
+		{
+			auto glyph2 = glyphs2[n2];
+			if(glyph1 == glyph2)
+			{
+				auto glyph_index = face2.char_index(n2);
+				print("Glyphs are equal", n0, n2, face2.glyph_name(glyph_index));
+				break;
+			}
+		}	
+	}
+}
+
+auto font1_fname = "../tmp/CLFGJN_Arial_Bold.font";
+//auto font1_data = readfile(font1_fname);
+//auto font1_glyphs = getFontGlyps(ft_library, font1_data, true);
+
+//auto font1_glyphs = getFontGlyps(ft_library, font1_fname);
+
+auto font_ref_bold_glyphs = getFontGlyps(ft_library, "../tmp/Arial_Bold.ttf");
+auto font_ref_glyphs = getFontGlyps(ft_library, "../tmp/Arial.ttf");
+//crossMatch(font1_glyphs, font2_glyphs);
+
+foreach(fn in ["CLFGJN_Arial_Bold.font", "CLFGKO_Arial.font", 
+	"CLFGON_Helvetica.font", "CLFGPO_Helvetica_Bold.font",
+	"CLFHEN_Helvetica_Bold.font", "CLFHEO_Helvetica.font"])
+{
+	print("\nShowing font ", fn);
+	auto font_glyphs = getFontGlyps(ft_library, "../tmp/" + fn);
+	crossMatch(font_glyphs, (fn.indexOf("Bold") > 0) ? font_ref_bold_glyphs : font_ref_glyphs);
+}
+
+
+/*
+for(auto n2=0, len2=glyphs2.len(); n2 < len2; ++n2)
+{
+	auto glyph_index = face2.char_index(n2);
+	print("Glyphs name", n2, glyph_index, face2.glyph_name(glyph_index));
+}
+*/