《OpenGL游戏程序设计》 K.霍金/D.阿斯特 著 田昱川 译
1. OpenGL位图
OpenGL位图被定义为像素的矩阵阵列,每个像素对应矩阵中一个位的数据(0或
者1),被当做窗口中一个矩形区域的绘制掩膜,通常用于字符。
比如一个16*16的位图,将其分割成一个16*16的栅格,如果一个像素对应的栅格中的值为1,那么就用当前的光栅颜色(就是glColor3f()这类函数设置的颜色)绘制该像素,如果为0,就什么也不绘制。
OpenGL位图转换成栅格阵列时,从位图的左下角开始:先画最下面的一行,然后是这行的上一行
例如位图是:(只说最后两行)
······
······(上面的行省略)
1·1·0·1·1·1·1·1·1·1·1·1·1·0·1·1(倒数第二行)
1·1·0·0·0·0·0·0·0·0·0·0·0·0·1·1(最后一行)
则转换成信息阵列是(每行用两位的十六进制表示)
unsigned char letter[]=
{
0xC0,0x03 ,//最后一行(共16位)
0xDF,0xFB ,//倒数第二行
······
······
};
a) glRasterPos*()
用来指定将要绘制位图或图像的屏幕位置,传递给此函数的坐标值定义了位图的左下角的位置。
void glRasterPos[234][sifd](TYPE x, TYPE y, TYPE z,TYPE w);
void glRasterPos[234][sifd]v(TYPE *coords);
除非为2D绘制指定了具体的模型视图矩阵和投影矩阵,否则传递给glRasterPos*()函数的坐标值就是相应的屏幕坐标。下面是使用glOrtho()函数定义一个2D视区,其宽度和高度定义了窗口的宽度和高度
glViewport(0,0,width,height);将视区设置为新的大小尺寸
glMatrixMode(GL_PROJECTION)投影矩阵设置为当前矩阵
glLoadIdentity();复位投影矩阵
定义2D视区
glOrtho(0.0f, width-1.0, 0.0, height-1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);设置模型视图矩阵
glLoadIdnetity()复位模型视图矩阵
b) glBitmap()
设置了当前光栅位置之后,可以调用glBitmap()函数绘制位图
void glBitmap(GLsizei width,GLsizei height,GLfloat xOrigin, GLfloat yOrigin,
GLfloat xIncrement ,GLfloat yIncrement ,const GLubyte *bitmap);
函数在当前光栅位置的(xOrigin,yOrigin)坐标处,以指定的宽度和高度绘制一个位图,(xIncrement,yIncrement)坐标指定绘制完成后用于设置新的光栅位置的坐标增量。
OpenGl位图不能被旋转不能被缩放
c)
2. 图像的使用
1. 图像的绘制
假设图像数据被载入到了内存中,可以调用glDrawPixels()函数来在窗口中指定的光栅位置显示这些图像数据。
void glDrawPixels(GLsizei width,GLsizei height ,Glenum format ,GLenum type,const GLovid *pixels);
format:
GL_ALPHA alpha颜色像素
GL_BGR 像素顺序为蓝色、绿色、红色
GL_BGRA 像素顺序为蓝色、绿色、红色、alpha
GL_BLUE 蓝色像素
GL_COLOR_INDEX 索引颜色像素
GL_GREEN 绿色像素
GL_RED 红色像素
GL_RGB 像素顺序为红色、绿色、蓝色
GL_RGBA 像素顺序为红色、绿色、蓝色、alpha
type:(不太理解)
GL_BITMAP 单个的位 0或者1
GL_BYTE 有符号的8bit整数 2字节
GL_UNSIGNED_BYTE 无符合的8bit整数 2字节
GL_SHORT 有符合的16bit整数 4字节
GL_UNSIGNED_SHORT 无符合的16bit整数,4字节
GL_INT 有符合的32bit整数 8字节
GL_UNSIGNED_INT 无符合的32bit整数 8字节
图像数据存储在imageData中,在屏幕300,300位置绘制图像
glRasterPos2i(300,300);
glDrawPixels(imageWidth,imageHeight,GL_RGB,GL_UNSIGNED_BYTE,imageData);
2. 屏幕的读取
void glReadPixels(Glint x,Glint y,GLsizei width ,GLsizei height ,GLenum format,GLenum type,GLvoid *pixels);
x,y 指定要从屏幕上读取矩形的左下角,width,height定义矩形区域的大小。
将窗口的上半部分读取到一个RGB缓存中:
void *imageData;
int screenWidth,screenHeight;
glReadPixels(0,screenHeight/2,screenWidth,screenHeight/2,GL_RGB,GL_UNSIGNED_BYTE, imageData);
3. 屏幕的复制
glCopyPixels()函数将屏幕上的一个部分的像素复制到另一个部分
glCopyPixels(Glint x ,Glint y,GLsizei width,GLsizei height ,GLenum buffer);
函数将帧缓存中的一个矩形区域的像素数据复制到当前的光栅位置,矩形区域的左下角是(x,y),(width,height)是宽和高
4. 放大、缩小、翻转
void glPixelZoom(GLfloat xZoom,GLfloat yZoom);
默认情况下xZoom和yZoom的值都是1.0,是一个正常的图像
0.0~1.0会缩小图像,大于1.0会放大图像
参数指定为负值,图像将相对于当前的光栅位置进行翻转
glPixelZoom(-1.0f,-1.0f);在垂直和水平方向上翻转图像
glPixelZoom(0.5f,0.5f);缩小到原来的一半
glPiexlZoom(5.0f,5.0f);各个方向放大5倍
5. 放大镜和狙击步枪的瞄准镜实现
利用glCopyPixel()复制指定区域并结合glPixelZoom()
3. 像素存储的管理
应用程序从一台电脑移动到另一台电脑,运行速度可能变慢,有可能是内存中数据的边界对准问题引起。
在内存中数据是2、4、8字节边界对齐的话,有些计算机能更快的传输数据
可以通过glPixelStorei()函数控制数据对齐
void glPixelStorei(GLenum pname ,TYPE param);
pname:
GL_PACK_ALIGNMENT 通知OpenGl如何将数据装入内存
GL_UNPACK_ALIGNMENT 如何从内存中提取数据
param:1,2,4,8
默认情况下GL_PACK_ALIGNMENT 和GL_UNPACK_ALIGNMENT都是4
···········································································
glReadPixels
glPixelStorei
以上内容,在OpenGL_ES的gl.h只找到这两个。。。。
···········································································
4. Windows位图
BMP不使用任何压缩算法,文件大,易于读取和使用
1. 文件格式
BMP文件由3部分构成:位图文件头、位图信息头、实际的位图数据
位图文件头 |
位图信息头 |
(调色板数据) |
位图数据 |
位图文件头数据结构:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; 指定文件类型,必须是BM(0x4D42)
DWORD bfSize; 按字节指定位图文件的大小
WORD bfReserved1; 必须为0
WORD bfReserved2; 必须为0
DWORD bOffBits; 按字节指定从BITMAPFILEHEADER数据结构到位图数据偏移
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;以像素指定位图的宽度
LONG biHeight; 以像素指定位图的高度
WORD biplanes; 颜色平面数,必须为1
WORD biBitCount; 每个像素的数据位数1.4.8.16.24.32之一
DWORD biCompression;压缩类型 BI_RGB表面无压缩
DWORD biSizeImage; 按字节指定图像数据的大小,只包括位图数据
LONG biXPelsPerMeter; X轴上每米的像素数
LONG biYPelsPerMeter; y轴上每米的像素数
DWORD biClrUsed; 指定位图使用的颜色数
DWORD biClrImportant 指定重要颜色的数量
}BITMAPINFOHEADER;
位图的颜色格式为BGR,需要交换R和B的值,得掉RGB数据
2. BMP的载入
unsigned char *LoadBitmapFile(char *filename,BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; //文件指针
BITMAPFILEHEADER bitmapFileHeader; //位图头文件
unsigned char *bitmapImage; //位图图像数据
int imageIdx =0; //位图索引计时器
unsigned char tempRGB; //交换变量
filePtr=fopen(filename,"rb"); //以读二进制模式打开文件
if (filePtr==NULL)
{
return NULL;
}
fread(&bitmapFileHeader,sizeof(BITMAPFILEHEADER),1,filePtr);
if (bitmapFileHeader.bfType!=0x4d42) //检查是否是BMP图像
{
fclose(filePtr);
return NULL;
}
fread(&bitmapInfoHeader,sizeof(BITMAPINFOHEADER),1,filePtr);//读取图像信息头
fseek(filePtr,bitmapFileHeader.bfOffBits,SEEK_SET); //将文件指针移动到位图数据开始处
bitmapImage = (unsigned char *)malloc(bitmapInfoHeader->biSizeImage);
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}
fread(bitmapImage,1,bitmapInfoHeader->biSizeImage,filePtr); //读入位图图像数据
if(bitmapImage==NULL)
{
fclose(filePtr);
return NULL;
}
//位图的颜色格式是BGR,交换R和B的值
for(imageIdx=0;imageIdx<bitmapInfoHeader->biSizeImage;imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx+2];
bitmapImage[imageIdx+2] = tempRGB;
}
fclose(filePtr);
return bitmapImage;
}
简单应用:
BITMAPINFOHEADER bitmapInfoHeader;
unsigned char * bitmapData;
bitmapData =LoadBitmapFile(“test.bmp”,&bitmapInfoHeader);
glPixelStorei(GL_UNPACK_ALIGNMENT,4);
glRasterPos2i(100,100);
glDrawPixels(bitmapInfoHeader.biWidth,bitmapInfoHeader.biHeight,GL_RGB,GL_UNSIGNED_BYTE,bitmapData);
3. BMP的输出
int WriteBitmapFile(char *filename,int width,int height,unsigned char *imageData)
{
FILE *filePtr; // 文件指针
BITMAPFILEHEADER bitmapFileHeader; //位图文件头
BITMAPINFOHEADER bitmapInfoHeader; //位图信息头
int imageIdx; //用于RGB->BGR交互
unsigned char tempRGB; //用于RGB->BGR交互
filePtr = fopen(filename,"wb");
if(!filePtr)
return 0;
//定义位图文件头
bitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER);
bitmapFileHeader.bfType = 0x4D42;
bitmapFileHeader.bfReserved1 = 0;
bitmapFileHeader.bfReserved2 = 0;
bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
//定义位图信息头
bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 24; //24位图
bitmapInfoHeader.biCompression = BI_RGB; //无压缩
bitmapInfoHeader.biSizeImage = width*abs(height)*3;//w*h*(RGB字节数)
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
bitmapInfoHeader.biWidth = width;
bitmapInfoHeader.biHeight = height;
for (imageIdx = 0;imageIdx<bitmapInfoHeader.biSizeImage;imageIdx+=3)
{
tempRGB = imageData[imageIdx];
imageData[imageIdx] = imageData[imageIdx+2];
imageData[imageIdx+2] = tempRGB;
}
fwrite(&bitmapFileHeader,1,sizeof(BITMAPFILEHEADER),filePtr);//写位图文件头
fwrite(&bitmapInfoHeader,1,sizeof(BITMAPINFOHEADER),filePtr);//写位图信息头
fwrite(imageData,1,bitmapInfoHeader.biSizeImage,filePtr); //写图像数据
fclose(filePtr);//关闭文件
return 1;
}
简单应用:
unsigned char * imageData;
imageData = malloc(winWidth*winHeight*3);分配内存
memset(imageData,0,winWidth*winHeight*3);清理imageData内存中的内容
//从窗口读取数据
glReadPixels(0,0,winWidth-1,winHeight-1,GL_RGB,GL_UNSIGNED_BYTE,imageData);
WriteBitmapFile(“writeout.bmp”,winWidth,winHeight,(unsigned char *)imageData);
free(imageData);
4.
5. Targa图像文件
TGA在BMP的基础上又添加了一个alpha通道
1. TGA文件格式
TGA文件格式分为两个部分:头+数据
头结构如下:
typedef struct tagTARGAFILEHEADER
{
unsigned char imageIDLength; //标识(ID)数据项中的字符数
//0表示没有表示数据项
unsigned char colorMapType; //颜色位图类型 总为0
unsigned char imageTypeCode; //未压缩的RGB为2
//未压缩的灰度为3
short int colorMapOrigin; //颜色图(低-高)的原点,总为0
short int colorMapLength; //颜色图(低-高)的长度,总为0
short int colorMapEntrySize; //颜色图元素大小尺寸(低-高),总为0
(这里应该是一个字节 不是short int)
参见:http://www.worldlingo.com/ma/dewiki/zh_cn/Targa_Image_File
short int imageXorigin; //图像(低-高)左下角的x坐标,总为0
short int imageYorigin; //图像(低-高)左下角的y坐标,总为0
short int imageWidth; //图像(低-高)的像素宽度
short int imageHeight; //图像(低-高)的像素高度
unsigned char bitCount; //位数 16 、24、32
unsigned char imageDescriptor; //24位=0x00,32位=0x08
}TARGAFILEHEADER;
在头数据结构结束后紧接着就是Targa图像数据
在头数据结构首先要关注的是imageTypeCode,此项数据表面了要处理的Targa文件类型,
imageTypeCode:
2------未压缩的RGB图
3------未压缩的黑白图
10----游长编码RGB图
11----压缩黑白图像
2. Targa图像的载入
typedef struct
{
unsigned char imageTypeCode;
short int imageWidth;
short int imageHeight;
unsigned char bitCount;
unsigned char *imageData;
}TGAFILE;
int LoadTGAFile(char *filename,TGAFILE *tgaFile)
{
FILE *filePtr; // 文件指针
unsigned char ucharBad; //无用的无符号字符数据
short int sintBad; //无用的短整数数据
long imageSize; //TGA文件的大小尺寸
int colorMdoe; //RGBA是4,RGB是3
long imageIdx; //计数器变量
unsigned char colorSwap;//交换变量
filePtr = fopen(filename,"rb");
if(!filePtr)
return 0;
//读取前两个不需要的字节
fread(&ucharBad,sizeof(unsigned char),1,filePtr);
fread(&ucharBad,sizeof(unsigned char),1,filePtr);
//读入图像类型码
fread(&tgaFile->imageTypeCode,sizeof(unsigned char),1,filePtr);
//只处理未压缩的图像
if ((tgaFile->imageTypeCode!=2)&&(tgaFile->imageTypeCode!=3))
{
fclose(filePtr);
return 0;
}
//读取13个不需要的数据字节 (应该是9个)
fread(&sintBad,sizeof(short int),1,filePtr);
fread(&sintBad,sizeof(short int),1,filePtr);
fread(&ucharBad,sizeof(unsigned char),1,filePtr);
fread(&sintBad,sizeof(short int),1,filePtr);
fread(&sintBad,sizeof(short int),1,filePtr);
//读取图像尺寸大小
fread(&tgaFile->imageWidth,sizeof(short int),1,filePtr);
fread(&tgaFile->imageHeight,sizeof(short int),1,filePtr);
//读取图像位深度
fread(&tgaFile->bitCount,sizeof(short int),1,filePtr);
//读取1个不需要的数据字节
fread(&ucharBad,sizeof(unsigned char),1,filePtr);
colorMdoe = tgaFile->bitCount/8;
imageSize = tgaFile->imageWidth*tgaFile->imageHeight*colorMdoe;
//分配内存
tgaFile->imageData = (unsigned char*)malloc(sizeof(unsigned char)*imageSize);
//读入图像数据
fread(&tgaFile->imageData,sizeof(unsigned char),imageSize,filePtr);
//将BGR转换为RGB
for (imageIdx = 0,imageIdx<imageSize;imageIdx +=colorMdoe)
{
colorSwap = tgaFile->imageData[imageIdx];
tgaFile->imageData[imageIdx] = tgaFile->imageData[imageIdx+2];
tgaFile->imageData[imageIdx+2] = colorSwap;
}
//关闭文件
fclose(filePtr);
return 1;
}
简单应用:
TGAFILE *myTga;
myTga = (TGAFILE *)malloc(sizeof(TGAFILE));
LoadTGAFile("test.tga",myTga);
glPixelStorei(GL_UNPACK_ALIGNMENT,4);
glRasterPos2i(200,200);
glDrawPixels(myTga->imageWidth,myTga->imageHeight,GL_RGB,GL_UNSIGNED_BYTE,myTga->imageData);
3. Targa图像的输出
需要指定tga文件类型、位深度、使用RGB还是RGBA颜色模式,头数据结构中不重要的数据项设置为0
int WriteTGAFile(char * filename,short int width,short int height,unsigned char *imaeData)
{
unsigned char byteSkip; // 用于无用数据字节
short int shortSkip; // 用于短整数型的无用数据
unsigned char imageType; // tga图像类型
int colorMode; //图像颜色模式
unsigned char colorSwap; //用于BGR->RGB转换
int imageIdx; //BGR->RGB转换计数器
unsigned char bitDepth; //图像位深度
long imageSize; //图像数据大小尺寸
FILE *filePtr; //文件指针
filePtr = fopen(filename,"wb");
if (!filePtr)
{
fclose(filePtr);
return 0;
}
imageType = 2; //未压缩的RGB图
bitDepth = 24; //24位深度
colorMode = 3; //RGB颜色模式
byteSkip = 0; //无用字节数据
byteSkip = 0; //无用短整数型数据
//先写两个字节的空白数据
fwrite(&byteSkip,sizeof(unsigned char),1,filePtr);
fwrite(&byteSkip,sizeof(unsigned char),1,filePtr);
//写tga图像类型
fwrite(&imageType,sizeof(unsigned char),1,filePtr);
//写9个字节的空白数据
fwrite(&shortSkip,sizeof(short int),1,filePtr);
fwrite(&shortSkip,sizeof(short int),1,filePtr);
fwrite(&byteSkip,sizeof(unsigned char),1,filePtr);
fwrite(&shortSkip,sizeof(short int),1,filePtr);
fwrite(&shortSkip,sizeof(short int),1,filePtr);
//写图像大小尺寸
fwrite(&width,sizeof(short int),1,filePtr);
fwrite(&height,sizeof(short int),1,filePtr);
fwrite(&bitDepth,sizeof(unsigned char),1,filePtr);
//写一个字节的空白数据
fwrite(&byteSkip,sizeof(unsigned char),1,filePtr);
//计算图像数据尺寸
imageSize = width*height*colorMode;
//将图像数据从RGB转换为BGR
for(imageIdx = 0;imageIdx<imageSize;imageIdx+=colorMode)
{
colorSwap = imaeData[imageIdx];
imaeData[imageIdx] = imaeData[imageIdx+2];
imaeData[imageIdx+2] = colorSwap;
}
fwrite(imaeData,sizeof(unsigned char),imageSize,filePtr);
fclose(filePtr);
return 1;
}
简单应用:
unsigned char *imageData;
imageData = malloc(800*600*3);
memset(imageData,0,800*600*3);
//从窗口获得图像
glReadPixels(0,0,799,599,GL_RGB,GL_UNSIGNED_BYTE,imageData);
//将图像写如文件
WriteTGAFile("writeout.tga",800,600,(unsigned char *)imageData);
//释放图像数据内存
free(imageData);
6.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ezhong的博客签名-------------------------------------
以上内容来自ezhong的博客园,作者:ezhong
ezhong的博客园: http://www.cnblogs.com/ezhong
感谢您的阅读。感谢您的分享。