Jumat, 22 Mei 2015

Belajar Pemrograman Grafik / Game OpenGL 2D

Hari masih pagi dan matahari mulai bersinar, wah hari ini cerah tidak mendung

Pagi semua...

Setelah kita belajar cara untuk membuat Empty Project pada Visual Studio 2013 sekarang saatnya rekan-rekan belajar cara membuat program grafik OpenGL dengan menggunakan Empty Project.

Bagi rekan-rekan yang baru pertama kali membuat program grafik dengan OpenGL ogut sarankan untuk memulai dari Win32 Console Application, karena program nya sangat sederhana dan lebih mudah dipelajari (tidak bermaksud merendahkan lho, hanya saran saja).

Ok kita mulai sekarang, program yang akan kita buat akan menghasilkan tampilan seperti gambar di bawah ini. Sederhana bukan? Akan tampil sebuah kotak dan sebuah garis.


Pertama kali Anda harus membuat Empty Project di Visual Studio 2013, lalu tambahkan kode-kode berikut ini.

Pasang ini di program rekan-rekan, gunanya tinggal baca (semua kan udah pinter membaca...hehehe).

//berguna untuk memangkas library
//yang tidak terpakai
#define WIN32_LEAN_AND_MEAN    
#define VC_LEANMEAN    
#define VC_EXTRALEAN

Header juga harus di tambahkan (ini permintaan VC++ lho, bukan aku yang minta, jadi rekan-rekan jangan marah yah).

//include yang harus disertakan
#include<windows.h>
#include<stdio.h>          
#include<stdlib.h>
#include<mmsystem.h>

//include khusus OpenGL
#include<gl/gl.h>               
#include<gl/glu.h>
#include "glaux/glaux.h" //header ini ada di dalam folder GLAUX

Habis itu kita tambahin juga Library (supaya adil library juga harus tampil, ntar pada irian lagi).

//library untuk OpenGL
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "GLAUX/glaux.lib") //library ini ada di dalam folder GLAUX

Berikutnya ada 4 fungsi yang harus rekan tambahin, 4 fungsi ini ngak bisa kita diskon, harus ada semuanya, kita belajar satu-satu yah....

Fungsi Pertama, ada keterangannya lho tinggal baca aja, tapi jangan asal baca nanti tidak paham.

