installing - Inicializando OpenGL sin GLUT
opengl library (7)
cada introducción y muestra que puedo encontrar parece usar 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?
Aquí hay una introducción básica y buena de cómo inicializar OpenGL (asumiendo Windows) sin usar GLUT:
Como dijo Luke, si no quieres usar GLUT, necesitas información específica sobre el sistema operativo en el que estás desarrollando. Usar GLUT hará que su código sea más fácil de portar.
Como señaló Luke, el código para crear y vincular el contexto es específico para cada plataforma de ventanas.
Aquí hay algunas funciones para comenzar en términos de inicialización de OpenGL en plataformas específicas:
Windows (hay un tutorial here )
- wglCreateContext (hDC)
Mac OS X: OS X tiene básicamente tres opciones: carbono, cacao y la capa subyacente de gráficos básicos.
- Toda la guía para el desarrollo OpenGL de Mac OS X
- Carbon : aglCreateContext
- Cocoa : crea (o subclase) un NSOpenGLView. Crean su propio contexto, y puede leer la documentación de su método para encontrar cómo actualizarlo.
- CoreGraphicsLayer: CGLCreateContext
Linux
- glx : glXCreateContext
GL es una API, y GLU es una biblioteca de utilidad además de GL. Es completamente independiente del sistema operativo.
La inicialización de OpenGL y la obtención de extensiones 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 ratón / teclado para que continúes.
Win32 también proporciona herramientas para inicializar el contexto OpenGL. 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.
Lo que estás 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 e independiente. Puede hacer la inicialización con llamadas nativas también.
Podrías tomar el GLUT y ver el código de inicio para cualquier plataforma que te interese.
Puede consultar la fuente de Galaxy Forces V2, http://www.galaxy-forces.com/
Implementa clases para OpenGL sin usar GLUT u otras bibliotecas en Windows, Mac y Linux. Usando el código de la plataforma nativa, todo el dominio público.
Ejemplo ejecutable mínimo de GLX
Adaptado de here .
También trata con 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;
}
Siempre se podría abrir la fuente de FreeGlut para ver cómo implementa cada función de exceso, pero ir más bajo que GLX es probable que sea difícil.
EGL
Parece una alternativa estandarizada de Khronos a GLX, actualmente la más utilizada con OpenGL ES.
https://cgit.freedesktop.org/mesa/demos/tree/src/egl contiene ejemplos que usan la implementación de Mesa, pero aún no los he podido hacer funcionar:
git checkout mesa-demos-8.1.0
./autogen.sh
./configure
make
Falla 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
, por lo que debe haber una forma.
Ver también: ¿Qué es EGL y cómo puedo usarlo?