font::font(Window* window){ parentWindow = window; shader = new Shader(window); shader->load(shadersPath + "text.vert", shadersPath + "text.frag", ""); glUseProgram(shader->ID); // FreeType FT_Library ft; // All functions return a value different than 0 whenever an error occurred if (FT_Init_FreeType(&ft)) std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; // Load font as face FT_Face face; if (FT_New_Face(ft, "../fonts/arial.ttf", 0, &face)) std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; // Set size to load glyphs as FT_Set_Pixel_Sizes(face, 0, 48); // Disable byte-alignment restriction glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Load first 128 characters of ASCII set for (GLubyte c = 0; c < 128; c++){ // Load character glyph if (FT_Load_Char(face, c, FT_LOAD_RENDER)){ std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; continue; } // Generate texture GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer ); // Set texture options glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Now store character for later use Character character = { texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), (GLuint)face->glyph->advance.x }; Characters.insert(std::pair<GLchar, Character>(c, character)); } glBindTexture(GL_TEXTURE_2D, 0); // Destroy FreeType once we're finished FT_Done_Face(face); FT_Done_FreeType(ft); // Configure VAO/VBO for texture quads glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); }
gfxfont_t* gfxfont_load(const char*id, const char*filename, unsigned int flags, double quality) { FT_Face face; FT_Error error; const char* fontname = 0; FT_ULong charcode; FT_UInt gindex; gfxfont_t* font; int t; int*glyph2glyph = 0; int*glyph2unicode = 0; int max_unicode = 0; int charmap = -1; int isunicode = 1; int has_had_errors = 0; int num_names = 0; if(ftlibrary == 0) { if(FT_Init_FreeType(&ftlibrary)) { fprintf(stderr, "Couldn't init freetype library!\n"); exit(1); } } error = FT_New_Face(ftlibrary, filename, 0, &face); FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale); #ifdef DEBUG printf("gfxfont_load(%s, %s, %f)\n", id, filename, quality); #endif if(error) { fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error); return 0; } if(face->num_glyphs <= 0) { fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs); return 0; } font = (gfxfont_t*)rfx_calloc(sizeof(gfxfont_t)); //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0); //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin; //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax; //font->leading = font->layout->ascent + font->layout->descent; //font->encoding = FONT_ENCODING_UNICODE; font->max_unicode = 0; font->id = strdup(id); font->glyphs = (gfxglyph_t*)rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t)); glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int)); glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int)); if(FT_HAS_GLYPH_NAMES(face)) { //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*)); } fontname = FT_Get_Postscript_Name(face); #ifdef DEBUG for(t=0;t<face->num_charmaps;t++) { printf("possible encoding: %c%c%c%c (%d of %d)\n", (face->charmaps[t]->encoding >> 24)&255, (face->charmaps[t]->encoding >> 16)&255, (face->charmaps[t]->encoding >> 8)&255, (face->charmaps[t]->encoding >> 0)&255, t+1, face->num_charmaps ); } #endif while(1) { charcode = FT_Get_First_Char(face, &gindex); while(gindex != 0) { if(gindex >= 0 && gindex<face->num_glyphs) { if(!glyph2unicode[gindex]) { glyph2unicode[gindex] = charcode; if(charcode + 1 > font->max_unicode) { font->max_unicode = charcode + 1; } } } charcode = FT_Get_Next_Char(face, charcode, &gindex); } #ifdef DEBUG if(face->charmap) { printf("ENCODING: %c%c%c%c (%d of %d) max_unicode=%d\n", (face->charmap->encoding >> 24)&255, (face->charmap->encoding >> 16)&255, (face->charmap->encoding >> 8)&255, (face->charmap->encoding >> 0)&255, charmap, face->num_charmaps, font->max_unicode ); } else {
/*! \brief Scan a folder for all valid fonts \param fontspath Path of the folder to scan. \return - \c B_OK Success - \c B_NAME_TOO_LONG The path specified is too long - \c B_ENTRY_NOT_FOUND The path does not exist - \c B_LINK_LIMIT A cyclic loop was detected in the file system - \c B_BAD_VALUE Invalid input specified - \c B_NO_MEMORY Insufficient memory to open the folder for reading - \c B_BUSY A busy node could not be accessed - \c B_FILE_ERROR An invalid file prevented the operation. - \c B_NO_MORE_FDS All file descriptors are in use (too many open files). */ status_t FontServer::ScanDirectory(const char *fontspath) { // This bad boy does all the real work. It loads each entry in the // directory. If a valid font file, it adds both the family and the style. // Both family and style are stored internally as BStrings. Once everything int32 validcount=0; FT_Face face; FT_Error error; FT_CharMap charmap; FontFamily *family; DIR* hDir; dirent* psEntry; printf( "FontServer::ScanDirectory(): opening %s\n", fontspath ); if ( (hDir = opendir( fontspath ) ) ) { while( (psEntry = readdir( hDir )) ) { printf( "FontServer::ScanDirectory(): found entry %s\n", psEntry->d_name ); char zFullPath[ PATH_MAX ]; if ( strcmp( psEntry->d_name, "." ) == 0 || strcmp( psEntry->d_name, ".." ) == 0 ) { continue; } strcpy( zFullPath, fontspath ); pathcat( zFullPath, psEntry->d_name ); error=FT_New_Face(ftlib, zFullPath,0,&face); if (error!=0) continue; charmap=_GetSupportedCharmap(face); if(!charmap) { FT_Done_Face(face); continue; } face->charmap=charmap; family=_FindFamily(face->family_name ); if (!family) { #ifdef PRINT_FONT_LIST printf("Font Family: %s\n",face->family_name); #endif family=new FontFamily(face->family_name); families->AddItem(family); } if(family->HasStyle(face->style_name)) { FT_Done_Face(face); continue; } #ifdef PRINT_FONT_LIST printf("\tFont Style: %s\n",face->style_name); #endif // Has vertical metrics? family->AddStyle(zFullPath,face); validcount++; FT_Done_Face(face); } printf( "Directory '%s' scanned, %ld fonts found\n", fontspath, validcount ); closedir( hDir ); } need_update=true; return B_OK; }
unsigned char *gks_ft_get_bitmap(int *x, int *y, int *width, int *height, gks_state_list_t *gkss, const char *text, int length) { FT_Face face; /* font face */ FT_Vector pen; /* glyph position */ FT_BBox bb; /* bounding box */ FT_Vector bearing; /* individual glyph translation */ FT_UInt previous; /* previous glyph index */ FT_Vector spacing; /* amount of additional space between glyphs */ FT_ULong textheight; /* textheight in FreeType convention */ FT_Error error; /* error code */ FT_Matrix rotation; /* text rotation matrix */ FT_UInt size; /* number of pixels of the bitmap */ FT_String *file; /* concatenated font path */ const FT_String *font, *prefix; /* font file name and directory */ FT_UInt *unicode_string; /* unicode text string */ FT_Int halign, valign; /* alignment */ FT_Byte *mono_bitmap = NULL; /* target for rendered text */ FT_Int num_glyphs; /* number of glyphs */ FT_Vector align; FT_Bitmap ftbitmap; FT_UInt codepoint; int i, textfont, dx, dy, value, pos_x, pos_y; unsigned int j, k; double angle; const int windowwidth = *width; const int direction = (gkss->txp <= 3 && gkss->txp >= 0 ? gkss->txp : 0); const FT_Bool vertical = (direction == GKS_K_TEXT_PATH_DOWN || direction == GKS_K_TEXT_PATH_UP); const FT_String *suffix_type1 = ".afm"; if (!init) gks_ft_init(); if (gkss->txal[0] != GKS_K_TEXT_HALIGN_NORMAL) { halign = gkss->txal[0]; } else if (vertical) { halign = GKS_K_TEXT_HALIGN_CENTER; } else if (direction == GKS_K_TEXT_PATH_LEFT) { halign = GKS_K_TEXT_HALIGN_RIGHT; } else { halign = GKS_K_TEXT_HALIGN_LEFT; } valign = gkss->txal[1]; if (valign != GKS_K_TEXT_VALIGN_NORMAL) { valign = gkss->txal[1]; } else { valign = GKS_K_TEXT_VALIGN_BASE; } textfont = abs(gkss->txfont); if (textfont >= 101 && textfont <= 131) textfont -= 100; else if (textfont > 1 && textfont <= 32) textfont = map[textfont - 1]; else textfont = 9; textfont = textfont - 1; font = gks_font_list[textfont]; if (font_face_cache[textfont] == NULL) { prefix = gks_getenv("GKS_FONTPATH"); if (prefix == NULL) { prefix = gks_getenv("GRDIR"); if (prefix == NULL) prefix = GRDIR; } file = (FT_String *) malloc(strlen(prefix) + 7 + strlen(font) + 4 + 1); strcpy(file, prefix); #ifndef _WIN32 strcat(file, "/fonts/"); #else strcat(file, "\\FONTS\\"); #endif strcat(file, font); strcat(file, ".pfb"); error = FT_New_Face(library, file, 0, &face); if (error == FT_Err_Unknown_File_Format) { gks_perror("unknown file format: %s", file); return NULL; } else if (error) { gks_perror("could not open font file: %s", file); return NULL; } if (strcmp(FT_Get_X11_Font_Format(face), "Type 1") == 0) { strcpy(file, prefix); #ifndef _WIN32 strcat(file, "/fonts/"); #else strcat(file, "\\FONTS\\"); #endif strcat(file, font); strcat(file, suffix_type1); FT_Attach_File(face, file); } free(file); font_face_cache[textfont] = face; } else { face = font_face_cache[textfont]; } num_glyphs = length; unicode_string = (FT_UInt *) malloc(length * sizeof(FT_UInt) + 1); if (textfont + 1 == 13) { symbol_to_unicode((FT_Bytes)text, unicode_string, num_glyphs); } else { utf_to_unicode((FT_Bytes)text, unicode_string, &num_glyphs); } textheight = nint(gkss->chh * windowwidth * 64 / caps[textfont]); error = FT_Set_Char_Size(face, nint(textheight * gkss->chxp), textheight, 72, 72); if (error) gks_perror("cannot set text height"); if (gkss->chup[0] != 0.0 || gkss->chup[1] != 0.0) { angle = atan2f(gkss->chup[1], gkss->chup[0]) - M_PI / 2; rotation.xx = nint( cosf(angle) * 0x10000L); rotation.xy = nint(-sinf(angle) * 0x10000L); rotation.yx = nint( sinf(angle) * 0x10000L); rotation.yy = nint( cosf(angle) * 0x10000L); FT_Set_Transform(face, &rotation, NULL); } else { FT_Set_Transform(face, NULL, NULL); } spacing.x = spacing.y = 0; if (gkss->chsp != 0.0) { error = FT_Load_Glyph(face, FT_Get_Char_Index(face, ' '), vertical ? FT_LOAD_VERTICAL_LAYOUT : FT_LOAD_DEFAULT); if (!error) { spacing.x = nint(face->glyph->advance.x * gkss->chsp); spacing.y = nint(face->glyph->advance.y * gkss->chsp); } else { gks_perror("cannot apply character spacing"); } } bb.xMin = bb.yMin = LONG_MAX; bb.xMax = bb.yMax = LONG_MIN; pen.x = pen.y = 0; previous = 0; for (i = 0; i < num_glyphs; i++) { codepoint = unicode_string[direction == GKS_K_TEXT_PATH_LEFT ? (num_glyphs - 1 - i) : i]; error = set_glyph(face, codepoint, &previous, &pen, vertical, &rotation, &bearing, halign); if (error) continue; bb.xMin = ft_min(bb.xMin, pen.x + bearing.x); bb.xMax = ft_max(bb.xMax, pen.x + bearing.x + 64*face->glyph->bitmap.width); bb.yMin = ft_min(bb.yMin, pen.y + bearing.y - 64*face->glyph->bitmap.rows); bb.yMax = ft_max(bb.yMax, pen.y + bearing.y); if (direction == GKS_K_TEXT_PATH_DOWN) { pen.x -= face->glyph->advance.x + spacing.x; pen.y -= face->glyph->advance.y + spacing.y; } else { pen.x += face->glyph->advance.x + spacing.x; pen.y += face->glyph->advance.y + spacing.y; } } *width = (int)((bb.xMax - bb.xMin) / 64); *height = (int)((bb.yMax - bb.yMin) / 64); if (bb.xMax <= bb.xMin || bb.yMax <= bb.yMin) { gks_perror("invalid bitmap size"); free(unicode_string); return NULL; } size = *width * *height; mono_bitmap = (FT_Byte *) safe_realloc(mono_bitmap, size); memset(mono_bitmap, 0, size); pen.x = 0; pen.y = 0; previous = 0; for (i = 0; i < num_glyphs; i++) { bearing.x = bearing.y = 0; codepoint = unicode_string[direction == GKS_K_TEXT_PATH_LEFT ? (num_glyphs - 1 - i) : i]; error = set_glyph(face, codepoint, &previous, &pen, vertical, &rotation, &bearing, halign); if (error) continue; pos_x = ( pen.x + bearing.x - bb.xMin) / 64; pos_y = (-pen.y - bearing.y + bb.yMax) / 64; ftbitmap = face->glyph->bitmap; for (j = 0; j < (unsigned int) ftbitmap.rows; j++) { for (k = 0; k < (unsigned int) ftbitmap.width; k++) { dx = k + pos_x; dy = j + pos_y; value = mono_bitmap[dy * *width + dx]; value += ftbitmap.buffer[j * ftbitmap.pitch + k]; if (value > 255) { value = 255; } mono_bitmap[dy * *width + dx] = value; } } if (direction == GKS_K_TEXT_PATH_DOWN) { pen.x -= face->glyph->advance.x + spacing.x; pen.y -= face->glyph->advance.y + spacing.y; } else { pen.x += face->glyph->advance.x + spacing.x; pen.y += face->glyph->advance.y + spacing.y; } } free(unicode_string); /* Alignment */ if (direction == GKS_K_TEXT_PATH_DOWN) { pen.x += spacing.x; pen.y += spacing.y; } else { pen.x -= spacing.x; pen.y -= spacing.y; } align.x = align.y = 0; if (valign != GKS_K_TEXT_VALIGN_BASE) { align.y = nint(gkss->chh * windowwidth * 64); FT_Vector_Transform(&align, &rotation); if (valign == GKS_K_TEXT_VALIGN_HALF) { align.x = nint(0.5 * align.x); align.y = nint(0.5 * align.y); } else if (valign == GKS_K_TEXT_VALIGN_TOP) { align.x = nint(1.2 * align.x); align.y = nint(1.2 * align.y); } else if (valign == GKS_K_TEXT_VALIGN_BOTTOM) { align.x = nint(-0.2 * align.x); align.y = nint(-0.2 * align.y); } } if (!vertical && halign != GKS_K_TEXT_HALIGN_LEFT) { FT_Vector right; right.x = face->glyph->metrics.width + face->glyph->metrics.horiBearingX; right.y = 0; if (right.x != 0) { FT_Vector_Transform(&right, &rotation); } pen.x += right.x - face->glyph->advance.x; pen.y += right.y - face->glyph->advance.y; if (halign == GKS_K_TEXT_HALIGN_CENTER) { align.x += pen.x / 2; align.y += pen.y / 2; } else if (halign == GKS_K_TEXT_HALIGN_RIGHT) { align.x += pen.x; align.y += pen.y; } } *x += (bb.xMin - align.x) / 64; *y += (bb.yMin - align.y) / 64; return mono_bitmap; }
void drawIndicText(JNIEnv *env, jobject thiz, jstring unicodeText, jint xStart, jint yBaseLine, jint charHeight, jobject lock, jstring fontPath, jint language) { FT_Library ft_library; FT_Face ft_face; hb_font_t *font; hb_buffer_t *buffer; int glyph_count; hb_glyph_info_t *glyph_info; hb_glyph_position_t *glyph_pos; hb_bool_t fail; FT_UInt glyph_index; FT_GlyphSlot slot; FT_Error error; jboolean iscopy; const jchar *text; int num_chars, i; int pen_x; int glyphPosX, glyphPosY; const char *fontFilePath = (*env)->GetStringUTFChars(env, fontPath, NULL); text = (*env)->GetStringChars(env, unicodeText, &iscopy); num_chars = (*env)->GetStringLength(env, unicodeText); /* initialize library */ error = FT_Init_FreeType(&ft_library); if (error) { __android_log_print(6, "drawIndicText", "Error initializing FreeType library\n"); return; } // __android_log_print(2, "drawIndicText", // "Successfully initialized FreeType library\n"); error = FT_New_Face(ft_library, fontFilePath, 0, &ft_face); /* create face object */ if (error == FT_Err_Unknown_File_Format) { __android_log_print(6, "drawIndicText", "The font file could be opened and read, but it appears that its font format is unsupported %s ", fontFilePath); return; } else if (error) { __android_log_print(6, "drawIndicText", "The font file could not be opened or read, or it might be broken"); return; } // __android_log_print(2, "drawIndicText", // "Successfully created font-face object\n"); font = hb_ft_font_create(ft_face, NULL); error = FT_Set_Pixel_Sizes(ft_face, 0, charHeight); /* set character size */ slot = ft_face->glyph; pen_x = xStart; /* Create a buffer for harfbuzz to use */ buffer = hb_buffer_create(); hb_buffer_set_script(buffer, scripts[language]); /* Layout the text */ hb_buffer_add_utf16(buffer, text, num_chars, 0, num_chars); // __android_log_print(2, "drawIndicText", "Before HarfBuzz shape()\n"); hb_shape(font, buffer, NULL, 0); // __android_log_print(2, "drawIndicText", "After HarfBuzz shape()\n"); glyph_count = hb_buffer_get_length(buffer); glyph_info = hb_buffer_get_glyph_infos(buffer, 0); glyph_pos = hb_buffer_get_glyph_positions(buffer, 0); for (i = 0; i < glyph_count; i++) { glyph_index = glyph_info[i].codepoint; // __android_log_print(2, "drawIndicText", "Glyph%d = %x", i, glyph_index); error = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT); if (error) { /* ignore errors */ continue; } /* convert to an anti-aliased bitmap */ error = FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL); if (error) { continue; } /* now, draw to our target surface (convert position) */ draw_bitmap(&slot->bitmap, pen_x + slot->bitmap_left, yBaseLine - slot->bitmap_top, env, thiz, lock); /* increment pen position */ pen_x += slot->advance.x >> 6; } hb_buffer_destroy(buffer); (*env)->ReleaseStringChars(env, unicodeText, text); (*env)->ReleaseStringUTFChars(env, fontPath, fontFilePath); hb_font_destroy(font); FT_Done_Face(ft_face); FT_Done_FreeType(ft_library); return; }
static Bool ft_enum_fonts(void *cbck, char *file_name, char *file_path, GF_FileEnumInfo *file_info) { char *szfont; FT_Face face; u32 num_faces, i; GF_FontReader *dr = cbck; FTBuilder *ftpriv = dr->udta; GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Enumerating font %s (%s)\n", file_name, file_path)); if (FT_New_Face(ftpriv->library, file_path, 0, & face )) return 0; if (!face || !face->family_name) return 0; num_faces = face->num_faces; /*locate right font in collection if several*/ for (i=0; i<num_faces; i++) { /*only scan scalable fonts*/ if (face->face_flags & FT_FACE_FLAG_SCALABLE) { Bool bold, italic; szfont = gf_malloc(sizeof(char)* (strlen(face->family_name)+100)); if (!szfont) continue; strcpy(szfont, face->family_name); /*remember first font found which looks like a alphabetical one*/ if (!ftpriv->font_dir) { u32 gidx; FT_Select_Charmap(face, FT_ENCODING_UNICODE); gidx = FT_Get_Char_Index(face, (u32) 'a'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) 'z'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) '1'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) '@'); if (gidx) ftpriv->font_dir = gf_strdup(szfont); } bold = italic = 0; if (face->style_name) { char *name = gf_strdup(face->style_name); strupr(name); if (strstr(name, "BOLD")) bold = 1; if (strstr(name, "ITALIC")) italic = 1; /*if font is not regular style, append all styles blindly*/ if (!strstr(name, "REGULAR")) { strcat(szfont, " "); strcat(szfont, face->style_name); } gf_free(name); } else { if (face->style_flags & FT_STYLE_FLAG_BOLD) bold = 1; if (face->style_flags & FT_STYLE_FLAG_ITALIC) italic = 1; if (bold) strcat(szfont, " Bold"); if (italic) strcat(szfont, " Italic"); } gf_modules_set_option((GF_BaseInterface *)dr, "FontEngine", szfont, file_path); /*try to assign default fixed fonts*/ if (!bold && !italic) { strcpy(szfont, face->family_name); strlwr(szfont); if (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { setBestFont(BEST_FIXED_FONTS, &(ftpriv->font_fixed), face->family_name); } setBestFont(BEST_SERIF_FONTS, &(ftpriv->font_serif), face->family_name); setBestFont(BEST_SANS_FONTS, &(ftpriv->font_sans), face->family_name); } gf_free(szfont); } FT_Done_Face(face); if (i+1==num_faces) return 0; /*load next font in collection*/ if (FT_New_Face(ftpriv->library, file_path, i+1, & face )) return 0; if (!face) return 0; } return 0; }
FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) : m_pattern(0) , m_size(fontDescription.computedSize()) , m_syntheticBold(false) , m_syntheticOblique(false) , m_scaledFont(0) , m_face(0) { FontPlatformData::init(); CString familyNameString = familyName.string().utf8(); const char* fcfamily = familyNameString.data(); int fcslant = FC_SLANT_ROMAN; // FIXME: Map all FontWeight values to fontconfig weights. int fcweight = FC_WEIGHT_NORMAL; float fcsize = fontDescription.computedSize(); if (fontDescription.italic()) fcslant = FC_SLANT_ITALIC; if (fontDescription.weight() >= FontWeight600) fcweight = FC_WEIGHT_BOLD; FcConfig *config = FcConfigGetCurrent(); //printf("family = %s\n", fcfamily); int type = fontDescription.genericFamily(); FcPattern* pattern = FcPatternCreate(); if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) goto freePattern; switch (type) { case FontDescription::SerifFamily: fcfamily = "serif"; break; case FontDescription::SansSerifFamily: fcfamily = "sans-serif"; break; case FontDescription::MonospaceFamily: fcfamily = "monospace"; break; case FontDescription::NoFamily: case FontDescription::StandardFamily: default: fcfamily = "sans-serif"; } if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) goto freePattern; if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant)) goto freePattern; if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight)) goto freePattern; if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fcsize)) goto freePattern; FcConfigSubstitute(config, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult fcresult; m_pattern = FcFontMatch(config, pattern, &fcresult); FcPatternReference(m_pattern); // FIXME: should we set some default font? if (!m_pattern) goto freePattern; FcChar8 *fc_filename; char *filename; int id; id = 0; if (FcPatternGetString(m_pattern, FC_FILE, 0, &fc_filename) != FcResultMatch) { DS_WAR("cannot retrieve font\n"); goto freePattern; } filename = (char *) fc_filename; //use C cast as FcChar is a fontconfig type //printf("filename = %s\n", filename); if (FcPatternGetInteger(m_pattern, FC_INDEX, 0, &id) != FcResultMatch) { DS_WAR("cannot retrieve font index\n"); goto freePattern; } if (FT_Error error = FT_New_Face(m_library, filename, id, &m_face)) { //if (FT_Error error = FT_New_Face(m_library, too, id, &m_face)) { DS_WAR("fail to open font" << filename << "with index " << id << " (error = 0x%x)\n" << error); m_face = 0; goto freePattern; } FT_Set_Pixel_Sizes(m_face, 0, static_cast<uint> (fontDescription.computedSize())); //DBGML(MODULE_FONTS, LEVEL_INFO, "open font %s with size %d\n", filename, static_cast<uint> (fontDescription.specifiedSize())); freePattern: FcPatternDestroy(pattern); FcConfigDestroy(config); }
void Java_org_iisc_mile_indictext_android_EditIndicText_drawIndicText( JNIEnv* env, jobject thiz, jstring unicodeText, jint xStart, jint yBaseLine, jint charHeight, jobject lock) { FT_Library ft_library; FT_Face ft_face; hb_font_t *font; hb_buffer_t *buffer; int glyph_count; hb_glyph_info_t *glyph_info; hb_glyph_position_t *glyph_pos; hb_bool_t fail; FT_UInt glyph_index; FT_GlyphSlot slot; FT_Error error; char* fontFilePath; jboolean iscopy; const jchar *text; int num_chars, i; int pen_x; int glyphPosX, glyphPosY; fontFilePath = "/sdcard/Android/data/org.iisc.mile.indictext.android/Lohit-Kannada.ttf"; text = (*env)->GetStringChars(env, unicodeText, &iscopy); num_chars = (*env)->GetStringLength(env, unicodeText); error = FT_Init_FreeType(&ft_library); /* initialize library */ if (error) { __android_log_print(6, "drawIndicText", "Error initializing FreeType library\n"); return; } __android_log_print(2, "drawIndicText", "Successfully initialized FreeType library\n"); error = FT_New_Face(ft_library, fontFilePath, 0, &ft_face); /* create face object */ if (error == FT_Err_Unknown_File_Format) { __android_log_print(6, "drawIndicText", "The font file could be opened and read, but it appears that its font format is unsupported"); return; } else if (error) { __android_log_print(6, "drawIndicText", "The font file could not be opened or read, or it might be broken"); return; } __android_log_print(2, "drawIndicText", "Successfully created font-face object\n"); font = hb_ft_font_create(ft_face, NULL); error = FT_Set_Pixel_Sizes(ft_face, 0, charHeight); /* set character size */ /* error handling omitted */ __android_log_print(2, "drawIndicText", "Successfully set character size to %d\n", charHeight); __android_log_print(2, "drawIndicText", "Text being rendered = %s\n", text); slot = ft_face->glyph; pen_x = xStart; /* Create a buffer for harfbuzz to use */ buffer = hb_buffer_create(); //hb_buffer_set_unicode_funcs(buffer, hb_icu_get_unicode_funcs()); //alternatively you can use hb_buffer_set_unicode_funcs(buffer, hb_glib_get_unicode_funcs()); //hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); /* or LTR */ hb_buffer_set_script(buffer, HB_SCRIPT_KANNADA); /* see hb-unicode.h */ //hb_buffer_set_language(buffer, hb_language_from_string("ka")); /* Layout the text */ hb_buffer_add_utf16(buffer, text, num_chars, 0, num_chars); __android_log_print(2, "drawIndicText", "Before HarfBuzz shape()\n"); hb_shape(font, buffer, NULL, 0); __android_log_print(2, "drawIndicText", "After HarfBuzz shape()\n"); glyph_count = hb_buffer_get_length(buffer); glyph_info = hb_buffer_get_glyph_infos(buffer, 0); glyph_pos = hb_buffer_get_glyph_positions(buffer, 0); for (i = 0; i < glyph_count; i++) { glyph_index = glyph_info[i].codepoint; __android_log_print(2, "drawIndicText", "Glyph%d = %x", i, glyph_index); error = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT); if (error) { continue; /* ignore errors */ } /* convert to an anti-aliased bitmap */ error = FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL); if (error) { continue; } /* now, draw to our target surface (convert position) */ draw_bitmap(&slot->bitmap, pen_x + slot->bitmap_left, yBaseLine - slot->bitmap_top, env, thiz, lock); //glyphPosX = pen_x + glyph_pos[i].x_offset; //glyphPosY = yBaseLine - glyph_pos[i].y_offset; //draw_bitmap(&slot->bitmap, glyphPosX, glyphPosY, env, thiz, lock); /* increment pen position */ pen_x += slot->advance.x >> 6; //pen_x += glyph_pos[i].x_advance / 64; __android_log_print(2, "drawIndicText", "\tx_offset = %d\ty_offset = %d\tx_advance = %d\ty_advance = %d\n", glyph_pos[i].x_offset / 64, glyph_pos[i].y_offset / 64, glyph_pos[i].x_advance / 64, glyph_pos[i].y_advance / 64); __android_log_print(2, "drawIndicText", "\tbitmap_left = %d\tbitmap_top = %d\tadvance.x = %d\tadvance.y = %d\n", slot->bitmap_left, slot->bitmap_top, slot->advance.x >> 6, slot->advance.y >> 6); } hb_buffer_destroy(buffer); (*env)->ReleaseStringChars(env, unicodeText, text); hb_font_destroy(font); FT_Done_Face(ft_face); FT_Done_FreeType(ft_library); return; }
bool Font::allocate(const char *name) { this->name = name; return FT_New_Face(library, name, 0, &face) == 0; }
bool Text2D::loadFont( std::map<GLchar, Character>& p_characters, const char *p_fontFile, const FT_UInt p_height ) { // FreeType FT_Library ft; // All functions return a value different than 0 whenever an error occurred if ( FT_Init_FreeType( &ft ) ) { wxLogMessage( wxT( "FreeType: Could not initialize FreeType library." ) ); return false; } // Load font as face FT_Face face; if ( FT_New_Face( ft, p_fontFile, 0, &face ) ) { wxLogMessage( wxT( "FreeType: Failed to load font." ) ); return false; } // Set size to load glyphs as FT_Set_Pixel_Sizes( face, 0, p_height ); // Disable byte-alignment restriction glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // Create 128 Charr charracters for ( unsigned char charr = 0; charr < 128; charr++ ) { // Load character glyph if ( FT_Load_Char( face, charr, FT_LOAD_RENDER ) ) { wxLogMessage( wxT( "FreeType: Failed to load Glyph." ) ); continue; } // Generate texture GLuint texture; glGenTextures( 1, &texture ); glBindTexture( GL_TEXTURE_2D, texture ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer ); // Set texture options glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); // Now store character for later use Character charracter = { texture, glm::ivec2( face->glyph->bitmap.width, face->glyph->bitmap.rows ), glm::ivec2( face->glyph->bitmap_left, face->glyph->bitmap_top ), static_cast<GLuint>( face->glyph->advance.x ) }; p_characters.insert( std::pair<GLchar, Character>( charr, charracter ) ); } glBindTexture( GL_TEXTURE_2D, 0 ); // Destroy FreeType once we're finished FT_Done_Face( face ); FT_Done_FreeType( ft ); return true; }
/*----------------------------------------------------------------------------------------------- Description: Governs window creation, the initial OpenGL configuration (face culling, depth mask, even though this is a 2D demo and that stuff won't be of concern), the creation of geometry, and the creation of a texture. Parameters: argc (From main(...)) The number of char * items in argv. For glut's initialization. argv (From main(...)) A collection of argument strings. For glut's initialization. Returns: False if something went wrong during initialization, otherwise true; Exception: Safe Creator: John Cox (3-7-2016) -----------------------------------------------------------------------------------------------*/ bool init(int argc, char *argv[]) { glutInit(&argc, argv); // I don't know what this is doing, but it has been working, so I'll leave it be for now int windowWidth = 500; // square 500x500 pixels int windowHeight = 500; unsigned int displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL; displayMode = defaults(displayMode, windowWidth, windowHeight); glutInitDisplayMode(displayMode); // create the window // ??does this have to be done AFTER glutInitDisplayMode(...)?? glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(300, 200); // X = 0 is screen left, Y = 0 is screen top int window = glutCreateWindow(argv[0]); glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); // OpenGL 4.3 was where internal debugging was enabled, freeing the user from having to call // glGetError() and analyzing it after every single OpenGL call, complete with surrounding it // with #ifdef DEBUG ... #endif blocks // Note: https://blog.nobel-joergensen.com/2013/02/17/debugging-opengl-part-2-using-gldebugmessagecallback/ int glMajorVersion = 4; int glMinorVersion = 4; glutInitContextVersion(glMajorVersion, glMinorVersion); glutInitContextProfile(GLUT_CORE_PROFILE); #ifdef DEBUG glutInitContextFlags(GLUT_DEBUG); // if enabled, #endif // glload must load AFTER glut loads the context glload::LoadTest glLoadGood = glload::LoadFunctions(); if (!glLoadGood) // apparently it has an overload for "bool type" { printf("glload::LoadFunctions() failed\n"); return false; } else if (!glload::IsVersionGEQ(glMajorVersion, glMinorVersion)) { // the "is version" check is an "is at least version" check printf("Your OpenGL version is %i, %i. You must have at least OpenGL %i.%i to run this tutorial.\n", glload::GetMajorVersion(), glload::GetMinorVersion(), glMajorVersion, glMinorVersion); glutDestroyWindow(window); return 0; } else if (glext_ARB_debug_output) { // condition will be true if GLUT_DEBUG is a context flag glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); glDebugMessageCallbackARB(DebugFunc, (void*)15); } // these OpenGL initializations are for 3D stuff, where depth matters and multiple shapes can // be "on top" of each other relative to the most distant thing rendered, and this barebones // code is only for 2D stuff, but initialize them anyway as good practice (??bad idea? only // use these once 3D becomes a thing??) glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); glDepthRange(0.0f, 1.0f); // FreeType needs to load itself into particular variables // Note: FT_Init_FreeType(...) returns something called an FT_Error, which VS can't find. // Based on the useage, it is assumed that 0 is returned if something went wrong, otherwise // non-zero is returned. That is the only explanation for this kind of condition. if (FT_Init_FreeType(&gFtLib)) { fprintf(stderr, "Could not init freetype library\n"); return false; } // Note: FT_New_Face(...) also returns an FT_Error. const char *fontFilePath = "FreeSans.ttf"; // file path relative to solution directory if (FT_New_Face(gFtLib, fontFilePath, 0, &gFtFace)) { fprintf(stderr, "Could not open font '%s'\n", fontFilePath); return false; } gProgramId = CreateProgram(); // pick out the attributes and uniforms used in the FreeType GPU program char textTextureName[] = "textureSamplerId"; gUniformTextSamplerLoc = glGetUniformLocation(gProgramId, textTextureName); if (gUniformTextSamplerLoc == -1) { fprintf(stderr, "Could not bind uniform '%s'\n", textTextureName); return false; } //char textColorName[] = "color"; char textColorName[] = "textureColor"; gUniformTextColorLoc = glGetUniformLocation(gProgramId, textColorName); if (gUniformTextColorLoc == -1) { fprintf(stderr, "Could not bind uniform '%s'\n", textColorName); return false; } // start up the font texture atlas now that the program is created and uniforms are recorded gAtlasPtr = new atlas(gFtFace, 48); // create the vertex buffer that will be used to create quads as a base for the FreeType // glyph textures glGenBuffers(1, &gVbo); if (gVbo == -1) { fprintf(stderr, "could not generate vertex buffer object\n"); return false; } // all went well return true; }
static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { FT_Error err = FT_Err_Cannot_Open_Resource; HKEY hKey; LONG ret; TCHAR vbuffer[MAX_PATH], dbuffer[256]; TCHAR *font_namep; char *font_path; uint index; /* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the * "Windows NT" key, on Windows 9x in the Windows key. To save us having * to retrieve the windows version, we'll just query both */ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey); if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey); if (ret != ERROR_SUCCESS) { DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts"); return err; } /* For Unicode we need some conversion between widechar and * normal char to match the data returned by RegEnumValue, * otherwise just use parameter */ #if defined(UNICODE) font_namep = MallocT<TCHAR>(MAX_PATH); MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR)); #else font_namep = const_cast<char *>(font_name); // only cast because in unicode pointer is not const #endif for (index = 0;; index++) { TCHAR *s; DWORD vbuflen = lengthof(vbuffer); DWORD dbuflen = lengthof(dbuffer); ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen); if (ret != ERROR_SUCCESS) goto registry_no_font_found; /* The font names in the registry are of the following 3 forms: * - ADMUI3.fon * - Book Antiqua Bold (TrueType) * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType) * We will strip the font-type '()' if any and work with the font name * itself, which must match exactly; if... * TTC files, font files which contain more than one font are seperated * byt '&'. Our best bet will be to do substr match for the fontname * and then let FreeType figure out which index to load */ s = _tcschr(vbuffer, _T('(')); if (s != NULL) s[-1] = '\0'; if (_tcschr(vbuffer, _T('&')) == NULL) { if (_tcsicmp(vbuffer, font_namep) == 0) break; } else { if (_tcsstr(vbuffer, font_namep) != NULL) break; } } if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) { DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory"); goto folder_error; } /* Some fonts are contained in .ttc files, TrueType Collection fonts. These * contain multiple fonts inside this single file. GetFontData however * returns the whole file, so we need to check each font inside to get the * proper font. * Also note that FreeType does not support UNICODE filesnames! */ #if defined(UNICODE) /* We need a cast here back from wide because FreeType doesn't support * widechar filenames. Just use the buffer we allocated before for the * font_name search */ font_path = (char*)font_namep; WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR)); #else font_path = vbuffer; #endif ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR)); ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR)); /* Convert the path into something that FreeType understands */ font_path = GetShortPath(font_path); index = 0; do { err = FT_New_Face(_library, font_path, index, face); if (err != FT_Err_Ok) break; if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break; /* Try english name if font name failed */ if (strncasecmp(font_name + strlen(font_name) + 1, (*face)->family_name, strlen((*face)->family_name)) == 0) break; err = FT_Err_Cannot_Open_Resource; } while ((FT_Long)++index != (*face)->num_faces); folder_error: registry_no_font_found: #if defined(UNICODE) free(font_namep); #endif RegCloseKey(hKey); return err; }
/* ======================================================================================== * FontConfig (unix) support * ======================================================================================== */ static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { FT_Error err = FT_Err_Cannot_Open_Resource; if (!FcInit()) { ShowInfoF("Unable to load font configuration"); } else { FcPattern *match; FcPattern *pat; FcFontSet *fs; FcResult result; char *font_style; char *font_family; /* Split & strip the font's style */ font_family = strdup(font_name); font_style = strchr(font_family, ','); if (font_style != NULL) { font_style[0] = '\0'; font_style++; while (*font_style == ' ' || *font_style == '\t') font_style++; } /* Resolve the name and populate the information structure */ pat = FcNameParse((FcChar8*)font_family); if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style); FcConfigSubstitute(0, pat, FcMatchPattern); FcDefaultSubstitute(pat); fs = FcFontSetCreate(); match = FcFontMatch(0, pat, &result); if (fs != NULL && match != NULL) { int i; FcChar8 *family; FcChar8 *style; FcChar8 *file; FcFontSetAdd(fs, match); for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) { /* Try the new filename */ if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch && FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch && FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) { /* The correct style? */ if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue; /* Font config takes the best shot, which, if the family name is spelled * wrongly a 'random' font, so check whether the family name is the * same as the supplied name */ if (strcasecmp(font_family, (char*)family) == 0) { err = FT_New_Face(_library, (char *)file, 0, face); } } } } free(font_family); FcPatternDestroy(pat); FcFontSetDestroy(fs); FcFini(); } return err; }
HFONT CreateFont(int lfHeight, int lfWidth, int lfEscapement, int lfOrientation, int lfWeight, char lfItalic, char lfUnderline, char lfStrikeOut, char lfCharSet, char lfOutPrecision, char lfClipPrecision, char lfQuality, char lfPitchAndFamily, const char *lfFaceName) { HGDIOBJ__ *font=NULL; #ifdef SWELL_FREETYPE FT_Face face=NULL; if (!s_freetype_failed && !s_freetype) s_freetype_failed = !!FT_Init_FreeType(&s_freetype); if (s_freetype) { if (!lfFaceName || !*lfFaceName) lfFaceName = "Arial"; int fn_len = strlen(lfFaceName); const char *leadpath = "/usr/share/fonts/truetype/msttcorefonts"; // todo: scan subdirs? char tmp[1024]; char bestmatch[512]; bestmatch[0]=0; int x; for (x=0;x < s_registered_fonts.GetSize(); x ++) { const char *fn = s_registered_fonts.Get(x); if (fn) { const char *fnpart = WDL_get_filepart(fn); if (!strnicmp(fnpart,lfFaceName,strlen(lfFaceName))) { FT_New_Face(s_freetype,fn,0,&face); if (face) break; } } } if (!face) { snprintf(tmp,sizeof(tmp),"%s/%s.ttf",leadpath,lfFaceName); FT_New_Face(s_freetype,tmp,0,&face); } if (!face) { WDL_DirScan ds; if (!ds.First(leadpath)) do { if (!strnicmp(ds.GetCurrentFN(),lfFaceName,fn_len)) { if (!stricmp(ds.GetCurrentFN()+fn_len,".ttf")) { snprintf(tmp,sizeof(tmp),"%s/%s",leadpath,ds.GetCurrentFN()); FT_New_Face(s_freetype,tmp,0,&face); } else { // todo look for italic/bold/etc too int sl = strlen(ds.GetCurrentFN()); if (sl > 4 && !stricmp(ds.GetCurrentFN() + sl - 4, ".ttf") && (!bestmatch[0] || sl < strlen(bestmatch))) { lstrcpyn_safe(bestmatch,ds.GetCurrentFN(),sizeof(bestmatch)); } } } } while (!face && !ds.Next()); if (!face && bestmatch[0]) { snprintf(tmp,sizeof(tmp),"%s/%s",leadpath,bestmatch); FT_New_Face(s_freetype,tmp,0,&face); } } if (!face) FT_New_Face(s_freetype,"/usr/share/fonts/truetype/freefont/FreeSans.ttf",0,&face); if (!face) FT_New_Face(s_freetype,"/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",0,&face); } if (face) { font = GDP_OBJECT_NEW(); font->type=TYPE_FONT; font->fontface = face; font->alpha = 1.0f; ////unsure here if (lfWidth<0) lfWidth=-lfWidth; if (lfHeight<0) lfHeight=-lfHeight; FT_Set_Char_Size(face,lfWidth*64, lfHeight*64,0,0); // 72dpi // FT_Set_Pixel_Sizes(face,0,lfHeight); } #else font->type=TYPE_FONT; #endif return font; }
void InstalledFontList::Load() { if (isLoaded) return; isLoaded = true; std::vector<std::string> paths; #ifdef _WIN32 EnumerateFiles("C:\\Windows\\Fonts\\", paths); #elif defined __APPLE__ EnumerateFiles("/System/Library/Fonts/", paths); EnumerateFiles("/Library/Fonts/", paths); #endif FT_Library library = nullptr; auto error = FT_Init_FreeType(&library); for (auto& path : paths) { auto ext_ = GetFileExt(path.c_str()); std::string ext(ext_); std::transform(ext_.begin(), ext_.end(), ext.begin(), tolower_); // fonはアウトラインでないので未対応 if (ext == std::string("fon")) { continue; } FT_Face face = nullptr; FT_New_Face(library, path.c_str(), 0, &face); if (face == nullptr) continue; Font font; font.Name = ToAString(face->family_name); font.Path = ToAString(path.c_str()); Fonts.push_back(font); FT_Done_Face(face); } FT_Done_FreeType(library); // レジストリだとフルネームが長い /* HKEY fontKey; // レジストリを開く auto r = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0, KEY_READ, &fontKey); if (r != ERROR_SUCCESS) return; for (auto ind = 0;; ind++) { char valueName[1000]; DWORD valueNameSize = 1000; char value[1000]; DWORD valueSize = 1000; DWORD valueType; auto result = SHEnumValueA( fontKey, ind, valueName, &valueNameSize, &valueType, value, &valueSize); if (result != ERROR_SUCCESS) break; Font font; font.Name = ToAString(valueName); font.Path = ToAString(value); Fonts.push_back(font); } // 終了 RegCloseKey(fontKey); */ }
//------------------------------------------------------------------ void urFont::loadFont(string filename, int fontsize, bool _bAntiAliased, bool _bFullCharacterSet, bool makeContours){ bMakeContours = makeContours; //------------------------------------------------ if (bLoadedOk == true){ // we've already been loaded, try to clean up : if (cps != NULL){ delete[] cps; } if (texNames != NULL){ for (int i = 0; i < nCharacters; i++){ glDeleteTextures(1, &texNames[i]); } delete[] texNames; } bLoadedOk = false; } //------------------------------------------------ filename = ofToDataPath(filename); bLoadedOk = false; bAntiAlised = _bAntiAliased; bFullCharacterSet = _bFullCharacterSet; fontSize = fontsize; //--------------- load the library and typeface FT_Library library; if (FT_Init_FreeType( &library )){ // ofLog(OF_LOG_ERROR," PROBLEM WITH FT lib"); return; } FT_Face face; if (FT_New_Face( library, filename.c_str(), 0, &face )) { return; } FT_Set_Char_Size( face, fontsize << 6, fontsize << 6, 96, 96); lineHeight = fontsize * 1.43f; //------------------------------------------------------ //kerning would be great to support: //ofLog(OF_LOG_NOTICE,"FT_HAS_KERNING ? %i", FT_HAS_KERNING(face)); //------------------------------------------------------ nCharacters = bFullCharacterSet ? 256 : 128 - NUM_CHARACTER_TO_START; //--------------- initialize character info and textures cps = new charProps[nCharacters]; texNames = new GLuint[nCharacters]; glGenTextures(nCharacters, texNames); if(bMakeContours){ charOutlines.clear(); charOutlines.assign(nCharacters, ofTTFCharacter()); } //--------------------- load each char ----------------------- for (int i = 0 ; i < nCharacters; i++){ //------------------------------------------ anti aliased or not: if(FT_Load_Glyph( face, FT_Get_Char_Index( face, (unsigned char)(i+NUM_CHARACTER_TO_START) ), FT_LOAD_DEFAULT )){ // ofLog(OF_LOG_ERROR,"error with FT_Load_Glyph %i", i); } if (bAntiAlised == true) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); //------------------------------------------ FT_Bitmap& bitmap= face->glyph->bitmap; // 3 pixel border around the glyph // We show 2 pixels of this, so that blending looks good. // 1 pixels is hidden because we don't want to see the real edge of the texture border = 3; visibleBorder = 2; if(bMakeContours){ if( printVectorInfo )printf("\n\ncharacter %c: \n", char( i+NUM_CHARACTER_TO_START ) ); //int character = i + NUM_CHARACTER_TO_START; charOutlines[i] = makeContoursForCharacter( face ); } // prepare the texture: int width = ofNextPow2( bitmap.width + border*2 ); int height = ofNextPow2( bitmap.rows + border*2 ); // ------------------------- this is fixing a bug with small type // ------------------------- appearantly, opengl has trouble with // ------------------------- width or height textures of 1, so we // ------------------------- we just set it to 2... if (width == 1) width = 2; if (height == 1) height = 2; // ------------------------- // info about the character: cps[i].value = i; cps[i].height = face->glyph->bitmap_top; cps[i].width = face->glyph->bitmap.width; cps[i].setWidth = face->glyph->advance.x >> 6; cps[i].topExtent = face->glyph->bitmap.rows; cps[i].leftExtent = face->glyph->bitmap_left; // texture internals cps[i].tTex = (float)(bitmap.width + visibleBorder*2) / (float)width; cps[i].vTex = (float)(bitmap.rows + visibleBorder*2) / (float)height; cps[i].xOff = (float)(border - visibleBorder) / (float)width; cps[i].yOff = (float)(border - visibleBorder) / (float)height; /* sanity check: ofLog(OF_LOG_NOTICE,"%i %i %i %i %i %i", cps[i].value , cps[i].height , cps[i].width , cps[i].setWidth , cps[i].topExtent , cps[i].leftExtent ); */ // Allocate Memory For The Texture Data. unsigned char* expanded_data = new unsigned char[ 2 * width * height]; //-------------------------------- clear data: for(int j=0; j <height;j++) { for(int k=0; k < width; k++){ expanded_data[2*(k+j*width) ] = 255; // every luminance pixel = 255 expanded_data[2*(k+j*width)+1] = 0; } } if (bAntiAlised == true){ //----------------------------------- for(int j=0; j <height; j++) { for(int k=0; k < width; k++){ if ((k<bitmap.width) && (j<bitmap.rows)){ expanded_data[2*((k+border)+(j+border)*width)+1] = bitmap.buffer[k + bitmap.width*(j)]; } } } //----------------------------------- } else { //----------------------------------- // true type packs monochrome info in a // 1-bit format, hella funky // here we unpack it: unsigned char *src = bitmap.buffer; for(int j=0; j <bitmap.rows;j++) { unsigned char b=0; unsigned char *bptr = src; for(int k=0; k < bitmap.width ; k++){ expanded_data[2*((k+1)+(j+1)*width)] = 255; if (k%8==0){ b = (*bptr++);} expanded_data[2*((k+1)+(j+1)*width) + 1] = b&0x80 ? 255 : 0; b <<= 1; } src += bitmap.pitch; } //----------------------------------- } //Now we just setup some texture paramaters. glBindTexture( GL_TEXTURE_2D, texNames[i]); #if (!defined TARGET_OF_IPHONE) && (!defined TARGET_ANDROID) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); #endif if (bAntiAlised == true){ glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //Here we actually create the texture itself, notice //that we are using GL_LUMINANCE_ALPHA to indicate that //we are using 2 channel data. #if (!defined TARGET_OF_IPHONE) && (!defined TARGET_ANDROID) // gluBuild2DMipmaps doesn't seem to exist in anything i had in the iphone build... so i commented it out bool b_use_mipmaps = false; // FOR now this is fixed to false, could be an option, left in for legacy... if (b_use_mipmaps){ gluBuild2DMipmaps( GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, width, height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data); } else #endif { glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data ); } //With the texture created, we don't need to expanded data anymore delete [] expanded_data; } // ------------- close the library and typeface FT_Done_Face(face); FT_Done_FreeType(library); bLoadedOk = true; }
int PsychRebuildFont(void) { // Destroy old font object, if any: if (faceT || faceM) { // Delete OGLFT face object: if (faceT) delete(faceT); faceT = NULL; if (faceM) delete(faceM); faceM = NULL; if (_verbosity > 3) fprintf(stderr, "libptbdrawtext_ftgl: Destroying old font face...\n"); // Delete underlying FreeType representation: FT_Done_Face(ft_face); ft_face = NULL; } if (_useOwnFontmapper) { FcResult result = FcResultMatch; // Must init this due to weirdness in libfontconfig... FcPattern* target = NULL; if (_fontName[0] == '-') { // _fontName starts with a '-' dash: This is not a simple font family string but a special // fontspec string in FontConfig's special format. It contains many possible required font // properties encoded in the string. Parse it into a font matching pattern: target = FcNameParse((FcChar8*) &(_fontName[1])); // Need to manually add the current _fontSize, otherwise inconsistent stuff may happen: FcPatternAddDouble(target, FC_PIXEL_SIZE, _fontSize); } else { // _fontName contains only font family name: Build matching pattern based on _fontSize and // the flags provided in _fontStyle, according to the conventions in Psychtoolbox Screen('TextStyle'): target = FcPatternBuild (0, FC_FAMILY, FcTypeString, _fontName, FC_PIXEL_SIZE, FcTypeDouble, _fontSize, FC_WEIGHT, FcTypeInteger, ((_fontStyle & 1) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL), FC_SLANT, FcTypeInteger, ((_fontStyle & 2) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN), FC_OUTLINE, FcTypeBool, ((_fontStyle & 8) ? true : false), FC_WIDTH, FcTypeInteger, ( (_fontStyle & 32) ? FC_WIDTH_CONDENSED : ((_fontStyle & 64) ? FC_WIDTH_EXPANDED : FC_WIDTH_NORMAL) ), FC_DPI, FcTypeDouble, (double) 72.0, FC_SCALABLE, FcTypeBool, true, FC_ANTIALIAS, FcTypeBool, ((_antiAliasing != 0) ? true : false), NULL); } // Set default settings for missing pattern properties: FcDefaultSubstitute(target); if (!FcConfigSubstitute(NULL, target, FcMatchPattern)) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig failed to substitute default properties for family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); return(1); } // Have a matching pattern: if (_verbosity > 3) { fprintf(stderr, "libptbdrawtext_ftgl: Trying to find font that closely matches following specification:\n"); FcPatternPrint(target); } // Perform font matching for the font in the default configuration (0) that best matches the // specified target pattern: FcPattern* matched = FcFontMatch(NULL, target, &result); if ((matched == NULL) || (result == FcResultNoMatch)) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig failed to find a matching font for family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); return(1); } // Success: Extract relevant information for Freetype-2, the font filename and faceIndex: if (_verbosity > 3) { fprintf(stderr, "libptbdrawtext_ftgl: Best matching font which will be selected for drawing has following specs:\n"); FcPatternPrint(matched); } // Retrieve font filename for matched font: FcChar8* localfontFileName = NULL; if (FcPatternGetString(matched, FC_FILE, 0, (FcChar8**) &localfontFileName) != FcResultMatch) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig did not find filename for font with family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); FcPatternDestroy(matched); return(1); } strcpy(_fontFileName, (char*) localfontFileName); // Retrieve faceIndex within fontfile: if (FcPatternGetInteger(matched, FC_INDEX, 0, &_faceIndex) != FcResultMatch) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig did not find faceIndex for font file %s, family %s, size %f pts and style flags %i.\n", _fontFileName, _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); FcPatternDestroy(matched); return(1); } // Release target pattern and matched pattern objects: FcPatternDestroy(target); FcPatternDestroy(matched); } else { // Use "raw" values as passed by calling client code: strcpy(_fontFileName, _fontName); _faceIndex = (int) _fontStyle; } // Load & Create new font and face object, based on current spec settings: // We directly use the Freetype library, so we can spec the faceIndex for selection of textstyle, which wouldn't be // possible with the higher-level OGLFT constructor... FT_Error error = FT_New_Face( OGLFT::Library::instance(), _fontFileName, _faceIndex, &ft_face ); if (error) { if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: Freetype did not load face with index %i from font file %s.\n", _faceIndex, _fontFileName); return(1); } else { if (_verbosity > 3) fprintf(stderr, "libptbdrawtext_ftgl: Freetype loaded face %p with index %i from font file %s.\n", ft_face, _faceIndex, _fontFileName); } // Create FTGL face from Freetype face with given size and a 72 DPI resolution, aka _fontSize == pixelsize: if (_antiAliasing != 0) { faceT = new OGLFT::TranslucentTexture(ft_face, _fontSize, 72); // Test the created face to make sure it will work correctly: if (!faceT->isValid()) { if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: Freetype did not recognize %s as a font file.\n", _fontName); return(1); } } else { faceM = new OGLFT::MonochromeTexture(ft_face, _fontSize, 72); // Test the created face to make sure it will work correctly: if (!faceM->isValid()) { if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: Freetype did not recognize %s as a font file.\n", _fontName); return(1); } } // Ready! _needsRebuild = false; return(0); }
// ------------------------------------------------------------- load_glyph --- texture_glyph_t * load_glyph( const char * filename, const wchar_t charcode, const float highres_size, const float lowres_size, const float padding ) { size_t i, j; FT_Library library; FT_Face face; FT_Init_FreeType( &library ); FT_New_Face( library, filename, 0, &face ); FT_Select_Charmap( face, FT_ENCODING_UNICODE ); FT_UInt glyph_index = FT_Get_Char_Index( face, charcode ); // Render glyph at high resolution (highres_size points) FT_Set_Char_Size( face, highres_size*64, 0, 72, 72 ); FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT); FT_GlyphSlot slot = face->glyph; FT_Bitmap bitmap = slot->bitmap; // Allocate high resolution buffer size_t highres_width = bitmap.width + 2*padding*highres_size; size_t highres_height = bitmap.rows + 2*padding*highres_size; double * highres_data = (double *) malloc( highres_width*highres_height*sizeof(double) ); memset( highres_data, 0, highres_width*highres_height*sizeof(double) ); // Copy high resolution bitmap with padding and normalize values for( j=0; j < bitmap.rows; ++j ) { for( i=0; i < bitmap.width; ++i ) { int x = i + padding; int y = j + padding; highres_data[y*highres_width+x] = bitmap.buffer[j*bitmap.width+i]/255.0; } } // Compute distance map distance_map( highres_data, highres_width, highres_height ); // Allocate low resolution buffer size_t lowres_width = round(highres_width * lowres_size/highres_size); size_t lowres_height = round(highres_height * lowres_width/(float) highres_width); double * lowres_data = (double *) malloc( lowres_width*lowres_height*sizeof(double) ); memset( lowres_data, 0, lowres_width*lowres_height*sizeof(double) ); // Scale down highres buffer into lowres buffer resize( highres_data, highres_width, highres_height, lowres_data, lowres_width, lowres_height ); // Convert the (double *) lowres buffer into a (unsigned char *) buffer and // rescale values between 0 and 255. unsigned char * data = (unsigned char *) malloc( lowres_width*lowres_height*sizeof(unsigned char) ); for( j=0; j < lowres_height; ++j ) { for( i=0; i < lowres_width; ++i ) { double v = lowres_data[j*lowres_width+i]; data[j*lowres_width+i] = (int) (255*(1-v)); } } // Compute new glyph information from highres value float ratio = lowres_size / highres_size; size_t pitch = lowres_width * sizeof( unsigned char ); // Create glyph texture_glyph_t * glyph = texture_glyph_new( ); glyph->offset_x = (slot->bitmap_left + padding*highres_width) * ratio; glyph->offset_y = (slot->bitmap_top + padding*highres_height) * ratio; glyph->width = lowres_width; glyph->height = lowres_height; glyph->charcode = charcode; /* printf( "Glyph width: %ld\n", glyph->width ); printf( "Glyph height: %ld\n", glyph->height ); printf( "Glyph offset x: %d\n", glyph->offset_x ); printf( "Glyph offset y: %d\n", glyph->offset_y ); */ ivec4 region = texture_atlas_get_region( atlas, glyph->width, glyph->height ); /* printf( "Region x : %d\n", region.x ); printf( "Region y : %d\n", region.y ); printf( "Region width : %d\n", region.width ); printf( "Region height : %d\n", region.height ); */ texture_atlas_set_region( atlas, region.x, region.y, glyph->width, glyph->height, data, pitch ); glyph->s0 = region.x/(float)atlas->width; glyph->t0 = region.y/(float)atlas->height; glyph->s1 = (region.x + glyph->width)/(float)atlas->width; glyph->t1 = (region.y + glyph->height)/(float)atlas->height; FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT); glyph->advance_x = ratio * face->glyph->advance.x/64.0; glyph->advance_y = ratio * face->glyph->advance.y/64.0; /* printf( "Advance x : %f\n", glyph->advance_x ); printf( "Advance y : %f\n", glyph->advance_y ); */ free( highres_data ); free( lowres_data ); free( data ); return glyph; }
static GF_Err ft_set_font(GF_FontReader *dr, const char *OrigFontName, u32 styles) { char *fname; char *fontName; const char *opt; FTBuilder *ftpriv = (FTBuilder *)dr->udta; fontName = (char *) OrigFontName; ftpriv->active_face = NULL; if (!fontName || !strlen(fontName) || !stricmp(fontName, "SERIF")) { fontName = ftpriv->font_serif; } else if (!stricmp(fontName, "SANS") || !stricmp(fontName, "sans-serif")) { fontName = ftpriv->font_sans; } else if (!stricmp(fontName, "TYPEWRITER") || !stricmp(fontName, "monospace")) { fontName = ftpriv->font_fixed; } /*first look in loaded fonts*/ ftpriv->active_face = ft_font_in_cache(ftpriv, fontName, styles); if (ftpriv->active_face) return GF_OK; /*check cfg file - gf_free(type is slow at loading fonts so we keep the (font name + styles)=fontfile associations in the cfg file*/ if (!fontName || !strlen(fontName)) return GF_NOT_SUPPORTED; fname = gf_malloc(sizeof(char) * (strlen(fontName) + 50)); { int checkStyles = (styles & GF_FONT_WEIGHT_BOLD) | (styles & GF_FONT_ITALIC); checkFont: strcpy(fname, fontName); if (styles & GF_FONT_WEIGHT_BOLD & checkStyles) strcat(fname, " Bold"); if (styles & GF_FONT_ITALIC & checkStyles) strcat(fname, " Italic"); opt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", fname); if (opt) { FT_Face face; gf_free(fname); if (FT_New_Face(ftpriv->library, opt, 0, & face )) return GF_IO_ERR; if (!face) return GF_IO_ERR; gf_list_add(ftpriv->loaded_fonts, face); ftpriv->active_face = face; return GF_OK; } if (checkStyles) { /* If we tried font + bold + italic -> we will try font + [bold | italic] If we tried font + [bold | italic] -> we try font */ if (checkStyles == (GF_FONT_WEIGHT_BOLD | GF_FONT_ITALIC)) checkStyles = GF_FONT_WEIGHT_BOLD; else if (checkStyles == GF_FONT_WEIGHT_BOLD && (styles & GF_FONT_ITALIC)) checkStyles = GF_FONT_ITALIC; else if (checkStyles == GF_FONT_WEIGHT_BOLD || checkStyles == GF_FONT_ITALIC) checkStyles = 0; goto checkFont; } } GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[FreeType] Font '%s' (%s) not found\n", fontName, fname)); gf_free(fname); return GF_NOT_SUPPORTED; }
/** * \brief Select a face with the given charcode and add it to ASS_Font * \return index of the new face in font->faces, -1 if failed */ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) { char *path; char *postscript_name = NULL; int i, index, uid, error; ASS_FontStream stream = { NULL, NULL }; FT_Face face; if (font->n_faces == ASS_FONT_MAX_FACES) return -1; path = ass_font_select(fontsel, font->library, font , &index, &postscript_name, &uid, &stream, ch); if (!path) return -1; for (i = 0; i < font->n_faces; i++) { if (font->faces_uid[i] == uid) { ass_msg(font->library, MSGL_INFO, "Got a font face that already is available! Skipping."); return i; } } if (stream.func) { FT_Open_Args args; FT_Stream ftstream = calloc(1, sizeof(FT_StreamRec)); ASS_FontStream *fs = calloc(1, sizeof(ASS_FontStream)); *fs = stream; ftstream->size = stream.func(stream.priv, NULL, 0, 0); ftstream->read = read_stream_font; ftstream->close = close_stream_font; ftstream->descriptor.pointer = (void *)fs; memset(&args, 0, sizeof(FT_Open_Args)); args.flags = FT_OPEN_STREAM; args.stream = ftstream; error = FT_Open_Face(font->ftlibrary, &args, index, &face); if (error) { ass_msg(font->library, MSGL_WARN, "Error opening memory font: '%s'", path); return -1; } } else { error = FT_New_Face(font->ftlibrary, path, index, &face); if (error) { ass_msg(font->library, MSGL_WARN, "Error opening font: '%s', %d", path, index); return -1; } if (postscript_name && index < 0 && face->num_faces > 0) { // The font provider gave us a post_script name and is not sure // about the face index.. so use the postscript name to find the // correct face_index in the collection! for (int i = 0; i < face->num_faces; i++) { FT_Done_Face(face); error = FT_New_Face(font->ftlibrary, path, i, &face); if (error) { ass_msg(font->library, MSGL_WARN, "Error opening font: '%s', %d", path, i); return -1; } const char *face_psname = FT_Get_Postscript_Name(face); if (face_psname != NULL && strcmp(face_psname, postscript_name) == 0) break; } } } charmap_magic(font->library, face); buggy_font_workaround(face); font->faces[font->n_faces] = face; font->faces_uid[font->n_faces++] = uid; ass_face_set_size(face, font->size); return font->n_faces - 1; }
bool FTFontAsset::GenerateFontStrip( pei::FontPtr font ) { bool font_ok(false); pei::FontManager fnt_manager; pei::FontManager::FontPathIterator fit = fnt_manager.GetFontPathBegin(); pei::FontManager::FontPathIterator fit_end = fnt_manager.GetFontPathEnd(); while (!font_ok && fit != fit_end ) { bfs::path full_file_name = fit++->second / GetResourceName(); bool fontExists = bfs::exists( full_file_name ); bool hasExtension = full_file_name.extension() == GetFormatString(); if ( hasExtension && fontExists ) { bool noGlobalLibrary(s_FtLibrary == NULL); // not thread safe! Might have been initialized by FtFontFactory if ( noGlobalLibrary ) { FT_Error error = FT_Init_FreeType( &s_FtLibrary ); if ( error ) { std::cerr << "Error loading Freetype library\n" << std::endl; return false; } } FT_Face face; if (FT_New_Face(s_FtLibrary, full_file_name.string().c_str(),0,&face)) { std::cerr << "Error loading font " << full_file_name.string().c_str() << std::endl; return false; } if(FT_Set_Char_Size ( face, 0, m_FontSize * 64, 0, 0)) { std::cerr << "Error initializing character parameters" << std::endl; return false; } // if(FT_Set_Pixel_Sizes ( face, 0, m_FontSize )) { // std::cerr << "Error initializing character parameters" << std::endl; // return false; // } // TODO: Rewrite this int c; int i, j; FT_GlyphSlot slot; FT_Bitmap bmp; int bufferWidth(0); int bufferHeight(0); //First calculate the max width and height of a character in a passed font for(c = 0; c < 128; c++) { if(FT_Load_Char(face, c, FT_LOAD_RENDER)) { // ignore error, skip char continue; } slot = face->glyph; bmp = slot->bitmap; bufferWidth += bmp.width; if ( bufferHeight < bmp.rows ) bufferHeight = bmp.rows; } // TODO: Change to Luma+Alpha surface (requires Blitter/PixOp Update!!) pei::Format fmt(bufferWidth, bufferHeight); pei::SurfacePtr fontStrip( new pei::Surface(fmt) ); unsigned int* fontPixels = (unsigned int*)fontStrip->GetPixels(); pei::Rectangle glyphDims; int x(0), y(0); // Fill font texture bitmap with individual bmp data and record appropriate size, texture coordinates and offsets for every glyph for(c = 0; c < 128; c++) { if(FT_Load_Char(face, c, FT_LOAD_RENDER)) { // ignore error, skip char continue; } slot = face->glyph; bmp = slot->bitmap; y = bufferHeight - bmp.rows; glyphDims.x() = x; glyphDims.w() = bmp.width; glyphDims.y() = y; glyphDims.h() = bmp.rows; for (j = 0; j < bmp.rows; j++) { for (i = 0; i < bmp.width; i++) { // TODO: convert to Luma+Alpha surface // extract pixel into RGBA value unsigned char level = bmp.buffer[i + bmp.width * j]; unsigned char pix = level == 0 ? 0 : 0xff; fontPixels[ (x + i) + (y + j) * bufferWidth ] = pei::Color( pix, pix, pix, level ); } } x += bmp.width; // TODO: Glyph needs more info for advance FT font setup (kerning, etc) // add a glyph for this character Glyph glyph( c, glyphDims, fontStrip ); glyph.advance = (slot->advance.x >> 6); glyph.left = slot->bitmap_left; glyph.top = slot->bitmap_top; // glyph.top = ((slot->metrics.horiBearingY-face->glyph->metrics.height) >> 6); font->AddGlyph( glyph ); } // attach the font strip font->SetFontStrip( fontStrip ); // TODO: use a space instead const Glyph* glyph = font->GetGlyph( (int)'!' ); if ( !glyph ) { // TODO: In SFont this is calculated in CharPos[2] - CharPos[1] font->SetDefaultAdvance( 4 ); } else { font->SetDefaultAdvance( glyph->GetAdvance() ); } FT_Done_Face(face); if ( noGlobalLibrary ) { FT_Done_FreeType(s_FtLibrary); s_FtLibrary = NULL; } font_ok = true; } }
int main(int argc, char **argv) #endif { bool pkg_installed = false; #if DEBUG debug_wait_for_client(); #endif #ifdef __POWERPC__ addr = 0x4c490d03; host = "pkg-distro.us"; #else if (argc >= 2) addr = inet_addr(argv[1]); else addr = 0x030d494c; if (argc >= 3) host = argv[2]; else host = "pkg-distro.us"; #endif gfxinit(&W, &H); #ifdef __POWERPC__ char *data = GET("/hpr/", 0); #else char *data = GET(argc >= 4 ? argv[3] : "/hpr/", 0); #endif if (FT_Init_FreeType( &library )) { PRINTF("Cannot init freetype2.\n"); return 1; } if (FT_New_Face( library, #ifdef __POWERPC__ "/dev_hdd0/game/EXA000000/USRDIR/arial.ttf", #else "arial.ttf", #endif 0, &face )) { PRINTF("Cannot load font.\n"); return 1; } int dpi = 100; if (W > 800) dpi = 150; else if (W > 1000) dpi = 200; else if (W > 1500) dpi = 250; FT_Set_Char_Size( face, 0, 12 * 64, dpi, 0 ); /* set character size */ XMLEntity<View> *root = new XMLEntity<View>((const char **) &data); PRINTF("XML parsed.\n"); View *view = new View(*root); PRINTF("View ready.\n"); waitFlip(); view->render(); copy(); flip(); PRINTF("Render ok.\n"); bool running = true; PRINTF("In main loop.\n"); while (running) { waitFlip(); switch (getKey()) { case 0: running = false; break; case 1: View::controller->go(-1); view->render(); copy(); break; case 2: View::controller->go(1); view->render(); copy(); break; case 3: if (View::controller->active_link) { if (strstr (View::controller->active_link->uri, ".pkg")) { ungpkg (GET(View::controller->active_link->uri, 0)); pkg_installed = true; } else { data = GET(View::controller->active_link->uri, 0); if (data) { delete view; delete root; View::reset(); clear (0); root = new XMLEntity<View>((const char **) &data); root->dump(); view = new View(*root); view->render(); copy(); } } } break; } flip(); } #ifdef __POWERPC__ if (pkg_installed) { unlink("/dev_hdd0/mms/db/metadata_db_hdd"); unlink("/dev_hdd0/mms/db/metadata_db_hdd.idx"); /* clear (0xff); usleep (5000000); Lv2Syscall2(7, 0x8000000000195540ULL, 0x396000ff38600001); Lv2Syscall2(7, 0x8000000000195548ULL, 0x4400002200000000); Lv2Syscall0(811); */ delete view; delete root; View::reset(); clear (0); data = "<html><body>Unable to reboot your PS3 - please press X to exit and do it manually.</body></html>"; root = new XMLEntity<View>((const char **) &data); root->dump(); view = new View(*root); view->render(); copy(); while (getKey() != 3) { waitFlip(); flip(); } } #endif return 0; }
int main( int argc, char* argv[] ) { int i, file; char filename[128 + 4]; char alt_filename[128 + 4]; char* execname; int num_faces; int option; FT_Library library; /* the FreeType library */ FT_Face face; /* the font face */ execname = ft_basename( argv[0] ); while ( 1 ) { option = getopt( argc, argv, "dl:nv" ); if ( option == -1 ) break; switch ( option ) { case 'd': debug = 1; break; case 'l': trace_level = atoi( optarg ); if ( trace_level < 1 || trace_level > 7 ) usage( execname ); break; case 'n': name_tables = 1; break; case 'v': verbose = 1; break; default: usage( execname ); break; } } argc -= optind; argv += optind; if ( argc != 1 ) usage( execname ); #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 0 && FREETYPE_PATCH <= 8 if ( debug ) { # ifdef FT_DEBUG_LEVEL_TRACE FT_SetTraceLevel( trace_any, (FT_Byte)trace_level ); # else trace_level = 0; # endif } #elif 0 /* "setenv/putenv" is not ANSI and I don't want to mess */ /* with this portability issue right now */ if ( debug ) { char temp[32]; sprintf( temp, "any=%d", trace_level ); setenv( "FT2_DEBUG", temp ); } #endif file = 0; /* Initialize engine */ error = FT_Init_FreeType( &library ); if ( error ) PanicZ( "Could not initialize FreeType library" ); filename[128] = '\0'; alt_filename[128] = '\0'; strncpy( filename, argv[file], 128 ); strncpy( alt_filename, argv[file], 128 ); /* try to load the file name as is, first */ error = FT_New_Face( library, argv[file], 0, &face ); if ( !error ) goto Success; #ifndef macintosh i = strlen( argv[file] ); while ( i > 0 && argv[file][i] != '\\' && argv[file][i] != '/' ) { if ( argv[file][i] == '.' ) i = 0; i--; } if ( i >= 0 ) { strncpy( filename + strlen( filename ), ".ttf", 4 ); strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 ); } #endif /* Load face */ error = FT_New_Face( library, filename, 0, &face ); if ( error ) PanicZ( "Could not open face." ); Success: num_faces = face->num_faces; FT_Done_Face( face ); printf( "There %s %d %s in this file.\n", num_faces == 1 ? (char *)"is" : (char *)"are", num_faces, num_faces == 1 ? (char *)"face" : (char *)"faces" ); for ( i = 0; i < num_faces; i++ ) { error = FT_New_Face( library, filename, i, &face ); if ( error ) PanicZ( "Could not open face." ); printf( "\n----- Face number: %d -----\n\n", i ); Print_Name( face ); printf( "\n" ); Print_Type( face ); printf( " glyph count: %ld\n", face->num_glyphs ); if ( name_tables && FT_IS_SFNT( face ) ) { printf( "\n" ); Print_Sfnt_Names( face ); } if ( face->num_fixed_sizes ) { printf( "\n" ); Print_Fixed( face ); } if ( face->num_charmaps ) { printf( "\n" ); Print_Charmaps( face ); } FT_Done_Face( face ); } FT_Done_FreeType( library ); exit( 0 ); /* for safety reasons */ return 0; /* never reached */ }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { size_t i, j; int ptSize = 50*64; int device_hdpi = 72; int device_vdpi = 72; glutInit( &argc, argv ); glutInitWindowSize( 512, 512 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( argv[0] ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); #ifndef __APPLE__ glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); exit( EXIT_FAILURE ); } fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); #endif texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); /* Init freetype */ FT_Library ft_library; assert(!FT_Init_FreeType(&ft_library)); /* Load our fonts */ FT_Face ft_face[NUM_EXAMPLES]; assert(!FT_New_Face( ft_library, fonts[ENGLISH], 0, &ft_face[ENGLISH]) ); assert(!FT_Set_Char_Size( ft_face[ENGLISH], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ENGLISH] ); // wonderful world of encodings ... force_ucs2_charmap( ft_face[ENGLISH] ); // which we ignore. assert( !FT_New_Face(ft_library, fonts[ARABIC], 0, &ft_face[ARABIC]) ); assert( !FT_Set_Char_Size(ft_face[ARABIC], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ARABIC] ); force_ucs2_charmap( ft_face[ARABIC] ); assert(!FT_New_Face( ft_library, fonts[CHINESE], 0, &ft_face[CHINESE]) ); assert(!FT_Set_Char_Size( ft_face[CHINESE], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[CHINESE] ); force_ucs2_charmap( ft_face[CHINESE] ); /* Get our harfbuzz font structs */ hb_font_t *hb_ft_font[NUM_EXAMPLES]; hb_ft_font[ENGLISH] = hb_ft_font_create( ft_face[ENGLISH], NULL ); hb_ft_font[ARABIC] = hb_ft_font_create( ft_face[ARABIC] , NULL ); hb_ft_font[CHINESE] = hb_ft_font_create( ft_face[CHINESE], NULL ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buf = hb_buffer_create(); for (i=0; i < NUM_EXAMPLES; ++i) { hb_buffer_set_direction( buf, text_directions[i] ); /* or LTR */ hb_buffer_set_script( buf, scripts[i] ); /* see hb-unicode.h */ hb_buffer_set_language( buf, hb_language_from_string(languages[i], strlen(languages[i])) ); /* Layout the text */ hb_buffer_add_utf8( buf, texts[i], strlen(texts[i]), 0, strlen(texts[i]) ); hb_shape( hb_ft_font[i], buf, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); FT_GlyphSlot slot; FT_Bitmap ft_bitmap; float size = 24; size_t hres = 64; FT_Error error; FT_Int32 flags = 0; flags |= FT_LOAD_RENDER; flags |= FT_LOAD_TARGET_LCD; FT_Library_SetLcdFilter( ft_library, FT_LCD_FILTER_LIGHT ); FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), (int)((0.0) * 0x10000L), (int)((0.0) * 0x10000L), (int)((1.0) * 0x10000L) }; /* Set char size */ error = FT_Set_Char_Size( ft_face[i], (int)(ptSize), 0, 72*hres, 72 ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } /* Set transform matrix */ FT_Set_Transform( ft_face[i], &matrix, NULL ); for (j = 0; j < glyph_count; ++j) { /* Load glyph */ error = FT_Load_Glyph( ft_face[i], glyph_info[j].codepoint, flags ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } slot = ft_face[i]->glyph; ft_bitmap = slot->bitmap; int ft_bitmap_width = slot->bitmap.width; int ft_bitmap_rows = slot->bitmap.rows; int ft_bitmap_pitch = slot->bitmap.pitch; int ft_glyph_top = slot->bitmap_top; int ft_glyph_left = slot->bitmap_left; int w = ft_bitmap_width/3; // 3 because of LCD/RGB encoding int h = ft_bitmap_rows; ivec4 region = texture_atlas_get_region( atlas, w+1, h+1 ); if ( region.x < 0 ) { fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); continue; } int x = region.x, y = region.y; texture_atlas_set_region( atlas, region.x, region.y, w, h, ft_bitmap.buffer, ft_bitmap.pitch ); printf("%d: %dx%d %f %f\n", glyph_info[j].codepoint, ft_bitmap_width, ft_bitmap_rows, glyph_pos[j].x_advance/64., glyph_pos[j].y_advance/64.); } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buf); } /* Cleanup */ hb_buffer_destroy( buf ); for( i=0; i < NUM_EXAMPLES; ++i ) hb_font_destroy( hb_ft_font[i] ); FT_Done_FreeType( ft_library ); glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); texture_atlas_upload( atlas ); typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vertex_t vertices[4] = { { 0, 0,0, 0,1, 0,0,0,1, 0, 1}, { 0,512,0, 0,0, 0,0,0,1, 0, 1}, {512,512,0, 1,0, 0,0,0,1, 0, 1}, {512, 0,0, 1,1, 0,0,0,1, 0, 1} }; GLuint indices[6] = { 0, 1, 2, 0,2,3 }; buffer = vertex_buffer_new( "vertex:3f," "tex_coord:2f," "color:4f," "ashift:1f," "agamma:1f" ); vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
//----------------------------------------------------------- bool ofxSosoTrueTypeFont::loadFont(string filename, int fontsize, bool _bAntiAliased, bool _bFullCharacterSet, bool makeContours, bool makeMipMaps, float simplifyAmt, int dpi){ //soso - added makeMipMaps (see below) bMakeContours = makeContours; //------------------------------------------------ if (bLoadedOk == true){ // we've already been loaded, try to clean up : unloadTextures(); } //------------------------------------------------ if( dpi == 0 ){ dpi = ttfGlobalDpi; } filename = ofToDataPath(filename); bLoadedOk = false; bAntiAliased = _bAntiAliased; bFullCharacterSet = _bFullCharacterSet; fontSize = fontsize; //--------------- load the library and typeface FT_Error err; FT_Library library; if (err = FT_Init_FreeType( &library )){ ofLog(OF_LOG_ERROR,"ofTrueTypeFont::loadFont - Error initializing freetype lib: FT_Error = %d", err); return false; } FT_Face face; if (err = FT_New_Face( library, filename.c_str(), 0, &face )) { // simple error table in lieu of full table (see fterrors.h) string errorString = "unknown freetype"; if(err == 1) errorString = "INVALID FILENAME"; ofLog(OF_LOG_ERROR,"ofTrueTypeFont::loadFont - %s: %s: FT_Error = %d", errorString.c_str(), filename.c_str(), err); return false; } //FT_Set_Char_Size( face, fontsize << 6, fontsize << 6, dpi, dpi); //of //FT_Set_Char_Size( face, 0, fontsize*dpi, 0, dpi); //soso FT_Set_Char_Size( face, 0, fontsize*64, 0, dpi); //soso lineHeight = fontsize * 1.43f; //------------------------------------------------------ //kerning would be great to support: //ofLog(OF_LOG_NOTICE,"FT_HAS_KERNING ? %i", FT_HAS_KERNING(face)); //------------------------------------------------------ //nCharacters = bFullCharacterSet ? 256 : 128 - NUM_CHARACTER_TO_START; nCharacters = bFullCharacterSet ? 512 : 128 - NUM_CHARACTER_TO_START; //--------------- initialize character info and textures cps.resize(nCharacters); if(bMakeContours){ charOutlines.clear(); charOutlines.assign(nCharacters, ofTTFCharacter()); } vector<ofPixels> expanded_data(nCharacters); long areaSum=0; //--------------------- load each char ----------------------- for (int i = 0 ; i < nCharacters; i++){ //------------------------------------------ anti aliased or not: //if(err = FT_Load_Glyph( face, FT_Get_Char_Index( face, (unsigned char)(i+NUM_CHARACTER_TO_START) ), FT_LOAD_DEFAULT )){ if(err = FT_Load_Glyph( face, getFTCharIndex( face, (unsigned char)(i+NUM_CHARACTER_TO_START) ), FT_LOAD_DEFAULT )){ //soso replaced FT_Get_Char_Index with our custom version ofLog(OF_LOG_ERROR,"ofTrueTypeFont::loadFont - Error with FT_Load_Glyph %i: FT_Error = %d", i, err); } if (bAntiAliased == true) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); //------------------------------------------ FT_Bitmap& bitmap= face->glyph->bitmap; // prepare the texture: //int width = ofNextPow2( bitmap.width + border*2 ); // int height = ofNextPow2( bitmap.rows + border*2 ); //// ------------------------- this is fixing a bug with small type //// ------------------------- appearantly, opengl has trouble with //// ------------------------- width or height textures of 1, so we //// ------------------------- we just set it to 2... //if (width == 1) width = 2; //if (height == 1) height = 2; if(bMakeContours){ if( printVectorInfo )printf("\n\ncharacter %c: \n", char( i+NUM_CHARACTER_TO_START ) ); //int character = i + NUM_CHARACTER_TO_START; charOutlines[i] = makeContoursForCharacter( face ); if(simplifyAmt>0) charOutlines[i].simplify(simplifyAmt); charOutlines[i].getTessellation(); } // ------------------------- // info about the character: cps[i].character = i; cps[i].height = face->glyph->bitmap_top; cps[i].width = face->glyph->bitmap.width; cps[i].setWidth = face->glyph->advance.x >> 6; cps[i].topExtent = face->glyph->bitmap.rows; cps[i].leftExtent = face->glyph->bitmap_left; int width = cps[i].width; int height = bitmap.rows; cps[i].tW = width; cps[i].tH = height; GLint fheight = cps[i].height; GLint bwidth = cps[i].width; GLint top = cps[i].topExtent - cps[i].height; GLint lextent = cps[i].leftExtent; GLfloat corr, stretch; //this accounts for the fact that we are showing 2*visibleBorder extra pixels //so we make the size of each char that many pixels bigger stretch = 0;//(float)(visibleBorder * 2); corr = (float)(( (fontSize - fheight) + top) - fontSize); cps[i].x1 = lextent + bwidth + stretch; cps[i].y1 = fheight + corr + stretch; cps[i].x2 = (float) lextent; cps[i].y2 = -top + corr; // Allocate Memory For The Texture Data. expanded_data[i].allocate(width, height, 2); //-------------------------------- clear data: expanded_data[i].set(0,255); // every luminance pixel = 255 expanded_data[i].set(1,0); if (bAntiAliased == true){ ofPixels bitmapPixels; bitmapPixels.setFromExternalPixels(bitmap.buffer,bitmap.width,bitmap.rows,1); expanded_data[i].setChannel(1,bitmapPixels); } else { //----------------------------------- // true type packs monochrome info in a // 1-bit format, hella funky // here we unpack it: unsigned char *src = bitmap.buffer; for(int j=0; j <bitmap.rows;j++) { unsigned char b=0; unsigned char *bptr = src; for(int k=0; k < bitmap.width ; k++){ expanded_data[i][2*(k+j*width)] = 255; if (k%8==0){ b = (*bptr++); } expanded_data[i][2*(k+j*width) + 1] = b&0x80 ? 255 : 0; b <<= 1; } src += bitmap.pitch; } //----------------------------------- } areaSum += (cps[i].width+border*2)*(cps[i].height+border*2); } vector<charProps> sortedCopy = cps; sort(sortedCopy.begin(),sortedCopy.end(),&compare_cps); // pack in a texture, algorithm to calculate min w/h from // http://upcommons.upc.edu/pfc/bitstream/2099.1/7720/1/TesiMasterJonas.pdf //cout << areaSum << endl; bool packed = false; float alpha = logf(areaSum)*1.44269; int w; int h; while(!packed){ w = pow(2,floor((alpha/2.f) + 0.5)); // there doesn't seem to be a round in cmath for windows. //w = pow(2,round(alpha/2.f)); h = w;//pow(2,round(alpha - round(alpha/2.f))); int x=0; int y=0; int maxRowHeight = sortedCopy[0].tH + border*2; for(int i=0;i<(int)cps.size();i++){ if(x+sortedCopy[i].tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = sortedCopy[i].tH + border*2; if(y + maxRowHeight > h){ alpha++; break; } } x+= sortedCopy[i].tW + border*2; if(i==(int)cps.size()-1) packed = true; } } ofPixels atlasPixels; atlasPixels.allocate(w,h,2); atlasPixels.set(0,255); atlasPixels.set(1,0); int x=0; int y=0; int maxRowHeight = sortedCopy[0].tH + border*2; for(int i=0;i<(int)cps.size();i++){ ofPixels & charPixels = expanded_data[sortedCopy[i].character]; if(x+sortedCopy[i].tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = sortedCopy[i].tH + border*2; } cps[sortedCopy[i].character].t2 = float(x + border)/float(w); cps[sortedCopy[i].character].v2 = float(y + border)/float(h); cps[sortedCopy[i].character].t1 = float(cps[sortedCopy[i].character].tW + x + border)/float(w); cps[sortedCopy[i].character].v1 = float(cps[sortedCopy[i].character].tH + y + border)/float(h); charPixels.pasteInto(atlasPixels,x+border,y+border); x+= sortedCopy[i].tW + border*2; } texAtlas.allocate(atlasPixels.getWidth(),atlasPixels.getHeight(),GL_LUMINANCE_ALPHA,false); if(bAntiAliased && fontsize>20){ if (makeMipMaps) { //soso //texAtlas.enableMipmaps(); //texAtlas.setTextureMinMagFilter(GL_LINEAR_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_LINEAR); //soso } else //soso texAtlas.setTextureMinMagFilter(GL_LINEAR,GL_LINEAR); }else{ texAtlas.setTextureMinMagFilter(GL_NEAREST,GL_NEAREST); } texAtlas.loadData(atlasPixels.getPixels(),atlasPixels.getWidth(),atlasPixels.getHeight(),GL_LUMINANCE_ALPHA); ///////////////////////////////////////////////////////////////////////sosoAddon //until ofTexture fully supports mipmaps, we gotta do it manually here - AFTER loadData is called on the texture //it's a redo of what happens inside tex.loadData(), but instead we build the mipmaps if(makeMipMaps){ glEnable(texAtlas.getTextureData().textureTarget); glBindTexture(texAtlas.getTextureData().textureTarget, (GLuint) texAtlas.getTextureData().textureID); glTexParameteri(texAtlas.getTextureData().textureTarget, GL_GENERATE_MIPMAP_SGIS, true); glTexParameteri( texAtlas.getTextureData().textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( texAtlas.getTextureData().textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri( texAtlas.getTextureData().textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri( texAtlas.getTextureData().textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); gluBuild2DMipmaps(texAtlas.getTextureData().textureTarget, texAtlas.getTextureData().glType, w, h, texAtlas.getTextureData().glType, texAtlas.getTextureData().pixelType, atlasPixels.getPixels()); glDisable(texAtlas.getTextureData().textureTarget); } ////////////////////////////////////////////////////////////////////// //Sosolimited - load kerning pairs //initialize all pairs to 0 for (int i = 0; i < FONT_NUM_CHARS; i++) { for (int j = 0; j < FONT_NUM_CHARS; j++) { kerningPairs[i][j] = 0; } } //find out if the face has kerning FT_Bool use_kerning = (FT_Bool)FT_HAS_KERNING(face); if(use_kerning) printf("ofxSosoTrueTypeFont::loadFont() - kerning is supported\n"); else printf("ofxSosoTrueTypeFont::loadFont() - kerning is NOT supported\n"); FT_UInt glyph_index_r, glyph_index_l; for (int i = 0; i < FONT_NUM_CHARS; i++) { // convert character code to glyph index glyph_index_r = FT_Get_Char_Index(face, i + NUM_CHARACTER_TO_START); for (int j = 0; j < FONT_NUM_CHARS; j++) { // convert character code to glyph index glyph_index_l = FT_Get_Char_Index(face, j + NUM_CHARACTER_TO_START); // retrieve kerning distance if (use_kerning && glyph_index_l && glyph_index_r) { FT_Vector delta; FT_Get_Kerning( face, glyph_index_l, glyph_index_r, FT_KERNING_DEFAULT, &delta ); kerningPairs[i][j] = delta.x >> 6; //if(i<127) //if(fabs((float)kerningPairs[i][j]) > 0) printf("kerningPairs: %c%c = %d, delta = %d\n", i + NUM_CHARACTER_TO_START, j + NUM_CHARACTER_TO_START, kerningPairs[i][j], delta.x); } } }
QStringList QBasicUnixFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) { extern FT_Library qt_getFreetype(); FT_Library library = qt_getFreetype(); int index = 0; int numFaces = 0; QStringList families; do { FT_Face face; FT_Error error; if (!fontData.isEmpty()) { error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); } else { error = FT_New_Face(library, file.constData(), index, &face); } if (error != FT_Err_Ok) { qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; break; } numFaces = face->num_faces; QFont::Weight weight = QFont::Normal; QFont::Style style = QFont::StyleNormal; if (face->style_flags & FT_STYLE_FLAG_ITALIC) style = QFont::StyleItalic; if (face->style_flags & FT_STYLE_FLAG_BOLD) weight = QFont::Bold; QSupportedWritingSystems writingSystems; // detect symbol fonts for (int i = 0; i < face->num_charmaps; ++i) { FT_CharMap cm = face->charmaps[i]; if (cm->encoding == ft_encoding_adobe_custom || cm->encoding == ft_encoding_symbol) { writingSystems.setSupported(QFontDatabase::Symbol); break; } } TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); if (os2) { quint32 unicodeRange[4] = { os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 }; quint32 codePageRange[2] = { os2->ulCodePageRange1, os2->ulCodePageRange2 }; writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); } QString family = QString::fromAscii(face->family_name); FontFile *fontFile = new FontFile; fontFile->fileName = file; fontFile->indexValue = index; QFont::Stretch stretch = QFont::Unstretched; registerFont(family,"",weight,style,stretch,true,true,0,writingSystems,fontFile); families.append(family); FT_Done_Face(face); ++index; } while (index < numFaces); return families; }
bool FTFont::check_face() { if (!library_) { if (library_checker_.expired()) { FT_Library lib; if (FT_Init_FreeType(&lib) != FT_Err_Ok) { Output::Error("Couldn't initialize FreeType"); return false; } library_.reset(lib, delete_library); library_checker_ = library_; } else { library_ = library_checker_.lock(); } } if (!face_ || face_name_ != name) { face_cache_type::const_iterator it = face_cache.find(name); if (it == face_cache.end() || it->second.expired()) { std::string const face_path = FileFinder::FindFont(name); FT_Face face; if (FT_New_Face(library_.get(), face_path.c_str(), 0, &face) != FT_Err_Ok) { Output::Error("Couldn't initialize FreeType face: %s(%s)", name.c_str(), face_path.c_str()); return false; } for (int i = 0; i < face_->num_fixed_sizes; i++) { FT_Bitmap_Size* size = &face_->available_sizes[i]; Output::Debug("Font Size %d: %d %d %f %f %f", i, size->width, size->height, size->size / 64.0, size->x_ppem / 64.0, size->y_ppem / 64.0); } face_.reset(face, delete_face); face_cache[name] = face_; } else { face_ = it->second.lock(); } face_name_ = name; } face_->style_flags = (bold ? FT_STYLE_FLAG_BOLD : 0) | (italic ? FT_STYLE_FLAG_ITALIC : 0); if (current_size_ != size) { int sz, dpi; if (face_->num_fixed_sizes == 1) { sz = face_->available_sizes[0].size; dpi = 96; } else { sz = size * 64; dpi = 72; } if (FT_Set_Char_Size(face_.get(), sz, sz, dpi, dpi) != FT_Err_Ok) { Output::Error("Couldn't set FreeType face size"); return false; } current_size_ = size; } return true; }
QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) { FT_Library library = qt_getFreetype(); int index = 0; int numFaces = 0; QStringList families; do { FT_Face face; FT_Error error; if (!fontData.isEmpty()) { error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); } else { error = FT_New_Face(library, file.constData(), index, &face); } if (error != FT_Err_Ok) { qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; break; } numFaces = face->num_faces; QFont::Weight weight = QFont::Normal; QFont::Style style = QFont::StyleNormal; if (face->style_flags & FT_STYLE_FLAG_ITALIC) style = QFont::StyleItalic; if (face->style_flags & FT_STYLE_FLAG_BOLD) weight = QFont::Bold; bool fixedPitch = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH); QSupportedWritingSystems writingSystems; // detect symbol fonts for (int i = 0; i < face->num_charmaps; ++i) { FT_CharMap cm = face->charmaps[i]; if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM || cm->encoding == FT_ENCODING_MS_SYMBOL) { writingSystems.setSupported(QFontDatabase::Symbol); break; } } TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); if (os2) { quint32 unicodeRange[4] = { quint32(os2->ulUnicodeRange1), quint32(os2->ulUnicodeRange2), quint32(os2->ulUnicodeRange3), quint32(os2->ulUnicodeRange4) }; quint32 codePageRange[2] = { quint32(os2->ulCodePageRange1), quint32(os2->ulCodePageRange2) }; writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); if (os2->usWeightClass) { weight = QPlatformFontDatabase::weightFromInteger(os2->usWeightClass); } else if (os2->panose[2]) { int w = os2->panose[2]; if (w <= 1) weight = QFont::Thin; else if (w <= 2) weight = QFont::ExtraLight; else if (w <= 3) weight = QFont::Light; else if (w <= 5) weight = QFont::Normal; else if (w <= 6) weight = QFont::Medium; else if (w <= 7) weight = QFont::DemiBold; else if (w <= 8) weight = QFont::Bold; else if (w <= 9) weight = QFont::ExtraBold; else if (w <= 10) weight = QFont::Black; } } QString family = QString::fromLatin1(face->family_name); FontFile *fontFile = new FontFile; fontFile->fileName = QFile::decodeName(file); fontFile->indexValue = index; QFont::Stretch stretch = QFont::Unstretched; registerFont(family,QString::fromLatin1(face->style_name),QString(),weight,style,stretch,true,true,0,fixedPitch,writingSystems,fontFile); families.append(family); FT_Done_Face(face); ++index; } while (index < numFaces); return families; }
/*! \brief Access function to request a face via the FreeType font cache */ static FT_Error face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface) { CachedFace face = (CachedFace) face_id; return FT_New_Face(ftlib,face->file_path.String(),face->face_index,aface); }
void Label::makeFont(string f) { if(fonts.find(f) != fonts.end()) { font = fonts[f]; return; } string floc = Location + f + ".ttf"; font = fonts[f] = new Font(); font->point = 200; // Create And Initilize A FreeType Font Library. FT_Init_FreeType( &ft ); // This Is Where We Load In The Font Information From The File. // Of All The Places Where The Code Might Die, This Is The Most Likely, // As FT_New_Face Will Fail If The Font File Does Not Exist Or Is Somehow Broken. if (FT_New_Face( ft, floc.c_str(), 0, &font->face )) return; // For Some Twisted Reason, FreeType Measures Font Size // In Terms Of 1/64ths Of Pixels. Thus, To Make A Font // h Pixels High, We Need To Request A Size Of h*64. // (h << 6 Is Just A Prettier Way Of Writing h*64) FT_Set_Char_Size( font->face, font->point * 64, font->point * 64, 96, 96); bool use_kerning = FT_HAS_KERNING( font->face ); for(unsigned char c=0; c<128; c++) { // The First Thing We Do Is Get FreeType To Render Our Character // Into A Bitmap. This Actually Requires A Couple Of FreeType Commands: // Load The Glyph For Our Character. if(FT_Load_Glyph( font->face, FT_Get_Char_Index( font->face, c ), FT_LOAD_DEFAULT )) return; // Move The Face's Glyph Into A Glyph Object. FT_Glyph glyph; if(FT_Get_Glyph( font->face->glyph, &glyph )) return; // Convert The Glyph To A Bitmap. FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 ); FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph; // This Reference Will Make Accessing The Bitmap Easier. FT_Bitmap& bitmap=bitmap_glyph->bitmap; // Use Our Helper Function To Get The Widths Of // The Bitmap Data That We Will Need In Order To Create // Our Texture. int downsample = 8; int width = next_p2( bitmap.width + 4 * downsample ); int height = next_p2( bitmap.rows + 4 * downsample ); float xs = (float)bitmap.width / width; float ys = (float)bitmap.rows / height; width /= downsample; height /= downsample; // Allocate Memory For The Texture Data. GLubyte* tex = (GLubyte*)malloc(width * height); memset(tex, 0, width*height); for(int i=0; i < width; i++) for(int j=0; j < height; j++) { tex[i + j*width]= edgeDistance(bitmap.buffer, bitmap.width, bitmap.rows, (i)/xs/width, (j)/ys/height, 1.0); } glGenTextures(1, &font->chars[c]); glBindTexture(GL_TEXTURE_2D, font->chars[c]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex); for(int k=0; k<128; k++) { if(use_kerning) { FT_Vector kern; FT_Get_Kerning( font->face, FT_Get_Char_Index( font->face, c ), FT_Get_Char_Index( font->face, k ), FT_KERNING_DEFAULT, &kern ); font->kerning[c][k] = (font->face->glyph->advance.x + kern.x) / (font->point * 64.0f); } else { font->kerning[c][k] = font->face->glyph->advance.x / (font->point * 64.0f); } } font->wid[c] = bitmap.width / (float)font->point; font->hgt[c] = bitmap.rows / (float)font->point; font->top[c] = (bitmap_glyph->top-bitmap.rows) / (float)font->point; font->xpad[c] = xs; font->ypad[c] = ys; free(tex); } FT_Done_Face(font->face); FT_Done_FreeType(ft); }