您的位置:首页 > 编程语言

Ogre 代码分析 -- 关于中文字体分析OgreFont

2010-03-05 09:14 441 查看
void MovableText::setFontName(const String &fontName)

里面加载纹理---只需改变这个纹理即可达到中文显示

mpMaterial = mpFont->getMaterial()->clone(mName + "Material");

这个纹理是通过 Font->getMaterial()获得的材质!

inline const MaterialPtr& getMaterial()
{
return mpMaterial;
}
OgreFont返回一个材质指针,是类成员变量

MaterialPtr mpMaterial; 这个就是成员变量-材质
TexturePtr mTexture; 这个是图片的变量

OgreFont::void Font::loadImpl()
里面有创建材质
mpMaterial = MaterialManager::getSingleton().create(
"Fonts/" + mName, mGroup);
这个函数内下一行针对truetype的
if (mType == FT_TRUETYPE)
{
createTextureFromFont();
texLayer = mpMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0);
// Always blend by alpha
blendByAlpha = true;
}
下一个函数:
createTextureFromFont();

void Font::createTextureFromFont(void)
{

// Just create the texture here, and point it at ourselves for when
// it wants to (re)load for real
String texName = mName + "Texture";
// Create, setting isManual to true and passing self as loader
mTexture = TextureManager::getSingleton().create(
texName, mGroup, true, this);
mTexture->setTextureType(TEX_TYPE_2D);
mTexture->setNumMipmaps(0);
mTexture->load();

TextureUnitState* t = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState( texName );
// Allow min/mag filter, but no mip
t->setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_NONE);

}

也就是在这个函数内部只创建了一个空的纹理指针mTexture

到这目标跟丢了 ......
回头看下OgreFont类
class _OgreExport Font : public Resource, public ManualResourceLoader
继承自Resource ManualResourceLoader

virtual void ManualResourceLoader::loadResource(Resource* resource) = 0;
这个是纯虚函数,肯定会在初始化的时候自动调用这个函数 看下OgreFont中的这个函数

void Font::loadResource(Resource* res)
这个函数是OgreFont类中最多的一个函数:-D,接下来仔细看这个函数:
void Font::loadResource(Resource* res)
{
FT_Library ftLibrary;
加载TrueType库,使用Truetype转化到图片
if( FT_Init_FreeType( &ftLibrary ) )
OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Could not init FreeType library!",
"Font::Font");

声明一个truetype的表面
FT_Face face;
这个shi定义子间距
uint char_spacer = 5;
声明一段内存来存放字体的每个像素颜色值,使用DataStreamPtr
DataStreamPtr dataStreamPtr =
ResourceGroupManager::getSingleton().openResource(
mSource, mGroup, true, this);
MemoryDataStream ttfchunk(dataStreamPtr);
加载字体
if( FT_New_Memory_Face( ftLibrary, ttfchunk.getPtr(), (FT_Long)ttfchunk.size() , 0, &face ) )
OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
"Could not open font face!", "Font::createTextureFromFont" );

设置下truetype字体的大小 26.6每像素
FT_F26Dot6 ftSize = (FT_F26Dot6)(mTtfSize * (1 << 6));
if( FT_Set_Char_Size( face, ftSize, 0, mTtfResolution, mTtfResolution ) )
OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
"Could not set char size!", "Font::createTextureFromFont" );

设置字体最大最小值---在这只是声明一下:
int max_height = 0, max_width = 0;

设置向后兼容大小--具体干嘛的,暂时不知道
if (mCodePointRangeList.empty())
{
mCodePointRangeList.push_back(CodePointRange(33, 166));
}
根据truetype glyph计算字体的大小
size_t glyphCount = 0;
循环所有兼容大小
for (CodePointRangeList::const_iterator r = mCodePointRangeList.begin();
r != mCodePointRangeList.end(); ++r)
{
const CodePointRange& range = *r;
for(CodePoint cp = range.first; cp <= range.second; ++cp, ++glyphCount)
{
根据字体face计算最大最小的字体的宽高
FT_Load_Char( face, cp, FT_LOAD_RENDER );
if( ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY ) > max_height )
max_height = ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY );
if( face->glyph->metrics.horiBearingY > mTtfMaxBearingY )
mTtfMaxBearingY = face->glyph->metrics.horiBearingY;
if( (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 ) > max_width)
max_width = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
}
}

计算下字体所需要的空间
size_t rawSize = (max_width + char_spacer) *
((max_height >> 6) + char_spacer) * glyphCount;
uint32 tex_side = static_cast<uint32>(Math::Sqrt(rawSize));
计算其他glyph
tex_side += std::max(max_width, (max_height>>6));
计算出字体空间
uint32 roundUpSize = Bitwise::firstPO2From(tex_side);

