日志 教程
当前位置: 教程  >  游戏开发  >  程序开发基础  >  正文

OpenGL实现中文显示——改进版

作者:郭同学 发表于 2011/12/16 13:30:26     评论(0)     阅读(4947)     
上篇文章名为《OpenGL实现中文显示》地址:
http://school.ogdev.net/ArticleShow.asp?id=5043&categoryid=8

有朋友说使用 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[i]);
  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[i]);
  if glStr[i] 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[i]);
  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[i]);
  glDeleteLists(dwChar, 1);
  FreeMem(CharW, (Length(GLStrChn) + 1) * 2);
  i := i + 1;
  end
  else
  begin
  Chartmp := Byte(GLStrChn[i]);
  if GLStrChn[i] 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[i]);
  FreeMem(CharW, (Length(glStr) + 1) * 2);
  i := i + 1;

  glCallList(dwChar);
  end
  else
  begin
  Chartmp := Byte(glStr[i]);
  if glStr[i] 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.

评论
显示
悄悄话
汇众教育官网 | 联系方式 | 版权声明 | 友情链接
Copyright 2008© 汇众益智(北京)教育科技有限公司. All Rights Reserved
')京ICP备09092043号 京公网安备11010802009023号