前面已经介绍了显示人物名称的基本框架,但是使用OpenGL显示这个名称出来是需要很复杂的步骤。由于OpenGL是图形引擎显示,也就是说所有字符的显示都是基于图形来显示,而图形的显示,就需要获取字体的图片,即是获取字体的字模。由于不能使用Windows的标准GDI来显示,那么就需要实现GDI所做的所有功能,比如从字体里读取每个字符的轮廓,然后生成合适大小的位图,再把这幅位图当作纹理贴到3D的平面上去,这样才可以在OpenGL显示字符串出来。在第二人生里的代码流程如下:
1、LLFontGL::addChar()
添加一个字符纹理图片
2、mImageGLp->bind()
绑定纹理图片。
3、LLImageGL::bindTextureInternal()
真正绑定纹理图片,在这个函数里调用glBindTexture函数来绑定纹理。
4、LLFontGL::render()
这个函数显示所有字符串。
仔细地分析一下这个函数,看看怎么样显示字符串的,如下:
#001 S32 LLFontGL::render(const LLWString &wstr,
#002
const S32 begin_offset,
#003
const F32 x, const F32 y,
#004
const LLColor4 &color,
#005
const HAlign halign, const VAlign valign,
#006
U8 style,
#007
const S32 max_chars, S32 max_pixels,
#008
F32* right_x,
#009
BOOL use_embedded,
#010
BOOL use_ellipses) const
#011 {
#012
LLGLEnable texture_2d(GL_TEXTURE_2D);
#013
下面绑定纹理图片。
#089
#090
// Bind the font texture
#091
#092
mImageGLp->bind(0);
#093
#094
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
#095
下面开始循环地显示字符串。
#160
#161
for (i = begin_offset; i < begin_offset + length; i++)
#162
{
#163
llwchar wch = wstr[i];
#164
#165
// Handle embedded characters first, if they're enabled.
#166
// Embedded characters are a hack for notecards
#167
const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
#168
if (ext_data)
#169
{
……
#224
// Bind the font texture
#225
mImageGLp->bind();
#226
}
#227
else
#228
{
#229
if (!hasGlyph(wch))
#230
{
#231
(const_cast<LLFontGL*>(this))->addChar(wch);
#232
}
#233
#234
const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
#235
if (!fgi)
#236
{
#237
llerrs << "Missing Glyph Info" << llendl;
#238
break;
#239
}
#240
if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
#241
{
#242
// Not enough room for this character.
#243
break;
#244
}
#245
#246
// Draw the text at the appropriate location
#247
//Specify vertices and texture coordinates
#248
LLRectf uv_rect((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
#249
(fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height,
#250
(fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
#251
(fgi->mYBitmapOffset - PAD_AMT) * inv_height);
#252
LLRectf screen_rect(cur_render_x + (F32)fgi->mXBearing - PAD_AMT,
#253
cur_render_y + (F32)fgi->mYBearing + PAD_AMT,
#254
cur_render_x + (F32)fgi->mXBearing + (F32)fgi-
#255 >mWidth + PAD_AMT,
#256
cur_render_y + (F32)fgi->mYBearing - (F32)fgi-
#257 >mHeight - PAD_AMT);
#258
这里设置每个字符的纹理坐标以及顶点坐标。
#
259 drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);
#260
#261
chars_drawn++;
#262
cur_x += fgi->mXAdvance;
#263
cur_y += fgi->mYAdvance;
#264
#265
llwchar next_char = wstr[i+1];
#266
if (next_char && (next_char < LAST_CHARACTER))
#267
{
#268
// Kern this puppy.
#269
if (!hasGlyph(next_char))
#270
{
#271
(const_cast<LLFontGL*>(this))->addChar(next_char);
#272
}
#273
cur_x += getXKerning(wch, next_char);
#274
}
#275
#276
// Round after kerning.
#277
// Must do this to cur_x, not just to cur_render_x, otherwise you
#278
// will squish sub-pixel kerned characters too close together.
#279
// For example, "CCCCC" looks bad.
#280
cur_x = (F32)llfloor(cur_x + 0.5f);
#281
//cur_y = (F32)llfloor(cur_y + 0.5f);
#282
#283
cur_render_x = cur_x;
#284
cur_render_y = cur_y;
#285
}
#286
}
#287
……
#320
glPopMatrix();
#321
}
#322
#323
glPopMatrix();
#324
#325
return chars_drawn;
#326 }
#327
蔡军生
2008/01/25
QQ:9073204 深圳