2012年9月20日 星期四

Create a GLSL based project on Linux

since: 2012/09/20
update: 2012/09/20

reference:
1. OpenGL® Application Binary Interface for Linux
2. Getting Started with the OpenGL Shading Language (GLSL)
3. I touchs: Setting up Eclipse for OpenGL on Linux Mint
4. I touchs: OpenGL: Basic Setup
5. Graphics Shaders: Theory and Practice, 2/e (Hardcover)
6. CSCI 4229/5229: Computer Graphics
     > Fall 2012 > Handouts > Introduction to OpenGL


A. 說明:
      1. 目的: 建立一個可供練習 GLSL 的基本專案架構, 包含 OpenGL 的繪圖流程,
                     shader 的處理(編譯, 附加, 連結, 變數存取....)等.

      2. 開發環境:
           作業系統: Linux Mint (基於 Ubuntu 的另一個 Linux 版本)
           整合開發環境(IDE): Eclipse
           程式語言: C, GLSL

      3. 其它:
           a. 本篇文章是延續上一篇 Setting up Eclipse for OpenGL on Linux Mint 而來,
               一開始, 我先將 Getting Started with the OpenGL Shading Language
               source code 下載下來, 因為是 C++ 專案的原因, 修改了變數轉型的問題
               (參考: OpenGL: Starting with the Shading Language-0), 接著編譯就出現了
               錯誤訊息: 無法解析有關處理 shader 的函式.

           b. 接著, 在終端機下執行:
               $ glxinfo | grep -i opengl
               備註: "shading language version string: 4.30 NVIDIA via Cg compiler
                          看來不是使用原生的 GLSL compiler, 不過我們是用程式去
                          compiler shader, 所以應該不會是問題所在.

           c. 最後, 改成建立 C 專案(而非C++), 並作一些調整, 就可以正常編譯並執行了.

----------------------------------------------------------------------------

B. 新增 Eclipse 專案
      1. 啓動 Eclipse
          Select a workspace > /home/lanli/workspace (預設) > OK

      2. 新增 C 專案:
           step 1:
           File -> New -> C Project (或: Shift+ Alt + N > C Project)

           step 2:
           Project name: GLSL_base
           Project type > Executable: Empty Project
           Toolchains: Cross GCC (或 Linux GCC 亦可)
           > Finish

      3. 專案 Libraries 設定:
           1. 滑鼠右鍵點選
               > Project Explorer 下的專案名稱(此處為: GLSL_base)
               > Properties
       
           2. C/C++ Build > Settings
               Cross GCC Linker > Libraries
               利用 "+" 新增以下的 Libraries: glut, GL, GLU
               > OK

----------------------------------------------------------------------------

C. 加入用來處理 shader 的檔案
     1. 下載 glsl_lighting-1.tar.gz 解壓縮後, 將 opengl.hshader.c 複製到
         專案目錄下(在此為: /home/lanli/workspace/GLSL_base)

     2.Eclipse 中, 點選此專案, 按下 "F5" 鍵來 Refresh, 使剛加入的檔案
         出現在專案目錄裡.

     3. 開啟 opengl.h 檔案, 修改如下:
#ifndef __OPENGL_H__
#define __OPENGL_H__


#define LINUX
//#define APPLE

#ifdef LINUX
    #define GL_GLEXT_PROTOTYPES
    #include <GL/glut.h>
#else


    #ifdef APPLE
        #include <OpenGL/gl.h>
        #include <OpenGL/glext.h>
        #include <GLUT/glut.h>
    #else
        #include <GL/gl.h>
        #include <GL/glext.h>
        #include <GL/glut.h>
    #endif /* APPLE */


#endif /* LINUX */

#endif /* __OPENGL_H__ */


說明: 主要修改 Linux 的部分:
           a. 要先定義: GL_GLEXT_PROTOTYPES
           b. 只需引入: <GL/glut.h>

----------------------------------------------------------------------------

D. 新增公用函式

     1. File -> New -> Source File
         Source file: utility.c
         Template: <Default C source template><None>
          > Finish

     2. 開啟 utility.c 檔案, 修改如下:
/*
 * utility.c
 *
 *  Created on: 2012/9/13
 *      Author: lanli
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "opengl.h"


// 用來檢查 OpenGL 可能發生的錯誤問題

void checkGLErrors(const char* caller);


/*********************************************/

