目次 - API(機能別) - 2Dレンダリング - SDL_GL_BindTexture

SDL_GL_BindTexture

OpenGLプリミティブを直接レンダリングするとき, それをOpenGLインストラクションで使うためにOpenGL/ES/ES2テクスチャをカレントコンテキストにバインドする

構文

int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)

引数

textureOpenGL/ES/ES2カレントコンテキストにバインドするテクスチャ
texwテクスチャの幅を代入するfloat型の変数へのポインタ, 必要ない場合はNULL
texhテクスチャの高さを代入するfloat型の変数へのポインタ, 必要ない場合はNULL

戻り値

成功のとき0, 操作が対応していないときは-1を戻す. SDL_GetError()で詳細を知ることができる.

サンプルコード

以下の3つの例はIgnifuga Game Engineから得たもので, SDL2を使ってlibRocket(レンダラーにOpenGLを使っている)をどのように統合しているかを示す.

(1)

void RocketSDLRenderInterfaceOpenGL::RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation)
{
    // SDLはシェーダーを使うので, ここでは無効化する必要がある
    render_data.glUseProgramObjectARB(0);
    render_data.glPushMatrix();
    render_data.glTranslatef(translation.x, translation.y, 0);

    std::vector<Rocket::Core::Vector2f> Positions(num_vertices);
    std::vector<Rocket::Core::Colourb> Colors(num_vertices);
    std::vector<Rocket::Core::Vector2f> TexCoords(num_vertices);
    float texw, texh;

    SDL_Texture* sdl_texture = NULL;
    if(texture) {
        render_data.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        sdl_texture = (SDL_Texture *) texture;
        SDL_GL_BindTexture(sdl_texture, &texw, &texh);
    }

    for (int  i = 0; i < num_vertices; i++) {
        Positions[i] = vertices[i].position;
        Colors[i] = vertices[i].colour;
        if (sdl_texture) {
            TexCoords[i].x = vertices[i].tex_coord.x * texw;
            TexCoords[i].y = vertices[i].tex_coord.y * texh;
        } else {
            TexCoords[i] = vertices[i].tex_coord;
        }
    }

    render_data.glEnableClientState(GL_VERTEX_ARRAY);
    render_data.glEnableClientState(GL_COLOR_ARRAY);
    render_data.glVertexPointer(2, GL_FLOAT, 0, &Positions[0]);
    render_data.glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]);
    render_data.glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]);


    render_data.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    render_data.glEnable(GL_BLEND);
    render_data.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    render_data.glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
    render_data.glDisableClientState(GL_VERTEX_ARRAY);
    render_data.glDisableClientState(GL_COLOR_ARRAY);


    if (sdl_texture) {
        SDL_GL_UnbindTexture(sdl_texture);
        render_data.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

    render_data.glColor4f(1.0, 1.0, 1.0, 1.0);
    render_data.glPopMatrix();
}

(2)

void RocketSDLRenderInterfaceOpenGLES::RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation)
{
    render_data.glPushMatrix();
    render_data.glTranslatef(translation.x, translation.y, 0);

    std::vector<Rocket::Core::Vector2f> Positions(num_vertices);
    std::vector<Rocket::Core::Colourb> Colors(num_vertices);
    std::vector<Rocket::Core::Vector2f> TexCoords(num_vertices);
    float texw, texh;

    SDL_Texture* sdl_texture = NULL;
    if(texture) {
        render_data.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        sdl_texture = (SDL_Texture *) texture;
        SDL_GL_BindTexture(sdl_texture, &texw, &texh);
    }

    for (int  i = 0; i < num_vertices; i++) {
        Positions[i] = vertices[i].position;
        Colors[i] = vertices[i].colour;
        if (sdl_texture) {
            TexCoords[i].x = vertices[i].tex_coord.x * texw;
            TexCoords[i].y = vertices[i].tex_coord.y * texh;
        } else {
            TexCoords[i] = vertices[i].tex_coord;
        }
    }

    unsigned short newIndicies[num_indices];
    for (int i = 0; i < num_indices; i++) {
        newIndicies[i] = (unsigned short) indices[i];
    }

    render_data.glEnableClientState(GL_VERTEX_ARRAY);
    render_data.glEnableClientState(GL_COLOR_ARRAY);
    render_data.glVertexPointer(2, GL_FLOAT, 0, &Positions[0]);
    render_data.glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]);
    render_data.glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]);

    render_data.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    render_data.glEnable(GL_BLEND);
    render_data.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    render_data.glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, newIndicies);
    render_data.glDisableClientState(GL_VERTEX_ARRAY);
    render_data.glDisableClientState(GL_COLOR_ARRAY);
    render_data.glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    if (sdl_texture) {
        SDL_GL_UnbindTexture(sdl_texture);
        render_data.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

    render_data.glColor4f(1.0, 1.0, 1.0, 1.0);
    render_data.glPopMatrix();
}

