织梦CMS - 轻松建站从此开始!

罗索

OpenGL中位图的操作(glReadPixels,glDrawPixels和glCopyPixels

落鹤生 发布于 2012-03-14 10:56 点击:次 
OpenGL中位图的操作(glReadPixels,glDrawPixels和glCopyPixels应用举例)3:glDrawPixels、glCopyPixels的用法和举例
TAG:

4、glDrawPixels的用法和举例
glDrawPixels函数与glReadPixels函数相比,参数内容大致相同。它的第一、二、三、四个参数分别对应于glReadPixels函数的第三、四、五、六个参数,依次表示图象宽度、图象高度、像素数据内容、像素数据在内存中的格式。两个函数的最后一个参数也是对应的,glReadPixels中表示像素读取后存放在内存中的位置,glDrawPixels则表示用于绘制的像素数据在内存中的位置。
注意到glDrawPixels函数比glReadPixels函数少了两个参数,这两个参数在glReadPixels中分别是表示图象的起始位置。在glDrawPixels中,不必显式的指定绘制的位置,这是因为绘制的位置是由另一个函数glRasterPos*来指定的。glRasterPos*函数的参数与glVertex*类似,通过指定一个二维/三维/四维坐标,OpenGL将自动计算出该坐标对应的屏幕位置,并把该位置作为绘制像素的起始位置。
很自然的,我们可以从BMP文件中读取像素数据,并使用glDrawPixels绘制到屏幕上。我们选择Windows XP默认的桌面背景Bliss.bmp作为绘制的内容(如果你使用的是Windows XP系统,很可能可以在硬盘中搜索到这个文件。当然你也可以使用其它BMP文件来代替,只要它是24位的BMP文件。注意需要修改代码开始部分的FileName的定义),先把该文件复制一份放到正确的位置,我们在程序开始时,就读取该文件,从而获得图象的大小后,根据该大小来创建合适的OpenGL窗口,并绘制像素。
绘制像素本来是很简单的过程,但是这个程序在骨架上与前面的各种示例程序稍有不同,所以我还是打算给出一份完整的代码。

  1. #include <gl/glut.h> 
  2. #define FileName "Bliss.bmp" 
  3.  
  4. static GLint    ImageWidth; 
  5. static GLint    ImageHeight; 
  6. static GLint    PixelLength; 
  7. static GLubyte* PixelData; 
  8.  
  9. #include <stdio.h> 
  10. #include <stdlib.h> 
  11.  
  12. void display(void) 
  13.     // 清除屏幕并不必要 
  14.         // 每次绘制时,画面都覆盖整个屏幕 
  15.         // 因此无论是否清除屏幕,结果都一样 
  16.         // glClear(GL_COLOR_BUFFER_BIT); 
  17.      
  18.     // 绘制像素 
  19.         glDrawPixels(ImageWidth, ImageHeight, 
  20.     GL_BGR_EXT, GL_UNSIGNED_BYTE, PixelData); 
  21.      
  22.     // 完成绘制 
  23.         glutSwapBuffers(); 
  24.     } 
  25.      
  26.     int main(int argc, char* argv[]) 
  27.     { 
  28.     // 打开文件 
  29.         FILE* pFile = fopen("Bliss.bmp", "rb"); 
  30.     if( pFile == 0 ) 
  31.     exit(0); 
  32.      
  33.     // 读取图象的大小信息 
  34.         fseek(pFile, 0x0012, SEEK_SET); 
  35.     fread(&ImageWidth, sizeof(ImageWidth), 1, pFile); 
  36.     fread(&ImageHeight, sizeof(ImageHeight), 1, pFile); 
  37.      
  38.     // 计算像素数据长度 
  39.         PixelLength = ImageWidth * 3; 
  40.     while( PixelLength % 4 != 0 ) 
  41.     ++PixelLength; 
  42.     PixelLength *= ImageHeight; 
  43.      
  44.     // 读取像素数据 
  45.         PixelData = (GLubyte*)malloc(PixelLength); 
  46.     if( PixelData == 0 ) 
  47.     exit(0); 
  48.      
  49.     fseek(pFile, 54, SEEK_SET); 
  50.     fread(PixelData, PixelLength, 1, pFile); 
  51.      
  52.     // 关闭文件 
  53.         fclose(pFile); 
  54.      
  55.     // 初始化GLUT并运行 
  56.         glutInit(&argc, argv); 
  57.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); 
  58.     glutInitWindowPosition(100, 100); 
  59.     glutInitWindowSize(ImageWidth, ImageHeight); 
  60.     glutCreateWindow(FileName); 
  61.     glutDisplayFunc(&display); 
  62.     glutMainLoop(); 
  63.      
  64.     // 释放内存 
  65.         // 实际上,glutMainLoop函数永远不会返回,这里也永远不会到达 
  66.         // 这里写释放内存只是出于一种个人习惯 
  67.         // 不用担心内存无法释放。在程序结束时操作系统会自动回收所有内存 
  68.         free(PixelData); 
  69.      
  70.     return 0; 
  71. }  

