2009-05-18 21 views
37

cada introducción y muestra que puedo encontrar parece utilizar GLUT o algún otro marco para "inicializar" OpenGL. ¿Hay alguna manera de inicializar OpenGL con solo lo que está disponible en GL y GLU? Si no, ¿qué está haciendo GLUT que no es posible sin eso?Inicializando OpenGL sin GLUT

+1

Nadie mencionó [EGL] (http://www.khronos.org/egl)? Es un estándar de Khronos para la interoperabilidad entre el sistema operativo y las API como OpenGL, con el objetivo de unificar tales cosas. IDK, sin embargo, qué tan amplio es admitido hoy. – Kos

+0

que solo es de Windows. – rotoglup

+0

Sí, pero sigue siendo instructivo. :-) ¡Gracias! –

Respuesta

33

Como señaló Luke, el código para crear y vincular el contexto es específico para cada plataforma de ventanas.

Estas son algunas de las funciones para ayudarle a empezar en términos de inicializar OpenGL en plataformas específicas:

de Windows (un tutorial es here)

  • wglCreateContext (hDC)

Mac OS X - OS X tiene esencialmente tres opciones: Carbono, Cacao y la Capa Gráfica Core subyacente

Linux

  • glx: glXCreateContext
+0

Gracias, estos son útiles. Ahora me doy cuenta de que mi problema es específico de Windows lado del código en lugar de solo OpenGL (es decir, tratando de que OpenGL funcione en la parte superior o al lado de? GDI +). –

+1

No subclasifica NSOpenGLView, subclase NSView y usa NSOpenGLContext y NSPixelFormat para obtener más flexibilidad (y usted solo use un NSOpenGLView para cosas muy simples). – mk12

+2

Además, tenga en cuenta que Carbon es prácticamente un callejón sin salida (sin soporte de 64 bits) y CGL no puede crear una ventana, por lo que para OS X use NSGL para ventanas Cocoa, menús, etc. y CGL para aplicaciones de pantalla completa. – mk12

5

Lo que está haciendo es inicializar una ventana con un contexto OpenGL. Esto requiere algunas llamadas al sistema operativo. No es posible inicializar OpenGL con solo gl.h y glu.h. GLUT (o SDL, SMFL, etc.) funciona para usted de una manera agradable plataforma independiente. Puede hacer la inicialización con llamadas nativas también.

2

Puede tomar el GLUT source code y ver el código de inicio para cualquier plataforma que le preocupe.

-2

Aquí hay una introducción básica y buena a la forma de inicializar OpenGL (suponiendo ventanas) sin usar GLUT:

Init OpenGL without GLUT

Como dijo Lucas, si no quieres usar GLUT, necesita información específica acerca de la sistema operativo en el que está desarrollando Usar GLUT hará que su código sea más fácil de portar.

+1

Esta muestra utiliza glut? –

-1

GL es una API, y GLU es una biblioteca de utilidades en la parte superior de GL. Es completamente independiente del sistema operativo.

La inicialización de OpenGL y la recuperación de extensión son operaciones dependientes de la plataforma. Por lo tanto, no puede hacer nada con OpenGL solo.

GLUT es una biblioteca insuficiente y terriblemente pobre, y lo único que hace es inicializar el contexto opengl y proporciona algunos módulos primitivos de entrada de mouse/teclado para que pueda continuar.

Win32 proporciona herramientas para inicializar el contexto OpenGL también. Para Linux, puedes ver GLX. Además, si desea una forma de hacerlo independiente del sistema, puede ver SDL. Para diferentes lenguajes de programación, puede haber utilidades que le proporcionen una API de escritorio independiente de la plataforma.

-1

Es posible que echa un vistazo a la fuente del Galaxy Fuerzas V2, http://www.galaxy-forces.com/

Implementa clases para OpenGL sin usando GLUT u otras bibliotecas en Windows, Mac, y Linux. Usando el código de la plataforma nativa, todo el dominio público.

2

GLX mínimo ejemplo runnable

Adaptado de here.

También se trata de entradas de teclado.

compilar con:

gcc glx.c -lGLU -lGL -lX11 

Probado en 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; 
} 

Uno siempre podría abrir la fuente de FreeGlut para ver cómo se implementa cada función exceso, pero yendo nivel más bajo que GLX es probable hardcore.

EGL

Parece que una alternativa estandarizada Khronos a GLX, actualmente se utiliza con más frecuencia OpenGL ES.

https://cgit.freedesktop.org/mesa/demos/tree/src/egl contiene ejemplos que utilicen la implementación de Mesa, pero aún no han logrado que funcionen:

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

error con:

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

Pero Ubuntu 14.04 tiene es2gears en el paquete mesa-utils-extra, entonces debe haber una manera.

Consulte también: What is EGL And How Can I Use It