//----------------------------------------------------------------------------//
void FreeTypeFont::rasterise(utf32 start_codepoint, utf32 end_codepoint) const
{
CodepointMap::const_iterator s = d_cp_map.lower_bound(start_codepoint);
if (s == d_cp_map.end())
return;
CodepointMap::const_iterator orig_s = s;
CodepointMap::const_iterator e = d_cp_map.upper_bound(end_codepoint);
while (true)
{
// Create a new Imageset for glyphs
uint texsize = getTextureSize(s, e);
// If all glyphs were already rendered, do nothing
if (!texsize)
break;
Imageset& is = ImagesetManager::getSingleton().create(
d_name + "_auto_glyph_images_" + int (s->first),
System::getSingleton().getRenderer()->createTexture());
d_glyphImages.push_back(&is);
argb_t *mem_buffer = new argb_t [texsize * texsize];
memset(mem_buffer, 0, texsize * texsize * sizeof(argb_t));
uint x = INTER_GLYPH_PAD_SPACE, y = INTER_GLYPH_PAD_SPACE;
uint yb = INTER_GLYPH_PAD_SPACE;
bool finished = false;
bool forward = true;
while (s != d_cp_map.end())
{
// Check if we finished rendering all the required glyphs
finished ¦= (s == e);
// Check if glyph already rendered
if (!s->second.getImage())
{
// Render the glyph
if (FT_Load_Char(d_fontFace, s->first, FT_LOAD_RENDER ¦ FT_LOAD_FORCE_AUTOHINT ¦
(d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO)))
{
std::stringstream err;
err << "Font::loadFreetypeGlyph - Failed to load glyph for codepoint: ";
err << static_cast<unsigned int>(s->first);
err << ". Will use an empty image for this glyph!";
Logger::getSingleton().logEvent(err.str(), Errors);
Rect area(0, 0, 0, 0);
Point offset(0, 0);
String name;
name += s->first;
is.defineImage(name, area, offset);
((FontGlyph &)s->second).setImage(&is.getImage(name));
float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);
((FontGlyph &)s->second).setAdvance(adv);
}
else
{
uint glyph_w = d_fontFace->glyph->bitmap.width + INTER_GLYPH_PAD_SPACE;
FT_Glyph_Metrics metrics = d_fontFace->glyph->metrics;
if (s->first == 32)
{
if(!FT_Load_Char (d_fontFace, 0x4e00, FT_LOAD_RENDER ¦ FT_LOAD_FORCE_AUTOHINT ¦ (d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO)))
{
glyph_w = d_fontFace->glyph->bitmap.width + INTER_GLYPH_PAD_SPACE;
metrics = d_fontFace->glyph->metrics;
FT_Load_Char (d_fontFace, 32 , FT_LOAD_RENDER ¦ FT_LOAD_FORCE_AUTOHINT ¦ (d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO));
}
}
uint glyph_h = d_fontFace->glyph->bitmap.rows + INTER_GLYPH_PAD_SPACE;
// Check if glyph right margin does not exceed texture size
uint x_next = x + glyph_w;
if (x_next > texsize)
{
x = INTER_GLYPH_PAD_SPACE;
x_next = x + glyph_w;
y = yb;
}
// Check if glyph bottom margine does not exceed texture size
uint y_bot = y + glyph_h;
if (y_bot > texsize)
break;
// Copy rendered glyph to memory buffer in RGBA format
drawGlyphToBuffer(mem_buffer + (y * texsize) + x, texsize);
// Create a new image in the imageset
Rect area(static_cast<float>(x),
static_cast<float>(y),
static_cast<float>(x + glyph_w - INTER_GLYPH_PAD_SPACE),
static_cast<float>(y + glyph_h - INTER_GLYPH_PAD_SPACE));
Point offset(metrics.horiBearingX * static_cast<float>(FT_POS_COEF),-d_fontFace->glyph->metrics.horiBearingY * static_cast<float>(FT_POS_COEF));
String name;
name += s->first;
is.defineImage(name, area, offset);
((FontGlyph &)s->second).setImage(&is.getImage(name));
float adv = metrics.horiAdvance * float(FT_POS_COEF);
((FontGlyph &)s->second).setAdvance(adv);
// Advance to next position
x = x_next;
if (y_bot > yb)
{
yb = y_bot;
}
}
}
// Go to next glyph, if we are going forward
if (forward)
if (++s == d_cp_map.end())
{
finished = true;
forward = false;
s = orig_s;
}
// Go to previous glyph, if we are going backward
if (!forward)
if ((s == d_cp_map.begin()) ¦¦ (--s == d_cp_map.begin()))
break;
}
is.getTexture()->loadFromMemory(mem_buffer, Size(texsize, texsize), Texture::PF_RGBA);
delete [] mem_buffer;
if (finished)
break;
}
}
// amount of bits in a uint
#define BITS_PER_UINT (sizeof (uint) *
// must be a power of two
#define GLYPHS_PER_PAGE 256
//----------------------------------------------------------------------------//
const FontGlyph * FreeTypeFont::getGlyphData (utf32 codepoint)
{
/*if (codepoint > d_maxCodepoint)
return 0;
CodepointMap::const_iterator pos = d_hz_map.find(codepoint);
if (!d_hz_map[codepoint].getImage())
{
// Check if glyph page has been rasterised
uint page = codepoint / GLYPHS_PER_PAGE;
uint mask = 1 << (page & (BITS_PER_UINT - 1));
if (!(d_glyphPageLoaded[page / BITS_PER_UINT] & mask))
{
d_glyphPageLoaded[page / BITS_PER_UINT] ¦= mask;
rasteriseHZ(codepoint);
//}
}*/
if(codepoint < 256) //决定保留一张纹理放英文和字符
{
if (!m_Words)
{
/*uint page = codepoint / GLYPHS_PER_PAGE;
uint mask = 1 << (page & (BITS_PER_UINT - 1));
if (!(d_glyphPageLoaded [page / BITS_PER_UINT] & mask))
{}
d_glyphPageLoaded [page / BITS_PER_UINT] ¦= mask;*/
rasterise (codepoint & ~(GLYPHS_PER_PAGE - 1),
codepoint ¦ (GLYPHS_PER_PAGE - 1));
m_Words = true;
}
CodepointMap::const_iterator pos = d_cp_map.find (codepoint);
return (pos != d_cp_map.end()) ? &pos->second : 0;
}
else //显示汉字啦
{
CodepointMap::const_iterator pos;
pos = d_hz_map.find (codepoint);
if(pos != d_hz_map.end())
{
return (pos != d_hz_map.end()) ? &pos->second : 0;
}
else
{
rasteriseHZ(codepoint);
pos = d_hz_map.find (codepoint);
return (pos != d_hz_map.end()) ? &pos->second : 0;
}
}
}
//----------------------------------------------------------------------------//
void FreeTypeFont::rasteriseHZ(utf32 codepoint)
{
uint texsize = 512;
if(d_hz_map.size() == 0)
{
hzImageset = &(ImagesetManager::getSingleton ().create(d_name + "_auto_glyph_images_" + int (codepoint),System::getSingleton().getRenderer ()->createTexture ()));
hzmem_buffer = new argb_t[texsize * texsize];
memset(hzmem_buffer, 0, texsize * texsize * sizeof(argb_t));
m_nHZX = m_nHZY = m_nHZYB = INTER_GLYPH_PAD_SPACE;
}
/*//d_hz_map.clear();
//ImagesetManager::getSingleton ().destroy(hzImageset->getName());
hzImageset = &(ImagesetManager::getSingleton ().create(
d_name + "_auto_glyph_images_" ,
System::getSingleton ().getRenderer ()->createTexture ());)
//d_glyphImages.push_back (hzImageset);
float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);
d_hz_map[codepoint] = FontGlyph(adv);*/
d_hz_map[codepoint] = FontGlyph (0.0f);
CodepointMap::const_iterator hzInter = d_hz_map.find(codepoint);
if (!hzInter->second.getImage())
{
if (FT_Load_Char (d_fontFace, hzInter->first, FT_LOAD_RENDER ¦ FT_LOAD_FORCE_AUTOHINT ¦ (d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO)))
{
std::stringstream err;
err << "Font::loadFreetypeGlyph - Failed to load glyph for codepoint: ";
err << static_cast<unsigned int> (hzInter->first);
err << ". Will use an empty image for this glyph!";
Logger::getSingleton ().logEvent (err.str (), Errors);
// Create a 'null' image for this glyph so we do not seg later
Rect area(0, 0, 0, 0);
Point offset(0, 0);
String name;
name += hzInter->first;
hzImageset->defineImage(name, area, offset);
((FontGlyph &)hzInter->second).setImage(&hzImageset->getImage(name));
float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);
d_hz_map[codepoint].setAdvance(adv);
}
else
{
uint glyph_w = d_fontFace->glyph->bitmap.width + INTER_GLYPH_PAD_SPACE;
uint glyph_h = d_fontFace->glyph->bitmap.rows + INTER_GLYPH_PAD_SPACE;
// Check if glyph right margin does not exceed texture size
uint x_next = m_nHZX + glyph_w;
if (x_next > texsize)
{
m_nHZX = INTER_GLYPH_PAD_SPACE;
x_next = m_nHZX + glyph_w;
m_nHZY = m_nHZYB;
}
// Check if glyph bottom margine does not exceed texture size
uint y_bot = m_nHZY + glyph_h;
if (y_bot > texsize)
{
hzImageset = &(ImagesetManager::getSingleton ().create(d_name + "_auto_glyph_images_" + int (codepoint),System::getSingleton().getRenderer ()->createTexture ()));
hzmem_buffer = new argb_t[texsize * texsize];
memset(hzmem_buffer, 0, texsize * texsize * sizeof(argb_t));
m_nHZX = m_nHZY = m_nHZYB = INTER_GLYPH_PAD_SPACE;
}
// Copy rendered glyph to memory buffer in RGBA format
drawGlyphToBuffer (hzmem_buffer + (m_nHZY * texsize) + m_nHZX, texsize);
// Create a new image in the imageset
Rect area(static_cast<float>(m_nHZX),
static_cast<float>(m_nHZY),
static_cast<float>(m_nHZX + glyph_w - INTER_GLYPH_PAD_SPACE),
static_cast<float>(m_nHZY + glyph_h - INTER_GLYPH_PAD_SPACE));
Point offset(d_fontFace->glyph->metrics.horiBearingX * static_cast<float>(FT_POS_COEF),
-d_fontFace->glyph->metrics.horiBearingY * static_cast<float>(FT_POS_COEF));
String name;
name += hzInter->first;
hzImageset->defineImage (name, area, offset);
((FontGlyph &)hzInter->second).setImage (&hzImageset->getImage (name));
float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);
((FontGlyph &)hzInter->second).setAdvance(adv);
// Advance to next position
m_nHZX = x_next;
if (y_bot > m_nHZYB)
{
m_nHZYB = y_bot;
}
}
}
// Copy our memory buffer into the texture and free it
hzImageset->getTexture ()->loadFromMemory (hzmem_buffer, CEGUI::Size(texsize,texsize), Texture::PF_RGBA);
}
//----------------------------------------------------------------------------//
void FreeTypeFont::drawGlyphToBuffer(argb_t *buffer, uint buf_width) const
{
FT_Bitmap *glyph_bitmap = &d_fontFace->glyph->bitmap;
for (int i = 0; i < glyph_bitmap->rows; ++i)
{
uchar *src = glyph_bitmap->buffer + (i * glyph_bitmap->pitch);
switch (glyph_bitmap->pixel_mode)
{
case FT_PIXEL_MODE_GRAY:
{
uchar *dst = reinterpret_cast<uchar*>(buffer);
for (int j = 0; j < glyph_bitmap->width; ++j)
{
// RGBA
*dst++ = mColour.r;
*dst++ = mColour.g;
*dst++ = mColour.b;
*dst++ = (*src++);
}
}
break;
case FT_PIXEL_MODE_MONO:
for (int j = 0; j < glyph_bitmap->width; ++j)
buffer [j] = (src [j / 8] & (0x80 >> (j & 7))) ? 0xFFFFFFFF : 0x00000000;
break;
default:
CEGUI_THROW(InvalidRequestException("Font::drawGlyphToBuffer: "
"The glyph could not be drawn because the pixel mode is "
"unsupported."));
break;
}
buffer += buf_width;
}
}
//----------------------------------------------------------------------------//
void FreeTypeFont::free()
{
if (!d_fontFace)
return;
d_cp_map.clear();
for (size_t i = 0; i < d_glyphImages.size(); i++)
ImagesetManager::getSingleton().destroy(d_glyphImages [i]->getName());
d_glyphImages.clear();
FT_Done_Face(d_fontFace);
d_fontFace = 0;
System::getSingleton().getResourceProvider()->unloadRawDataContainer(d_fontData);
}
//----------------------------------------------------------------------------//
void FreeTypeFont::updateFont()
{
//free();
System::getSingleton().getResourceProvider()->loadRawDataContainer(
d_filename, d_fontData, d_resourceGroup.empty() ?
getDefaultResourceGroup() : d_resourceGroup);
FT_Error error;
// create face using input font
if ((error = FT_New_Memory_Face(ft_lib, d_fontData.getDataPtr(),
static_cast<FT_Long>(d_fontData.getSize()), 0,
&d_fontFace)) != 0)
CEGUI_THROW(GenericException("FreeTypeFont::updateFont: Failed to "
"create face from font file '" + d_filename + "' error was: " +
((error < FT_Err_Max) ? ft_errors[error] : "unknown error")));
// check that default Unicode character map is available
if (!d_fontFace->charmap)
{
FT_Done_Face(d_fontFace);
d_fontFace = 0;
CEGUI_THROW(GenericException("FreeTypeFont::updateFont: "
"The font '" + d_name + "' does not have a Unicode charmap, and "
"cannot be used."));
}
uint horzdpi = System::getSingleton().getRenderer()->getDisplayDPI().d_x;
uint vertdpi = System::getSingleton().getRenderer()->getDisplayDPI().d_y;
float hps = d_ptSize * 64;
float vps = d_ptSize * 64;
if (d_autoScale)
{
hps *= d_horzScaling;
vps *= d_vertScaling;
}
if (FT_Set_Char_Size(d_fontFace, FT_F26Dot6(hps), FT_F26Dot6(vps), horzdpi, vertdpi))
{
// For bitmap fonts we can render only at specific point sizes.
// Try to find nearest point size and use it, if that is possible
float ptSize_72 = (d_ptSize * 72.0f) / vertdpi;
float best_delta = 99999;
float best_size = 0;
for (int i = 0; i < d_fontFace->num_fixed_sizes; i++)
{
float size = d_fontFace->available_sizes [i].size * float(FT_POS_COEF);
float delta = fabs(size - ptSize_72);
if (delta < best_delta)
{
best_delta = delta;
best_size = size;
}
}
if ((best_size <= 0) ¦¦
FT_Set_Char_Size(d_fontFace, 0, FT_F26Dot6(best_size * 64), 0, 0))
{
char size [20];
snprintf(size, sizeof(size), "%g", d_ptSize);
CEGUI_THROW(GenericException("FreeTypeFont::load - The font '" + d_name + "' cannot be rasterised at a size of " + size + " points, and cannot be used."));
}
}
if (d_fontFace->face_flags & FT_FACE_FLAG_SCALABLE)
{
//float x_scale = d_fontFace->size->metrics.x_scale * FT_POS_COEF * (1.0/65536.0);
float y_scale = d_fontFace->size->metrics.y_scale * float(FT_POS_COEF) * (1.0f / 65536.0f);
d_ascender = d_fontFace->ascender * y_scale;
d_descender = d_fontFace->descender * y_scale;
d_height = d_fontFace->height * y_scale;
}
else
{
d_ascender = d_fontFace->size->metrics.ascender * float(FT_POS_COEF);
d_descender = d_fontFace->size->metrics.descender * float(FT_POS_COEF);
d_height = d_fontFace->size->metrics.height * float(FT_POS_COEF);
}
if (d_specificLineSpacing > 0.0f)
{
d_height = d_specificLineSpacing;
}
if (!m_Words)
{
// Create an empty FontGlyph structure for every glyph of the font
FT_UInt gindex;
FT_ULong codepoint = FT_Get_First_Char(d_fontFace, &gindex);
FT_ULong max_codepoint = codepoint;
while (gindex)
{
if (max_codepoint < codepoint)
max_codepoint = codepoint;
// load-up required glyph metrics (don't render)
/* if (FT_Load_Char(d_fontFace, codepoint,
FT_LOAD_DEFAULT ¦ FT_LOAD_FORCE_AUTOHINT))
continue; // glyph error
float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);*/
// create a new empty FontGlyph with given character code
if(codepoint < 256)
d_cp_map[codepoint] = FontGlyph(0.0f);
// proceed to next glyph
codepoint = FT_Get_Next_Char(d_fontFace, codepoint, &gindex);
}
setMaxCodepoint(max_codepoint);
}
}
转载至:
http://lisuyong.com/2010/06/10/cegui