Jumat, 22 Mei 2015

Pemrograman Grafik OpenGL 3D dengan Empty Project VS 2013 Express

Hari masih pagi, tapi ngak pagi bener, udah jam 8 nyamuk-nyamuk udah pada ngumpet

Salam Sejahterah dan terima kasih kepada rekan-rekan yang mau membaca artikel ini.

Hari ini kita akan belajar tentang pemrograman grafik 3D OpenGL dengan menggunakan Empty Project, bagi rekan-rekan yang belum bisa membuat Empty Project bisa klik link ini. Kenapa harus Empty Project? Karena dengan Empty Project rekan-rekan bisa membuat program dengan lebih leluasa dibandingkan dengan Win32 Console Application.


Sekarang kita langsung saja yah bahas programnya, program yang akan kita pelajari akan menampilkan objek 3D bujur sangkar  berwarna merah dan hijau seperti gambar di atas.

Pertama kali rekan-rekan harus membuat Empty Project lalu tambahkan kode-kode dibawah ini.

Pasang ini nih sebagai pembukaan.

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

Jangan lupa pasang juga header yang dibutuhkan, ini harus lho kalo ngak VC++ nya ngambek dan terjadilah error.

//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

Tambahkan Library yang digunakan untuk program OpenGL, jangan protes lho ini untuk kebaikan bersama, tapi tambah-tambah terus ngak bayar, coba kalo nambah di warung nasi pasti bayar 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

Nah berikutnya ada 4 fungsi yang harus ada di program OpenGL dengan Empty Project, 4 fungsi harus rekan-rekan pasang jangan sampe lupa, kalo lupa tanggung sendiri akibatnya.

Fungsi pertama, agak ribet memang tapi rekan-rekan harus tetap semangat untuk mempelajarinya.

//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;
}

Yang kedua ngak boleh ketinggalan.

//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();

        //memakai pandangan 3D perspektif
        gluPerspective(45.0, (GLfloat)lebar_window_Screen / (GLfloat)tinggi_window_Screen, 1.0, 1000.0);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

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

        //perhitungan depth buffer diaktifkan
        glEnable(GL_DEPTH_TEST);

        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));
}

Yang ketiga dan ngak kalah pentingnya.

//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);
}

Terakhir untuk menampilkan objek 3D ke layar monitor.

//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
    //...........................
    //mundurkan objek sebanyak 5 satuan
    //ke arah sumbu -Z
    glTranslatef(0.0f, 0.0f, -5.0f);
    glRotatef(Sudut_Putar, 1.0f, 1.0f, 0.0f);

    Sudut_Putar += 0.1f;
    if (Sudut_Putar > 360.0f)
        Sudut_Putar = 0.0f;

    //Kotak 1 warna merah
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_LINE_LOOP);
    //titik kiri bawah
    glVertex3f(-1.0f, -1.0f, 1.0f);
    //titik kanan bawah
    glVertex3f(1.0f, -1.0f, 1.0f);
    //titik kanan atas
    glVertex3f(1.0f, 1.0f, 1.0f);
    //titik kiri atas
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();

    //Kotak 2 warna hijau
    glColor3f(0.0f, 1.0f, 0.0f);
    glBegin(GL_LINE_LOOP);
    //titik kiri bawah
    glVertex3f(-1.0f, -1.0f, -1.0f);
    //titik kanan bawah
    glVertex3f(1.0f, -1.0f, -1.0f);
    //titik kanan atas
    glVertex3f(1.0f, 1.0f, -1.0f);
    //titik kiri atas
    glVertex3f(-1.0f, 1.0f, -1.0f);
    glEnd();

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

Jika rekan-rekan ingin kode program secara lengkap, dapat di copy paste di bawah  ini nih, ngak usah repot-repot bayar gratis koq dan terserah rekan-rekan mau cantumin author ato tidak, tidak ada paksaan.

//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;

float Sudut_Putar = 0.0f;

//+++++++++++++++++++++++++++++++++++++++++++
//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();

        //memakai pandangan 3D perspektif
        gluPerspective(45.0, (GLfloat)lebar_window_Screen / (GLfloat)tinggi_window_Screen, 1.0, 1000.0);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

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

        //perhitungan depth buffer diaktifkan
        glEnable(GL_DEPTH_TEST);

        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
    //...........................
    //mundurkan objek sebanyak 5 satuan
    //ke arah sumbu -Z
    glTranslatef(0.0f, 0.0f, -5.0f);
    glRotatef(Sudut_Putar, 1.0f, 1.0f, 0.0f);

    Sudut_Putar += 0.1f;
    if (Sudut_Putar > 360.0f)
        Sudut_Putar = 0.0f;

    //Kotak 1 warna merah
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_LINE_LOOP);
    //titik kiri bawah
    glVertex3f(-1.0f, -1.0f, 1.0f);
    //titik kanan bawah
    glVertex3f(1.0f, -1.0f, 1.0f);
    //titik kanan atas
    glVertex3f(1.0f, 1.0f, 1.0f);
    //titik kiri atas
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();

    //Kotak 2 warna hijau
    glColor3f(0.0f, 1.0f, 0.0f);
    glBegin(GL_LINE_LOOP);
    //titik kiri bawah
    glVertex3f(-1.0f, -1.0f, -1.0f);
    //titik kanan bawah
    glVertex3f(1.0f, -1.0f, -1.0f);
    //titik kanan atas
    glVertex3f(1.0f, 1.0f, -1.0f);
    //titik kiri atas
    glVertex3f(-1.0f, 1.0f, -1.0f);
    glEnd();

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

Bagaimana hasilnya, mudah kan, sampai dengan tahap ini rekan-rekan sudah maju satu langkah lagi, dan tinggal nunggu waktu rekan-rekan jadi ahli kalo sudah jadi ahli jangan lupa ya kasih contoh-contoh programnya ke ogut, biar ogut juga bisa belajar.


Salam Sukses


Heriady
heriady.yoh@gmail.com


Link source code program dapat rekan-rekan download disini


Artikel terkait
Cara membuat Empty Project
Program OpenGL 3D sederhana untuk pemula