#ifndef __TEXTUREPOOL_H #define __TEXTUREPOOL_H /* テクスチャの管理クラス ・読み込み可能なテクスチャの画像形式はbmp,tga,jpeg,png ただし jpegの読み込みにはJPEGライブラリ(libjpeg.lib, jpeglib.h)が別途必要 jpegの読み込みを有効にするには,このヘッダの DEF_USE_LIBJPEG を 1 にすること pngの読み込みにはPNGライブラリ(libpng.lib, zlib.lib, png.h ,zlib.h)が別途必要 pngの読み込みを有効にするには,このヘッダの DEF_USE_LIBPNG を 1 にすること ・テクスチャ画像のサイズは「一辺が2のn乗サイズ(64,128,256…)の正方形」に限る ・テクスチャのサイズは縦横同じものにしか対応していません。 ・ビットマップ、TGAファイルは画素の格納が  左→右。下→上。の順にしか対応してません。 ・TGAファイルはリトルエディアンで格納されているものとして処理しています。 注意☆デストラクタで登録したテクスチャを解放しています。    テクスチャ使用中にこのクラスを解放しないでください。 使用方法 1)コンストラクタの中身はカラです。テキトーにクラス作成 2)setメソッドで登録したいテクスチャのファイル名を指定 3)setメソッドの戻り値がOpenGLへ登録された番号なので   ソレを使用してテクスチャを使う。 例) texturePool pool ; GLuint texName ; texName = pool.set("テクスチャ.bmp","透明度.tga") ; glBindTexture(GL_TEXTURE_2D,texName) ; code by kei */ #define DEF_USE_LIBJPEG 0 // libjpegの使用(1=使用 0=未使用) #define DEF_USE_LIBPNG 0 // libpng の使用(1=使用 0=未使用) #ifdef WIN32 #include #else #ifndef MAX_PATH #define MAX_PATH 256 #endif #ifndef TRUE #define TRUE (1==1) #endif #ifndef FALSE #define FALSE (1!=1) #endif #endif #include #include #ifdef __APPLE__ #include #else #include #endif #include "endianConverter.h" // JPEGを使用する #ifdef D_JPEG #undef DEF_USE_LIBJPEG #define DEF_USE_LIBJPEG 1 #endif // JPEGを使用しない #ifdef D_NO_JPEG #undef DEF_USE_LIBJPEG #define DEF_USE_LIBJPEG 0 #endif // PNGを使用する #ifdef D_PNG #undef DEF_USE_LIBPNG #define DEF_USE_LIBPNG 1 #endif // PNGを使用しない #ifdef D_NO_PNG #undef DEF_USE_LIBPNG #define DEF_USE_LIBPNG 0 #endif #if DEF_USE_LIBJPEG #define XMD_H // INT16とINT32の再定義エラーを防ぐ #ifdef FAR #undef FAR #endif #ifdef __cplusplus extern "C" { #endif #include "jpeglib.h" #ifdef __cplusplus } #endif #pragma comment(lib,"libjpeg.lib") #endif #if DEF_USE_LIBPNG #include "png.h" #include "zlib.h" #pragma comment(lib,"libpng.lib") #pragma comment(lib,"zlib.lib") #endif using namespace std ; class texturePool { public : //TGAファイルタイプ enum ENUM_TGA_TYPE { NON = 0, INDEX, FULL, MONO, RLEINDEX = 9, RLEFULL, RLEMONO } ; private : typedef struct { unsigned char id; unsigned char color_map_flag; unsigned char type; unsigned short color_map_entry; unsigned char color_map_entry_size; unsigned short x; unsigned short y; unsigned short width; unsigned short height; unsigned char depth; unsigned char bit_info; } STR_TGA_HEAD;//TGAファイルヘッダの構造体 typedef struct { GLuint texture_id; // テクスチャID int texsize; // テクスチャサイズ char texfile[MAX_PATH]; // テクスチャファイル char alpfile[MAX_PATH]; // アルファテクスチャファイル } TEXTURE_POOL;//テクスチャプール用データ vector m_pool ;//テクスチャ情報保存コンテナ public : GLuint get(int num) { return m_pool[num].texture_id ; } //コンストラクタ texturePool() { } //デストラクタ // ここで登録したテクスチャを解放している。 virtual ~texturePool() { int pos; int max = (int)m_pool.size() ; for ( pos = 0; pos < max; pos++ ) { glDeleteTextures(1,&m_pool[pos].texture_id) ; } m_pool.clear() ; } //テクスチャ登録 // in texfile テクスチャファイル // in alpfile 透明度ファイル(PNG、TGAのみ) // 戻り値 GLuint OpenGLに登録したテクスチャ番号 GLuint set(char *texfile,char *alpfile=NULL) { int pos; GLubyte *image; int max = (int)m_pool.size() ; for ( pos = 0; pos < max; pos++ ) { if ( texfile != NULL ) { if ( strcmp(texfile,m_pool[pos].texfile) != 0 ) { continue; } } if ( alpfile != NULL ) { if ( strcmp(alpfile,m_pool[pos].alpfile) != 0 ) { continue; } } break; } if ( pos < max ) { //すでに読み込み済み return m_pool[pos].texture_id; } TEXTURE_POOL pooldata ; memset(&pooldata,0,sizeof(pooldata)) ; image = loadTexture(texfile,alpfile,&pooldata.texsize); if ( image == NULL ) { return 0; } if ( texfile != NULL ) strncpy(pooldata.texfile,texfile,MAX_PATH); if ( alpfile != NULL ) strncpy(pooldata.alpfile,alpfile,MAX_PATH); glPixelStorei(GL_UNPACK_ALIGNMENT,1); glPixelStorei(GL_PACK_ALIGNMENT,1); glGenTextures(1,&pooldata.texture_id); // テクスチャを生成 int bindtex ; glGetIntegerv(GL_TEXTURE_BINDING_2D,&bindtex) ; // 現在のテクスチャを保存 glBindTexture(GL_TEXTURE_2D,pooldata.texture_id); // テクスチャの割り当て glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, pooldata.texsize, pooldata.texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); //登録すれば、読み込んだバッファは不要 free(image); m_pool.push_back(pooldata) ; glBindTexture(GL_TEXTURE_2D,bindtex); //元のテクスチャの割り当て return pooldata.texture_id ; } private : //ファイル読み込み処理 // in texfile テクスチャファイル // in alpfile 透明度ファイル(PNG、TGAのみ) // out 読み込んだテクスチャのサイズ(縦横同じファイルにしか対応していない) // 戻り値 読み込んだイメージデータ GLubyte* loadTexture(char *texfile,char *alpfile,int *tex_size) { FILE *fp; size_t namelen; char ext[4]; char wbuf[3]; int isTGA; int isPNG; int isJPEG; int other; int y,x,size; int fl; char *filename[2]; int width[2]; int sts; STR_TGA_HEAD tgah; GLubyte *pImage, *pRead; #if DEF_USE_LIBJPEG struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY jpegimage; #endif #if DEF_USE_LIBPNG unsigned char **pngimage; unsigned long pngwidth, pngheight; int pngdepth; int color_type; #endif filename[0] = texfile; filename[1] = alpfile; width[0] = -1; width[1] = -1; pImage = NULL; fp = NULL; sts = 0; #if DEF_USE_LIBJPEG jpegimage = NULL; #endif #if DEF_USE_LIBPNG pngimage = NULL; #endif size = - 1; for ( fl = 0; fl < 2; fl++ ) {//テクスチャ=fl=0 アルファ=fl=1 if ( filename[fl] == NULL ) continue; namelen = strlen(filename[fl]); ext[0] = tolower(filename[fl][namelen-3]); ext[1] = tolower(filename[fl][namelen-2]); ext[2] = tolower(filename[fl][namelen-1]); ext[3] = 0x00; isTGA = (strcmp(ext,"tga")==0)?1:0; isPNG = (strcmp(ext,"png")==0)?1:0; isJPEG = (strcmp(ext,"jpg")==0)?1:0; /* */ if ( (! isTGA) && (! isPNG) &&(! isJPEG) ) { filename[fl][namelen-3] = 'b'; filename[fl][namelen-2] = 'm'; filename[fl][namelen-1] = 'p'; } /* */ if ( fl == 1 ) { //アルファの読み込みはTGAorPNG if ( ! (isTGA || isPNG) ) { printf("アルファのファイルに対応できない→%s\n",filename[fl]); break; } } if ( fp != NULL ) fclose(fp); if ( (fp=fopen(filename[fl],"rb"))==NULL ) { printf("%s:テクスチャ読み込みエラー[%s]\n",__FILE__,filename[fl]); continue; } // ヘッダのロード if ( isTGA ) { fread(&tgah,sizeof(STR_TGA_HEAD),1,fp); #if DEF_IS_LITTLE_ENDIAN #else TGAHeaderEndianConverter(&tgah); #endif size = width[fl] = tgah.width; } if ( isJPEG ) { #if DEF_USE_LIBJPEG unsigned int i; cinfo.err = jpeg_std_error( &jerr ); jpeg_create_decompress( &cinfo ); //解凍用情報作成 jpeg_stdio_src( &cinfo, fp ); //読み込みファイル指定 jpeg_read_header( &cinfo, TRUE ); //jpegヘッダ読み込み jpeg_start_decompress( &cinfo ); //解凍開始 if ( cinfo.out_color_components == 3 && cinfo.out_color_space == JCS_RGB ) { if ( jpegimage != NULL ) { for (i = 0; i < cinfo.output_height; i++) free(jpegimage[i]); // 以下2行は2次元配列を解放します free(jpegimage); } //読み込みデータ配列の作成 jpegimage = (JSAMPARRAY)malloc( sizeof( JSAMPROW ) * cinfo.output_height ); for ( i = 0; i < cinfo.output_height; i++ ) { jpegimage[i] = (JSAMPROW)malloc( sizeof( JSAMPLE ) * cinfo.out_color_components * cinfo.output_width ); } //解凍データ読み込み while( cinfo.output_scanline < cinfo.output_height ) { jpeg_read_scanlines( &cinfo, jpegimage + cinfo.output_scanline, cinfo.output_height - cinfo.output_scanline ); } size = width[fl] = cinfo.output_width; } jpeg_finish_decompress( &cinfo ); //解凍終了 jpeg_destroy_decompress( &cinfo ); //解凍用情報解放 if ( !(cinfo.out_color_components == 3 && cinfo.out_color_space == JCS_RGB) ) { printf("JPEG 対応できないフォーマット→%s\n",filename[fl]); } #else printf("このテクスチャは対応できないフォーマット→%s\n",filename[fl]); continue; #endif } if ( isPNG ) { #if DEF_USE_LIBPNG png_structp png_ptr; png_infop info_ptr; int bit_depth, interlace_type; unsigned int i; int j,k; png_ptr = png_create_read_struct( // png_ptr構造体を確保・初期化します PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); // info_ptr構造体を確保・初期化します png_init_io(png_ptr, fp); // libpngにfpを知らせます png_read_info(png_ptr, info_ptr); // PNGファイルのヘッダを読み込みます png_get_IHDR(png_ptr, info_ptr, &pngwidth, &pngheight, // IHDRチャンク情報を取得します &bit_depth, &color_type, &interlace_type, &j,&k); if ( pngimage != NULL ) { for (i = 0; i < pngheight; i++) free(pngimage[i]); // 以下2行は2次元配列を解放します free(pngimage); } pngimage = (png_bytepp)malloc(pngheight * sizeof(png_bytep)); // 以下3行は2次元配列を確保します i = png_get_rowbytes(png_ptr, info_ptr); pngdepth = i / pngwidth; for (i = 0; i < pngheight; i++) pngimage[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr)); png_read_image(png_ptr, pngimage); // 画像データを読み込みます png_destroy_read_struct( // 2つの構造体のメモリを解放します &png_ptr, &info_ptr, (png_infopp)NULL); size = width[fl] = pngwidth; #else printf("このテクスチャは対応できないフォーマット→%s\n",filename[fl]); continue; #endif } if ( width[fl] == -1 ) {//ココまできてサイズが指定されていない = ビットマップ fseek(fp,14+4,SEEK_SET); // 画像幅が格納されている位置までシーク fread(&size,sizeof(int),1,fp); // BiWidthの情報だけ取得 fseek(fp,14+40,SEEK_SET); // 画素データが格納されている位置までシーク #if DEF_IS_LITTLE_ENDIAN #else endianConverter(&size,sizeof(int)); #endif width[fl] = size; } if ( width[0] != -1 && width[1] != -1 ) { if ( width[0] != width[1] ) { sts = -1; break; } } if ( fl == 1 && isTGA ) { //アルファの読み込みはTGAの8ビットモノクロor32ビットフル if ( !( (tgah.depth == 8 && tgah.type == /*ENUM_TGA_TYPE::*/MONO) || (tgah.depth == 32 && tgah.type == /*ENUM_TGA_TYPE::*/FULL) ) ) { break; } } if ( fl == 1 && isPNG ) { //アルファの読み込みはPNGのトゥルーカラー+アルファorグレースケール+アルファ #if DEF_USE_LIBPNG if ( !( (color_type== 6 ) || (color_type== 4 ) ) ) { break; } #endif } // メモリの確保 if ( pImage == NULL ) { pImage = (GLubyte*)malloc(sizeof(unsigned char)*size*size*4); } if (pImage==NULL) return NULL; for (y=0; ycolor_map_entry,sizeof(tgah->color_map_entry)); endianConverter(&tgah->x,sizeof(tgah->x)); endianConverter(&tgah->y,sizeof(tgah->y)); endianConverter(&tgah->width,sizeof(tgah->width)); endianConverter(&tgah->height,sizeof(tgah->height)); } }; #endif