(3)

    SDL_Texture* sdl_texture = NULL;
    if(texture) render_data.glUseProgram(program_texture_id);
    else render_data.glUseProgram(program_color_id);
    int width, height;
    SDL_Rect rvp;
    SDL_RenderGetViewport(renderer, &rvp);

    GLfloat projection[4][4];

    // 平行投影の準備をする
    projection[0][0] = 2.0f / rvp.w;
    projection[0][1] = 0.0f;
    projection[0][2] = 0.0f;
    projection[0][3] = 0.0f;
    projection[1][0] = 0.0f;
    //if (renderer-;>target) {
    //    projection[1][1] = 2.0f / height;
    //} else {
        projection[1][1] = -2.0f / rvp.h;
    //}
    projection[1][2] = 0.0f;
    projection[1][3] = 0.0f;
    projection[2][0] = 0.0f;
    projection[2][1] = 0.0f;
    projection[2][2] = 0.0f;
    projection[2][3] = 0.0f;
    projection[3][0] = -1.0f;
    //if (renderer->target) {
    //    projection[3][1] = -1.0f;
    //} else {
        projection[3][1] = 1.0f;
    //}
    projection[3][2] = 0.0f;
    projection[3][3] = 1.0f;

    // 投影行列を設定する
    if (texture) {
        render_data.glUniformMatrix4fv(u_texture_projection, 1, GL_FALSE, (GLfloat *)projection);
        render_data.glUniform2f(u_texture_translation, translation.x, translation.y);
    } else {
        render_data.glUniformMatrix4fv(u_color_projection, 1, GL_FALSE, (GLfloat *)projection);
        render_data.glUniform2f(u_color_translation, translation.x, translation.y);
    }

    render_data.glEnable(GL_BLEND);
    render_data.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    float texw, texh;

    unsigned short newIndicies[num_indices];
    for (int i = 0; i < num_indices; i++) {
      newIndicies[i] = (unsigned short) indices[i];
    }

    glVertexAttribPointer(ROCKETGLUE_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(Rocket::Core::Vertex), &vertices[0].position);
    glVertexAttribPointer(ROCKETGLUE_ATTRIBUTE_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Rocket::Core::Vertex), &vertices[0].colour);
    render_data.glEnableVertexAttribArray(ROCKETGLUE_ATTRIBUTE_POSITION);
    render_data.glEnableVertexAttribArray(ROCKETGLUE_ATTRIBUTE_TEXCOORD);
    render_data.glEnableVertexAttribArray(ROCKETGLUE_ATTRIBUTE_COLOR);

    if (texture) {
        sdl_texture = (SDL_Texture *) texture;
        SDL_GL_BindTexture(sdl_texture, &texw, &texh);
        render_data.glUniform1i(u_texture, 0);
        glVertexAttribPointer(ROCKETGLUE_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Rocket::Core::Vertex), &vertices[0].tex_coord);
    } else {
        render_data.glActiveTexture(GL_TEXTURE0);
        render_data.glDisable(GL_TEXTURE_2D);
        render_data.glDisableVertexAttribArray(ROCKETGLUE_ATTRIBUTE_TEXCOORD);
    }

    render_data.glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, newIndicies);

    /* ROCKETGLUE_ATTRIBUTE_COLOR (2)を安全に無効化できる. SDLは必要ならばvertex attrib 2を再び有効化できる */
    render_data.glDisableVertexAttribArray(ROCKETGLUE_ATTRIBUTE_COLOR);

    /* SDLがRenderCopy/Exを呼ぶとき有効化されないため互換性のために有効化した
       ROCKETGLUE_ATTRIBUTE_POSITION (0) とROCKETGLUE_ATTRIBUTE_TEXCOORD (1) を離す */
    if(sdl_texture) SDL_GL_UnbindTexture(sdl_texture);
    else render_data.glEnableVertexAttribArray(ROCKETGLUE_ATTRIBUTE_TEXCOORD);

    /* ブレンドをリセットし, 画面の外にフェイクの点を描画してテクスチャをレンダリング場合に備えて
       状態をリセットする必要があることをSDLに知らせる */
    render_data.glDisable(GL_BLEND);
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
    SDL_RenderDrawPoint(renderer, -1, -1);

詳細

値が得られたなら, texwtexhには得られたテクスチャに適した幅と高さが代入されている. ほとんどの場合, 両方の値は1.0である. しかし, GL_ARB_texture_rectangle拡張に対応した環境では, これらの値はテクスチャの生成のために使われた実際のピクセル数の幅と高さである. このことはOpenGLにテクスチャの座標を与える場合に考慮する必要がある.

SDL_Textureを生成するためにはレンダラーが必要である. よって, この関数では あなた自身のOpenGLコンテキストではなく, SDL_CreateRenderer()で生成した暗黙のOpenGLコンテキストを使うしかない. もしあなたのOpenGLコンテキストを扱う必要があるならば, テクスチャを読み込むメソッドを自分自身で書かなければならない.

さらに, SDLはRGBテクスチャをBGR順(つまり逆にして)アップロードし, シェーダーの段階でカラーチャネルを並び替える. よって, アップロードされたテクスチャはカラーチャネルが逆になっているので注意すること.

バージョン

SDL 2.0.0以降

関連項目(関数)

SDL_GL_MakeCurrent
SDL_GL_UnbindTexture

SDL Wikiへのリンク

SDL_GL_BindTexture - SDL Wiki