web-dev-qa-db-ja.com

GLUTを使用しないOpenGLの初期化

私が見つけることができるすべての紹介とサンプルは、GLUTまたは他のフレームワークを使用してOpenGLを「初期化」するようです。 GL and GLU?で利用可能なものだけでOpenGLを初期化する方法はありますか?そうでない場合、GLUTがそれなしでは不可能なことは何ですか?

39
TholePin

気が付くように、コンテキストを作成してバインドするコードは、各ウィンドウプラットフォームに固有です。

特定のプラットフォームでOpenGLを初期化するという観点から始めるためのいくつかの機能を次に示します。

Windows(チュートリアルは here

  • wglCreateContext(hDC)

Mac OS X-OS Xには本質的に3つのオプションがあります:Carbon、Cocoa、および基盤となるCore Graphics Layer

Linux

  • glx :glXCreateContext
34
fixermark

あなたがしているのは、OpenGLコンテキストでウィンドウを初期化することです。これには、オペレーティングシステムへのいくつかの呼び出しが必要です。 gl.hとglu.hだけでOpenGLを初期化することはできません。 [〜#〜] glut [〜#〜] (または [〜#〜] sdl [〜#〜][〜#〜] smfl [ 〜#〜] など)は、ニースプラットフォームに依存しない方法で機能します。ネイティブ呼び出しでも初期化を行うことができます。

5
luke

[〜#〜] glx [〜#〜] 最小限の実行可能な例

here から適応。

キーボード入力も扱います。

コンパイル:

gcc glx.c -lGLU -lGL -lX11

Ubuntu 14.04でテスト済み。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#define GL_GLEXT_PROTOTYPES
#define GLX_GLXEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>

struct MyWin {
    Display  *display;
    Window win;
    int displayed;
    int width;
    int height;
};

const int WIN_XPOS = 256;
const int WIN_YPOS = 64;
const int WIN_XRES = 320;
const int WIN_YRES = 320;
const int NUM_SAMPLES = 4;

struct MyWin Win;

double elapsedMsec(const struct timeval *start, const struct timeval *stop) {
    return ((stop->tv_sec  - start->tv_sec ) * 1000.0 +
            (stop->tv_usec - start->tv_usec) / 1000.0);
}

void displayCB() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f( 0.0f, 1.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 0.0f);
    glVertex3f( 1.0f, -1.0f, 0.0f);
    glEnd();
    glFlush();
    glXSwapBuffers(Win.display, Win.win);
}

void keyboardCB(KeySym sym, unsigned char key, int x, int y,
        int *setting_change) {
    switch (tolower(key)) {
        case 27:
            exit(EXIT_SUCCESS);
            break;
        case 'k':
            printf("You hit the 'k' key\n");
            break;
        case 0:
            switch (sym) {
                case XK_Left  :
                    printf("You hit the Left Arrow key\n");
                    break;
                case XK_Right :
                    printf("You hit the Right Arrow key\n");
                    break;
            }
            break;
    }
}

void reshapeCB(int width, int height) {
    Win.width = width;
    Win.height = height;
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    glMatrixMode(GL_MODELVIEW);
}

/* Try to find a framebuffer config that matches
 * the specified pixel requirements.
 */
GLXFBConfig chooseFBConfig(Display *display, int screen) {
    static const int Visual_attribs[] = {
        GLX_X_RENDERABLE  , True,
        GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
        GLX_RENDER_TYPE   , GLX_RGBA_BIT,
        GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
        GLX_RED_SIZE      , 8,
        GLX_GREEN_SIZE    , 8,
        GLX_BLUE_SIZE     , 8,
        GLX_ALPHA_SIZE    , 8,
        GLX_DEPTH_SIZE    , 24,
        GLX_STENCIL_SIZE  , 8,
        GLX_DOUBLEBUFFER  , True,
        GLX_SAMPLE_BUFFERS, 1,
        GLX_SAMPLES       , 4,
        None
    };
    int attribs [ 100 ] ;
    memcpy(attribs, Visual_attribs, sizeof(Visual_attribs));
    GLXFBConfig ret = 0;
    int fbcount;
    GLXFBConfig *fbc = glXChooseFBConfig(display, screen, attribs, &fbcount);
    if (fbc) {
        if (fbcount >= 1)
            ret = fbc[0];
        XFree(fbc);
    }
    return ret;
}

GLXContext createContext(Display *display, int screen,
        GLXFBConfig fbconfig, XVisualInfo *visinfo, Window window) {
#define GLX_CONTEXT_MAJOR_VERSION_ARB       0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB       0x2092
    typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*,
            GLXFBConfig, GLXContext, int, const int*);
    /* Verify GL driver supports glXCreateContextAttribsARB() */
    /*   Create an old-style GLX context first, to get the correct function ptr. */
    glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
    GLXContext ctx_old = glXCreateContext(display, visinfo, 0, True);
    if (!ctx_old) {
        printf("Could not even allocate an old-style GL context!\n");
        exit(EXIT_FAILURE);
    }
    glXMakeCurrent (display, window, ctx_old) ;
    /* Verify that GLX implementation supports the new context create call */
    if (strstr(glXQueryExtensionsString(display, screen),
                "GLX_ARB_create_context") != 0)
        glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
            glXGetProcAddress((const GLubyte *) "glXCreateContextAttribsARB");
    if (!glXCreateContextAttribsARB) {
        printf("Can't create new-style GL context\n");
        exit(EXIT_FAILURE);
    }
    /* Got the pointer.  Nuke old context. */
    glXMakeCurrent(display, None, 0);
    glXDestroyContext(display, ctx_old);

    /* Try to allocate a GL 4.2 COMPATIBILITY context */
    static int Context_attribs[] = {
        GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
        GLX_CONTEXT_MINOR_VERSION_ARB, 2,
        GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
        /*GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, */
        /*GLX_CONTEXT_FLAGS_ARB       , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, */
        /*GLX_CONTEXT_FLAGS_ARB       , GLX_CONTEXT_DEBUG_BIT_ARB, */
        None
    };
    GLXContext context = glXCreateContextAttribsARB(display, fbconfig, 0,
            True, Context_attribs);
    /* Forcably wait on any resulting X errors */
    XSync(display, False);
    if (!context) {
        printf("Failed to allocate a GL 4.2 context\n");
        exit(EXIT_FAILURE);
    }
    printf("Created GL 4.2 context\n");
    return context;
}

void createWindow() {
    /* Init X and GLX */
    Win.displayed = 0;
    Display *display = Win.display = XOpenDisplay(":0.0");
    if (!display)
        printf("Cannot open X display\n");
    int    screen   = DefaultScreen(display);
    Window root_win = RootWindow(display, screen);
    if (!glXQueryExtension(display, 0, 0))
        printf("X Server doesn't support GLX extension\n");
    /* Pick an FBconfig and visual */
    GLXFBConfig fbconfig = chooseFBConfig(display, screen);
    if (!fbconfig) {
        printf("Failed to get GLXFBConfig\n");
        exit(EXIT_FAILURE);
    }
    XVisualInfo *visinfo = glXGetVisualFromFBConfig(display, fbconfig);
    if (!visinfo) {
        printf("Failed to get XVisualInfo\n");
        exit(EXIT_FAILURE);
    }
    printf("X Visual ID = 0x%.2x\n", (int)visinfo->visualid);
    /* Create the X window */
    XSetWindowAttributes winAttr ;
    winAttr.event_mask = StructureNotifyMask | KeyPressMask ;
    winAttr.background_pixmap = None ;
    winAttr.background_pixel  = 0    ;
    winAttr.border_pixel      = 0    ;
    winAttr.colormap = XCreateColormap(display, root_win,
            visinfo->visual, AllocNone);
    unsigned int mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
    Window win = Win.win = XCreateWindow (display, root_win,
            WIN_XPOS, WIN_YPOS,
            WIN_XRES, WIN_YRES, 0,
            visinfo->depth, InputOutput,
            visinfo->visual, mask, &winAttr) ;
    XStoreName(Win.display, win, "My GLX Window");
    /* Create an OpenGL context and attach it to our X window */
    GLXContext context = createContext(display, screen, fbconfig, visinfo, win);
    if (! glXMakeCurrent(display, win, context))
        printf("glXMakeCurrent failed.\n");
    if (! glXIsDirect (display, glXGetCurrentContext()))
        printf("Indirect GLX rendering context obtained\n");
    /* Display the window */
    XMapWindow(display, win);
    if (! glXMakeCurrent(display, win, context))
        printf("glXMakeCurrent failed.\n");
    printf("Window Size    = %d x %d\n", WIN_XRES, WIN_YRES);
    printf("Window Samples = %d\n", NUM_SAMPLES);
}

void processXEvents(Atom wm_protocols, Atom wm_delete_window) {
    int setting_change = 0;
    while (XEventsQueued(Win.display, QueuedAfterFlush)) {
        XEvent event;
        XNextEvent(Win.display, &event);
        if(event.xany.window != Win.win)
            continue;
        switch (event.type) {
            case MapNotify:
                {
                    Win.displayed = 1;
                    break;
                }
            case ConfigureNotify:
                {
                    XConfigureEvent cevent = event.xconfigure;
                    reshapeCB(cevent.width, cevent.height);
                    break;
                }
            case KeyPress:
                {
                    char chr;
                    KeySym symbol;
                    XComposeStatus status;
                    XLookupString(&event.xkey, &chr, 1, &symbol, &status);
                    keyboardCB(symbol, chr, event.xkey.x, event.xkey.y,
                            &setting_change);
                    break;
                }
            case ClientMessage:
                {
                    if (event.xclient.message_type == wm_protocols &&
                            (Atom)event.xclient.data.l[0] == wm_delete_window) {
                        exit(EXIT_SUCCESS);
                    }
                    break;
                }
        }
    }
}

void mainLoop() {
    /* Register to receive window close events (the "X" window manager button) */
    Atom wm_protocols     = XInternAtom(Win.display, "WM_PROTOCOLS"    , False);
    Atom wm_delete_window = XInternAtom(Win.display, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(Win.display, Win.win, &wm_delete_window, True);

    while (1) {
        /* Redraw window (after it's mapped) */
        if (Win.displayed)
            displayCB();

        /* Update frame rate */
        struct timeval last_xcheck = {0, 0};
        struct timeval now;
        gettimeofday(&now, 0);

        /* Check X events every 1/10 second */
        if (elapsedMsec(&last_xcheck, &now) > 100) {
            processXEvents(wm_protocols, wm_delete_window);
            last_xcheck = now;
        }
    }
}

int main(int argc, char *argv[]) {
    Win.width = WIN_XRES;
    Win.height = WIN_YRES;
    createWindow();

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);

    printf("Valid keys: Left, Right, k, ESC\n");
    printf("Press ESC to quit\n");
    mainLoop();
    return EXIT_SUCCESS;
}

FreeGlut のソースを常に開いて、各glut機能をどのように実装するかを確認できますが、GLXよりも低レベルになるのは筋金入りのようです。

[〜#〜] egl [〜#〜]

GLXに対するKhronos標準化代替品のように見えます。現在、OpenGL ESで最も頻繁に使用されています。

https://cgit.freedesktop.org/mesa/demos/tree/src/egl にはMesaの実装を使用した例が含まれていますが、それらを機能させることができていません。

git checkout mesa-demos-8.1.0
./autogen.sh
./configure
make

失敗する:

/work/git/mesa-demos/src/egl/opengl/demo1.c:26: undefined reference to `eglGetScreensMESA'

しかし、Ubuntu 14.04にはes2gears の中に mesa-utils-extraパッケージなので、方法が必要です。

参照: EGLとは何か、どのように使用できますか

GLUTソースコード を取得して、関心のあるプラットフォームの初期化コードを確認できます。

2
Jim Buck