opengl显示文字

在目前的项目中因为有涉及到OpenGL文字输出之类的操作,于是做了一个总结,并把一个库进行了改进,在这里贴出来,希望大家能够在将来的编程中省去一些写细节代码的时间,同时也是抛砖引玉。

首先,要注明的是唐明理先生的开源库还有OpenGL资料是相当宝贵的,也是我见过的许多资料中最好的,如果初学者有了一定的应用水平,看他的这些东西,提高会是飞速的,而且会顺利过渡到框架开发的思维。我们做游戏与图像编程,必须要有把握全局代码的意识,必须要了解程序架构还有经典常用的数据结构与事件机制,而这一切的学习我觉得看别人代码是最快的,特别是象他这样循序渐进的代码。

  OpenGL是一个3D图形界面,在它上面显示文字有别于在Windows图形环境下显示文字。在OpenGL上文字需要一些特殊的方法,因为在3D图形界面上,有平面文字、3D文字之分。特别是汉字的显示要麻烦一些,因为OpenGL的底层不支持汉字的双字节编码。 本文的解决方案可以实现三种不同方式的文字显示:

 常规文字
    这种文字显示是一种高效能的、以位图方式绘制字体的方法,它采用了一种平面图形的方法,所以显示的是平面文字。只可惜,这个平面文字显示方法不能支持汉字。

 3D文字
    OpenGL中文字也可以作为3D对象来显示。这种3D文字可以缩放、旋转、贴图,有其它3D对象的所有特性。我们在程序还加入了对双字节汉字的特殊处理,所以它也能显示立体汉字。

 平面汉字
    OpenGL平面汉字。基本原理是:在系统内部建立一个确定字体的设备场景(MDC),用GDI方式将文字在设备场景中形成单色位图,再用OpenGL的平面位图显示函数glBitmap(…)将文字显示出来。

以下是源码:

//GLFont.h----------------------------------------------------------------------

// GLFont.h: interface for the CGLFont class.

#if !defined(AFX_GLFONT_H__88F1F000_50F5_452A_B95E_60ED83712FA5__INCLUDED_)
#define AFX_GLFONT_H__88F1F000_50F5_452A_B95E_60ED83712FA5__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CGLFont  
{
public:
 void entext(float x,float y, LPCTSTR str,HFONT hFont,float r,float g,float b);
 void c3dtext(LPCTSTR str,HFONT hFont,float z);
 void Printfc3d(LPCTSTR strText,HFONT hFont,float z=0.05f);
 void Printftext(int x, int y, LPCTSTR lpszText,HFONT hFont);
 void settext(float x,float y,LPCTSTR str,HFONT Font,float r,float g,float b);

 CGLFont();
 virtual ~CGLFont();
protected:
 HFONT hFont;
};

#endif

 

//GLFont.cpp----------------------------------------------------------------------

CGLFont::CGLFont()
{
}
CGLFont::~CGLFont()
{
}
void CGLFont::entext( float x,float y, LPCTSTR str, HFONT hFont,
       float r, float g, float b) 
{  HDC hdc = wglGetCurrentDC();  
 SelectObject(hdc, hFont); 
 unsigned int Base = glGenLists(96);
 wglUseFontBitmaps(hdc, 32, 96,Base);
 glDisable(GL_TEXTURE_2D); 
 glDisable(GL_LIGHTING); 
 glPushAttrib(GL_LIST_BIT);  
 glColor3f(r,g,b);
 glRasterPos2f(x/100, y/100); 
  glListBase(Base - 32); 
  glCallLists(_tcslen(str), GL_UNSIGNED_BYTE, str); 
 glPopAttrib(); 
 glEnable(GL_LIGHTING); 
 glEnable(GL_TEXTURE_2D); 
 glDeleteLists(Base, 96); 
}

void CGLFont::c3dtext(LPCTSTR str,HFONT hFont,float z)
{ glDisable(GL_TEXTURE_2D); 
 glDisable(GL_LIGHTING);
 Printfc3d(TEXT("立体汉字"),hFont,z);
 glEnable(GL_LIGHTING);   
 glEnable(GL_TEXTURE_2D);
}
void CGLFont::Printfc3d(LPCTSTR strText,HFONT hFont,float z)
{ HDC hdc = wglGetCurrentDC();
 HFONT hOldFont=(HFONT)::SelectObject(hdc,hFont);
 UCHAR * pChar=(UCHAR*)strText/*.GetBuffer(strText.GetLength())*/;
 int   nListNum;  
 DWORD dwChar;  
 GLYPHMETRICSFLOAT pgmf[1]; 
 glPushMatrix();   
 for(int i = 0; i < _tcslen(strText)/*strText.GetLength()*/; i++)
 { if(IsDBCSLeadByte((BYTE)pChar[i]))
  { dwChar=(DWORD)((pChar[i]<<8)|pChar[i+1]);
    i++;
  }
   else dwChar = pChar[i];
   nListNum = glGenLists(1);  
   wglUseFontOutlines( hdc, 
        dwChar, 
        1,
        nListNum, 
        0.0f, 
        z,
        WGL_FONT_POLYGONS,
        pgmf 
      );
   glCallList(nListNum);  
   glDeleteLists(nListNum, 1);   
 } 
 glPopMatrix();    
 //strText.ReleaseBuffer();
 ::SelectObject(hdc,hOldFont); 
}
void CGLFont:: settext (float x,float y,LPCTSTR str,HFONT Font,float r,float g,float b)
  
