Jumat, 13 November 2015

Program OpenGL 3D dengan Developer CPP (DevCPP)

Selamat pagi rekan-rekan sekalian, salam sejahterah selalu, kali ini ogut akan memberikan contoh program OpenGL 3D dengan menggunakan compiler C++, tidak dengan Visual Studio tetapi dengan Dev-C++.



Alternatif bagi rekan-rekan yang ingin belajar membuat program grafik / game, tetapi memiliki hardware yang kurang memadai untuk meng-install Visual Studio. Tujuan ogut membuat postingan ini agar rekan-rekan bisa belajar walaupun resources yang rekan-rekan miliki sangat terbatas.
Program tidak akan ogut bahas secara detail karena program sangat mirip dengan postingan / contoh-contoh program OpenGL 3D yang sudah ogut bahas sebelumnya.
image hasil contoh program dibawah ini


Di bawah ini adalah listing kode program yang ogut buat dengan menggunakan Dev-C++ versi 4.9.9.2, hasil program bila dijalankan akan tampak seperti gambar di atas.

/**************************
 * Includes
 *
 **************************/
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <stdio.h>

/**************************
 * Function Declarations
 *
 **************************/
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC);
void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC);
bool CreateBmpTexture(unsigned int &IDTexture, char *filename);

/**************************
 * WinMain
 *
 **************************/
int WINAPI WinMain (HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine,
                    int iCmdShow)
{
    WNDCLASS wc;
    HWND hWnd;
    HDC hDC;
    HGLRC hRC;        
    MSG msg;
    BOOL bQuit = FALSE;
    float theta = 0.0f;
    
    unsigned int KulitTeko;
    int w = 512, h = 512;

    /* register window class */
    wc.style = CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "GLSample";
    RegisterClass (&wc);

    /* create main window */
    hWnd = CreateWindow (
      "GLSample", "OpenGL Sample", 
      WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
      0, 0, w, h,
      NULL, NULL, hInstance, NULL);

    /* enable OpenGL for the window */
    EnableOpenGL (hWnd, &hDC, &hRC);
    
    //////////////////////////////////////////////////
    glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
    glLoadIdentity();    

    gluPerspective(45.0, (GLfloat)w/(GLfloat)h, 1.0, 1000.0);
    //gluPerspective(45.0, 256.0/256.0, 1.0, 1000.0);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glClearColor (1.0, 1.0, 1.0, 0.0);
    glEnable(GL_DEPTH_TEST); 

//pilihan untuk mengaktifkan penggunaan tekstur
glEnable(GL_TEXTURE_2D); 

//load tekstur
if (!CreateBmpTexture(KulitTeko, "BmpFile/logo Dev-C++.bmp"))
return 0;
    //////////////////////////////////////////////////

    /* program main loop */
    while (!bQuit)
    {
        /* check for messages */
        if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
        {
            /* handle or dispatch messages */
            if (msg.message == WM_QUIT)
            {
                bQuit = TRUE;
            }
            else
            {
                TranslateMessage (&msg);
                DispatchMessage (&msg);
            }
        }
        else
        {
            /* OpenGL animation code goes here */
            glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
            
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
       glLoadIdentity();

            glTranslatef(0.0f, 0.0f, -4.0f);
            glRotatef (theta, 0.0f, 1.0f, 1.0f);
            //sisi belakang
            glBegin (GL_POLYGON);
                glTexCoord2f(0.0f, 0.0f );glVertex3f (-0.75f, -0.5f, -0.75f);
                glTexCoord2f(1.0f, 0.0f); glVertex3f (0.75f, -0.5f, -0.75f);
                glTexCoord2f(1.0f, 1.0f); glVertex3f (0.75f, 0.5f, -0.75f);
                glTexCoord2f(0.0f, 1.0f); glVertex3f (-0.75f, 0.5f, -0.75f);
            glEnd ();
            //sisi depan
            glBegin (GL_LINE_LOOP);
                glVertex3f (-0.75f, -0.5f, 0.75f);
                glVertex3f (0.75f, -0.5f, 0.75f);
                glVertex3f (0.75f, 0.5f, 0.75f);
                glVertex3f (-0.75f, 0.5f, 0.75f);
            glEnd ();
            //sisi kiri
            glBegin (GL_LINE_LOOP);
                glVertex3f (-0.75f, -0.5f, 0.75f);
                glVertex3f (-0.75f, -0.5f, -0.75f);
                glVertex3f (-0.75f, 0.5f, -0.75f);
                glVertex3f (-0.75f, 0.5f, 0.75f);
            glEnd ();
            //sisi kanan
            glBegin (GL_LINE_LOOP);
                glVertex3f (0.75f, -0.5f, 0.75f);
                glVertex3f (0.75f, -0.5f, -0.75f);
                glVertex3f (0.75f, 0.5f, -0.75f);
                glVertex3f (0.75f, 0.5f, 0.75f);
            glEnd ();

            SwapBuffers (hDC);

            theta += 1.0f;
            Sleep (1);
        }
    }

    /* shutdown OpenGL */
    DisableOpenGL (hWnd, hDC, hRC);

    /* destroy the window explicitly */
    DestroyWindow (hWnd);

    return msg.wParam;
}

