[DEV] dynamic font add elements and support multyple language

This commit is contained in:
Edouard DUPIN 2013-09-30 00:06:39 +02:00
parent a1e89a83a1
commit 7a8cabb625
6 changed files with 144 additions and 140 deletions

2
external/egami vendored

@ -1 +1 @@
Subproject commit a2ec749e8e34a40de57c714117dbaa4d0272de11
Subproject commit 9ab5eea1f349fdae52932508d108d2e954813bad

2
external/etk vendored

@ -1 +1 @@
Subproject commit e443c8a405d4b10febcd0d22d7ab4b7ce34fbd6d
Subproject commit 78d0986454e70b2292984f15e66ffe4c5c146d31

View File

@ -739,7 +739,7 @@ void ewol::Text::Print(const etk::UniChar& _charcode)
return;
}
// get a pointer on the glyph property :
ewol::GlyphProperty * myGlyph = m_font->GetGlyphPointer(_charcode, m_mode);
ewol::GlyphProperty* myGlyph = m_font->GetGlyphPointer(_charcode, m_mode);
if (NULL==myGlyph) {
EWOL_ERROR(" font does not really existed ...");
return;
@ -756,7 +756,7 @@ void ewol::Text::Print(const etk::UniChar& _charcode)
}
}
// 0x01 == 0x20 == ' ';
if (_charcode != 0x01) {
if (_charcode.Get() != 0x01) {
/* Bitmap position
* xA xB
* yC *------*
@ -770,9 +770,9 @@ void ewol::Text::Print(const etk::UniChar& _charcode)
float dyD = dyC - myGlyph->m_sizeTexture.y();
float tuA = myGlyph->m_texturePosStart.x();
float tuB = myGlyph->m_texturePosStop.x();
float tuB = tuA + myGlyph->m_texturePosSize.x();
float tvC = myGlyph->m_texturePosStart.y();
float tvD = myGlyph->m_texturePosStop.y();
float tvD = tvC + myGlyph->m_texturePosSize.y();
// Clipping and drawing area

View File

@ -8,6 +8,7 @@
#include <etk/types.h>
#include <etk/os/FSNode.h>
#include <egami/egami.h>
#include <ewol/resources/ResourceManager.h>
#include <ewol/renderer/eContext.h>
@ -42,33 +43,6 @@ etk::CCout& ewol::operator <<(etk::CCout& _os, const ewol::font::mode_te& _obj)
#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.... request power 2 of "<< value);
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;
}
ewol::TexturedFont::TexturedFont(etk::UString fontName) :
ewol::Texture(fontName)
{
@ -82,10 +56,10 @@ ewol::TexturedFont::TexturedFont(etk::UString fontName) :
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_lastGlyphPos[0].setValue(1,1);
m_lastGlyphPos[1].setValue(1,1);
m_lastGlyphPos[2].setValue(1,1);
m_lastGlyphPos[3].setValue(1,1);
m_lastRawHeigh[0] = 0;
m_lastRawHeigh[1] = 0;
@ -215,104 +189,34 @@ ewol::TexturedFont::TexturedFont(etk::UString fontName) :
}
EWOL_INFO("Load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" ==> size=" << m_size);
m_font[iiiFontId] = ewol::FontFreeType::Keep(m_fileName[iiiFontId]);
if (NULL == m_font[iiiFontId]) {
return;
if (m_font[iiiFontId] == NULL) {
EWOL_DEBUG("error in loading FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" ==> size=" << m_size );
}
}
for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) {
// 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.Clear(etk::Color<>(0x00000000));
if (m_font[iiiFontId] == NULL) {
continue;
}
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]);
// TODO : basic font use 512 is better ... ==> maybe estimate it with the dpi ???
SetImageSize(ivec2(256,32));
// now we can acces directly on the image
m_data.Clear(etk::Color<>(0x00000000));
}
// 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 );
}
// Add error glyph
{
etk::UniChar tmpchar;
tmpchar.Set(0);
AddGlyph(tmpchar);
}
// by default we set only the first AINSI char availlable
for (int32_t iii=0x20; iii<0x7F; iii++) {
etk::UniChar tmpchar;
tmpchar.Set(iii);
AddGlyph(tmpchar);
}
#endif
EWOL_DEBUG("End generation of the Fond bitmap, start adding texture");
//m_data.DistanceField();
Flush();
EWOL_DEBUG("Wrapping properties : ");
EWOL_DEBUG(" " << ewol::font::Regular << "==>" << GetWrappingMode(ewol::font::Regular));
@ -328,6 +232,75 @@ ewol::TexturedFont::~TexturedFont(void)
}
}
bool ewol::TexturedFont::AddGlyph(const etk::UniChar& _val)
{
bool hasChange = false;
// for each font :
for (int32_t iii=0; iii<4 ; iii++) {
if (m_font[iii] == NULL) {
continue;
}
// add the curent "char"
GlyphProperty tmpchar;
tmpchar.m_UVal = _val;
if (true == m_font[iii]->GetGlyphProperty(m_size, tmpchar)) {
//EWOL_DEBUG("load char : '" << _val << "'=" << _val.Get());
hasChange = true;
// change line if needed ...
if (m_lastGlyphPos[iii].x()+tmpchar.m_sizeTexture.x() > m_data.GetSize().x()) {
m_lastGlyphPos[iii].setX(1);
m_lastGlyphPos[iii] += ivec2(0, m_lastRawHeigh[iii]);
m_lastRawHeigh[iii] = 0;
}
while(m_lastGlyphPos[iii].y()+tmpchar.m_sizeTexture.y() > m_data.GetSize().y()) {
ivec2 size = m_data.GetSize();
size.setY(size.y()*2);
m_data.Resize(size, etk::Color<>(0));
// note : need to rework all the lyer due to the fact that the texture is used by the faur type...
for (int32_t kkk=0; kkk<4 ; kkk++) {
// change the coordonate on the element in the texture
for (int32_t jjj=0 ; jjj<m_listElement[kkk].Size() ; ++jjj) {
m_listElement[kkk][jjj].m_texturePosStart *= vec2(1.0f, 0.5f);
m_listElement[kkk][jjj].m_texturePosSize *= vec2(1.0f, 0.5f);
}
}
}
// draw the glyph
m_font[iii]->DrawGlyph(m_data, m_size, m_lastGlyphPos[iii], tmpchar, iii);
// set video position
tmpchar.m_texturePosStart.setValue( (float)m_lastGlyphPos[iii].x() / (float)m_data.GetSize().x(),
(float)m_lastGlyphPos[iii].y() / (float)m_data.GetSize().y() );
tmpchar.m_texturePosSize.setValue( (float)tmpchar.m_sizeTexture.x() / (float)m_data.GetSize().x(),
(float)tmpchar.m_sizeTexture.y() / (float)m_data.GetSize().y() );
// update the maximum of the line hight :
if (m_lastRawHeigh[iii]<tmpchar.m_sizeTexture.y()) {
// note : +1 is for the overlapping of the glyph (Part 2)
m_lastRawHeigh[iii] = tmpchar.m_sizeTexture.y()+1;
}
// note : +1 is for the overlapping of the glyph (Part 3)
// update the Bitmap position drawing :
m_lastGlyphPos[iii] += ivec2(tmpchar.m_sizeTexture.x()+1, 0);
} else {
EWOL_WARNING("Did not find char : '" << _val << "'=" << _val.Get());
tmpchar.SetNotExist();
}
m_listElement[iii].PushBack(tmpchar);
//m_font[iii]->Display();
// generate the kerning for all the characters :
if (tmpchar.Exist() == true) {
// TODO : Set the kerning back ...
//m_font[iii]->GenerateKerning(m_size, m_listElement[iii]);
}
}
if (hasChange==true) {
Flush();
egami::Store(m_data, "fileFont.bmp");
}
return hasChange;
}
bool ewol::TexturedFont::HasName(const etk::UString& fileName)
{
@ -339,19 +312,30 @@ bool ewol::TexturedFont::HasName(const etk::UString& fileName)
}
int32_t ewol::TexturedFont::GetIndex(const uniChar_t& charcode, const ewol::font::mode_te displayMode) const
int32_t ewol::TexturedFont::GetIndex(const uniChar_t& charcode, const ewol::font::mode_te displayMode)
{
if (charcode < 0x20) {
if (charcode.Get() < 0x20) {
return 0;
} else if (charcode < 0x80) {
} else if (charcode.Get() < 0x80) {
return charcode.Get() - 0x1F;
} else {
for (int32_t iii=0x80-0x20; iii < m_listElement[displayMode].Size(); iii++) {
//EWOL_DEBUG("search : '" << charcode << "' =?= '" << (m_listElement[displayMode])[iii].m_UVal << "'");
if (charcode == (m_listElement[displayMode])[iii].m_UVal) {
return iii;
//EWOL_DEBUG("search : '" << charcode << "'");
if ((m_listElement[displayMode])[iii].Exist()) {
//EWOL_DEBUG("return " << iii);
return iii;
} else {
return 0;
}
}
}
}
if (AddGlyph(charcode) == true) {
// TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!!
ewol::GetContext().ForceRedrawAll();
}
return 0;
}
@ -360,8 +344,8 @@ ewol::GlyphProperty* ewol::TexturedFont::GetGlyphPointer(const uniChar_t& _charc
{
//EWOL_DEBUG("Get glyph property for mode: " << _displayMode << " ==> wrapping index : " << m_modeWraping[_displayMode]);
int32_t index = GetIndex(_charcode, _displayMode);
if( index <0
|| index >=m_listElement[_displayMode].Size() ) {
if( index < 0
|| index >= m_listElement[_displayMode].Size() ) {
EWOL_ERROR(" Try to get glyph index inexistant ... ==> return the index 0 ... id=" << index);
if (m_listElement[_displayMode].Size()>=0) {
return &((m_listElement[_displayMode])[0]);

View File

@ -67,7 +67,7 @@ namespace ewol
* @param[in] displayMode Mode to display the currrent font
* @return The ID in the table (if it does not exist : return 0)
*/
int32_t GetIndex(const uniChar_t& charcode, const ewol::font::mode_te displayMode) const;
int32_t GetIndex(const uniChar_t& charcode, const ewol::font::mode_te displayMode);
/**
* @brief Get the pointer on the coresponding glyph
* @param[in] charcode The unicodeValue
@ -95,6 +95,13 @@ namespace ewol
* @param[in,out] reference on the object pointer
*/
static void Release(ewol::TexturedFont*& _object);
private:
/**
* @brief Add a glyph in a texture font.
* @param[in] _val Char value to add.
* @return true if the image size have change, false otherwise
*/
bool AddGlyph(const etk::UniChar& _val);
};

View File

@ -53,23 +53,27 @@ namespace ewol
{
public:
uniChar_t m_UVal; //!< Unicode value
private:
bool m_exist;
public:
int32_t m_glyphIndex; //!< Glyph index in the system
ivec2 m_sizeTexture; //!< size of the element to display
ivec2 m_bearing; //!< offset to display the data (can be negatif id the texture sise is bigger than the theoric places in the string)
ivec2 m_advance; //!< space use in the display for this specific char
vec2 m_texturePosStart; //!< Texture normalised position (START)
vec2 m_texturePosStop; //!< Texture normalised position (STOP)
vec2 m_texturePosSize; //!< Texture normalised position (SIZE)
private:
etk::Vector<ewol::Kerning> m_kerning; //!< kerning values of link of all elements
public:
GlyphProperty(void) :
m_UVal(0),
m_exist(true),
m_glyphIndex(0),
m_sizeTexture(0,0),
m_bearing(0,0),
m_advance(0,0),
m_texturePosStart(0,0),
m_texturePosStop(0,0)
m_texturePosSize(0,0)
{ };
float KerningGet(const uniChar_t charcode)
{
@ -79,15 +83,24 @@ namespace ewol
}
}
return 0;
}
};
void KerningAdd(const uniChar_t charcode, float value)
{
m_kerning.PushBack(ewol::Kerning(charcode, value));
}
};
void KerningClear(void)
{
m_kerning.Clear();
}
};
/**
* @brief Get the status of the char, if it exist or not in the FONT
* @return true if the char is availlable, false otherwise
*/
bool Exist(void) const { return m_exist; };
/**
* @brief Set the element doen not exist !!!
*/
void SetNotExist(void) { m_exist = false; };
};
};