質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Android

    7402questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Unity

    5651questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • iOS

    4772questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • C++

    4519questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • OpenGL ES

    34questions

    携帯電話のような組込み機器のためにデザインされたOpenGLのサブセットです。

OpenGl ES2でインデックス画像を使用したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 855

fumiasi

score 6

以前に作成していたアプリをUnityに移植する事になりました。
元々はOpenGL ES1で作成していたのですが、UnityがES1のサポートが終了していたので、
ES2に移行させる必要が発生しました。

ES1の時は、8bitインデックを読み込む場合、
GL_PALETTE8_RGB8_OES
GL_PALETTE8_RGBA8_OES
GL_PALETTE8_R5_G6_B5_OES
GL_PALETTE8_RGBA4_OES
GL_PALETTE8_RGB5_A1_OES
GL_PALETTE8_RGB8_OES 等
を使用していたのですが、ES2ではこれらのサポートが終了しているようで
ES2での読み込み方法が解らなかった為、質問致しました。

OpenGE ES1のソース

// test.cpp

#include "test.h"

TEXTURE::TEXTURE() : Width(0), Height(0), TexID(0), TexParam(0)
{
}

TEXTURE::~TEXTURE()
{
    release();
}

bool    TEXTURE::loadBmpData(unsigned char *pLoadBuffer, int KeyIndex, unsigned char *pPalette)
{
    int                    i;

    BITMAPFILEHEADER    *pBF    = NULL;
    BITMAPINFOHEADER    *pBI    = NULL;

    unsigned int        BmpPitch;
    int                    PalCount;
    unsigned char        *pBmpPal;
    unsigned char        *pBmpBits;

    unsigned int        Pitch;
    unsigned int        Size;
    unsigned char        *pData;
    unsigned short        *pPal;
    unsigned char        *pBits;

    int                    Point    = 0;
    int                    Point2    = 0;
    unsigned int        Format = 0;

    if( pLoadBuffer == NULL )                return false;
    if( 0 != memcpy( pLoadBuffer, "BM", 2 ) )    return false;

    // ヘッダ部抽出。
    pBF = (BITMAPFILEHEADER*)( pLoadBuffer );
    pBI = (BITMAPINFOHEADER*)( pLoadBuffer + sizeof(BITMAPFILEHEADER) );

    BmpPitch    = ( ( ((pBI->biWidth * pBI->biBitCount) >> 2) + 7 ) & ~7 ) >> 1;
    pBmpPal        = &pLoadBuffer[ sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) ];
    pBmpBits    = &pLoadBuffer[ pBF->bfOffBits ];

    // パレット変更があるならポインタ差し替え
    if( pPalette != NULL ) pBmpPal = pPalette;

    // パレット数
    PalCount    = (1 << pBI->biBitCount);

    // サイズを2の乗数になるように調整
    Width = Height = 1;
    while( Width  < pBI->biWidth  ) Width  <<= 1;
    while( Height < pBI->biHeight ) Height <<= 1;

    Pitch        = ((Width * pBI->biBitCount) >> 3);
    Size        = PalCount * sizeof(unsigned short) + Pitch * Height;
    pData        = (unsigned char*)malloc( Size );
    if( pData == NULL ) return false;
    pPal        = (unsigned short*)&pData[ 0 ];
    pBits        = (unsigned char*)&pData[ PalCount * sizeof(unsigned short) ];

    // 8888を5551に変換 不透明部分に0xFF 透過部分に0x00を入れる
    for( i = 0 ; i < PalCount ; i++ )
    {
        if( KeyIndex == i ) pPal[ i ] = RGBA_TO_R5G5B5A1( pBmpPal[ i * 4 + 2 ], pBmpPal[ i * 4 + 1 ], pBmpPal[ i * 4 + 0 ], 0x00 );
        else                pPal[ i ] = RGBA_TO_R5G5B5A1( pBmpPal[ i * 4 + 2 ], pBmpPal[ i * 4 + 1 ], pBmpPal[ i * 4 + 0 ], 0xFF );
    }

    // データ部分を上下反転
    for( i = pBI->biHeight - 1 ; i >= 0 ; i-- )
    {
        Point = BmpPitch * i;

        memcpy( &pBits[ Point2 ], &pBmpBits[ Point ], BmpPitch );

        Point2 += Pitch;
    }

    if( pBI->biBitCount == 4 )    Format = GL_PALETTE4_RGB5_A1_OES;
    else                        Format = GL_PALETTE8_RGB5_A1_OES;

    // OpenGLバッファ作成
    glEnable( GL_TEXTURE_2D );
    glGenTextures( 1, &TexID );
    glBindTexture( GL_TEXTURE_2D, TexID );

    // テクスチャ作成
    glCompressedTexImage2D( GL_TEXTURE_2D, 0, Format, Width, Height, 0, Size, pData );

    // パラメータ設定
    glBindTexture( GL_TEXTURE_2D, TexID );

    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_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

    if(pData) { free((void *)pData); pData = 0; }

    return true;
}