//fungsi yang dipanggil pertama kali
//oleh Operating system Windows, pada
//saat program dijalankan
int WINAPI WinMain(HINSTANCE hinstance_p, HINSTANCE hprevinstance_p, LPSTR lpcmdline_p, int nshowcmd_p)
{
    MSG My_MSG;
    WNDCLASSEX My_WNDCLASSEX;
    HWND My_HWND;
    bool My_MainLoop = false;

    //deklarasi variable untuk membuat window
    My_WNDCLASSEX.cbSize = sizeof(WNDCLASSEX);
    My_WNDCLASSEX.style = CS_HREDRAW | CS_VREDRAW;

    //My_WindowProc adalah fungsi yang kita buat
    //untuk memproses message-message,
    //fungsi ini yang terus menerus akan dipanggil
    //oleh fungsi WinMain, sehingga harus kita
    //daftarkan di bawah ini
    My_WNDCLASSEX.lpfnWndProc = My_WindowProc;

    My_WNDCLASSEX.cbClsExtra = 0;
    My_WNDCLASSEX.cbWndExtra = 0;
    My_WNDCLASSEX.hInstance = hinstance_p;
    My_WNDCLASSEX.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    My_WNDCLASSEX.hCursor = LoadCursor(NULL, IDC_WAIT);
    My_WNDCLASSEX.hbrBackground = NULL;
    My_WNDCLASSEX.lpszMenuName = NULL;
    My_WNDCLASSEX.lpszClassName = "MyOpenGL";
    My_WNDCLASSEX.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

    //register window Class
    //jika terjadi error program dihentikan
    if (!RegisterClassEx(&My_WNDCLASSEX))
    {
        MessageBox(NULL,
            "Register Window Class Failed", "Window Error", MB_OK);
        return 0;
    }

    //jika register window class berhasil
    //lanjutkan dengan create window
    My_HWND = CreateWindowEx(
        NULL,
        "MyOpenGL",
        "Heriady Blog heriadyblog.blogspot.com (Esc to quit)",
        NULL,
        X_window_Screen,
        Y_window_Screen,
        lebar_window_Screen,
        tinggi_window_Screen,
        NULL,
        NULL,
        hinstance_p,
        NULL);

    //jika window tidak bisa di-create
    //program dihentikan
    if (!My_HWND)
    {
        MessageBox(NULL,
            "Failed to Create Window", "Window Error", MB_OK);
        return 0;
    }

    //jika window bisa di-create
    //tampilkan window ke monitor
    ShowWindow(My_HWND, SW_SHOW);
    UpdateWindow(My_HWND);

    //Looping utama
    while (!My_MainLoop)
    {
        //proses message dari antrian
        PeekMessage(&My_MSG, 0, 0, 0, PM_REMOVE);

        //selama tidak ada message 'Quit'
        //looping akan terus berjalan
        if (My_MSG.message != WM_QUIT)
        {
            //panggil fungsi untuk render window
            //disini
            Display_Grafik();

            //translate Virtual key message,
            //menjadi chararcter message dan
            //buang message yang sudah diproses
            TranslateMessage(&My_MSG);
            DispatchMessage(&My_MSG);
        }
        else
            //jika message = 'Quit'
            //keluar dari looping
            My_MainLoop = true;


    } //while (!My_MainLoop)

    //unregister window class
    UnregisterClass("MyOpenGL", My_WNDCLASSEX.hInstance);

    //akhiri program
    return (int)My_MSG.wParam;
}

Fungsi Kedua, nih juga ada keterangannya, jika sulit untuk dipahami sabar aja, orang sabar di sayang ama Tuhan.

//fungsi yang dipanggil oleh WinMain
//untuk memproses message-message
LRESULT CALLBACK My_WindowProc(HWND hwnd_p, UINT message_p, WPARAM wparam_p, LPARAM lparam_p)
{
    static HGLRC My_HGLRC;
    static HDC My_HDC;

    //pada saat window dibuat pertama kali
    //kondisi if di bawah memenuhi
    if (message_p == WM_CREATE)
    {
        My_HDC = GetDC(hwnd_p);
        My_HDC_Global = My_HDC;

        //pada saat pertama kali dibuat 
        //window screen harus di setup pixel
        //agar bisa dibuat untuk tampilan grafik
        Window_Pixel_Format(My_HDC);

        My_HGLRC = wglCreateContext(My_HDC);
        wglMakeCurrent(My_HDC, My_HGLRC);

        return 0;
    }

    //pada saat program hendak keluar
    //kondisi if di bawah memenuhi
    if (message_p == WM_DESTROY)
    {
        wglMakeCurrent(My_HDC, NULL);
        wglDeleteContext(My_HGLRC);
        PostQuitMessage(0);

        return 0;
    }

    //untuk saat window dibuat pertama kali atau
    //window diubah ukurannya.
    //pada program ini ukuran window
    //tidak bisa diubah, tetapi kondisi if
    //di bawah harus tetap di pasang
    if (message_p == WM_SIZE)
    {
        //fungsi OpenGL untuk set
        //tinggi dan lebar window screen
        glViewport(0, 0, lebar_window_Screen, tinggi_window_Screen);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        //fungsi untuk membuat sistem
        //koordinat kartesius 2D
        // -X = -800, X = +800 dan,
        // -Y = -600, Y = +600
        gluOrtho2D(-Xmax, Xmax, -Ymax, Ymax);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        //warna latar belakang hitam
        glClearColor(0.0, 0.0, 0.0, 0.0);

        return 0;
    }

    //tombol ESC ditekan
    //untuk keluar dari program
    if ((message_p == WM_KEYDOWN) && (wparam_p == VK_ESCAPE))
    {
        //fungsi untuk mengirimkan
        //message WM_QUIT
        PostQuitMessage(0);

        return 0;
    }

    //return kembali nilai LRESULT
    return (DefWindowProc(hwnd_p, message_p, wparam_p, lparam_p));
}