接下来是把glyph转换成位图矩阵,声明最终的宽高
size_t finalWidth, finalHeight;
if (roundUpSize*roundUpSize*0.5 >= rawSize)
{
finalHeight = static_cast<size_t>(roundUpSize * 0.5);
}
else
{
finalHeight = roundUpSize;
}
finalWidth = roundUpSize;

计算出纹理图片的宽高比例
Real textureAspect = finalWidth / finalHeight;
计算出纹理空间的宽高,根据每个像素占用空间
const size_t pixel_bytes = 2; //颜色占一个字节,alpha值占一个字节
size_t data_width = finalWidth * pixel_bytes;
size_t data_size = finalWidth * finalHeight * pixel_bytes;
重点:
分配内存空间
uchar* imageData = OGRE_ALLOC_T(uchar, data_size, MEMCATEGORY_GENERAL);

对这个内存空间进行一次清空
for (size_t i = 0; i < data_size; i += pixel_bytes)
{
对像素设置成255--全是白色
imageData[i + 0] = 0xFF; // luminance
对alpha值全部设置成0 黑色
imageData[i + 1] = 0x00; // alpha
}
下面就是对纹理进行填充值了

首先声明两个临时变量
要在循环中使用
size_t l = 0, m = 0;
循环所有兼容大小
for (CodePointRangeList::const_iterator r = mCodePointRangeList.begin();
r != mCodePointRangeList.end(); ++r)
{
const CodePointRange& range = *r;
for(CodePoint cp = range.first; cp <= range.second; ++cp )
{
声明一个truetype的返回类型
FT_Error ftResult;
加载TrueType glyph Render
ftResult = FT_Load_Char( face, cp, FT_LOAD_RENDER );
加载失败,判断
if (ftResult)
{
// problem loading this glyph, continue
LogManager::getSingleton().logMessage("Info: cannot load character " +
StringConverter::toString(cp) + " in font " + mName);
continue;
}

FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
获得glyph的位图内存
unsigned char* buffer = face->glyph->bitmap.buffer;
加载失败,判断
if (!buffer)
{
// Yuck, FT didn't detect this but generated a null pointer!
LogManager::getSingleton().logMessage("Info: Freetype returned null for character " +
StringConverter::toString(cp) + " in font " + mName);
continue;
}

int y_bearnig = ( mTtfMaxBearingY >> 6 ) - ( face->glyph->metrics.horiBearingY >> 6 );
开始了---循环所有兼容大小face->glyph的位图rows
for(int j = 0; j < face->glyph->bitmap.rows; j++ )
{
size_t row = j + m + y_bearnig;
获得纹理材质内存空间的地址,作为引用来替代赋值
uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];
在循环所有兼容大小face->glyph的位图的高
for(int k = 0; k < face->glyph->bitmap.width; k++ )
{
if (mAntialiasColour)
{
使用字体位图的颜色
*pDest++= *buffer;
}
else
{
// Always white whether 'on' or 'off' pixel, since alpha
// will turn off
*pDest++= 0xFF;
}
给 ALPHA 赋值,使用位图
*pDest++= *buffer++;
}
}

在这调用了setGlyphTexCoords()这个函数,下面会进行这个函数分析
this->setGlyphTexCoords(cp,
(Real)l / (Real)finalWidth, // u1
(Real)m / (Real)finalHeight, // v1
(Real)( l + ( face->glyph->advance.x >> 6 ) ) / (Real)finalWidth, // u2
( m + ( max_height >> 6 ) ) / (Real)finalHeight, // v2
textureAspect
);
l += (advance + char_spacer);

if( finalWidth - 1 < l + ( advance ) )
{
m += ( max_height >> 6 ) + char_spacer;
l = 0;
}
申请内存保存图片
DataStreamPtr memStream(
OGRE_NEW MemoryDataStream(imageData, data_size, true));
保存到图片image
Image img;
img.loadRawData( memStream, finalWidth, finalHeight, PF_BYTE_LA );
通过Image写到Texture
ConstImagePtrList imagePtrs;
imagePtrs.push_back(&img);
tex->_loadImages( imagePtrs );
FreeType 完毕
FT_Done_FreeType(ftLibrary);
}

下面分析setGlyphTexCoords
CodePointMap::iterator i = mCodePointMap.find(id);
if (i != mCodePointMap.end())
{
i->second.uvRect.left = u1;
i->second.uvRect.top = v1;
i->second.uvRect.right = u2;
i->second.uvRect.bottom = v2;
i->second.aspectRatio = textureAspect * (u2 - u1) / (v2 - v1);
}
else
{
mCodePointMap.insert(
CodePointMap::value_type(id,
GlyphInfo(id, UVRect(u1, v1, u2, v2),
textureAspect * (u2 - u1) / (v2 - v1))));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: