/** * @author Edouard DUPIN * * @copyright 2011, Edouard DUPIN, all right reserved * * @license BSD v3 (see license file) */ #include #include #include #include #include #include #undef __class__ #define __class__ "TexturedFont" static int32_t nextP2(int32_t value) { int32_t val=1; for (int32_t iii=1; iii<31; iii++) { if (value <= val) { return val; } val *=2; } EWOL_CRITICAL("impossible CASE...."); return val; } static int32_t simpleSQRT(int32_t value) { int32_t val=1; for (int32_t iii=1; iii<1000; iii++) { val =iii*iii; if (value <= val) { return iii; } } EWOL_CRITICAL("impossible CASE...."); return val; } static bool& GetFontInSystem(void) { static bool fontInOs = true; return fontInOs; } void ewol::font::SetFontPropety(bool inOSSystem) { GetFontInSystem() = inOSSystem; } ewol::TexturedFont::TexturedFont(etk::UString fontName) : ewol::Texture(fontName) { m_font[0] = NULL; m_font[1] = NULL; m_font[2] = NULL; m_font[3] = NULL; m_modeWraping[0] = ewol::font::Regular; m_modeWraping[1] = ewol::font::Regular; m_modeWraping[2] = ewol::font::Regular; m_modeWraping[3] = ewol::font::Regular; m_lastGlyphPos[0].setValue(0,0); m_lastGlyphPos[1].setValue(0,0); m_lastGlyphPos[2].setValue(0,0); m_lastGlyphPos[3].setValue(0,0); m_lastRawHeigh[0] = 0; m_lastRawHeigh[1] = 0; m_lastRawHeigh[2] = 0; m_lastRawHeigh[3] = 0; int32_t tmpSize = 0; // extarct name and size : etk::Char tmpChar = fontName.c_str(); const char * tmpData = tmpChar; const char * tmpPos = strchr(tmpData, ':'); if (tmpPos==NULL) { m_size = 1; EWOL_CRITICAL("Can not parse the font name : \"" << fontName << "\" ??? ':' " ); return; } else { if (sscanf(tmpPos+1, "%d", &tmpSize)!=1) { m_size = 1; EWOL_CRITICAL("Can not parse the font name : \"" << fontName << "\" ==> size ???"); return; } } m_name = fontName.Extract(0, (tmpPos - tmpData)); m_size = tmpSize; etk::UString fontBaseFolder("DATA:fonts"); if (true==GetFontInSystem()) { #if defined(__TARGET_OS__Android) fontBaseFolder = "/system/font"; #elif defined(__TARGET_OS__Linux) fontBaseFolder = "/usr/share/fonts/truetype"; #endif } etk::FSNode myFolder(fontBaseFolder); EWOL_INFO("try to find font named : '" << m_name << "' in : '" << myFolder <<"'"); // find the real Font name : etk::Vector output; myFolder.FolderGetRecursiveFiles(output); for (int32_t iii=0; iii=0; iii--) { if (m_fileName[iii] != "") { refMode = (ewol::font::mode_te)iii; } } // generate the wrapping on the preventing error for(int32_t iii=3; iii>=0; iii--) { if (m_fileName[iii] != "") { m_modeWraping[iii] = (ewol::font::mode_te)iii; } else { m_modeWraping[iii] = refMode; } } for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) { if (m_fileName[iiiFontId] == "") { EWOL_CRITICAL("can not load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" ==> size=" << m_size ); m_font[iiiFontId] = NULL; continue; } EWOL_INFO("Load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" ==> size=" << m_size); ewol::resource::Keep(m_fileName[iiiFontId], m_font[iiiFontId]); if (NULL == m_font[iiiFontId]) { return; } // set the bassic charset: m_listElement[iiiFontId].Clear(); GlyphProperty tmpchar1; tmpchar1.m_UVal = 0; m_listElement[iiiFontId].PushBack(tmpchar1); for (int32_t iii=0x20; iii<0xFF; iii++) { GlyphProperty tmpchar; tmpchar.m_UVal = iii; m_listElement[iiiFontId].PushBack(tmpchar); if (0x7F == iii) { iii = 0x9F; } } /* this is a bad code for now ... */ // ==> determine the texture Size GlyphProperty tmpproperty; tmpproperty.m_UVal = 'A'; m_font[iiiFontId]->GetGlyphProperty(m_size, tmpproperty); int32_t nbElement = 0xFF - 0x20 + 1; int32_t coter = simpleSQRT(nbElement); // note : +1 is for the overlapping of the glyph (Part 1) int32_t glyphMaxWidth = tmpproperty.m_advance.x() +1; int32_t glyphMaxHeight = tmpproperty.m_advance.y() +1; int32_t textureWidth = nextP2(coter*glyphMaxWidth); int32_t nbRaws = textureWidth / glyphMaxWidth; if (nbRaws <= 0) { EWOL_ERROR("devide by 0"); nbRaws = 1; } int32_t nbLine = (nbElement / nbRaws) + 1; int32_t textureHeight = nextP2(nbLine*glyphMaxHeight); // for android : textureHeight = etk_max(textureHeight, textureWidth); textureWidth = textureHeight; if (iiiFontId == 0) { EWOL_DEBUG("Generate a text texture for char(" << nbRaws << "," << nbLine << ") with size=(" << textureWidth << "," << textureHeight << ")"); // resize must be done on the texture ... SetImageSize(ivec2(textureWidth,textureHeight)); // now we can acces directly on the image m_data.SetFillColor(draw::Color(0x00000000)); m_data.Clear(); } m_height[iiiFontId] = m_font[iiiFontId]->GetHeight(m_size); int32_t CurrentLineHigh = 0; ivec2 glyphPosition(1,1); for (int32_t iii=0; iiiGetGlyphProperty(m_size, (m_listElement[iiiFontId])[iii])) { // change line if needed ... if (glyphPosition.x()+(m_listElement[iiiFontId])[iii].m_sizeTexture.x() > textureWidth) { glyphPosition.setX(0); glyphPosition.setY(glyphPosition.y()+CurrentLineHigh); CurrentLineHigh = 0; } // draw the glyph m_font[iiiFontId]->DrawGlyph(m_data, m_size, glyphPosition, (m_listElement[iiiFontId])[iii], iiiFontId); // set video position (m_listElement[iiiFontId])[iii].m_texturePosStart.setValue( (float)(glyphPosition.x()) / (float)textureWidth, (float)(glyphPosition.y()) / (float)textureHeight ); (m_listElement[iiiFontId])[iii].m_texturePosStop.setValue( (float)(glyphPosition.x() + (m_listElement[iiiFontId])[iii].m_sizeTexture.x()) / (float)textureWidth, (float)(glyphPosition.y() + (m_listElement[iiiFontId])[iii].m_sizeTexture.y()) / (float)textureHeight ); // update the maximum of the line hight : if (CurrentLineHigh<(m_listElement[iiiFontId])[iii].m_sizeTexture.y()) { // note : +1 is for the overlapping of the glyph (Part 2) CurrentLineHigh = (m_listElement[iiiFontId])[iii].m_sizeTexture.y()+1; } // note : +1 is for the overlapping of the glyph (Part 3) // update the Bitmap position drawing : glyphPosition.setX(glyphPosition.x() + (m_listElement[iiiFontId])[iii].m_sizeTexture.x()+1); } } //m_font[iiiFontId]->Display(); // generate the kerning for all the characters : m_font[iiiFontId]->GenerateKerning(m_size, m_listElement[iiiFontId]); } // For testing cheree the box are set) #if 0 draw::Color tlpppp(0xFF,0xFF,0xFF,0x00); for(int32_t jjj=0; jjj < textureHeight;jjj++) { for(int32_t iii=0; iii < textureWidth; iii++){ tlpppp = m_data.Get(ivec2(iii, jjj) ); // set only alpha : tlpppp.a = etk_min( tlpppp.a+0x60, 0xFF); // real set of color m_data.Set(ivec2(iii, jjj), tlpppp ); } } #endif EWOL_DEBUG("End generation of the Fond bitmap, start adding texture"); //m_data.DistanceField(); Flush(); } ewol::TexturedFont::~TexturedFont(void) { for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) { if (NULL!= m_font[iiiFontId]) { ewol::resource::Release(m_font[iiiFontId]); m_font[iiiFontId] = NULL; } } } bool ewol::TexturedFont::HasName(const etk::UString& fileName) { etk::UString tmpName = m_name; tmpName += ":"; tmpName += m_size; EWOL_VERBOSE("S : check : " << fileName << " ?= " << tmpName << " = " << (fileName==tmpName) ); return (fileName==tmpName); } int32_t ewol::TexturedFont::GetIndex(const uniChar_t charcode, const ewol::font::mode_te displayMode) const { if (charcode < 0x20) { return 0; } else if (charcode < 0x80) { return charcode.Get() - 0x1F; } else { for (int32_t iii=0x80-0x20; iii < m_listElement[displayMode].Size(); iii++) { if ((m_listElement[displayMode])[iii].m_UVal == charcode) { return iii; } } } return 0; } ewol::GlyphProperty* ewol::TexturedFont::GetGlyphPointer(const uniChar_t charcode, const ewol::font::mode_te displayMode) { int32_t index = GetIndex(charcode, displayMode); return &((m_listElement[displayMode])[index]); }