Fungsi ketiga, ribet ya banyak angka-angka, ngak usah dihapalin, ogut juga ngak hapal sama fungsi ini, yang penting ngerti.

//fungsi untuk setup pixel, yang
//dipakai untuk program grafik,
//fungsi ini harus ada jika hendak membuat
//program grafik
void Window_Pixel_Format(HDC hdc_GPF_p)
{
    int My_Pixel_Format;

    static PIXELFORMATDESCRIPTOR My_PFD =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW |
        PFD_SUPPORT_OPENGL |
        PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        16,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,
        16,
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };

    My_Pixel_Format = ChoosePixelFormat(hdc_GPF_p, &My_PFD);

    SetPixelFormat(hdc_GPF_p, My_Pixel_Format, &My_PFD);
}

Dan yang terakhir fungsi untuk menampilan objek grafik ke layar monitor, selesai deh semuanya. Pemrograman dengan Empty Project emang lebih panjang, tetapi percayalah, ini lebih berguna jika rekan-rekan ingin naik ke tingkat selajutnya.

//fungsi yang dipakai untuk menampilkan
//semua object(Polygon) yang akan kita buat
//pada window screen
void Display_Grafik()
{
    //clear buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    //...........................
    //display object  di sini
    //...........................

    //Kotak
    glBegin(GL_LINE_LOOP);
    //titik kiri bawah
    glVertex2d(-300.0, -100.0);
    //titik kanan bawah
    glVertex2d(200.0, -100.0);
    //titik kanan atas
    glVertex2d(200.0, 100.0);
    //titik kiri atas
    glVertex2d(-300.0, 100.0);
    glEnd();

    //garis miring
    glBegin(GL_LINE_LOOP);
    //titik atas
    glVertex2d(300.0, 400.0);
    //titik bawah
    glVertex2d(400.0, -200.0);
    glEnd();

    //fungsi swapbuffer harus dipasang pada akhir Display_Grafik()
    SwapBuffers(My_HDC_Global);
}

Selamat deh untuk rekan-rekan karena telah melewati babak berikutnya, ini ogut sertakan kode program nya secara lengkap, bisa copy paste dan terserah rekan-rekan mau kasih author ato tidak ngak dosa koq.

//berguna untuk memangkas library
//yang tidak terpakai
#define WIN32_LEAN_AND_MEAN    
#define VC_LEANMEAN    
#define VC_EXTRALEAN       

//include yang harus disertakan
#include<windows.h>
#include<stdio.h>          
#include<stdlib.h>
#include<mmsystem.h>

//include khusus OpenGL
#include<gl/gl.h>               
#include<gl/glu.h>
#include "glaux/glaux.h" //header ini ada di dalam folder GLAUX

//library untuk OpenGL
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "GLAUX/glaux.lib") //library ini ada di dalam folder GLAUX

//Variable global yang dipakai untuk program ini
HDC My_HDC_Global;

//set tinggi dan lebar untuk window screen
unsigned int tinggi_window_Screen = 600;
unsigned int lebar_window_Screen = 800;

//penempatan posisi window screen di monitor
unsigned int X_window_Screen = 150;
unsigned int Y_window_Screen = 50;

//berguna untuk setup pixel
//dengan sistem koordinat kartesius 2D
double Xmax = 800.0;
double Ymax = 600.0;

//+++++++++++++++++++++++++++++++++++++++++++
//untuk membuat program grafik dengan OpenGL
//hanya dibutuhkan empat buah fungsi, dengan
//WinMain sebagai fungsi utama (WinMain 1 fungsi tambah 3 fungsi dibawah ini jadi 4 semuanya)
LRESULT CALLBACK My_WindowProc(HWND hwnd_p, UINT message_p, WPARAM wparam_p, LPARAM lparam_p);
void Window_Pixel_Format(HDC hdc_GPF_p);
void Display_Grafik();

