OpenGL dengan SDL

Selain untuk membuat game 2D, SDL juga bisa digunakan untuk membuat game 3D dengan bantuan OpenGL. SDL bisa kita gunakan sebagai pembuat window dan penerima event dari OpenGL. Untuk menggunakan OpenGL bersama dengan SDL, kalian perlu menginstall "glut" setelah kalian menginstal SDL. Jika kalian menggunakan Ubuntu atau distro linux sejenis, kalian bisa menginstal glut lewat terminal dengan mengetik :

  • "sudo apt-get install freeglut3-dev"

Untuk OS lainnya, kalian bisa membaca cara menginstalnya situs resmi opengl/. Setelah kalian menginstal SDL2 dan OpenGL. Selanjutnya, kalian bisa mencoba membuat programnya. Jika kalian menggunakan CodeBlock, linker option yang perlu kalian ketik, yaitu :

  • Window : `sdl2-config --libs` -lSDL2 -lglut -lGLU -lGL
  • Linux (ubuntu) : -lmingw32 -lSDL2main -lSDL2 -lglut -lGLU -lGL

Setelah membuat project baru dan mengubah linker option dengan menu "Project => Build Options", kalian bisa mencoba mengetik kode programnya.

#include <SDL2/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>

#define GL3_PROTOTYPES 1

SDL_Window *mainWindow;
SDL_GLContext mainContext;

int init(){
    //Set atribut

	// Set versi OpenGL yg digunakan
	// SDL_GL_CONTEXT_CORE akan memberikan versi terbaru, fungsi yang deprecated tidak akan digunakan
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

	// Kita akan coba menggunakan versi 3.2
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

	// Nyalakan double buffering dengan 24bit Z buffer.
	// Jika perlu, ganti ke 16 atau 32 sesuai sistem yang digunakan
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); //mungkin bisa diabaikan

	//Set interval untuk swap
	SDL_GL_SetSwapInterval(1);

    //Mulai inisialisasi openGL
    glClearColor(0.0, 0.0, 0.0, 1.0);  //background color dan alpha
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, 640.0/480.0, 1.0, 500.0);//Perspektif, dan jarak
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_DEPTH_TEST);//Izinkan openGL melakukan Depth Test untuk objek 3D
    return 1;
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//Bersihkan layar
    glLoadIdentity();//Memuat (ulang) "informasi" dari openGL

    glTranslatef(0.0, 0.0, -2.0);//Ubah posisi / Sudut pandang
    glRotatef(30, 1.0, 1.0, 1.0);//Rotasi tampilan
    //Mulai menggambar ... ????
}

int loop_utama(SDL_Event *evt, int lanjut){
    while(SDL_PollEvent(evt)) {
        switch(evt->type) {
            case SDL_QUIT:
                lanjut = 0;
                break;
            case SDL_KEYDOWN:
                switch(evt->key.keysym.sym){
                    case SDLK_ESCAPE:
                        lanjut = 0;
                        break;
                }
                break;
        }
    }

    display();//Buat objek 2d atau 3d
    SDL_GL_SwapWindow(mainWindow);//Perbarui tampilan
    return lanjut;
}

int main(int argc, char** argv){
    int lanjut = 1;
    char *programName = "OpenGL  dengan SDL";
    SDL_Event event;

    if (SDL_Init(SDL_INIT_VIDEO) < 0){
        return 0;
    }

    mainWindow = SDL_CreateWindow(programName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL);
    mainContext = SDL_GL_CreateContext(mainWindow);

    if(init()==0)return 0;
    while(loop_utama(&event, lanjut));
    SDL_Quit();
    return 0;
}

Program di atas hanya akan menampilkan window yang berlatar belakang hitam saja. Warna tersebut bisa kalian ganti dengan mengganti "argumen" atau nilai dari 3 parameter pertama function glClearColor(). Warna yang digunakan function tersebut adalah nilai RGB yang bisa bernilai antara 0 hingga 1.

Program di atas belum menampilkan gambar atau objek apapun. Untuk menambahkan gambar, kalian perlu mengganti isi dari function display(). Tapi, sebelumnya, kita akan coba bahas function-function yang ada dalam program di atas.

Function Utama

Fungsi utama dari kode program di atas cukup singkat karena isinya dibagi menjadi beberapa function.

