テクスチャ読み込みルーチン その4
朝の一番頭の働く時期になにやっているんだか・・・。
原因不明なのが分かりました。
透明色をALPHAチャンネルに変換するように指定した場合、画像のBPPが上がるんですね。それに対応していなかった。
色々試行錯誤した挙句、以下のようなコードになりましたとさ。
結構簡単になるものね。・・・というより例外処理使えよ > 自分。
/** 指定値より大きい2の累乗の値を得る * SDL/test/testgl.cから借用 */ inline static int power_of_two(int input_) { int value = 1; while (value < input_) { value *= 2; } return value; } static void readPNGData(png_structp png_ptr, png_bytep buf, png_size_t length) { Reader* io = (Reader*)(png_ptr->io_ptr); io->read*1 { png_set_tRNS_to_alpha(png_); colortype_ |= PNG_COLOR_MASK_ALPHA; } // 16bitは8bitに縮小 if (bpp_ == 16) { png_set_strip_16(png_); } return true; } //-------------------------------------------------------------------------------- /** グレイスケールのイメージの読み取り */ void loadGrayScaleBit() { glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width_align_, height_align_, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); unsigned char* buffer = new unsigned char[width_]; for (int y = 0; y < height_; ++y) { png_read_row(png_, buffer, NULL); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, width_, 1, GL_ALPHA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer); } delete buffer; } //-------------------------------------------------------------------------------- /** アルファチャンネル付きのグレイスケールイメージの読み取り a*/ void loadGrayScaleAlphaBit( void ) { glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width_align_, height_align_, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); glPixelStorei(GL_UNPACK_ALIGNMENT, 2); unsigned char* buffer = new unsigned char[width_ * 2]; for (int y = 0; y < height_; ++y) { png_read_row(png_, buffer, NULL); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, width_, 1, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer); } delete buffer; } //-------------------------------------------------------------------------------- /** true color のイメージの読み取り */ bool loadRGBBit( void ) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width_align_, height_align_, 0, GL_BGR, GL_UNSIGNED_BYTE, NULL); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); unsigned char* buffer = new unsigned char[width_ * 3]; for (int y = 0; y < height_; ++y) { png_read_row(png_, buffer, NULL); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, width_, 1, GL_BGR, GL_UNSIGNED_BYTE, (const GLvoid*)buffer); } delete buffer; } //-------------------------------------------------------------------------------- /** true color のイメージの読み取り(アルファ値付き) */ bool loadRGBAlphaBit( void ) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_align_, height_align_, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); unsigned char* buffer = new unsigned char[width_ * 4]; for (int y = 0; y < height_; ++y) { png_read_row(png_, buffer, NULL); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, width_, 1, GL_BGRA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer); } delete buffer; } //-------------------------------------------------------------------------------- /** イメージの読み取り */ bool loadImage() { // テクスチャを作成 glGenTextures(1, &id_); glBindTexture(GL_TEXTURE_2D, id_); switch(colortype_) { case PNG_COLOR_TYPE_GRAY: loadGrayScaleBit(); break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_PALETTE: loadRGBBit(); break; case PNG_COLOR_TYPE_GRAY_ALPHA: loadGrayScaleAlphaBit(); break; case PNG_COLOR_TYPE_RGB_ALPHA: loadRGBAlphaBit(); break; default: return false; } // テクスチャの設定 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); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); return true; } };
*1:pointer)buf, (size_type)length); } class LoadPNG { private: png_structp png_; png_infop info_; png_infop endinfo_; png_uint_32 width_; // 幅 png_uint_32 width_align_; // 幅 png_uint_32 height_; // 高さ png_uint_32 height_align_; // 高さ int bpp_; // 1pixelのbit数 int colortype_; // ピクセルの表すデータの種類 png_colorp palette_; // パレット情報 int palette_number_; // パレットの数 GLuint id_; public: bool load(Reader& reader) { if (loadInit() == false) { return false; } // 読み込み関数のセット png_set_read_fn(png_, &reader, readPNGData); if (loadHeader() == false ) { return false; } if (loadImage() == false) { return false; } png_read_end(png_, info_); png_destroy_read_struct(&png_, &info_, &endinfo_); return true; } public: TextureInfo textureInfo() const { return TextureInfo(id_, 0, 0, (float)width_ / width_align_, (float)height_ / height_align_); } protected: //-------------------------------------------------------------------------------- bool loadInit() { png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ = png_create_info_struct(png_); if (info_ == NULL) { png_destroy_read_struct(&png_, NULL, NULL); return false; } endinfo_ = png_create_info_struct(png_); if (endinfo_ == NULL) { png_destroy_read_struct(&png_, &info_, NULL); return false; } if (setjmp(png_jmpbuf(png_))) { png_destroy_read_struct(&png_, &info_, &endinfo_); return false; } return true; } //-------------------------------------------------------------------------------- bool loadHeader() { // ヘッダ情報を読み込む png_read_info(png_, info_); png_get_IHDR(png_, info_, &width_, &height_, &bpp_, &colortype_, NULL, NULL, NULL); // 2のべき乗に合わせる width_align_ = power_of_two(width_); height_align_ = power_of_two(height_); // 入力データの変換ルール設定 switch (colortype_) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_); png_set_bgr(png_); // 以後RGBと同じように扱う colortype_ = PNG_COLOR_TYPE_RGB; break; case PNG_COLOR_TYPE_GRAY: if (bpp_ < 8) { png_set_gray_1_2_4_to_8(png_); } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: png_set_bgr(png_); break; default: ; } // 透明色がある場合にはALPHAレイヤを追加する if (png_get_valid(png_, info_, PNG_INFO_tRNS