opengl除了渲染几何数据, 还可以渲染两种重要类型的数据:
1. 位图 :一般用于表示字体中的字符。
2. 图像和数据 :可以被扫描或计算。
相同点:都采用矩形的像素数组的格式。
不同点:位图的每个像素是由单个位的信息组成, 图像的每个像素一般包含了好几段数据。
位图就像掩码一样,一般用于覆盖其他的图像。图像数据既可以简单的进行覆盖,也可以采用某种方法与帧缓冲区中的数据进行混合。
本章描述:1.如何把像素数据从内存绘制到帧缓冲区, 和帧缓冲区读取到内存。
2.像素数据从一个缓冲区复制到另一个缓冲区,或者在同一个缓冲区中进行复制。
位图和字体:
1. 位图是由1 和 0 组成的矩形数组, 做为窗口中一个矩形区域的绘图掩码。 若当前光栅颜色是红色,在位图中为1的地方,帧缓冲去中的对应像素就用红色像素代替。位于位图中为0的地方,就不会生成片断, 像素的内容不会受影响。
GLubyte rasters[24] = {0xc0, 0x00, 0xc0, 0x00, 0xc0,
0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0x00, 0xff, 0x00, 0xc0,
0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0xc0, 0xff, 0xc0};
void init()
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0, 0, 0, 0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glRasterPos2i(20, 20); // 它是从屏幕左下角(20, 20)处绘制F的。
glBitmap(10, 12, 0, 0, 11, 0, rasters);
glBitmap(10, 12, 0, 0, 11, 0, rasters);
glBitmap(10, 12, 0, 0, 11, 0, rasters);
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, 0, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
这里有几个陌生的函数:
glRasterPos2i, glBitmap, glPixelStorei.
1. 指定光栅位置
glRasterPos{2, 3, 4}{sifd}(Type x, Type y, Type z, Type w); 或者
glRasterPosv(const Type* coords);
上面这两个函数都是用来设置光栅的位置。
2. 绘制位图
glBitmap函数用来绘制数据。
<span style="font-size:18px;">void glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);</span>
bitmap是一个指向位图图像的指针。位图的原点是当前光栅位置,就是上面那个函数设置的位置,如果当前光栅位置无效, 这个函数不会绘制任何东西,且光栅位置继续无效。width, height表示位图的宽度和高度(以像素为单位)。xorig, yorig定义了位图的原点它是根据当前光栅位置确定的,xmove, ymove表示位图光栅化之后光栅位置的x增加值和y增加值。
3. 设置位图颜色
glColor3f(1.0, 1.0, 1.0);
glRasterPos2i(20, 20); // 它是从屏幕左下角(20, 20)处绘制F的。
glColor3f(1.0, 0, 0);
glBegin(GL_LINE_LOOP);
glVertex2d(100, 100);
glVertex2d(100, 250);
glVertex2d(220, 180);
glEnd();
glBitmap(10, 12, 0, 0, 11, 0, rasters);
glBitmap(10, 12, 0, 0, 11, 0, rasters);
glBitmap(10, 12, 0, 0, 11, 0, rasters);
上面就是效果图,可以看到位图还是白色,但是下面的三角形是红色。
当程序调用glRasterPosfv()时, GL_CURRENT_RASTER_COLOR被设置为白色。第二个调用glColor3f()调用修改了GL_CURRENT_COLOR的值,用于以后的几何图形渲染。
字体和显示列表:
一种字体一般由一组字符组成, 其中每个字符都有一个标识码和一个绘制方法。
对于ASCII字符集:大写字母A用65来表示,B用66来表示。那么DAB就可以用显示列表68,65,66.
可以按照这种方法来调用glCallLists();
<span style="font-size:18px;">void glCallLists (GLsizei n, GLenum type, const GLvoid *lists);</span>
第一个参数n表示要绘制的字符数量, type通常是GL_BYTE,lists是一个字符代码数组。
由于许多应用程序需要多种字体和字号来绘制字符串, 上面这种简单方法就不是很实用。我可以想到的一种方法不管什么字体都用65来表示A。可以强制把字体1的A、B和C编码为1065, 1066, 1067,把字体2的A, B,C编码为2065,2066,2067.但是8位的字节无法表示大于256的数。一种更好的解决方案是选择显示列表前向字符串中的每个字母增加一个偏移值。为用字体1绘制字符,可以把偏移值设置为1000,如果用字体2,可以把偏移值设置为2000.为了设置偏移值,可以使用glListBase()函数。接下来所需要的是一系列连续的未使用显示列表标识符,可以通过调用glGenLists来获取它们。
如:GLuint FontStart = glGenLists(26);
若FontStart返回的是100, 那么101, 102---125, 用来表示这些字符,且返回的标识符都标记为“已使用”,若无法找到一块满足请求长度的未使用标识符,它就返回0。大多数欧美字体的字符数量都能见到的表示,但是亚洲字体一般都比较庞大,所以用单个字节来表示每个字符的做法是不行的。所有glCallLists()函数的type参数,可以使用:GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT.......