使用DevIL来加载OpenGL纹理

时间:2021-10-05 04:47:48

OpenGL本身并没有带图象文件的读取函数,D3DX则有,以前我用的IPicture的接口来加载图象,但是TGA ,MNG PNG 等图象它并不支持.需要其他的代码来加载TGA等,非常不方便,最倒霉的是,代码的问题很多,经常不能成功加载一些图象.早就想把那个该死的库移植到DevIL上了,但是人懒,一直等到今天,呵呵。终于做了个简单的包装了。
代码很乱,只加了读取图象到建立OpenGL纹理,应该还有更广泛的用途的.比如SaveImage等.
回头等有空的时候做一个更好用的。
这里的的代码只有一个文件,是一个dll,自己编译一下就可以了。DevIL当前为1.6.7请到http://www.sourceforge.net/Projects/openil/去下载,说明一下,DevIL原来叫OpenIL,是一个学习了OpenGL的库,因为某些原因,改名为devil了。

/***
Source code for gltexture.h
***/
#ifndef _GL_TEXTURE_H_
#define _GL_TEXTURE_H_

#include <windows.h>
#include <GL/gl.h>

typedef struct ImageSize
{
 int width,height;
 int bits;
}IMAGESIZE,*PIMAGESIZE;

typedef unsigned char* IMAGEDATA;

typedef struct
{
 int            width,height;
 unsigned char* pdata;
 int            bits;
 GLuint         format;
 int            ImageID;
}DIBTEXDATA,*PDIBTEXDATA;

#ifdef _DEBUG
#pragma comment(lib,"gltextured.lib")
#else
#pragma comment(lib,"gltexture.lib")
#endif

typedef GLuint GLTEXTURE;

extern "C" int          FlowToPower2(int w);
extern "C" IMAGEDATA    LoadBlankImage(IMAGESIZE size);
extern "C" int          SetImagePixel(unsigned char* image,int x,int y,IMAGESIZE size,unsigned char cl[4]);
extern "C" int          GetImagePixel(unsigned char* image,int x,int y,IMAGESIZE size,unsigned char cl[4]);
extern "C" void         SetKeyColorAlpha(unsigned char* image,IMAGESIZE size,unsigned char cl[4],int r);
extern "C" int          IsPowerOfTwo(int n);
extern "C" int          RoundFourByte(int n);
extern "C" DIBTEXDATA LoadTexData(char* filename);
extern "C" DIBTEXDATA CreateDibTexData(int w,int h);
extern "C" void   FreeDibTexData(DIBTEXDATA dib);
extern "C" void   SetTexAlpha(GLubyte color[],GLubyte alpha,DIBTEXDATA dib,int r);
extern "C" void   SetTexPixel(int x,int y,GLubyte color[],DIBTEXDATA dib);
extern "C" void   GetTexPixel(int x,int y,GLubyte color[],DIBTEXDATA dib);
extern "C" GLuint  BuildTexture(char* filename);
extern "C" GLuint  BuildTransparencyTexture(char* filename,GLubyte color[],GLubyte alpha,int r);
extern "C" GLuint  BuildTextureFromImage(unsigned char* image,IMAGESIZE size);
extern "C" GLuint  BuildTextureFromRGBImage(unsigned char* image,IMAGESIZE size);

 

#endif


/**
以下为.def文件,
**/

EXPORTS
 LoadBlankImage
 SetImagePixel
 GetImagePixel
 SetKeyColorAlpha
 IsPowerOfTwo
 RoundFourByte
 LoadTexData
 CreateDibTexData
 FreeDibTexData
 SetTexAlpha
 SetTexPixel
 GetTexPixel
 BuildTexture
 BuildTransparencyTexture
 BuildTextureFromImage
 BuildTextureFromRGBImage


+++++++++++++++++++++++++++++++++++++++++++++++++++++
下面为真正代码
+++++++++++++++++++++++++++++++++++++++++++++++++++++
/**
source code for
gltexture.cpp
**/
// GLTexture.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include <fstream>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
using namespace std;

#include <IL/il.h>
#include <IL/ilu.h>

#pragma  comment(lib,"Devil.lib")
#pragma  comment(lib,"ILu.lib")

/****
以下内容为需要写到头文件里
****/
typedef struct ImageSize
{
 int width,height;
 int bits;
}IMAGESIZE,*PIMAGESIZE;

