在使用OpenGL进行绘图的时候需要为纹理添加一些提示信息(比如方向),并且要求模型旋转后相对位置不变,这就需要绘制可以旋转的文字。
OpenGL是图形绘制的标准,其中并不包含绘制文字的内容,因此我们想要绘制文字必须使用操作系统中自带的文字绘制功能进行绘制,比如Windows就要用到MFC相关的接口。
一般的绘制轮廓文字采用的是显式列表的形式,需要一些变量保存列表的相关信息。
HDC m_HDC;//存储当前设备的指针
GLYPHMETRICSFLOAT m_Gmf[256];//记录256个字符信息,状态
GLuint m_Base;//存储字体显示列表的开始位置
其中HDC是通过相关接口函数获得的一个指针,m_Gmf是用于保存列表文字的相关信息(例如高度,宽度),具体的大小根据生成列表的不同可以调节,比如可以生成128个字符的列表。,此处采用的是最常见的256个字符的列表(也就是8位可以表示的字符数)。
绘制文字首先要获得HDC,就个人理解可以把它当做一个画图的工具,这个画图的工具需要通过系统获得。
m_HDC = GetDC(NULL);//通过窗口句柄获得hdc
在这里我踩到了一个坑,我在获得HDC之前获取了窗口的句柄。
hWND = (HWND)winId();//获得当前窗口句柄,基本别用
m_HDC = GetDC(NULL);//通过窗口句柄获得hdc
获得了窗口句柄后,当我切换qt的界面的时候,界面就卡住了,需要进行一些列的操作才会显示,并且显示额内容是不正确的。这句话没有特殊的要求基本别用,窗口句柄是用来跨平台的。
之后要进行字体的生成
HFONT font;//字体句柄
m_Base = glGenLists(256);//创建大小为256的显示列表
font = CreateFont(1, //字体高度
0, //字体宽度
0, //字体的旋转角度
0, //字体底线的旋转角度
FW_DONTCARE, //字体的重量
FALSE, //是否斜体
FALSE, //是否使用下划线
FALSE, //是否使用删除线
ANSI_CHARSET, //设置字符集
OUT_TT_PRECIS, //输出精度
CLIP_DEFAULT_PRECIS, //剪裁精度
ANTIALIASED_QUALITY, //输出质量
FF_DONTCARE | DEFAULT_PITCH, //Family and Pitch的设置
LPCWSTR("Times New Roman")); //字体名称(电脑中已装的)
SelectObject(m_HDC, font); //选择字体
wglUseFontOutlines(m_HDC, //当前HDC
0, //从ASCII码第一个字符开始
255, //字符数
m_Base, //第一个显示列表的名称
0.0f, //字体光滑度,越小越光滑
0.01f, //在z方向突出的距离(字体的厚度)
WGL_FONT_POLYGONS, //使用多边形来生成字符,每个顶点具有独立法线
m_Gmf);
上面是有关文字的设置,基本上大同小异。
之后要调用显示
glCallLists(strlen(fmt), GL_UNSIGNED_BYTE, fmt);//调用显示列表绘制文字
fmt是一个字符串的指针。
之后就可以像opengl的图像一样使用旋转,移动等函数,字体会跟随进行旋转。
考虑到字体本身的位置,可以在调用是上面的显示之前进行位置的调整。
for (unsigned int i = 0; i < strlen(fmt); ++i)//计算字符串的长度
{
length += m_Gmf[(int)fmt[i]].gmfCellIncX;//此处计算的长度不是通常的字符数,而是绘制所占字符的长度
}
glTranslatef(-length / 2, 0.0f, 0.0f);//左移一半
glPushAttrib(GL_LIST_BIT);//显示列表属性压栈
glListBase(m_Base);//设置显示列表的基础值
glCallLists(strlen(fmt), GL_UNSIGNED_BYTE, fmt);//调用显示列表绘制文字
glPopAttrib();
这样文字就绘制完成。之后只需要向OpenGL一样操作它就可以了。
最后别忘了释放列表和DC
glDeleteLists(m_Base, 256);//删除显示列表
ReleaseDC(NULL, m_HDC);