int main(int argc, char** argv){
    int lanjut = 1;
    char *programName = "OpenGL  dengan SDL";
    SDL_Event event;

    if (SDL_Init(SDL_INIT_VIDEO) < 0){
        return 0;
    }

    mainWindow = SDL_CreateWindow(programName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL);
    mainContext = SDL_GL_CreateContext(mainWindow);

    if(init()==0)return 0;
    while(loop_utama(&event, lanjut));
    SDL_Quit();
    return 0;
}

Seperti biasa, untuk menggunakan SDL, kita perlu memanggil function SDL_Init di awal program. Setelah itu, kita perlu membuat windownya dengan SDL_CreateWindow(). Bedanya, kali ini kita juga perlu menggunakan SDL_GL_CreateContext() untuk menentukan window yang akan digunakan openGL.

Inisiasi OpenGL

Sebelum kalian menggunakan OpenGL, kalian perlu mengatur atribut dan melakukan inisiasi. Dalam program yang akan saya berikan di sini, pengaturan atribut dan inisiasi OpenGL saya satukan di function init. Function init() dipanggil dari function utama program setelah function SDL_CreateWindow() dan SDL_GL_CreateContext(). Function init() yang akan kita gunakan minimal seperti di bawah ini.

int init(){
    //Set atribut

	// Set versi OpenGL yg digunakan
	// SDL_GL_CONTEXT_CORE akan memberikan versi terbaru, fungsi yang deprecated tidak akan digunakan
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

	// Kita akan coba menggunakan versi 3.2
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

	// Nyalakan double buffering dengan 24bit Z buffer.
	// Jika perlu, ganti ke 16 atau 32 sesuai sistem yang digunakan
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); //mungkin bisa diabaikan

	//Set interval untuk swap
	SDL_GL_SetSwapInterval(1);

    //Mulai inisialisasi openGL
    glClearColor(0.0, 0.0, 0.0, 1.0);  //background color dan alpha
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, 640.0/480.0, 1.0, 500.0);//Perspektif, dan jarak
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_DEPTH_TEST);//Izinkan openGL melakukan Depth Test untuk objek 3D
    return 1;
}

Loop Utama

Setelah inisialisasi dan pembuatan window berhasil, loop (dengan menggunakan while) akan dimulai. Loopnya terlihat singkat karena isinya saya ubah menjadi function loop_utama().

int loop_utama(SDL_Event *evt, int lanjut){
    while(SDL_PollEvent(evt)) {
        switch(evt->type) {
            case SDL_QUIT:
                lanjut = 0;
                break;
            case SDL_KEYDOWN:
                switch(evt->key.keysym.sym){
                    case SDLK_ESCAPE:
                        lanjut = 0;
                        break;
                }
                break;
        }
    }

    display();//Buat objek 2d atau 3d
    SDL_GL_SwapWindow(mainWindow);//Perbarui tampilan
    return lanjut;
}

Function di atas berisi penanganan event dan juga pemanggilan function display(). Jika kalian memang sudah cukup paham dasar dari library SDL, kalian seharusnya mengetahui dari potongan kode program di atas bahwa program akan berakhir jika tombol ESC ditekan.

 

Menampilkan Bentuk Bangun Datar 2D dengan OpenGL

Untuk menampilkan bentuk bangun datar seperti segitiga dan segi empat kita bisa menggunakan sekumpulan glVertex2f atau glverted2d yang diapit function glBegin() dan glEnd(). Isi parameter dari glBegin akan menentukan bentuk yang ditampilan berdasarkan koordinat(x dan y) dalam glVertex2f() atau glVertex2d(). Sebelum pembuatan bentuk tertentu, kita perlu menggunakan glColor3f() untuk menentukan warnanya berdasarkan nilai warna RGB.

Supaya lebih mudah, gunakan saja kode program sebelumnya. Ubah function display-nya sehingga jadi seperti di bawah ini.
void display(){
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//Bersihkan layar
    glLoadIdentity();//Memuat (ulang) "informasi" dari openGL

    glTranslatef(0.0, 0.0, -2.0);//Ubah posisi / Sudut pandang
    //glRotatef(30, 1.0, 1.0, 1.0);//Rotasi tampilan

    //Mulai menggambar ... ????
    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_TRIANGLES);
        glVertex2f(0.5, -0.5);
        glVertex2f(-0.5, -0.5);
        glVertex2f(0.0, 0.5);
    glEnd();
}

