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中,在屏幕300300位置绘制图像

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 指定要从屏幕上读取矩形的左下角,widthheight定义矩形区域的大小。

将窗口的上半部分读取到一个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);

函数将帧缓存中的一个矩形区域的像素数据复制到当前的光栅位置,矩形区域的左下角是(xy),(widthheight)是宽和高

4.       放大、缩小、翻转

void glPixelZoom(GLfloat  xZoom,GLfloat yZoom);

默认情况下xZoomyZoom的值都是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.       像素存储的管理

应用程序从一台电脑移动到另一台电脑,运行速度可能变慢,有可能是内存中数据的边界对准问题引起。

在内存中数据是248字节边界对齐的话,有些计算机能更快的传输数据

可以通过glPixelStorei()函数控制数据对齐

void glPixelStorei(GLenum pname ,TYPE param);

pname:

GL_PACK_ALIGNMENT 通知OpenGl如何将数据装入内存

GL_UNPACK_ALIGNMENT 如何从内存中提取数据

param1248

默认情况下GL_PACK_ALIGNMENT GL_UNPACK_ALIGNMENT都是4

···········································································

glReadPixels

glPixelStorei

以上内容,在OpenGL_ESgl.h只找到这两个。。。。

···········································································

4.       Windows位图

BMP不使用任何压缩算法,文件大,易于读取和使用

1.       文件格式

BMP文件由3部分构成:位图文件头、位图信息头、实际的位图数据

位图文件头

位图信息头

(调色板数据)

位图数据

 

位图文件头数据结构:

typedef struct tagBITMAPFILEHEADER

{

   WORD              bfType;  指定文件类型,必须是BM0x4D42

   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,需要交换RB的值,得掉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,交换RB的值

   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图像文件

TGABMP的基础上又添加了一个alpha通道

1.       TGA文件格式

TGA文件格式分为两个部分:头+数据

头结构如下:

typedef struct tagTARGAFILEHEADER

{

unsigned char  imageIDLength;  //标识(ID)数据项中的字符数

                                                              //0表示没有表示数据项

unsigned char colorMapType;      //颜色位图类型 总为0

unsigned char imageTypeCode;  //未压缩的RGB2

                                                             //未压缩的灰度为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 2432

unsigned char imageDescriptor;   //24=0x0032=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;      //RGBA4RGB3

   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.