SDLとOpenGLをとりあえず組み合わせてみる

初期化

とりあえずSDL2.0とOpenGLとの連携において初期がで気をつけることは次の3つぐらい?

DoubleBufferingの有効化
    // enable double buffering
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_CreateWindowでSDL_WINDOW_OPENGLを指定する

SDL1.2ではSDL_SetVideoModeでやってた処理

static SDL_Window* window;

/* --- skip --- */

    // create indow
    // set SDL_WINDOW_OPENGL to use opengl for drawing
    window = SDL_CreateWindow(WINDOW_CAPTION.c_str(),
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              WINDOW_WIDTH, WINDOW_HEIGHT,
                              SDL_WINDOW_OPENGL);
    if (!window) return false;
OpenGLの実際の設定を行う前に前にSDL_GL_CreateContextを実行する (未だにコンテキストがよくわからん、うぐぐ)
static SDL_GLContext context;

/* --- skip --- */

    // create OpenGL context
    context = SDL_GL_CreateContext(window);
    if (!context) return false

試しに書いてみた

赤い球体を表示するコード、SDL2.0の初期化以外は
http://www.ownway.info/Graphics/index.php?cmd=read&page=SDL%2BOpenGL%2F2.%B5%E5%A4%F2%C9%C1%B2%E8%A4%B9%A4%EB
で公開されているサンプルコードを利用。

/* -*- coding:utf-8 -*- */

/**
 * sdl_with_opengl.cpp
 */

#include <SDL.h>
#include <SDL_opengl.h>
#include <OpenGL/glu.h>

#include <iostream>
#include <string>

#include <cmath>

static const std::string WINDOW_CAPTION = "SDL with OpenGL";
static const Uint32 WINDOW_WIDTH = 640;
static const Uint32 WINDOW_HEIGHT = 480;
static const Uint32 WINDOW_BPP = 32;

static const Uint32 FPS = 60;

static SDL_Window* window;
static SDL_GLContext context;

bool init();
bool finalize();

void update();
void draw();
bool pollingEvent();

int main() {
    // initialize
    if (!init()) {
        std::cerr << "ERROR: failed to initialize SDL" << std::endl;
        exit(1);
    }

    // mainloop
    static const Uint32 interval = 1000 / FPS;
    static Uint32 nextTime = SDL_GetTicks() + interval;
    bool skipDraw = false;
    while (true) {
        // check event
        if (!pollingEvent()) break;

        // update and draw
        update();
        if (!skipDraw) {
            draw();
            SDL_GL_SwapWindow(window);
        }

        int delayTime = (int)(nextTime - SDL_GetTicks());
        if (delayTime > 0) {
            SDL_Delay((Uint32)delayTime);
            skipDraw = false;
        } else {
            // skip next draw step because of no time
            skipDraw = true;
        }

        nextTime += interval;
    }

    // finalize
    finalize();
  
    return 0;
}

bool init() {
    // initialize SDL
    if( SDL_Init(SDL_INIT_VIDEO) < 0 ) return false;

    // enable double buffering
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    // create indow
    // set SDL_WINDOW_OPENGL to use opengl for drawing
    window = SDL_CreateWindow(WINDOW_CAPTION.c_str(),
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              WINDOW_WIDTH, WINDOW_HEIGHT,
                              SDL_WINDOW_OPENGL);
    if (!window) return false;

    // create OpenGL context
    context = SDL_GL_CreateContext(window);
    if (!context) return false;

    // setup viewport
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glEnable(GL_DEPTH_TEST);

    // setup projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLdouble) WINDOW_WIDTH / (GLdouble) WINDOW_HEIGHT, 2.0, 200.0);

    // setup light
    static GLfloat position[] = {-10.0f, 10.0f, 10.0f, 1.0f};
    static GLfloat ambient [] = { 1.0f, 1.0f, 1.0f, 1.0f};
    static GLfloat diffuse [] = { 1.0f, 1.0f, 1.0f, 1.0f};
    static GLfloat specular[] = { 0.0f, 0.0f, 0.0f, 0.0f};
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    return true;
}

bool finalize() {
  // finalize SDL
  SDL_Quit();

  return true;
}

void update() {
}

void draw() {
    // clear
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // setup view
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt( 0.0f,  0.0f,-30.0f,
               0.0f,  0.0f, 0.0f,
               0.0f, -1.0f, 0.0f);

    // setup material
    GLfloat ambient  [] = { 0.1f, 0.1f, 0.1f, 1.0f};
    GLfloat diffuse  [] = { 1.0f, 0.0f, 0.0f, 1.0f};
    GLfloat specular [] = { 1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat shininess[] = { 0.0f};
    glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, shininess);

    // draw sphere
    GLUquadric* quadric = gluNewQuadric();
    gluSphere(quadric, 10.0, 30, 30);
    gluDeleteQuadric(quadric);
}

// polling event and execute actions
bool pollingEvent()
{
    SDL_Event ev;
    SDL_Keycode key;
    while ( SDL_PollEvent(&ev) )
    {
        switch(ev.type){
        case SDL_QUIT:
            // raise when exit event is occur
            return false;
            break;
        case SDL_KEYDOWN:
        // raise when key down
        {
            key = ev.key.keysym.sym;
            // ESC
            if(key == SDLK_ESCAPE){
                return false;
            }
        }
        break;
        }
    }
    return true;
}

コンパイルは次のようにする

$ g++ -o sdl_with_opengl sdl_with_opengl.cpp `sdl2-config --cflags` `sdl2-config --libs` -framework GLUT -framework OpenGL

実行すると下のような画面がでる。

<注意>開発環境はmacなので、Linuxとか他の環境だと方法が異なるはず。
違いは確かヘッダとコンパイルオプションで、Linuxの場合は

#include -> #include

となって

g++ -o sdl_with_opengl sdl_with_opengl.cpp `sdl2-config --cflags` `sdl2-config --libs` -lGL -lGLU -lglut

とかだった気がする。



最低限の初期化の仕方はわかったけど、ビューポートとか視点とかOpenGLな部分がさっぱりなので、
そこを次は調べないといかんですね。
# 昔少しいじったはずなのにすっかり覚えてないorz