Function display() di atas hanya akan menampilkan segitiga dengan warna kuning. Jarak pandang segitiga tersebut bisa ditentukan dengan parameter ketiga pada function glTranslatef(). Function tersebut akan dipanggil dalam loop di fungsi utama program.

Untuk bisa menggunakan OpenGL, kalian perlu meletakkan function SDL_GL_SwapWindow() setelah pemanggilan function display() dalam "loop utama program".

Konstanta yang digunakan dalam glBegin menentukan berapa "vertex" yang akan dihubungkan untuk membentuk satu atau sekumpulan bangun datar. Beberapa konstanta yang bisa kalian gunakan sebagai parameter dalam glBegin, yaitu :

  • GL_TRIANGLES : Bentuk segitiga
  • GL_QUADS : Bentuk segi empat.
  • GL_LINE_LOOP : rangkaian garis (tertutup).
  • GL_POINTS
  • GL_LINES
  • GL_LINE_STRIP
  • GL_TRIANGLE_STRIP
  • GL_TRIANGLE_FAN
  • GL_QUAD_STRIP
  • GL_POLYGON : Bentuk poligon

Sebelum menggunakan glBegin kalian perlu mengubah warna bangun datar yang kalian tampilkan dengan menggunakan function glColor3f() yang nilainya mewakili warna RGB. Berbeda dengan HTML atau program pengedit foto yang menggunakan nilai antara 0 sampai dengan 255, openGL menggunakan nilai pecahan desimal antara 0 hingga 1.

Menampilkan Bentuk Bangun Ruang

Jika kalian ingin menampilkan bangun ruang, kalian perlu menggunakan beberapa segitiga, persegi atau poligon sebagai sisi-sisi bangun ruang tersebut. Untuk kode program selanjutnya, isi function display() perlu kalian ubah supaya jadi seperti di bawah ini.

void display(){
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glTranslatef(0.0, 0.0,-2.0);
    glRotatef(-60, 1.0, 1.0, 0.0);

    glColor3f(0.0, 1.0, 0.0);
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(0.0, -0.5, 0.0);
        glVertex3f(-0.5, -0.5, 0.0);
        glVertex3f(-0.5, 0.0, 0.0);

    glColor3f(1.0, 0.0, 0.0);
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, -0.5);
        glVertex3f(0.0, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, -0.5);
        glVertex3f(-0.5, 0.0, -0.5);
    glEnd();

    glColor3f(0.0, 0.0, 1.0);
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(0.0, 0.0, -0.5);
        glVertex3f(0.0, -0.5, -0.5);
        glVertex3f(0.0, -0.5, 0.0);

    glColor3f(0.0, 1.0, 1.0);
    glBegin(GL_QUADS);
        glVertex3f(-0.5, 0.0, 0.0);
        glVertex3f(-0.5, 0.0, -0.5);
        glVertex3f(-0.5, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, 0.0);
    glEnd();

    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_QUADS);
        glVertex3f(0.0, -0.5, 0.0);
        glVertex3f(0.0, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, 0.0);
    glEnd();

    glColor3f(1.0, 0.0, 1.0);
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(0.0, 0.0, -0.5);
        glVertex3f(-0.5, 0.0, -0.5);
        glVertex3f(-0.5, 0.0, 0.0);
    glEnd();
}

Selain mengubah isi function display, kalian juga perlu memperhatikan bahwa glEnable(GL_DEPTH_TEST) akan diperlukan jika kita menampilkan bentuk 3D sehingga bisa sesuai dengan apa yang seharusnya ingin kita tampilkan. Hasil dari program utuhnya seharusnya adalah bentuk kubus yang sudah diputar dengan function glRotatef().

 

Animasi?

Untuk membuat objek dalam openGL bergerak, kalian bisa mengunakan SDL_GetTicks atau timer yang tersedia di OpenGL. Saya tidak akan membahasnya terlalu detail karena tulisan ini sudah cukup panjang. Saya hanya akan memberikan contoh programnya yang bisa kalian analisa sendiri.

#include <SDL2/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>

#define GL3_PROTOTYPES 1
#define FPS 30
#define rotasi 1

SDL_Window *mainWindow;
SDL_GLContext mainContext;
struct informasi{
    int sudut;
};