//+++++++++++++++++++++++++++++++++++++++++++

//fungsi yang dipanggil pertama kali
//oleh Operating system Windows, pada
//saat program dijalankan
int WINAPI WinMain(HINSTANCE hinstance_p, HINSTANCE hprevinstance_p, LPSTR lpcmdline_p, int nshowcmd_p)
{
    MSG My_MSG;
    WNDCLASSEX My_WNDCLASSEX;
    HWND My_HWND;
    bool My_MainLoop = false;

    //deklarasi variable untuk membuat window
    My_WNDCLASSEX.cbSize = sizeof(WNDCLASSEX);
    My_WNDCLASSEX.style = CS_HREDRAW | CS_VREDRAW;

    //My_WindowProc adalah fungsi yang kita buat
    //untuk memproses message-message,
    //fungsi ini yang terus menerus akan dipanggil
    //oleh fungsi WinMain, sehingga harus kita
    //daftarkan di bawah ini
    My_WNDCLASSEX.lpfnWndProc = My_WindowProc;

    My_WNDCLASSEX.cbClsExtra = 0;
    My_WNDCLASSEX.cbWndExtra = 0;
    My_WNDCLASSEX.hInstance = hinstance_p;
    My_WNDCLASSEX.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    My_WNDCLASSEX.hCursor = LoadCursor(NULL, IDC_WAIT);
    My_WNDCLASSEX.hbrBackground = NULL;
    My_WNDCLASSEX.lpszMenuName = NULL;
    My_WNDCLASSEX.lpszClassName = "MyOpenGL";
    My_WNDCLASSEX.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

    //register window Class
    //jika terjadi error program dihentikan
    if (!RegisterClassEx(&My_WNDCLASSEX))
    {
        MessageBox(NULL,
            "Register Window Class Failed", "Window Error", MB_OK);
        return 0;
    }

    //jika register window class berhasil
    //lanjutkan dengan create window
    My_HWND = CreateWindowEx(
        NULL,
        "MyOpenGL",
        "Heriady Blog heriadyblog.blogspot.com (Esc to quit)",
        NULL,
        X_window_Screen,
        Y_window_Screen,
        lebar_window_Screen,
        tinggi_window_Screen,
        NULL,
        NULL,
        hinstance_p,
        NULL);

    //jika window tidak bisa di-create
    //program dihentikan
    if (!My_HWND)
    {
        MessageBox(NULL,
            "Failed to Create Window", "Window Error", MB_OK);
        return 0;
    }

    //jika window bisa di-create
    //tampilkan window ke monitor
    ShowWindow(My_HWND, SW_SHOW);
    UpdateWindow(My_HWND);

    //Looping utama
    while (!My_MainLoop)
    {
        //proses message dari antrian
        PeekMessage(&My_MSG, 0, 0, 0, PM_REMOVE);

        //selama tidak ada message 'Quit'
        //looping akan terus berjalan
        if (My_MSG.message != WM_QUIT)
        {
            //panggil fungsi untuk render window
            //disini
            Display_Grafik();

            //translate Virtual key message,
            //menjadi chararcter message dan
            //buang message yang sudah diproses
            TranslateMessage(&My_MSG);
            DispatchMessage(&My_MSG);
        }
        else
            //jika message = 'Quit'
            //keluar dari looping
            My_MainLoop = true;


    } //while (!My_MainLoop)

    //unregister window class
    UnregisterClass("MyOpenGL", My_WNDCLASSEX.hInstance);

    //akhiri program
    return (int)My_MSG.wParam;
}

