【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3769|回复: 0

[OpenGL] [转帖]OpenGL实现中文显示——改进版

[复制链接]
发表于 2006-9-7 11:49:57 | 显示全部楼层 |阅读模式
上次我发了个帖子,名为《OpenGL实现中文显示》。有朋友说使用 wglUseFontBitMapsW 函数就可以显示中文,由于考虑兼容问题,所以没有在原文给出实现方法。后来觉得使用 Window9X/Me 的人越来越少,所以决定改进一下原来的代码,以便支持 Unicode 编码。修改后的代码如下:

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
bUniCode : Boolean; //OS支持Unicode吗?
GLStrEng : PChar; //英文字串
GLStrChn : PChar; //中文字串

procedure Build(srcDC: HDC; glStr: PChar; glFont: PGLFont);
procedure GetWinVer;
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;
CharW : PWideChar;

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
if bUniCode then
if glFont.b3D then
wglUseFontOutLinesW(srcDC, 32, 125, 32, 0, 0, WGL_FONT_POLYGONS, @gmf)
else
wglUseFontBitMapsW(srcDC, 32, 125, 32)
else
if glFont.b3D then
wglUseFontOutLines(srcDC, 32, 125, 32, 0, 0, WGL_FONT_POLYGONS, @gmf)
else
wglUseFontBitMaps(srcDC, 32, 125, 32);
end
else
begin
i := 0;
While i < Length(glStr) do
begin
if bUniCode then
begin
GetMem(CharW, (Length(glStr) + 1) * 2);
StringToWideChar(glStr, CharW, Length(glStr) + 1);
dwChar := Word(CharW);
if glFont.b3D then
wglUseFontOutLinesW(srcDC, dwChar, 1, dwChar, 0, 0,
WGL_FONT_POLYGONS, @gmf)
else
wglUseFontBitMapsW(srcDC, dwChar, 1, dwChar);
FreeMem(CharW, (Length(glStr) + 1) * 2);
i := i + 1;
end
else
begin
Chartmp := Byte(glStr);
if glStr in LeadBytes 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;
end;

SelectObject(srcDC, oFont);
DeleteObject(Font);

end;

constructor TGLText.Create(srcDC : HDC; EngStr, ChnStr: PChar;
EngFont, ChnFont: PGLFont);
begin
GetWinVer;

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;
CharW : PWideChar;
dwChar : DWORD;
begin

if GLStrEng <> nil then
if GLStrEng = 'All English' then
begin
glDeleteLists(32, 93);
end
else
begin
i := 0;
While i < Length(GLStrEng) do
begin
dwChar := Byte(GLStrEng);
glDeleteLists(dwChar, 1);
i := i + 1;
end;
end;

if GLStrChn <> nil then
begin
i := 0;
While i < Length(GLStrChn) do
begin
if bUniCode then
begin
GetMem(CharW, (Length(GLStrChn) + 1) * 2);
StringToWideChar(GLStrChn, CharW, Length(GLStrChn) + 1);
dwChar := Word(CharW);
glDeleteLists(dwChar, 1);
FreeMem(CharW, (Length(GLStrChn) + 1) * 2);
i := i + 1;
end
else
begin
Chartmp := Byte(GLStrChn);
if GLStrChn in LeadBytes 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;
end;

inherited Destroy;

end;

procedure TGLText.GetWinVer;
var
VersionInfo: TOSVersionInfo;
begin
VersionInfo.dwOSVersionInfoSize := SizeOf(VersionInfo);
GetVersionEx(VersionInfo);
if Versioninfo.dwPlatformId < 2 then
bUniCode := False
else
bUniCode := True;
end;

procedure TGLText.glShowStr(glStr : PChar);
var
i,
Chartmp : Byte;
CharW : PWideChar;
dwChar : DWORD;
begin

i := 0;
While i < Length(glStr) do
begin
if bUniCode then
begin
GetMem(CharW, (Length(glStr) + 1) * 2);
StringToWideChar(glStr, CharW, Length(glStr) + 1);
dwChar := Word(CharW);
FreeMem(CharW, (Length(glStr) + 1) * 2);
i := i + 1;

glCallList(dwChar);
end
else
begin
Chartmp := Byte(glStr);
if glStr in LeadBytes 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;

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.

这次我把使用的例子也贴上了:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DotWindow, GL, GLu, GLext, Unit2;

type
TForm1 = class(TDotForm)
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormPaint(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
fX, fY : Integer;
MyText : TGLText;

procedure BuildLists;
procedure Clearing;
procedure DrawInfo;
procedure InitGLStatus(width, height: GLsizei);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation


{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
fX := 640;
fY := 480;
Self.BorderStyle := bsNone;
Self.Height := fY;
Self.Width := fX;
Self.Context.DC := GetDC(Self.Handle);
ShowCursor(False);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
Self.Context.QuickPF(32, 0, 24, 0);
Self.Context.InitGL;
InitGLStatus(Self.ClientWidth, Self.ClientHeight);
BuildLists;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MyText.Free;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
clearing;
DrawInfo;
Self.Context.PageFlip;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
case Key of
VK_ESCAPE :
begin
Clearing;
Self.Close;
end;
end;
end;

procedure TForm1.Clearing;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
end;

procedure TForm1.InitGLStatus(width, height: GLsizei);
begin
glClearColor(0, 0, 0, 0.5);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-(fX div 2), fX div 2, -(fY div 2), fY div 2);
glMatrixMode(GL_MODELVIEW);
end;

procedure TForm1.BuildLists;
var
StrE, StrC : TGLFont;
begin
//中、英文字体
StrE.b3D := False;
StrE.bBold := False;
StrE.bItalic := False;
StrE.Height := 13;
StrE.Weight := 0;
StrE.CharSet:= ANSI_CHARSET;
StrE.Typeface := 'Tahoma';

StrC.b3D := False;
StrC.bBold := False;
StrC.bItalic := False;
StrC.Height := 13;
StrC.Weight := 0;
StrC.CharSet:= GB2312_CHARSET;
StrC.Typeface := 'Tahoma';

MyText := TGLText.Create(Self.Context.DC,
'All English' , '这是中文请按键退出。……',
@StrE, @StrC);
end;

procedure TForm1.DrawInfo;
begin
glLoadIdentity;
glRasterPos2f(-250, 200);
MyText.glShowStr('这是中文。');

glRasterPos2f(-250, 150);
MyText.glShowStr('These are English characters. ');

glRasterPos2f(-80, -80);
MyText.glShowStr('请按 Esc 键退出……');
end;

end.

我用 Delphi 6 以及 Delphi 2006(Delphi 10) 验证通过。
有疑问可以发帖,或者发邮件给我,地址如下:
testerHooK@126.com
演示程序请见附件(含源代码)。

P.S. 演示程序用到了DOT工具,请到www.delphi3d.net下载最新版。


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 03:52

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表