int init(){
    //Set atribut

	// Set versi OpenGL yg digunakan
	// SDL_GL_CONTEXT_CORE akan memberikan versi terbaru, fungsi yang deprecated tidak akan digunakan
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

	// Kita akan coba menggunakan versi 3.2
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

	// Nyalakan double buffering dengan 24bit Z buffer.
	// Jika perlu, ganti ke 16 atau 32 sesuai sistem yang digunakan
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); //mungkin bisa diabaikan

	//Set interval untuk swap
	SDL_GL_SetSwapInterval(1);

    //Mulai inisialisasi openGL
    glClearColor(0.0,0.0,0.0,1.0);  //background color dan alpha
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, 640.0/480.0,1.0,500.0);//Perspektif dan jarak
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_DEPTH_TEST);//Izinkan openGL melakukan Depth Test untuk objek 3D
    return 1;
}

void display(int sudut){
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//Bersihkan layar
    glLoadIdentity();//Memuat (ulang) "informasi" dari openGL

    glTranslatef(0.3, 0.3, -2.0);//Ubah posisi / Sudut pandang (x dan z saja)
    glRotatef(sudut, 1.0, 1.0, 1.0);//Rotasi tampilan
    //Mulai menggambar ... ????

    glColor3f(0.0, 1.0, 0.0);//hijau:depan
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(0.0, -0.5, 0.0);
        glVertex3f(-0.5, -0.5, 0.0);
        glVertex3f(-0.5, 0.0, 0.0);

    glColor3f(1.0, 0.0, 0.0);//merah:belakang
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, -0.5);
        glVertex3f(0.0, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, -0.5);
        glVertex3f(-0.5, 0.0, -0.5);
    glEnd();

    glColor3f(0.0, 0.0, 1.0);//biru:kanan
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(0.0, 0.0, -0.5);
        glVertex3f(0.0, -0.5, -0.5);
        glVertex3f(0.0, -0.5, 0.0);

    glColor3f(0.0, 1.0, 1.0);//cyan:kiri
    glBegin(GL_QUADS);
        glVertex3f(-0.5, 0.0, 0.0);
        glVertex3f(-0.5, 0.0, -0.5);
        glVertex3f(-0.5, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, 0.0);
    glEnd();

    glColor3f(1.0, 1.0, 0.0);//kuning:bawah
    glBegin(GL_QUADS);
        glVertex3f(0.0, -0.5, 0.0);
        glVertex3f(0.0, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, -0.5);
        glVertex3f(-0.5, -0.5, 0.0);
    glEnd();

    glColor3f(1.0, 0.0, 1.0);//magenta:atas
    glBegin(GL_QUADS);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(0.0, 0.0, -0.5);
        glVertex3f(-0.5, 0.0, -0.5);
        glVertex3f(-0.5, 0.0, 0.0);
    glEnd();
}

int loop_utama(SDL_Event *evt, int lanjut, struct informasi *info){
int mulai=SDL_GetTicks();
    while(SDL_PollEvent(evt)) {
        switch(evt->type) {
            case SDL_QUIT:
                lanjut = 0;
                break;
            case SDL_KEYDOWN:
                switch(evt->key.keysym.sym){
                    case SDLK_ESCAPE:
                        lanjut = 0;
                        break;
                }
                break;
        }
    }

    display(info->sudut);//Buat objek 2d / 3d
    SDL_GL_SwapWindow(mainWindow);//Perbarui tampilan

    info->sudut += rotasi;
    if(info->sudut > 360)
        info->sudut -= 360;
    if(1000/FPS > SDL_GetTicks()-mulai)
        SDL_Delay(1000/FPS-(SDL_GetTicks()-mulai));

    return lanjut;
}

int main(int argc, char** argv){
    int lanjut = 1;
    char *programName = "OpenGL  dengan SDL";
    SDL_Event event;
    struct informasi info;

    if (SDL_Init(SDL_INIT_VIDEO) < 0){
        return 0;
    }

    mainWindow = SDL_CreateWindow(programName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL);
    mainContext = SDL_GL_CreateContext(mainWindow);

    if(init()==0)return 0;
    while(loop_utama(&event, lanjut, &info));
    SDL_Quit();
    return 0;
}

Untuk kalian yang masih malah mengetik atau bahkan copas kode program di atas, kalian bisa mendownload kode programnya di sini.