typedef unsigned char* IMAGEDATA;

typedef struct
{
 int            width,height;
 unsigned char* pdata;
 int            bits;
 GLuint         format;
 int            ImageID;
}DIBTEXDATA,*PDIBTEXDATA;

 

extern "C" IMAGEDATA    LoadBlankImage(IMAGESIZE size);
extern "C" int          SetImagePixel(unsigned char* image,int x,int y,IMAGESIZE size,unsigned char cl[4]);
extern "C" int          GetImagePixel(unsigned char* image,int x,int y,IMAGESIZE size,unsigned char cl[4]);
extern "C" void         SetKeyColorAlpha(unsigned char* image,IMAGESIZE size,unsigned char cl[4],int r);
extern "C" int          IsPowerOfTwo(int n);

extern "C" int          RoundFourByte(int n);
extern "C" DIBTEXDATA LoadTexData(char* filename);
extern "C" DIBTEXDATA CreateDibTexData(int w,int h);
extern "C" void   FreeDibTexData(DIBTEXDATA dib);
extern "C" void   SetTexAlpha(GLubyte color[],GLubyte alpha,DIBTEXDATA dib,int r);
extern "C" void   SetTexPixel(int x,int y,GLubyte color[],DIBTEXDATA dib);
extern "C" void   GetTexPixel(int x,int y,GLubyte color[],DIBTEXDATA dib);
extern "C" GLuint  BuildTexture(char* filename);
extern "C" GLuint  BuildTransparencyTexture(char* filename,GLubyte color[],GLubyte alpha,int r);
extern "C" GLuint  BuildTextureFromImage(unsigned char* image,IMAGESIZE size);
extern "C" GLuint  BuildTextureFromRGBImage(unsigned char* image,IMAGESIZE size);


/****
以上内容为需要写到头文件里
****/
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
void         FreeImageData(unsigned char* pData);
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 static bool ilIsInit  = false;
 if(ul_reason_for_call == DLL_PROCESS_ATTACH)
 {
  if(ilIsInit == false)
  {
   // Needed to initialize DevIL.
   ilInit();
   ilIsInit = true;
  }

 }

 if(ul_reason_for_call == DLL_PROCESS_DETACH)
 {
  if(ilIsInit == true)
  {
   // Needed to initialize DevIL.
   ilShutDown();
   ilIsInit  = false;
  }
 }
    return TRUE;
}


extern "C" int FlowToPower2(int w)
{
 return  1 << (int)floor((log((double)w)/log(2.0f)) + 0.5f);
}

extern "C" DIBTEXDATA LoadTexData(char* filename)
{
 int Width = 0;
 int Height  = 0;
 int Bpp   = 0; 
 int Format  = 0;
 int Depth  = 0;

 int NewW  = 0;
 int NewH  = 0;

 GLubyte* prgba = NULL;
 ILuint ImageID;

 ilGenImages(1,&ImageID);
 ilBindImage(ImageID);
 ILboolean IsLoaded =  ilLoadImage(filename);
 if(! IsLoaded)
 {
  goto exit_entry;
 }


 Width = ilGetInteger(IL_IMAGE_WIDTH);
 Height = ilGetInteger(IL_IMAGE_HEIGHT);
 Bpp    = ilGetInteger(IL_IMAGE_BPP);
 Format = ilGetInteger(IL_IMAGE_FORMAT);
 Depth  = ilGetInteger(IL_IMAGE_DEPTH);

 NewW = FlowToPower2(Width);
 NewH = FlowToPower2(Height);

 if(NewW != Width  ||
    NewH != Height )
 {
  iluScale(NewW,NewH,Depth);
 }
 
 if(Format != IL_RGBA)
 {
  ilConvertImage(IL_RGBA,ilGetInteger(IL_IMAGE_TYPE));
 }

 prgba = ilGetData();
   
    DIBTEXDATA dib;
exit_entry:
 //纹理数据已经创建好了,现在可以保存大小后返回
 dib.height = NewH;
 dib.width  = NewW;
 dib.pdata = prgba;
 dib.bits =32;
 dib.format = GL_RGBA;
 dib.ImageID = ImageID;
 return dib;
}