void    TEXTURE::release()
{
    if( TexID == 0 ) return;

    glBindTexture( GL_TEXTURE_2D, 0 );
    glDeleteTextures( 1, &TexID );

    Width            = 0;
    Height            = 0;
    TexID            = 0;
    TexParam        = 0;
}
// test.h

#ifndef __TEXTURE_HEADER__
#define __TEXTURE_HEADER__

#ifdef __ANDROID__
#include <GLES/gl.h>
#include <GLES/glxt.h>
#else
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#endif

#include <string.h>
#include <stdlib.h>

class TEXTURE
{
public:
    int            Width;    // 画像の幅
    int            Height;    // 画像の高さ
    GLuint        TexID;    // 識別番号
    int            TexParam;

private:

    void    loadIndexObmData(unsigned char *pLoadBuffer, unsigned char *pPalette );

public:
    TEXTURE();

    ~TEXTURE();

    bool    loadBmpData(unsigned char *pLoadBuffer, int KeyIndex, unsigned char *pPalette);

    void    release();
};

struct BITMAPFILEHEADER
{
    unsigned short  bfType;
    unsigned int    bfSize;
    unsigned short  bfReserved1;
    unsigned short  bfReserved2;
    unsigned int    bfOffBits;
};


struct BITMAPINFOHEADER
{
    unsigned int    biSize;
    int                biWidth;
    int                biHeight;
    unsigned short  biPlanes;
    unsigned short  biBitCount;
    unsigned int    biCompression;
    unsigned int    biSizeImage;
    int                biXPelsPerMeter;
    int                biYPelsPerMeter;
    unsigned int    biClrUsed;
    unsigned int    biClrImportant;
};

#define RGBA_TO_R5G5B5A1( r, g, b, a ) ( (((r) >> 3) << 11) | (((g) >> 3) << 6) | (((b) >> 3) << 1) | ((a) >> 7) )

// Unityからの呼び出し用に追加
extern "C"
{
    namespace
    {
        TEXTURE* g_pTexture;        // テクスチャー本体
        int g_itextureCount = 0;
    }

    // TEXTUREを生成してポインターを返す
    void* getTexture()
    {
        g_pTexture = new TEXTURE();
        return g_pTexture;
    }

    // TEXTUREを解放して削除する
    void releaseTexture()
    {
        if(g_pTexture != nullptr)
            delete g_pTexture;
    }

    // Bmpデータを読み込む
    bool loadBmpData(void* ptr, unsigned char *pLoadBuffer, int KeyIndex, unsigned char *pPalette)
    {
        TEXTURE* pTexture = reinterpret_cast<TEXTURE*>(ptr);
        return pTexture->loadBmpData( pLoadBuffer, KeyIndex, pPalette );
    }

    // Unityで作成したテクスチャハンドルに描画するよう設定する
    void setTextureID(void* ptr, void* texture_id)
    {
        TEXTURE* pTexture = reinterpret_cast<TEXTURE*>(ptr);
        pTexture->TexID = (GLuint)(size_t)texture_id;
    }
}

#endif // __TEXTURE_HEADER__


上記をUnityのプラグインに移植して、Unity側から呼び出して使用しようと思っています。
具体的には
http://tips.hecomi.com/entry/2016/01/04/183121
のサイトで行われているような感じでテクスチャをプラグイン側で作成して
Unity側で読み込んでAndroid/iOSで表示させようと思っています。

画像を16bitにして、インデックスを使用しないパターンやpng化も考慮しましたが
アプリ容量の問題や画像数がかなり多いので、従来のデータ(8bitインデックス)を
読み込ませたいと考えています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

ES2では、パレット付きの画像はそのままでは読み込めない事が判明しました。
無理やり読み込ませるには、読み込む前にパレット情報を展開して下記の形式に変換する必要があります。

