177 lines
6.6 KiB
C
177 lines
6.6 KiB
C
#include <sys/stat.h>
|
|
|
|
#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;
|
|
}
|