void checkGLErrors(const char* caller)
{
    unsigned int gle = glGetError();
    if(gle != GL_NO_ERROR)
    {
        fprintf(stderr, "GL Error discovered from caller %s: ", caller);

        switch (gle)
        {
            case GL_INVALID_ENUM:
                fprintf(stderr, "Invalid enum.\n");
                break;

            case GL_INVALID_VALUE:
                fprintf(stderr, "Invalid value.\n");
                break;

            case GL_INVALID_OPERATION:
                fprintf(stderr, "Invalid Operation.\n");
                break;

            case GL_STACK_OVERFLOW:
                fprintf(stderr, "Stack overflow.\n");
                break;

            case GL_STACK_UNDERFLOW:
                fprintf(stderr, "Stack underflow.\n");
                break;

            case GL_OUT_OF_MEMORY:
                fprintf(stderr, "Out of memory.\n");
                break;

            case GL_INVALID_FRAMEBUFFER_OPERATION:
                fprintf(stderr, "Framebuffer object is not complete.\n");
                break;
        }
        return;
    }
    else
    {
        fprintf(stderr, "NO Error from caller: %s \n",  caller);
    }
    return;
}


----------------------------------------------------------------------------

E. 新增 "場景繪製" 相關函式
     1. File -> New -> Source File
         Source file: scene.c
         Template: <Default C source template><None>
          > Finish

     2. 開啟 scene.c 檔案, 修改如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "opengl.h"


/* shader functions defined in shader.c */
extern void shaderAttachFromFile(GLuint, GLenum, const char *);

void sceneInit();
void sceneRender();
void sceneCycle();


/***********************************************************/


void sceneInit()
{

    //GLint result;

    /* create program object and attach shaders */

    /* link the program and make sure that there were no errors */

    /* get uniform locations */

    /* set up lights */

    /* create 2D/3D object */

    /* call the glutIdleFunc */

    /* setup camera */

    //glLoadIdentity();

}

void sceneRender()
{

    //glClear(GL_COLOR_BUFFER_BIT);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* enable program and set uniform variables */

    /* render the 2D/3D object */

    glColor3f(0.2, 0.4, 0.6);
    glutWireTeapot(3);


    /* disable program */

    /* render each light */


    glutSwapBuffers();

    //glFlush();
}

void sceneCycle()
{

    // refresh the screen
    glutPostRedisplay();
}


----------------------------------------------------------------------------

F. 新增 main 主函式
     1. File -> New -> Source File
          Source file: main.c
          Template: <Default C source template><None>
           > Finish

     2. 開啟 main.c 檔案, 修改如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "opengl.h"

static const int WINDOW_X = 0;
static const int WINDOW_Y = 0;
static const int WINDOW_WIDTH = 320;
static const int WINDOW_HEIGHT = 320;

/* checkGLErrors functions defined in utility.c */
extern void checkGLErrors(const char* caller);

/* scene functions defined in scene.c */
extern void sceneInit(void);
extern void sceneRender(void);
extern void sceneCycle(void);

static int g_window;

void glInit();
void keyboard(unsigned char key, int x, int y);

int main(int argc, char* argv[])
{
    /* initialize GLUT */
    glutInit(&argc, argv);
    //glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

    glutInitWindowPosition(WINDOW_X,  WINDOW_Y);
    glutInitWindowSize(WINDOW_WIDTH,  WINDOW_HEIGHT);

    g_window = glutCreateWindow("OpenGL Shading Language");

    /* initialize GL */
    glInit();

    /* initialize scene */
    sceneInit();

    /* setup callbacks */
    glutDisplayFunc(sceneRender);
    glutIdleFunc(sceneCycle);
    glutKeyboardFunc(keyboard);
    //glutReshapeFunc(resize);
    //glutSpecialFunc(special);
    //glutMouseFunc(mouse);


    /* check GL Errors */
    checkGLErrors("main");

    /* start GLUT main loop */
    glutMainLoop();

    return 0;
}

void glInit()
{
    /* setup initial GL settings */
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);

    /* set projection matrix */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(-5, 5, -5, 5, 5, 15);
    // or setPerspective

    glMatrixMode(GL_MODELVIEW);
    gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
}

// User Input Callbacks
void keyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
        case 27: /* escape */
            glutDestroyWindow(g_window);
            exit(0);
            break;

        case 'q': case 'Q':
             glutDestroyWindow(g_window);
            exit(EXIT_SUCCESS);
            break;

        case 'r': case 'R':
            fprintf(stderr, "call glutPostRedisplay() \n");
            // refresh the screen
            glutPostRedisplay();
            break;
    }
}


----------------------------------------------------------------------------

G. 編譯並執行
    功能選單:
    Project > Build Project
    Run > Run

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。