ewol/sources/ewol/renderer/resources/TexturedFont.cpp

323 lines
11 KiB
C++

/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#include <etk/types.h>
#include <etk/os/FSNode.h>
#include <ewol/config.h>
#include <ewol/renderer/ResourceManager.h>
#include <ewol/renderer/resources/font/FontBase.h>
#include <ewol/renderer/resources/TexturedFont.h>
#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<etk::UString> output;
myFolder.FolderGetRecursiveFiles(output);
for (int32_t iii=0; iii<output.Size(); iii++) {
//EWOL_DEBUG(" file : " << output[iii]);
if( true == output[iii].EndWith(m_name+"-"+"bold"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"b"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"bd"+".ttf", false)
|| true == output[iii].EndWith(m_name+"bold"+".ttf", false)
|| true == output[iii].EndWith(m_name+"bd"+".ttf", false)
|| true == output[iii].EndWith(m_name+"b"+".ttf", false)) {
EWOL_INFO(" find Font [Bold] : " << output[iii]);
m_fileName[ewol::font::Bold] = output[iii];
} else if( true == output[iii].EndWith(m_name+"-"+"oblique"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"italic"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"Light"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"i"+".ttf", false)
|| true == output[iii].EndWith(m_name+"oblique"+".ttf", false)
|| true == output[iii].EndWith(m_name+"italic"+".ttf", false)
|| true == output[iii].EndWith(m_name+"light"+".ttf", false)
|| true == output[iii].EndWith(m_name+"i"+".ttf", false)) {
EWOL_INFO(" find Font [Italic] : " << output[iii]);
m_fileName[ewol::font::Italic] = output[iii];
} else if( true == output[iii].EndWith(m_name+"-"+"bolditalic"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"boldoblique"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"bi"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"z"+".ttf", false)
|| true == output[iii].EndWith(m_name+"bolditalic"+".ttf", false)
|| true == output[iii].EndWith(m_name+"boldoblique"+".ttf", false)
|| true == output[iii].EndWith(m_name+"bi"+".ttf", false)
|| true == output[iii].EndWith(m_name+"z"+".ttf", false)) {
EWOL_INFO(" find Font [Bold-Italic] : " << output[iii]);
m_fileName[ewol::font::BoldItalic] = output[iii];
} else if( true == output[iii].EndWith(m_name+"-"+"regular"+".ttf", false)
|| true == output[iii].EndWith(m_name+"-"+"r"+".ttf", false)
|| true == output[iii].EndWith(m_name+"regular"+".ttf", false)
|| true == output[iii].EndWith(m_name+"r"+".ttf", false)
|| true == output[iii].EndWith(m_name+".ttf", false)) {
EWOL_INFO(" find Font [Regular] : " << output[iii]);
m_fileName[ewol::font::Regular] = output[iii];
}
}
// try to find the reference mode :
ewol::font::mode_te refMode = ewol::font::Regular;
for(int32_t iii=3; 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; iii<m_listElement[iiiFontId].Size(); iii++) {
if (true == m_font[iiiFontId]->GetGlyphProperty(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]);
}