/********************
 * Window Procedure
 *
 ********************/
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
                          WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
    case WM_CREATE:
        return 0;
    case WM_CLOSE:
        PostQuitMessage (0);
        return 0;

    case WM_DESTROY:
        return 0;

    case WM_KEYDOWN:
        switch (wParam)
        {
        case VK_ESCAPE:
            PostQuitMessage(0);
            return 0;
        }
        return 0;

    default:
        return DefWindowProc (hWnd, message, wParam, lParam);
    }
}

/*******************
 * Enable OpenGL
 *
 *******************/
void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC)
{
    PIXELFORMATDESCRIPTOR pfd;
    int iFormat;

    /* get the device context (DC) */
    *hDC = GetDC (hWnd);

    /* set the pixel format for the DC */
    ZeroMemory (&pfd, sizeof (pfd));
    pfd.nSize = sizeof (pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | 
      PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;
    iFormat = ChoosePixelFormat (*hDC, &pfd);
    SetPixelFormat (*hDC, iFormat, &pfd);

    /* create and enable the render context (RC) */
    *hRC = wglCreateContext( *hDC );
    wglMakeCurrent( *hDC, *hRC );
}

/******************
 * Disable OpenGL
 *
 ******************/
void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC)
{
    wglMakeCurrent (NULL, NULL);
    wglDeleteContext (hRC);
    ReleaseDC (hWnd, hDC);
}

bool CreateBmpTexture(unsigned int &IDTexture, char *filename)
{
FILE *pFile = 0;

BITMAPFILEHEADER BmpFileHeader;
BITMAPINFOHEADER BmpInfoHeader;

unsigned char ChangeToRGB = 0;
unsigned char *BmpData;

//open file
pFile = fopen(filename, "rb");    

if(pFile == 0)
{
MessageBox(NULL, filename, "File Bmp tidak ditemukan", MB_OK);
return false;      
}

//baca data BITMAP FILE HEADER
fread(&BmpFileHeader, sizeof(BITMAPFILEHEADER), 1, pFile);

//periksa bmp ID
if(BmpFileHeader.bfType != 0x4D42)
{
fclose(pFile);

MessageBox(NULL, filename, "Format file bukan Bmp", MB_OK);
return false;
}

//baca data BITMAP INFO HEADER
fread(&BmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, pFile);

//hitung ukuran image bmp 24 bit(3 byte)
if(BmpInfoHeader.biSizeImage == 0)
BmpInfoHeader.biSizeImage = BmpInfoHeader.biWidth * BmpInfoHeader.biHeight * 3;

//pindahkan pointer pembacaan data
fseek(pFile, BmpFileHeader.bfOffBits, SEEK_SET);

//siapkan tempat untuk data
BmpData = (unsigned char*)malloc(BmpInfoHeader.biSizeImage);

if(!BmpData)
{
free(BmpData);
fclose(pFile);

MessageBox(NULL, filename, "Alokasi memory gagal untuk texture", MB_OK);
return false;
}

//baca data image(format BGR)
fread(BmpData, 1, BmpInfoHeader.biSizeImage, pFile);

//file tidak digunakan lagi(tutup)
fclose(pFile);

if(BmpData == 0)
{
MessageBox(NULL, filename, "Gagal membaca data Bmp", MB_OK);
return false;
}

//mengubah dari BGR ke RGB

//================================================
//data asal data akhir
//================================================
//BmpData[0] = B BmpData[0] = R
//BmpData[1] = G BmpData[1] = G
//BmpData[2] = R BmpData[2] = B
// ... ...
// ... ...
// ... ...
//BmpData[i] = B BmpData[i] = R
//BmpData[i+1] = G BmpData[i+1]= G
//BmpData[i+2] = R BmpData[i+2]= B

for(int i = 0; i < (int)BmpInfoHeader.biSizeImage; i += 3)
{
ChangeToRGB = BmpData[i];
BmpData[i] = BmpData[i + 2];
BmpData[i + 2] = ChangeToRGB;
}

//OpenGL generate texture
glGenTextures(1, &IDTexture);
   
glBindTexture(GL_TEXTURE_2D, IDTexture);

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, 
BmpInfoHeader.biWidth, 
BmpInfoHeader.biHeight,
GL_RGB, GL_UNSIGNED_BYTE, 
BmpData);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 
BmpInfoHeader.biWidth, 
BmpInfoHeader.biHeight, 
0, GL_RGB, GL_UNSIGNED_BYTE, 
BmpData);
   
free(BmpData);

BmpData = 0;

return true;
}

Demikian rekan-rekan artikel kali ini, sampai jumpa di artikel berikutnya, jangan pernah berhenti untuk belajar, yakin akan tujuan rekan-rekan jika ingin mengejar sesuatu. Don’t Stop Until Finish It...

Update 30 Agustus 2016
Bagi rekan yang ingin alternatif lain, ogut sudah mencoba dan menurut ogut compiler Code Blocks lebih baik dari DevCPP. Untuk mempelajari Code Blocks rekan-rekan dapat klik disini. Ogut juga menulis beberapa artikel tentang Code Blocks.

Salam Hangat


Heriady
heriady.yoh@gmail.com




Artikel terkait

Instalasi DevCPP untuk proyek OpenGL

OpenGL GLUT dengan DevCpp