用OpenGL显示文字,一般使用wglUseFontOutLines以及wglUseFontBitMaps函数(Windows平台)。如果显示单字节文字(英文,法文,拉丁文……),效果很好;如果显示双字节文字(中文,日文,韩文……),效果就不太好了。 用wglUseFontOutLines时,文字较小会看不清笔画(用Windows的屏保“三维文字”就能发现);而wglUseFontBitMaps无法显示中文。那么贴图文字呢? 如果用字量不大,还是不要麻烦她了。 经过一番研究,我写了一个类可以实现中文的位图显示。源代码如下:
unit Unit2;
interface
uses Windows, Messages, SysUtils, Variants, Graphics, GL, GLu, GLext;
Type PGLFont = ^TGLFont; TGLFont = record b3D : Boolean; bBold : Boolean; bItalic : Boolean; Height : Integer; Weight : Integer; CharSet : Cardinal; Typeface: PChar; end; TGLText = class private GLStrEng : PChar; GLStrChn : PChar;
procedure Build(srcDC: HDC; glStr: PChar; glFont: PGLFont); procedure wglUseFontBitmapsExt(srcDC : HDC; First, Count, ListBase : DWORD); public constructor Create(srcDC : HDC; EngStr, ChnStr : PChar; EngFont, ChnFont : PGLFont); destructor Destroy; override; procedure glShowStr(glStr : PChar); end;
implementation
{ TGLText } procedure TGLText.Build(srcDC: HDC; glStr: PChar; glFont: PGLFont); var i, Chartmp : Byte; Font, oFont : HFONT; glBold : Integer; glItalic : Cardinal; dwChar : DWORD; gmf : GLYPHMETRICSFLOAT; begin
if glFont.bBold then glBold := FW_BOLD else glBold := FW_NORMAL;
if glFont.bItalic then glItalic := 1 else glItalic := 0;
Font := CreateFont(glFont.Height, glFont.Weight, 0, 0, glBold, glItalic, 0, 0, glFont.CharSet, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE or DEFAULT_PITCH, glFont.Typeface);
oFont := SelectObject(srcDC, Font);
if glStr = 'All English' then begin for i := 32 to 125 do if glFont.b3D then wglUseFontOutLines(srcDC, i, 1, i, 0, 0, WGL_FONT_POLYGONS, @gmf) else wglUseFontBitMaps(srcDC, i, 1, i); end else begin i := 0; While i < StrLen(glStr) do begin Chartmp := Byte(glStr[i]); if IsDBCSLeadByte(Chartmp) then begin dwChar := ((Chartmp shl 8) or Byte(glStr[i+1])); i := i + 2; end else begin dwChar := Chartmp; i := i + 1; end; if glFont.b3D then wglUseFontOutLines(srcDC, dwChar, 1, dwChar, 0, 0, WGL_FONT_POLYGONS, @gmf) else wglUseFontBitMapsExt(srcDC, dwChar, 1, dwChar); end; end;
SelectObject(srcDC, oFont); DeleteObject(Font);
end;
constructor TGLText.Create(srcDC : HDC; EngStr, ChnStr: PChar; EngFont, ChnFont: PGLFont); begin
GLStrEng := EngStr; GLStrChn := ChnStr;
if EngStr <> nil then Build(srcDC, EngStr, EngFont);
if ChnStr <> nil then Build(srcDC, ChnStr, ChnFont);
end;
destructor TGLText.Destroy; var i, Chartmp : Byte; dwChar : DWORD; begin
if GLStrEng <> nil then if GLStrEng = 'All English' then begin glDeleteLists(32, 93); end else begin i := 0; While i < StrLen(GLStrEng) do begin dwChar := Byte(GLStrEng[i]); glDeleteLists(dwChar, 1); i := i + 1; end; end;
if GLStrChn <> nil then begin i := 0; While i < StrLen(GLStrChn) do begin Chartmp := Byte(GLStrChn[i]); if IsDBCSLeadByte(Chartmp) then begin dwChar := ((Chartmp shl 8) or Byte(GLStrChn[i+1])); i := i + 2; end else begin dwChar := Chartmp; i := i + 1; end; glDeleteLists(dwChar, 1); end; end;
inherited Destroy;
end;
procedure TGLText.glShowStr(glStr : PChar); var i, Chartmp : Byte; dwChar : DWORD; begin
i := 0; While i < StrLen(glStr) do begin Chartmp := Byte(glStr[i]); if IsDBCSLeadByte(Chartmp) then begin dwChar := ((Chartmp shl 8) or Byte(glStr[i+1])); i := i + 2; end else begin dwChar := Chartmp; i := i + 1; end; glCallList(dwChar); end;
end;
procedure TGLText.wglUseFontBitmapsExt(srcDC: HDC; First, Count, ListBase: DWORD); var i : DWORD; size : DWORD; gm : GLYPHMETRICS; hBits : THANDLE; lpBits : PGLubyte; mat : MAT2; begin
mat.eM11.fract := 0; mat.eM11.value := 1; mat.eM12.fract := 0; mat.eM12.value := 0; mat.eM21.fract := 0; mat.eM21.value := 0; mat.eM22.fract := 0; mat.eM22.value := -1;
for i := 0 to Count - 1 do begin glNewList(ListBase+i, GL_COMPILE);
size := GetGlyphOutline(srcDC, First+i, GGO_BITMAP, gm, 0, nil, mat);
hBits := GlobalAlloc(GHND, size); lpBits := GlobalLock(hBits);
GetGlyphOutline(srcDC, //* handle to device context */ First+i, //* character to query */ GGO_BITMAP, //* format of data to return */ gm, //* pointer to structure for metrics */ size, //* size of buffer for data */ lpBits, //* pointer to buffer for data */ mat //* pointer to transformation */ //* matrix structure */ );
glBitmap(gm.gmBlackBoxX,gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y, gm.gmCellIncX,gm.gmCellIncY, lpBits);
GlobalUnlock(hBits); GlobalFree(hBits);
glEndList; end;
end;
end.
我用的是Delphi 6。最终显示还可以,但并不完美。不知有谁可以改进?欢迎交流,我的邮箱testerHooK@126.com 由于网络原因演示程序(含源代码)请发邮件索取。
P.S. 演示程序用到了DOT工具,请到www.delphi3d.net下载最新版。 |