这里仅仅是一个简单的显示24位BMP图象的程序,如果读者对BMP文件格式比较熟悉,也可以写出适用于各种BMP图象的显示程序,在像素处理时,它们所使用的方法是类似的。
OpenGL在绘制像素之前,可以对像素进行若干处理。最常用的可能就是对整个像素图象进行放大/缩小。使用glPixelZoom来设置放大/缩小的系数,该函数有两个参数,分别是水平方向系数和垂直方向系数。例如设置glPixelZoom(0.5f, 0.8f);则表示水平方向变为原来的50%大小,而垂直方向变为原来的80%大小。我们甚至可以使用负的系数,使得整个图象进行水平方向或垂直方向的翻转(默认像素从左绘制到右,但翻转后将从右绘制到左。默认像素从下绘制到上,但翻转后将从上绘制到下。因此,glRasterPos*函数设置的“开始位置”不一定就是矩形的左下角)。
5、glCopyPixels的用法和举例
从效果上看,glCopyPixels进行像素复制的操作,等价于把像素读取到内存,再从内存绘制到另一个区域,因此可以通过glReadPixels和glDrawPixels组合来实现复制像素的功能。然而我们知道,像素数据通常数据量很大,例如一幅1024*768的图象,如果使用24位BGR方式表示,则需要至少1024*768*3字节,即2.25兆字节。这么多的数据要进行一次读操作和一次写操作,并且因为在glReadPixels和glDrawPixels中设置的数据格式不同,很可能涉及到数据格式的转换。这对CPU无疑是一个不小的负担。使用glCopyPixels直接从像素数据复制出新的像素数据,避免了多余的数据的格式转换,并且也可能减少一些数据复制操作(因为数据可能直接由显卡负责复制,不需要经过主内存),因此效率比较高。
glCopyPixels函数也通过glRasterPos*系列函数来设置绘制的位置,因为不需要涉及到主内存,所以不需要指定数据在内存中的格式,也不需要使用任何指针。
glCopyPixels函数有五个参数,第一、二个参数表示复制像素来源的矩形的左下角坐标,第三、四个参数表示复制像素来源的举行的宽度和高度,第五个参数通常使用GL_COLOR,表示复制像素的颜色,但也可以是GL_DEPTH或GL_STENCIL,分别表示复制深度缓冲数据或模板缓冲数据。
值得一提的是,glDrawPixels和glReadPixels中设置的各种操作,例如glPixelZoom等,在glCopyPixels函数中同样有效。
下面看一个简单的例子,绘制一个三角形后,复制像素,并同时进行水平和垂直方向的翻转,然后缩小为原来的一半,并绘制。绘制完毕后,调用前面的grab函数,将屏幕中所有内容保存为grab.bmp。其中WindowWidth和WindowHeight是表示窗口宽度和高度的常量。

  1. void display(void
  2.     // 清除屏幕 
  3.         glClear(GL_COLOR_BUFFER_BIT); 
  4.      
  5.     // 绘制 
  6.         glBegin(GL_TRIANGLES); 
  7.     glColor3f(1.0f, 0.0f, 0.0f);    glVertex2f(0.0f, 0.0f); 
  8.     glColor3f(0.0f, 1.0f, 0.0f);    glVertex2f(1.0f, 0.0f); 
  9.     glColor3f(0.0f, 0.0f, 1.0f);    glVertex2f(0.5f, 1.0f); 
  10.     glEnd(); 
  11.     glPixelZoom(-0.5f, -0.5f); 
  12.     glRasterPos2i(1, 1); 
  13.     glCopyPixels(WindowWidth/2, WindowHeight/2, 
  14.     WindowWidth/2, WindowHeight/2, GL_COLOR); 
  15.      
  16.     // 完成绘制,并抓取图象保存为BMP文件 
  17.         glutSwapBuffers(); 
  18.     grab(); 
  19. }  



   

 

(zhengym02)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201203/15821.html]
本文出处:百度博客 作者:zhengym02 原文
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容