SDL_Surface和OpenGL texture

前言

最近重新學習OpenGL,再次面對之前沒有詳細理解的材質(texture)
過去就是使用SDL作爲開發基礎,加上有SDL_image這個套件可以協助讀取圖檔供SDL使用

“既然SDL後面也是用OpenGL實作,那大概可以直接讓OpenGL去使用吧”

抱着這樣的想法去查了一些資料,果真可行

資料結構

SDL_Surface,資料來自SDL wiki
SDL_PixelFormat,資料來自SDL wiki
而要在OpenGL裏面正確的讀入/設定Texture,需要有以下數據:

Pixel data

基本上就是色彩資訊,但是由於是純資料,還需要額外的資訊來輔助讀取
可以由SDL_Surface->pixels取得

format

色彩儲存有幾種常見的格式,例如RGB,RGBA,BGR和BGRA
必須知道資料的儲存格式才能如預期地讀取
可以由SDL_Surface->format->BytesPerPixel知道每pixel的資料量,再由SDL_Surface->format->Rmask得知RGB的排列順序

Image widht & height

長寬可供OpenGL知道需要讀取多少份pixel的資料,同時也能告知pixel排列的樣子
可以由SDL_Surface->w和SDL_Surface->h取得

實際程式碼

程式碼參考:https://gist.github.com/elms1990/8468274

我撰寫的簡略版本
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_opengl.h>

////////省略一堆
/* 程式碼內底線(_)結尾的變數,表示是class的成員變數 */

void
Texture::Load(string filePath, GLint minMagFilter,  GLint wrapMode)
{
    SDL_Surface* image;
    GLenum textureFormat;
    GLint bpp;     //Byte Per Pixel

    /* 先把圖像資料讀入SDL_Surface當中 */
    image = IMG_Load(filePath.c_str());

    /* 利用圖片中的資訊,找出pixel排列的格式 */
    bpp = image->format->BytesPerPixel;
    if (bpp == 4) {
        cout << "BytesPerPixel = 4" << endl;
        if (image->format->Rmask == 0x000000ff)
            textureFormat = GL_RGBA;
        else
            textureFormat = GL_BGRA;
    } else if (bpp == 3) {
        cout << "BytesPerPixel = 3" << endl;
        if (image->format->Rmask == 0x000000ff)
            textureFormat = GL_RGB;
        else
            textureFormat = GL_BGR;
    } else {
        cerr << "IMG error: Unknow pixel format" << endl;
    }

    /* originalWidth_是這個class的成員,不要理會 */
    originalWidth_ = image->w;
    originalHeight_ = image->h;

    /* 利用剛才得到的資訊,去產生OpenGL可以使用的texture */
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &object_);
    glBindTexture(GL_TEXTURE_2D, object_);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minMagFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, minMagFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
    glTexImage2D(
    GL_TEXTURE_2D,            // texture type
     0,               // level
     bpp,              // internal format
     image->w,            // width
     image->h,            // height
     0,               // border
     textureFormat,            // format
     GL_UNSIGNED_BYTE,     // data type
     image->pixels           // pointer to data
     );

    /* 處理後事 */
    glBindTexture(GL_TEXTURE_2D, 0);
    SDL_FreeSurface(image);
}

結語

大概就是這樣

像這種讀圖的library其實很多,找三篇文章就有三種做法(SOIL等,有些甚至自己幹一個),選擇使用SDL_image無疑是要省去麻煩,畢竟是平常就有在用的東西,同時可以讓程式碼清爽一點

Comments

comments powered by Disqus