|
用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);
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);
glDeleteLists(dwChar, 1);
i := i + 1;
end;
end;
if GLStrChn <> nil then
begin
i := 0;
While i < StrLen(GLStrChn) do
begin
Chartmp := Byte(GLStrChn);
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);
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下载最新版。
|
|