#include #include "gl3.h" #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, bool, const int*); #define ERROR(condition, msg, ...) if(condition){fprintf(stderr, msg, ##__VA_ARGS__); return false;} bool initGL(int screen, int mask, GLInfo *glinfo) { glinfo->display = XOpenDisplay(NULL); ERROR(!glinfo->display, "Failed to open X display\n"); // check GLX version >= 1.3 int glx_major, glx_minor; ERROR(!glXQueryVersion(glinfo->display, &glx_major, &glx_minor), "Could not query GLX version\n"); ERROR(glx_major == 1 && glx_minor < 3 || glx_major < 1, "Invalid GLX version\n"); // Let GLX suggest a frame buffer config with a minimum feature set static 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, None }; int fbcount; GLXFBConfig *fbclist = glXChooseFBConfig(glinfo->display, screen, visual_attribs, &fbcount); ERROR(!fbclist, "Failed to retrieve a framebuffer config\n"); GLXFBConfig fbc = fbclist[0]; XFree(fbclist); // Create X Window XVisualInfo *vi = glXGetVisualFromFBConfig(glinfo->display, fbc); ERROR(!vi, "Failed to get visual from framebuffer config\n"); XSetWindowAttributes swa; glinfo->cmap = XCreateColormap(glinfo->display, RootWindow(glinfo->display, vi->screen), vi->visual, AllocNone); swa.colormap = glinfo->cmap; swa.background_pixmap = None; swa.border_pixel = 0; swa.event_mask = mask; glinfo->win = XCreateWindow(glinfo->display, RootWindow(glinfo->display, vi->screen), 0, 0, 100, 100, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); ERROR(!glinfo->win, "Failed to create window.\n"); XFree(vi); // Print GLX Extensions // const char *glxExts = glXQueryExtensionsString(glinfo->display, screen); // printf("%s\n", glxExts); // Create GLX context glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB"); ERROR(!glXCreateContextAttribsARB, "GLX_ARB_create_context is not supported\n"); int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None }; glinfo->ctx = glXCreateContextAttribsARB(glinfo->display, fbc, 0, True, context_attribs); ERROR(!glXIsDirect(glinfo->display, glinfo->ctx), "GLX context is not direct\n"); XMapWindow(glinfo->display, glinfo->win); glXMakeCurrent(glinfo->display, glinfo->win, glinfo->ctx); GLenum result = glewInit(); ERROR(result != GLEW_OK, "Failed to initialize GLEW: %s\n", glewGetErrorString(result)); char name[] = "Billiards"; XClassHint *classHint = XAllocClassHint(); classHint->res_name = classHint->res_class = name; XSetClassHint(glinfo->display, glinfo->win, classHint); XStoreName(glinfo->display, glinfo->win, name); XFree(classHint); glinfo->wm_delete_window = XInternAtom(glinfo->display, "WM_DELETE_WINDOW", false); glinfo->wm_protocols = XInternAtom(glinfo->display, "WM_PROTOCOLS", false); XSetWMProtocols(glinfo->display, glinfo->win, &glinfo->wm_delete_window, 1); return true; } void destroyGL(GLInfo *glinfo) { glXMakeCurrent(glinfo->display, None, 0); glXDestroyContext(glinfo->display, glinfo->ctx); XDestroyWindow(glinfo->display, glinfo->win); XFreeColormap(glinfo->display, glinfo->cmap); XCloseDisplay(glinfo->display); } bool initShaders(const char *vertexShaderPath, const char *fragmentShaderPath, GLuint *program) { GLuint vertexShader, fragmentShader; GLint result; int infoLogLength; char *infoLog; FILE *file; struct stat filestat; char *vertexShaderSrc, *fragmentShaderSrc; // load vertex shader file = fopen(vertexShaderPath, "r"); ERROR(!file, "Could not open file %s\n", vertexShaderPath); fstat(fileno(file), &filestat); ERROR(filestat.st_size > 10000000, "Unreasonably large shader file\n"); vertexShaderSrc = (char*)malloc(filestat.st_size + 1); vertexShaderSrc[filestat.st_size] = 0; // just for safety fread(vertexShaderSrc, 1, filestat.st_size, file); fclose(file); // load framgent shader file = fopen(fragmentShaderPath, "r"); ERROR(!file, "Could not open file %s\n", fragmentShaderPath); fstat(fileno(file), &filestat); ERROR(filestat.st_size > 10000000, "Unreasonably large shader file\n"); fragmentShaderSrc = (char*)malloc(filestat.st_size + 1); fragmentShaderSrc[filestat.st_size] = 0; // just for safety fread(fragmentShaderSrc, 1, filestat.st_size, file); fclose(file); // compile vertex shader vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); glCompileShader(vertexShader); glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &result); glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength); infoLog = (char*)malloc(infoLogLength+1); glGetShaderInfoLog(vertexShader, infoLogLength, NULL, infoLog); ERROR(!result, "Vertex shader compile error: %s\n", infoLog); free(infoLog); // compile fragment shader fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &result); glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength); infoLog = (char*)malloc(infoLogLength+1); glGetShaderInfoLog(fragmentShader, infoLogLength, NULL, infoLog); ERROR(!result, "Fragment shader compile error: %s\n", infoLog); free(infoLog); // link program *program = glCreateProgram(); glAttachShader(*program, vertexShader); glAttachShader(*program, fragmentShader); glLinkProgram(*program); glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL); glCompileShader(fragmentShader); glGetShaderiv(*program, GL_LINK_STATUS, &result); glGetShaderiv(*program, GL_INFO_LOG_LENGTH, &infoLogLength); infoLog = (char*)malloc(infoLogLength+1); glGetProgramInfoLog(*program, infoLogLength, NULL, infoLog); ERROR(!result, "Shader linking error: %s\n", infoLog); free(infoLog); glDetachShader(*program, vertexShader); glDetachShader(*program, fragmentShader); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); free(vertexShaderSrc); free(fragmentShaderSrc); return true; }