{   glPushMatrix();
 glPushAttrib(GL_CURRENT_BIT);
 glDisable(GL_TEXTURE_2D); 
 //glDisable(GL_LIGHTING); 
 glColor3f(r,g,b);  
   
 //--坐标变换--begin
 double X = x;
 double Y = y;
 double Z;

 GLdouble ModeMatrix[16];
 GLdouble ProjectMatrix[16];
 GLint    ViewPort[4];

 glGetDoublev(GL_PROJECTION_MATRIX, ProjectMatrix);
 glGetDoublev(GL_MODELVIEW_MATRIX, ModeMatrix);
 glGetIntegerv(GL_VIEWPORT, ViewPort);
  
 gluUnProject((GLdouble)x,(GLdouble)y,(GLdouble)Z,ModeMatrix,ProjectMatrix,ViewPort, &X, &Y, &Z);
 //--坐标变换--end

 glTranslatef(X,Y,-0.4f);

 Printftext (0,0, str,Font);    
 //glEnable(GL_LIGHTING);     
 glEnable(GL_TEXTURE_2D);
 glPopAttrib();
 glPopMatrix();
}
void CGLFont:: Printftext (int x, int y, LPCTSTR lpszText,HFONT hFont)
{ //CBitmap bitmap;
  BITMAP bm;
  SIZE size; 
  HDC MDC = ::CreateCompatibleDC(0);
  SelectObject(MDC,hFont); 
  ::GetTextExtentPoint32(MDC,lpszText,_tcslen(lpszText),&size);
  //bitmap.CreateBitmap(size.cx, size.cy, 1, 1, NULL);
  HBITMAP hbm = CreateBitmap(
   size.cx,         // bitmap width, in pixels
   size.cy,        // bitmap height, in pixels
   1,       // number of color planes
   1,   // number of bits to identify color
   NULL // color data array
 );
  HBITMAP oldBmp=(HBITMAP)SelectObject(MDC,hbm/*bitmap*/);
  SetBkColor  (MDC, RGB(0,     0,   0));
  SetTextColor(MDC, RGB(255, 255, 255));
  TextOut(MDC, 0, 0, lpszText, _tcslen(lpszText));
  //bitmap.GetBitmap(&bm);
  ::GetObject(hbm, sizeof(BITMAP), &bm);

  //把图片大小变为2的幂次方
  size.cx = (bm.bmWidth + 31) & (~31);

  int bufsize =size.cy * size.cx;
  struct {  BITMAPINFOHEADER bih;
   RGBQUAD col[2];
    }bic; 
  BITMAPINFO *binf = (BITMAPINFO *)&bic; 
  binf->bmiHeader.biSize     = sizeof(binf->bmiHeader);
  binf->bmiHeader.biWidth    = bm.bmWidth;
  binf->bmiHeader.biHeight   = bm.bmHeight;
  binf->bmiHeader.biPlanes   = 1;   
  binf->bmiHeader.biBitCount = 1;
  binf->bmiHeader.biCompression = BI_RGB;
  binf->bmiHeader.biSizeImage   = bufsize;

  UCHAR* Bits = new UCHAR[bufsize]; 
  ::GetDIBits(MDC,hbm,0,bm.bmHeight,Bits,binf,DIB_RGB_COLORS); 
                                      
  glPixelStorei(GL_UNPACK_ALIGNMENT ,1);
  glRasterPos2i(x,y); 
  glBitmap(size.cx,size.cy,0,0,0,0,Bits); 
  delete[] Bits;    
  SelectObject(MDC, oldBmp);  
  ::DeleteDC(MDC);
  DeleteObject(hbm);
}

 

改写的主要目的是去掉(注释掉)了MFC的相关成份,改为由SDK实现,因为游戏中很少有人用MFC,有时候会发生代码冲突。但是STL在游戏中的应用却比较多,也很好用,看来MFC真的是先天不足。

调用示例:

//文字输出类
 CGLFont* Font;
 HFONT hFont,hFont0;

Font=new CGLFont();

//第一个参数是字号大小,最后一个是字体名称,其它的不想多说了,可以自己去查
 hFont  =CreateFont(-16,0,0,0,400,0,0,0,GB2312_CHARSET,0,0,0,FF_MODERN,TEXT("宋体"));
 hFont0 =CreateFont(-48,0,0,0,800,0,0,0,GB2312_CHARSET,0,0,0,FF_MODERN,TEXT("黑体"));


Font->settext(100,726,"小屈屈的Blog",hFont,1.0f,1.0f,0.0f);
Font->settext(180,726,"上海飞来飞去多媒体创意有限公司",hFont,1.0f,1.0f,0.0f);

 

另外,程序中已经做了坐标转换,不管视口有多大,都可以用分辨率来定位,分辨率取决于CreateWindow函数中的设置。

结束!

阅读更多

没有更多推荐了,返回首页