OpenGL系统设计-纹理贴图(4)_包含JPEG解压缩解码

 

1.1        JPEG纹理

    大型的应用程序特别是游戏程序使用的贴图非常多,如Quake III使用的JPEG和TGA文件就有将近2000个,其中JPEG文件超过一半,占用近30MB。如果都使用BMP格式的话,因为没有压缩,占用的空间将大大增加,至少达到180MB。因此,JPEG文件作为贴图也是大型程序的选择。

因为JPEG文件是压缩的,使用JPEG文件,必须先进行解码。因为JPEG格式已经尽人皆知,所以我们可以自己来写解码器。不过现在Internet上有不少免费的源代码,我们可以借鉴过来,把主要精力集中在我们的OpenGL应用上。我们使用Thomas G. Lane的JPEG程序库,他的Email地址是CHRISDL@PAGESZ.NET,他的代码是免费的,不过你要用于商业用途的话最好给作者打个招呼。

把JPEG代码编译后生成一个jpeg.lib库文件,我们就使用jpeg.lib和jpeglib.h两个文件。

       

为了使用JPEG纹理映射,我们增加两个函数tImageJPG *LoadJPG(const char *filename)和void DecodeJPG(jpeg_decompress_struct* cinfo, tImageJPG *pImageData)。

    其中tImageJPG放在jpeglib.h中定义。

   

// This stores the important jpeg data

    struct tImageJPG

    {

        int rowSpan;

        int sizeX;

        int sizeY;

        unsigned char *data;

    };

 

    我们的程序必须包含jpeglib.h文件,并且将jpeg.lib库文件链接进来。

 

    下面是DecodeJPG的代码,如果需要了解JPEG文件更加详细的信息,可以参考Thomas G. Lane的JPEG源代码库。

 

void DecodeJPG(jpeg_decompress_struct* cinfo, tImageJPG *pImageData)

{

    //读取JPEG文件头

    jpeg_read_header(cinfo, TRUE);

   

    // 使用压缩信息开始解压缩

    jpeg_start_decompress(cinfo);

 

    // 读取图像大小、像素数据

    pImageData->rowSpan = cinfo->image_width * cinfo->num_components;

    pImageData->sizeX   = cinfo->image_width;

    pImageData->sizeY   = cinfo->image_height;

   

    //为pImageData->data分配内存

    pImageData->data = new unsigned char[pImageData->rowSpan * pImageData->sizeY];

       

   

    //创建每一行数据的指针

    unsigned char** rowPtr = new unsigned char*[pImageData->sizeY];

    for (int i = 0; i < pImageData->sizeY; i++)

        rowPtr[i] = &(pImageData->data[i*pImageData->rowSpan]);

 

    //读取像素数据

    int rowsRead = 0;

    while (cinfo->output_scanline < cinfo->output_height)

    {

        rowsRead+=jpeg_read_scanlines(cinfo,&rowPtr[rowsRead],

 cinfo->output_height-rowsRead);

    }

   

    // 释放临时使用的指针

    delete [] rowPtr;

 

    // 解压缩结束

    jpeg_finish_decompress(cinfo);

}

 

DecodeJPG()调用的LoadJPG()如下:

   

tImageJPG *LoadJPG(const char *filename)

{

    struct jpeg_decompress_struct cinfo;

    tImageJPG *pImageData = NULL;       //存放JPEG数据

    FILE *pFile;

   

    //打开文件

    if((pFile = fopen(filename, "rb")) == NULL)

    {

        MessageBox(g_hWnd, "Fail to load JPG File!", "Error", MB_OK);

        return NULL;

    }

   

    // 定义一个错误句柄

    jpeg_error_mgr jerr;

 

    //解压缩信息对象指向错误句柄

    cinfo.err = jpeg_std_error(&jerr);

   

    // 初始化解压缩对象

    jpeg_create_decompress(&cinfo);

   

    //指定数据源

    jpeg_stdio_src(&cinfo, pFile);

   

    //分配内存,用于存放数据

    pImageData = (tImageJPG*)malloc(sizeof(tImageJPG));

 

    // 进行解压缩

    DecodeJPG(&cinfo, pImageData);

   

    // 释放内存

    jpeg_destroy_decompress(&cinfo);

   

    fclose(pFile);

 

    // 返回已经解压缩后的数据

    return pImageData;

}

 

 

为了能够同时利用BMP和JPG纹理文件,创建纹理函数CreateTextures也需要进行更改。首先增加一个pJpg的指针,用于保存从JPG文件读取的数据。为了避免空文件的传入,要对文件进行一次判断,若为空,就返回FALSE。

然后利用strstr()函数对文件名进行判断,如果是BMP文件则处理流程不变,如果是JPG文件,则调用LoadJPG将数据读入pJpg所指的内存。

为了使用pBitmap对纹理进行处理,还要pBitmap也指向这里。在最后之所以没有free(pJpg->data)是因为前面的free(pBitmap->data)已经把两者指向的共同内存释放了。

 

GLuint CreateTexture(LPSTR strTextureFileName)

{

    GLuint tex;             //纹理的标识

   

    AUX_RGBImageRec *pBitmap = 0;       //存放最终的纹理数据

 

    /*

    在glaux.h中定义如下

        typedef struct _AUX_RGBImageRec {

            GLint sizeX, sizeY;     //图像的大小

            unsigned char *data;        //像素数据

        } AUX_RGBImageRec;

    */

 

    tImageJPG *pJpg = 0;            //存放JPG纹理像素数据

 

    if(!strTextureFileName) //如果文件名为空则返回                     

    {

        return FALSE;

    }          

   

    //根据文件名来判断是哪一种文件

    if(strstr(strTextureFileName, ".bmp"))

    {

        pBitmap = auxDIBImageLoad(strTextureFileName);

    }

    else if(strstr(strTextureFileName, ".jpg") ||

        strstr(strTextureFileName, ".jpeg"))    //扩展名可能是jpeg或jpg

    {

        pJpg = LoadJPG(strTextureFileName);

        if(!pJpg) return FALSE;

        pBitmap=(AUX_RGBImageRec * )malloc(pJpg->sizeX*pJpg->sizeY+8);

        pBitmap->data=pJpg->data;

        pBitmap->sizeX=pJpg->sizeX;     //图像宽度

        pBitmap->sizeY=pJpg->sizeY;     //图像高度

    }

    else

        return FALSE;

 

    if(!pBitmap)

    {

        return FALSE;

    }                      

 

    glGenTextures(1, &tex);

   

    glBindTexture(GL_TEXTURE_2D, tex);

   

    glTexImage2D(GL_TEXTURE_2D, 0, 3, pBitmap->sizeX, pBitmap->sizeY,

                0,  GL_RGB, GL_UNSIGNED_BYTE, pBitmap->data);

 

    if(pBitmap && pBitmap->data)

        free(pBitmap->data);

                           

    if(pBitmap)

        free(pBitmap);

 

    if(pJpg)                        //pJpg->data已经被释放了

        free(pJpg);

 

    return tex;                     //返回生成纹理的标识   

}

 

在glInit中,将

g_Texture[0] = CreateTexture("baby.bmp")

改为

g_Texture[0] = CreateTexture("girl.jpg"),表示使用girl.jpg文件来创建一个纹理。

 

glMain不作改动,仍然使用立方体作为纹理的载体。程序运行后,效果如图5-8所示。

 

 

图5-8   JPEG纹理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值