web-dev-qa-db-fra.com

Initialisation d'OpenGL sans GLUT

chaque introduction et échantillon que je peux trouver semble utiliser GLUT ou un autre framework pour "initialiser" OpenGL. Existe-t-il un moyen d'initialiser OpenGL avec exactement ce qui est disponible dans GL et GLU? Sinon, alors que fait GLUT qui n'est pas possible sans lui?

39
TholePin

Comme luke l'a noté, le code pour créer et lier le contexte est spécifique à chaque plateforme de fenêtrage.

Voici quelques fonctions pour vous lancer dans l'initialisation d'OpenGL sur des plateformes spécifiques:

Windows (un tutoriel est ici )

  • wglCreateContext (hDC)

Mac OS X - OS X propose essentiellement trois options: Carbon, Cocoa et le Core Graphics Layer sous-jacent

Linux

  • glx : glXCreateContext
34
fixermark

Ce que vous faites, c'est initialiser une fenêtre avec un contexte OpenGL. Cela nécessite certains appels au système d'exploitation. Il n'est pas possible d'initialiser OpenGL avec juste gl.h et glu.h. GLUT (ou SDL , SMFL , etc.) cela fonctionne-t-il pour vous d'une manière indépendante de la plate-forme Nice. Vous pouvez également effectuer l'initialisation avec des appels natifs.

5
luke

GLX exemple exécutable minimal

Adapté de ici .

Traite également des entrées clavier.

Compiler avec:

gcc glx.c -lGLU -lGL -lX11

Testé dans 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;
}

On pourrait toujours ouvrir la source de FreeGlut pour voir comment il implémente chaque fonction de surabondance, mais descendre à un niveau inférieur à GLX est probablement hardcore.

[~ # ~] egl [~ # ~]

On dirait une alternative standardisée de Khronos à GLX, actuellement le plus souvent utilisée avec OpenGL ES.

https://cgit.freedesktop.org/mesa/demos/tree/src/egl contient des exemples utilisant l'implémentation de Mesa, mais je n'ai pas encore réussi à les faire fonctionner:

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

Échoue avec:

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

Mais Ubuntu 14.04 a es2gears dans le mesa-utils-extra package, donc il doit y avoir un moyen.

Voir aussi: Qu'est-ce que EGL et comment puis-je l'utiliser

Vous pouvez saisir le code source GLUT et voir le code init pour la plateforme qui vous intéresse.

2
Jim Buck