extern "C" DIBTEXDATA CreateDibTexData(int w,int h)
{
 DIBTEXDATA pt;
 int size = w * h* 4 ;
 pt.height = h;
 pt.width  = w;
 IMAGESIZE isize;
 isize.height = h;
 isize.width = w;
 isize.bits = 32;
 pt.pdata = LoadBlankImage(isize);
 pt.ImageID = -1;

 return pt;
}

extern "C" void FreeDibTexData(DIBTEXDATA dib)
{
 if( ilIsImage(dib.ImageID) )
 {
  ilDeleteImages(1,(const ILuint*)&dib.ImageID);
  return ;
 }
 if (dib.pdata)
 {
  FreeImageData(dib.pdata);
  return ;
 }
}

extern "C" void SetTexAlpha(GLubyte color[],GLubyte alpha,DIBTEXDATA dib,int r)
{
 int size=dib.height*dib.width*4; 
 for(int i=0;i<size;i+=4)
 {
  if(abs(color[0]-dib.pdata[i+2])<=r&&
     abs(color[1]-dib.pdata[i+1])<=r&&
     abs(color[2]-dib.pdata[i])<=r    )
  {
           dib.pdata[i+3]=alpha;
  }
 }
}

extern "C" void SetTexPixel(int x,int y,GLubyte color[],DIBTEXDATA dib)
{
 GLubyte* pstart = dib.pdata+(dib.height-1-y)*dib.width*4;
 pstart += x*4;

 pstart[0]=color[2];//r
 pstart[1]=color[1];//g
 pstart[2]=color[0];//b
 pstart[3]=color[3];//a

}
extern "C" void GetTexPixel(int x,int y,GLubyte color[],DIBTEXDATA dib)
{
 GLubyte* pstart = dib.pdata+(dib.height-1-y)*dib.width*4;
 pstart += x*4;


 color[0]=pstart[2];//r
 color[1]=pstart[1];//g
 color[2]=pstart[0];//b
 color[3]=pstart[3];//a

}
extern "C" GLuint BuildTexture(char* filename)
{

 GLubyte* prgba;
 ILuint ImageID;
 ilGenImages(1,&ImageID);
 ilBindImage(ImageID);
 ILboolean IsLoaded =  ilLoadImage(filename);
 if(! IsLoaded)
  return 0;

 int Width = ilGetInteger(IL_IMAGE_WIDTH);
 int Height = ilGetInteger(IL_IMAGE_HEIGHT);
 int Bpp    = ilGetInteger(IL_IMAGE_BPP);
 int Format = ilGetInteger(IL_IMAGE_FORMAT);
 int Depth  = ilGetInteger(IL_IMAGE_DEPTH);

 int NewW = FlowToPower2(Width);
 int NewH = FlowToPower2(Height);

 if(NewW != Width  ||
  NewH != Height )
 {
  iluScale(NewW,NewH,Depth);
 }

 if(Format != IL_RGBA)
 {
  ilConvertImage(IL_RGBA,ilGetInteger(IL_IMAGE_TYPE));
 }

 prgba = ilGetData();
 IMAGESIZE size;
 size.bits = 32;
 size.width = NewW;
 size.height =NewH;

 if(prgba == 0)
 {
  ilDeleteImages(1,&ImageID);
  return 0;
 }
 GLuint t = BuildTextureFromImage(prgba,size);
 ilDeleteImages(1,&ImageID);
 return t;
}

extern "C" GLuint BuildTransparencyTexture(char* filename,GLubyte color[],GLubyte alpha,int r)
{

 GLuint texture; 

 DIBTEXDATA dib=LoadTexData(filename);
 if(dib.pdata == NULL)
  return 0;

 glGenTextures(1,&texture);
 glBindTexture(GL_TEXTURE_2D,texture);

 

    SetTexAlpha(color,alpha,dib,r);

 {
  glTexImage2D( GL_TEXTURE_2D,0,4,dib.width,dib.height,0,GL_RGBA,GL_UNSIGNED_BYTE,dib.pdata);
 }


 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
 glEnable(GL_TEXTURE_2D);

 FreeDibTexData(dib);

 return texture;

}
extern "C" GLuint BuildTextureFromImage(unsigned char* image,IMAGESIZE size)
{
 GLuint texture;
 glGenTextures(1,&texture);
 glBindTexture(GL_TEXTURE_2D,texture);

 if(size.bits == 32)
 {
    glTexImage2D( GL_TEXTURE_2D,0,4,size.width,size.height,0,GL_RGBA,GL_UNSIGNED_BYTE,image);
 }
 if(size.bits == 24)
 {
    glTexImage2D( GL_TEXTURE_2D,0,4,size.width,size.height,0,GL_RGB,GL_UNSIGNED_BYTE,image);
 }
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
 glEnable(GL_TEXTURE_2D);

 return texture;
}

