第二人生的源码分析(二十一)显示人物名称的字体

前面已经介绍了显示人物名称的基本框架,但是使用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 

第二人生的源码分析(二十一)显示人物名称的字体_第1张图片 

蔡军生  2008/01/25 QQ:9073204 深圳

你可能感兴趣的:(源码分析)