//fungsi yang dipanggil oleh WinMain
//untuk memproses message-message
LRESULT CALLBACK My_WindowProc(HWND hwnd_p, UINT message_p, WPARAM wparam_p, LPARAM lparam_p)
{
    static HGLRC My_HGLRC;
    static HDC My_HDC;

    //pada saat window dibuat pertama kali
    //kondisi if di bawah memenuhi
    if (message_p == WM_CREATE)
    {
        My_HDC = GetDC(hwnd_p);
        My_HDC_Global = My_HDC;

        //pada saat pertama kali dibuat 
        //window screen harus di setup pixel
        //agar bisa dibuat untuk tampilan grafik
        Window_Pixel_Format(My_HDC);

        My_HGLRC = wglCreateContext(My_HDC);
        wglMakeCurrent(My_HDC, My_HGLRC);

        return 0;
    }

    //pada saat program hendak keluar
    //kondisi if di bawah memenuhi
    if (message_p == WM_DESTROY)
    {
        wglMakeCurrent(My_HDC, NULL);
        wglDeleteContext(My_HGLRC);
        PostQuitMessage(0);

        return 0;
    }

    //untuk saat window dibuat pertama kali atau
    //window diubah ukurannya.
    //pada program ini ukuran window
    //tidak bisa diubah, tetapi kondisi if
    //di bawah harus tetap di pasang
    if (message_p == WM_SIZE)
    {
        //fungsi OpenGL untuk set
        //tinggi dan lebar window screen
        glViewport(0, 0, lebar_window_Screen, tinggi_window_Screen);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        //fungsi untuk membuat sistem
        //koordinat kartesius 2D
        // -X = -800, X = +800 dan,
        // -Y = -600, Y = +600
        gluOrtho2D(-Xmax, Xmax, -Ymax, Ymax);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        //warna latar belakang hitam
        glClearColor(0.0, 0.0, 0.0, 0.0);

        return 0;
    }

    //tombol ESC ditekan
    //untuk keluar dari program
    if ((message_p == WM_KEYDOWN) && (wparam_p == VK_ESCAPE))
    {
        //fungsi untuk mengirimkan
        //message WM_QUIT
        PostQuitMessage(0);

        return 0;
    }

    //return kembali nilai LRESULT
    return (DefWindowProc(hwnd_p, message_p, wparam_p, lparam_p));
}

//fungsi untuk setup pixel, yang
//dipakai untuk program grafik,
//fungsi ini harus ada jika hendak membuat
//program grafik
void Window_Pixel_Format(HDC hdc_GPF_p)
{
    int My_Pixel_Format;

    static PIXELFORMATDESCRIPTOR My_PFD =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW |
        PFD_SUPPORT_OPENGL |
        PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        16,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,
        16,
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };

    My_Pixel_Format = ChoosePixelFormat(hdc_GPF_p, &My_PFD);

    SetPixelFormat(hdc_GPF_p, My_Pixel_Format, &My_PFD);
}

//fungsi yang dipakai untuk menampilkan
//semua object(Polygon) yang akan kita buat
//pada window screen
void Display_Grafik()
{
    //clear buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    //...........................
    //display object  di sini
    //...........................

    //Kotak
    glBegin(GL_LINE_LOOP);
    //titik kiri bawah
    glVertex2d(-300.0, -100.0);
    //titik kanan bawah
    glVertex2d(200.0, -100.0);
    //titik kanan atas
    glVertex2d(200.0, 100.0);
    //titik kiri atas
    glVertex2d(-300.0, 100.0);
    glEnd();

    //garis miring
    glBegin(GL_LINE_LOOP);
    //titik atas
    glVertex2d(300.0, 400.0);
    //titik bawah
    glVertex2d(400.0, -200.0);
    glEnd();

    //fungsi swapbuffer harus dipasang pada akhir Display_Grafik()
    SwapBuffers(My_HDC_Global);
}

Salam Sukses Selalu buat rekan-rekan, terima kasih telah membaca artikel ini semoga bermanfaat.


Heriady
heriady.yoh@gmail.com


Link download kode program dapat Anda klik disini nih, ngak capek ngetik lagi tinggal run aja


Artikel terkait
Cara Membuat Win32 Console Application
Cara Membuat Empty Project

Program OpenGL 2D Sederhana untuk pemula