extern "C" GLuint BuildTextureFromRGBImage(unsigned char* image,IMAGESIZE size)
{
 GLuint texture;
 glGenTextures(1,&texture);
 glBindTexture(GL_TEXTURE_2D,texture);

 if(size.bits == 32)
 {
    glTexImage2D( GL_TEXTURE_2D,0,4,size.width,size.height,0,GL_RGBA,GL_UNSIGNED_BYTE,image);
 }
 if(size.bits == 24)
 {
    glTexImage2D( GL_TEXTURE_2D,0,4,size.width,size.height,0,GL_RGB,GL_UNSIGNED_BYTE,image);
 }
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
 glEnable(GL_TEXTURE_2D);

 return texture;
}

/***************************************************************
检测一个数是不是 2 的 几 次方
输入: n 为待检测的数字
输出: 0 为 不是2的平方数。
1 为 是一个2的平方数
***************************************************************/
extern "C" int IsPowerOfTwo(int n)
{
 return !(  (( n - 1)& n )  != 0);
}

/**************************************************************
调整一个数到能被 4 整除
**************************************************************/
extern "C" int  RoundFourByte(int n)
{
 if ( ( n%4)==0 )
  return n;
 else
  return (n+ 4-(n%4));
}

extern "C" unsigned char* LoadBlankImage(IMAGESIZE size)
{
 if(size.bits != 24 && size.bits != 32)
  return NULL;
 int b_len = size.height * size.width * size.bits / 8;

 unsigned char* pData = new unsigned char[b_len];
 memset((void*)pData,0,b_len);
 if(size.bits == 32)
 {
  for(int i = 0;i<b_len;i+=4)
   pData[i+3] = 255;
 }
 return pData;
}

extern "C" int SetImagePixel(unsigned char* image,int x,int y,IMAGESIZE size,unsigned char cl[4])
{
 if(image == NULL)
  return 0;
 int bpp = size.bits / 8;
 unsigned char* pixel = & image[bpp * size.width * y + x * bpp];

 if(bpp == 3)
 {
  pixel[0] = cl[0];
  pixel[1] = cl[1];
  pixel[2] = cl[2];
  return 1;
 }
 if(bpp == 4)
 {
  pixel[0] = cl[0];
  pixel[1] = cl[1];
  pixel[2] = cl[2];
  pixel[3] = cl[3];
  return 1;
 }
 return 0;
}

extern "C" int GetImagePixel(unsigned char* image,int x,int y,IMAGESIZE size,unsigned char cl[4])
{
 if(image == NULL)
  return 0;

 int bpp = size.bits / 8;
 unsigned char* pixel = & image[bpp * size.width * y + x * bpp];

 if(bpp == 3)
 {
  cl[0] = pixel[0];
  cl[1] = pixel[1];
  cl[2] = pixel[2];
  return 1;
 }
 if(bpp == 4)
 {
  cl[0] = pixel[0];
  cl[1] = pixel[1];
  cl[2] = pixel[2];
  cl[3] = pixel[3];
  return 1;
 }
 return 0;
}
extern "C" void SetKeyColorAlpha(unsigned char* image,IMAGESIZE size,unsigned char cl[4],int r)
{

 if(image == NULL)
  return ;

 for(int y =0 ; y<size.height;y++)
  for(int x = 0; x < size.width ; x++)
  {
   unsigned char* pixel = & image[4 * size.width * y + x * 4];
   if(  abs(cl[0] - pixel[0]) <= r &&
    abs(cl[1] - pixel[1]) <= r &&
    abs(cl[2] - pixel[2]) <= r    )
    pixel[3] = cl[3];
  }
}

void FreeImageData(unsigned char* pData)
{
 if(pData)
  delete []pData;
}