openGL中为了增强场景的真实感,常使用纹理映射,需要读入图片,下面分享一下如何用C语言读一个深度为24位的windows的bmp(还有OS/2的,用到的不多,就将那部份代码删去了)。
要读一个bmp文件就要先了解bmp的格式 。
依据其格式真正要读取的就三部分,以像素为单位的图像宽度和高度,及RGB数据,宽度和高度分别在18和22,数据区的位置可以在10读到。
struct Image
{
char *pixels;
int width;
int height;
};
struct Image new_image;
struct Image *loadBMP (const char *filename)
{
FILE *pFile;
if(!filename)
return NULL;
pFile = fopen (filename, "r");
if (!pFile)
{
perror ("can't find file");
return NULL;
}
//10-13一个由低字节向高字节排放的二进制数,表示图象数据的起始位置,也可以理解为文件描述头的长度(单位为字节)
fseek (pFile, 10, SEEK_CUR);
int dataOffset;
fread (&dataOffset, sizeof(dataOffset), 1, pFile);
fseek (pFile, 4, SEEK_CUR);
int width;//18-21一个由低字节向高字节排放的二进制数,表示图象的宽度.
int height;//22-25一个由低字节向高字节排放的二进制数,表示图象的高度.
fread (&width, sizeof(width), 1, pFile);
fread (&height, sizeof(height), 1, pFile);
while (width % 4 != 0)
width ++;
int bytesPerRow = width * 3;
int size = bytesPerRow * height;
char pixels [size];
fseek (pFile, dataOffset, SEEK_SET);
fread (pixels, sizeof (pixels[0]), size, pFile);
char pixels2 [width * height * 3];
int y, x, c;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
for (c = 0; c < 3; c++)
pixels2[3 * (width * y + x) + c] = pixels[bytesPerRow * y + 3 * x + (2 - c)];
fclose (pFile);
new_image.pixels = pixels2;
new_image.width = width;
new_image.height = height;
return &new_image;
}
下面利用返回的图像数据,就可以调用glTexImage2D创建纹理了。
需要注意的是,如果在32位的计算机上,数据在内存中按照32位的边界对齐(地址为4字节的倍数),硬件提取数据的速度就会快得多,在64位计算机上就是地址为8字节的倍数。