Files
billiards_gl/gl3.c
Florian Stecker 04a707b4ed initial version
2025-12-07 19:04:34 -05:00

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