본문 바로가기

Developement/C/C++

[FLTK]minGW 에서 OpenGL 3.x 사용하기 (Shader programming)



 기본적으로 minGW 를 설치 하면 포함 되어 있는 OpenGL header 버젼은 1.2 대 버젼으로 현재 4.0 헤더가 크로노스 그룹에서 공개 된 걸 생각하면 한참이나 구시대의 유물인 상태 이다. 사실 이걸로는 GeForce2 나 RadeonX 시절의 pixel shader 없는 심심한 그래픽이나 그리는거 말곤 할수 있는게 없다.


 이번엔 FLTK 에서 OpenGL shader programming 을 통한 YUV422 이미지를 Programming Object ARB 를 이용하여 texture 1+2+3 을 겹쳐 하나의 완성된 이미지로 만들어 내는걸 해 보기로 하면서 기본 MinGW 에서 수정 되어야 할 점과, OpenGL 프로그래밍을 할때 추가 해야 하는 부분들을 정리 해 보도록 하겠다.


 먼저 기본 minGW 를 설치 한 상태에서 다음 URL 에서 4개의 header 파일을 받는다.

https://www.opengl.org/registry/#headers


<GL/glext.h> - OpenGL 1.2 and above compatibility profile and extension interfaces.
<GL/glcorearb.h> - OpenGL core profile and ARB extension interfaces, as described in appendix G.2 of the OpenGL 4.3 Specification. Does not include interfaces found only in the compatibility profile.
<GL/glxext.h> - GLX 1.3 and above API and GLX extension interfaces.
<GL/wglext.h> - WGL extension interfaces.


이제 이것을 minGW 가 설치 되어 있는 위치를 참조 하여 include/gl 안에 모두 덮어 쒸어 준다. (혹시나 하면 기존의 header 들은 모두 압축 해 둔다)

예) C:\MinGW 에 설치 된 것이라면 다음과 같음 : C:\MinGW\include


이걸로 준비는 끝.

혹시나 lib 안에 있는 libopengl32.a 를 변경 해야 하거나 할것 같지만 ... 안해도 된다.

다만, OpenGL 확장의 ARB 뭐시기 들어가는 함수들은 모두 동적인 할당을 해서 써야 한다.


예를 들어 다음과 같은 함수들.

glActiveTexture() 나, glCreateProgramObjectARB() 와 같은걸 쓰려면 이걸 먼저 할당하고 wglGetProcAddress() 로 함수 포인터를 지정해 주어야 한다.


고로 다음과 같은 코드를 만들어 쓰자.


#include <FL⁄gl.h>
#include <GL⁄gl.h>
#include <GL⁄glu.h>
#include <GL⁄glext.h>


⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄

PFNGLACTIVETEXTUREPROC                  glActiveTexture             = NULL;

PFNGLCREATEPROGRAMOBJECTARBPROC         glCreateProgramObjectARB    = NULL;
PFNGLDELETEOBJECTARBPROC                glDeleteObjectARB           = NULL;
PFNGLUSEPROGRAMOBJECTARBPROC            glUseProgramObjectARB       = NULL;
PFNGLCREATESHADEROBJECTARBPROC          glCreateShaderObjectARB     = NULL;
PFNGLSHADERSOURCEARBPROC                glShaderSourceARB           = NULL;
PFNGLCOMPILESHADERARBPROC               glCompileShaderARB          = NULL;
PFNGLGETOBJECTPARAMETERIVARBPROC        glGetObjectParameterivARB   = NULL;
PFNGLATTACHOBJECTARBPROC                glAttachObjectARB           = NULL;
PFNGLGETINFOLOGARBPROC                  glGetInfoLogARB             = NULL;
PFNGLLINKPROGRAMARBPROC                 glLinkProgramARB            = NULL;
PFNGLGETUNIFORMLOCATIONARBPROC          glGetUniformLocationARB     = NULL;
PFNGLUNIFORM4FARBPROC                   glUniform4fARB              = NULL;
PFNGLUNIFORM3FARBPROC                   glUniform3fARB              = NULL;
PFNGLUNIFORM1FARBPROC                   glUniform1fARB              = NULL;
PFNGLUNIFORM1IARBPROC                   glUniform1iARB              = NULL;

PFNGLGETATTRIBLOCATIONARBPROC           glGetAttribLocationARB      = NULL;
PFNGLVERTEXATTRIB3FARBPROC              glVertexAttrib3fARB         = NULL;

PFNGLVERTEXATTRIBPOINTERARBPROC         glVertexAttribPointerARB        = NULL;
PFNGLENABLEVERTEXATTRIBARRAYARBPROC     glEnableVertexAttribArrayARB    = NULL;
PFNGLDISABLEVERTEXATTRIBARRAYARBPROC    glDisableVertexAttribArrayARB   = NULL;

⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄

static bool loadGLShaderExt = false;

⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄⁄

void initShaderExtentions()
{
    if ( loadGLShaderExt == true )
        return;


    char* glverstr = (char*)glGetString( GL_VERSION );
    if ( glverstr == NULL )
        return;

    char* glextstr = (char*)glGetString( GL_EXTENSIONS );
    if ( glextstr == NULL )
        return;


    if ( strstr( glextstr, "GL_ARB_shading_language_100") == NULL )
    {
        return;
    }

    glActiveTexture             = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");

    glCreateProgramObjectARB    = (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB");
    glDeleteObjectARB           = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
    glUseProgramObjectARB       = (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB");
    glCreateShaderObjectARB     = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
    glShaderSourceARB           = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
    glCompileShaderARB          = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
    glGetObjectParameterivARB   = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
    glAttachObjectARB           = (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
    glGetInfoLogARB             = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
    glLinkProgramARB            = (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB");

    glGetUniformLocationARB     = (PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocationARB");
    glUniform4fARB              = (PFNGLUNIFORM4FARBPROC)wglGetProcAddress("glUniform4fARB");
    glUniform3fARB              = (PFNGLUNIFORM3FARBPROC)wglGetProcAddress("glUniform3fARB");
    glUniform1fARB              = (PFNGLUNIFORM1FARBPROC)wglGetProcAddress("glUniform1fARB");
    glUniform1iARB              = (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1iARB");
    glGetAttribLocationARB      = (PFNGLGETATTRIBLOCATIONARBPROC)wglGetProcAddress("glGetAttribLocationARB");
    glVertexAttrib3fARB         = (PFNGLVERTEXATTRIB3FARBPROC)wglGetProcAddress("glVertexAttrib3fARB");

    glVertexAttribPointerARB        = (PFNGLVERTEXATTRIBPOINTERARBPROC)wglGetProcAddress("glVertexAttribPointerARB");
    glEnableVertexAttribArrayARB    = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glEnableVertexAttribArrayARB");
    glDisableVertexAttribArrayARB   = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)wglGetProcAddress("glDisableVertexAttribArrayARB");

    loadGLShaderExt = true;
}

 이렇게 할 경우 iniShaderExtentions(); 를 main 등에서 최초 호출 하게 되면 Shader programming 에 써야 할 기본적인 함수들을 할당해서 쓸 수 있게 된다. 단, 이걸 먼저 하려면 wglCreateContext(); 나 wglMakeCurrent(); 를 먼저 불러 줘야 한다.

 FLTK 를 쓸 경우 Fl_Gl_Window 를 상속받아 만들어 지는 부분에선 이걸 절대 생성자에서 호출 할 수 없는 문제가 있다 (내부적으로 wgl 초기화 함수 등이 호출이 안되므로 glGetString() 에서 항상 NULL 이 돌아 옴 ... )