形式

  • GL_PALETTE4_RGB8_OES
    type:GL_UNSIGNED_BYTE format = GL_RGB bit:4 offset:3
  • GL_PALETTE4_RGBA8_OES
    type:GL_UNSIGNED_BYTE format = GL_RGBA bit:4 offset:4
  • GL_PALETTE4_R5_G6_B5_OES
    type:GL_UNSIGNED_SHORT_5_6_5 format = GL_RGB bit:4 offset:2
  • GL_PALETTE4_RGBA4_OES
    type:GL_UNSIGNED_SHORT_4_4_4_4 format = GL_RGBA bit:4 offset:2
  • GL_PALETTE4_RGB5_A1_OES
    type:GL_UNSIGNED_SHORT_5_5_5_1 format = GL_RGBA bit:4 offset:2
  • GL_PALETTE8_RGB8_OES
    type:GL_UNSIGNED_BYTE format = GL_RGB bit:8 offset:3
  • GL_PALETTE8_RGBA8_OES
    type:GL_UNSIGNED_BYTE format = GL_RGBA bit:8 offset:4
  • GL_PALETTE8_R5_G6_B5_OES
    type:GL_UNSIGNED_SHORT_5_6_5 format = GL_RGB bit:8 offset:2
  • GL_PALETTE8_RGBA4_OES
    type:GL_UNSIGNED_SHORT_4_4_4_4 format = GL_RGBA bit:8 offset:2
  • GL_PALETTE8_RGB5_A1_OES
    type:GL_UNSIGNED_SHORT_5_5_5_1 format = GL_RGBA bit:8 offset:2
// 引数はES1でglCompressedTexImage2Dに代入する値と同じ
// 使用するタイミングはES1でglCompressedTexImage2Dを呼び出していた部分から呼び出す
void glCompressedTexImage2D_pallet(GLenum target, GLint level, GLenum oldformat
    GLsizei width, GLsizei height, GLint border, GLsizei imageSize,
    const GLvoid *data)
{
    GLint b, o, x, y;     // bはbit数、oはoffset、それぞれ上記の形式を参考に指定して下さい
    GLenum format, type;  // format, typeの値は、上記の形式を参考に指定して下さい
    const GLubyte* palette, * p;
    GLubyte* image = (GLubyte*)malloc(o*width*height);

    // oldformatから様々な形式に変換を掛ける必要がある場合は
    // ここでswitch分岐する事をオススメします。単体の場合は上記の宣言時に直代入でも問題ない
    // (設定内容はi,o,format,typeで対応形式は上記を参照)

    palette = (GLubyte*)data;
    p = (GLubyte*)data+(1<<i)*o;

    // 4bit 
    if (b == 4) {
        for(y = 0; y < height; y++) {
            for(x = 0; x < width; x+=2, p++) {
                for(GLint j = 0; j < o; j++) {
                    image[(y*width+x)*o+j] = palette[((*p)>>4)*o+j];
                    if (x+1 < width) {
                        image[(y*width+x+1)*o+j] = palette[((*p)&0xf)*o+j];
                    }
                }
            }
        }
    // 8bit
    } else {
        for(y = 0; y < height; y++) {
            for(x = 0; x < width; x++, p++) {
                for(GLint j = 0; j < o; j++) {
                    image[(y*width+x)*o+j] = palette[(*p)*o+j];
                }
            }
        }
    }

    glTexImage2D(target, level, format, width, height, 0, format, type, image);
    if (image) free(image);
}

実際に処理する場合は様々な例外処理

ターゲットチェック
if (target != GL_TEXTURE_2D) return;

メモリー確保に失敗した場合
if (!(image = (GLubyte*)malloc(o*width*height))) return;

画像サイズのチェック
if (width <= 0 || height <= 0 ||
width > GL_MAX_2D_TEX_SIZE || height > GL_MAX_2D_TEX_SIZE ||
!GL_IS_P2(height) || !GL_IS_P2(width) || level < 0 || border != 0)         return;

変換後のサイズチェック(switchを使用する場合はその後ろ)
if (((width*i)+7)/8*height + (1<<i)*o != imageSize)    return;

とかが必要になるかと思いますが、
必須ではないので上記では省略しています。

ES2でどうしてもパレットデータの読み込みさせたいと、
お悩みの同士の参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Android

    7402questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Unity

    5651questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • iOS

    4772questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • C++

    4519questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • OpenGL ES

    34questions

    携帯電話のような組込み機器のためにデザインされたOpenGLのサブセットです。