初始化没有GLUT的OpenGL

我能find的每个介绍和示例似乎都使用GLUT或其他框架来“初始化”OpenGL。 有什么方法可以在GL和GLU中使用什么来初始化OpenGL? 如果没有,那么没有它,GLUT做什么是不可能的?

正如卢克指出的,创build和绑定上下文的代码是特定于每个窗口平台的。

以下是在特定平台上初始化OpenGL的一些function:

Windows(教程在这里 )

  • wglCreateContext(HDC)

Mac OS X OS X基本上有三个选项:Carbon,Cocoa和底层的Core Graphics Layer

  • 整个Mac OS X OpenGL开发指南
  • Carbon :aglCreateContext
  • cocoa :创build(或子类)一个NSOpenGLView。 他们创build自己的上下文,你可以阅读他们的方法文档,以find如何使其最新。
  • CoreGraphicsLayer :CGLCreateContext

Linux的

  • glx :glXCreateContext

你正在做的是用OpenGL上下文初始化一个窗口。 这需要对操作系统进行一些调用。 用gl.h和glu.h来初始化OpenGL是不可能的。 GLUT (或SDL , SMFL等)以独立于平台的方式为您工作。 您也可以使用本地调用进行初始化。

您可以获取GLUT源代码,并查看您所关心的任何平台的init代码。

GLX最小的可运行示例

改编自这里 。

还处理键盘input。

编译:

gcc glx.c -lGLU -lGL -lX11 

在Ubuntu 14.04testing。

 #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 = %dx %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的来源,看看它是如何实现每个过剩的function,但比GLX低一级可能是硬核。

EGL

看起来像Khronos标准化的替代GLX,目前最常用的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在mesa-utils-extra包中有es2gears ,所以一定有办法。

另请参阅: 什么是EGL?如何使用它?

GL是API,而GLU是GL之上的实用程序库。 它完全独立于操作系统。

OpenGL初始化和扩展抓取是平台相关的操作。 因此,你可以单独使用OpenGL。

GLUT是快速的不足和糟糕的库,只是它是初始化opengl上下文,并提供一些原始的鼠标/键盘input模块,让你继续。

Win32也提供了初始化opengl上下文的工具。 对于Linux,你可以检查出GLX。 另外,如果你想要一个独立于系统的方式,那么你可以检查一下SDL。 对于不同的编程语言,可能会有一些实用程序为您提供独立于平台的桌面API。

您可以查看Galaxy Forces V2的来源http://www.galaxy-forces.com/

它在Windows,Mac和Linux上不使用GLUT或其他库而实现OpenGL的类。 使用本地平台代码,所有公共领域。

下面是关于如何在不使用GLUT的情况下初始化OpenGL(假定为Windows)的一个基本和很好的介绍:

初始化没有GLUT的OpenGL

正如Luke所说,如果你不想使用GLUT,你需要关于你正在开发的操作系统的具体信息。 使用GLUT将使您的代码更容易移植。