目次

008 PNGテクスチャの読み込み

概要

libpng 使ってPNG画像を読み込みOpenGLで扱える形にします。

ソースコード

#include <png.h>
#include <pnginfo.h>
 
// データ読込時のコールバック関数
int offset = 0;
void ReadEndProcess( png_structp _pPng, png_bytep _buf, png_size_t _size )
{
	uint8* p = (uint8*)png_get_io_ptr( _pPng );
	memcpy( _buf, p+offset, _size );
	offset += _size;
}
 
bool IsPNG( const uint8* _pData )
{
	if( png_sig_cmp( _pData, 0, 8 ) != 0 )
	{
		return false;
	}
	return true;
}
 
// テクスチャの読み込み。
bool Load( const uint8* _pData, GLuint* _textureID, sint32* _width, sint32* _height )
{
	GLuint textureName;
	glGenTextures( 1, &textureName );
	glBindTexture( GL_TEXTURE_2D, textureName );
 
	// PNGファイルであるか?
	if( png_sig_cmp( _pData, 0, 8 ) != 0 )
	{
		return false;
	}
 
	png_structp png_ptr;
	png_infop info_ptr;
	sint32 depth;
	sint32 color_type;
 
	// 読み込み用メモリを生成
	png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
 
	// メモリが生成できなければ終了
	if( png_ptr == NULL )
	{
		return false;
	}
 
	// 画像情報用メモリを生成(必須)
	info_ptr = png_create_info_struct( png_ptr );
	if( info_ptr == NULL )
	{
		png_destroy_read_struct( &png_ptr, NULL, NULL );
		return false;
	}
 
	// データ読み込み時に呼ばれるコールバック関数を定義する
	png_set_read_fn( png_ptr, (png_voidp)_pData, ReadEndProcess );
	offset = 8;
 
	// 内部でエラーが発生したら、ここに飛んでくる
	if( setjmp( png_jmpbuf( png_ptr ) ) )
	{
		// 確保したメモリーを解放する
		png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
		return false;
	}
 
	// PNGファイルの識別エリア(8バイト)をスキップ
	png_set_sig_bytes( png_ptr, 8 );
 
	// PNGファイルを読み込む
	png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL );
 
	// PNG画像情報を取得
	*_width = info_ptr->width;
	*_height = info_ptr->height;
	color_type = info_ptr->color_type;
	depth = info_ptr->bit_depth;
 
	// 色のタイプからテクスチャの画像情報を設定
	GLint gl_type;
	switch( color_type )
	{
	case PNG_COLOR_TYPE_PALETTE:
		png_set_palette_to_rgb( png_ptr );
		gl_type = GL_RGB;
		break;
 
	case PNG_COLOR_TYPE_RGB:
		gl_type = GL_RGB;
		break;
 
	case PNG_COLOR_TYPE_RGBA:
		gl_type = GL_RGBA;
		break;
 
	default:
		// 対応していないタイプなので処理を終了
		png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
		return false;
	}
 
	uint8* outData;
 
	// 画像1ライン分のメモリ領域を確保.
	uint32 row_bytes = png_get_rowbytes( png_ptr, info_ptr );
	outData = new uint8[ row_bytes * *_height ];
 
	// 画像情報を行単位で取得できるようにする.
	png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
 
#if 1
	for ( sint32 i = 0; i < *_height; i++ )
	{
		// 画像が上下反転するように格納する
		// (OpenGLのテクスチャーは上下反転して表示されるため)
//			memcpy( outData+(row_bytes * (*_height-1-i)), row_pointers[i], row_bytes );
 
		// 反転しない。
		memcpy( outData+(row_bytes * (i)), row_pointers[i], row_bytes );
	}
#endif
	// メモリをすべて解放する
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
	// テクスチャーデータを割り当てる
	glTexImage2D( GL_TEXTURE_2D, 0, gl_type, *_width, *_height, 0, gl_type, GL_UNSIGNED_BYTE, outData );
 
	SafeDeleteArray( outData );
 
	*_textureID = textureName;
 
	return true;
}