opengl_x11

Playing with OpenGL
git clone git://bsandro.tech/opengl_x11
Log | Files | Refs | README | LICENSE

commit c2aa6601fedb944bfdbfef3d356626cafe9db466
parent 9425d42e4ffc29df695f8ea321a230efc1b734bc
Author: bsandro <email@bsandro.tech>
Date:   Thu, 16 Oct 2025 01:27:52 +0300

I'll try to figure out tesselation

Diffstat:
M.gitignore | 1+
MMakefile | 10+++++-----
Amain.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmain1.c | 1+
Mmain2.c | 267+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
5 files changed, 265 insertions(+), 121 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -3,3 +3,4 @@ main3 main3o test1 +test2 diff --git a/Makefile b/Makefile @@ -1,12 +1,12 @@ all: - ${CC} main1.c -std=gnu23 -Wpedantic -Os -s -fomit-frame-pointer -ffast-math -fno-stack-protector -march=native -fwrapv -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-unwind-tables -fmerge-all-constants -fno-ident -lm -lGL -lGLU -lX11 -Wl,--gc-sections -o test1 + ${CC} main2.c -std=gnu23 -Wpedantic -Os -s -fomit-frame-pointer -ffast-math -fno-stack-protector -march=native -fwrapv -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-unwind-tables -fmerge-all-constants -fno-ident -lm -lGL -lGLU -lX11 -Wl,--gc-sections -o test2 min: all - strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag ./test1 - upx -9 ./test1 + strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag ./test2 + upx -9 ./test2 clean: - rm -f ./test1 ./main3 + rm -f ./test1 ./test2 ./main3 main3: clean ${CC} -Os -s -fomit-frame-pointer -nostdlib main3.c -o main3o -Wl,-dynamic-linker,/usr/lib64/ld-linux-x86-64.so.2 -Wl,--no-as-needed /usr/lib64/libdl.so.2 /usr/lib64/libc.so @@ -16,4 +16,4 @@ main3: clean chmod +x main3 run: min - ./test1 + ./test2 diff --git a/main.c b/main.c @@ -0,0 +1,107 @@ +#include <stdio.h> +#include <stdlib.h> +#include <X11/Xlib.h> +#include <GL/glx.h> +#include <GL/gl.h> + +Display *dpy; +Window win; +Bool doubleBuffer = True; + +GLfloat xAngle = 42.0; +GLfloat yAngle = 82.0; +GLfloat zAngle = 112.0; + +static int sngBuf[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 12, + None }; + +static int dblBuf[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 12, + GLX_DOUBLEBUFFER, + None }; + +static void fatalError(char *str) { + fprintf(stderr, "%s\n", str); + exit(1); +} + +int main(int argc, char **argv) { + XVisualInfo *vinfo = NULL; + Colormap cmap; + XSetWindowAttributes winattr; + GLXContext ctx; + XEvent event; + int dummy; + + if (!(dpy = XOpenDisplay(NULL))) { + fatalError("cannot open display"); + } + + if (!glXQueryExtension(dpy, &dummy, &dummy)) { + fatalError("x server has no opengl glx extension"); + } + + if (!(vinfo = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf))) { + if (!(vinfo = glXChooseVisual(dpy, DefaultScreen(dpy), sngBuf))) { + fatalError("no rgb visual with depth buffer"); + } + doubleBuffer = False; + } + if (vinfo->class != TrueColor) { + fatalError("TrueColor required"); + } + + if (!(ctx = glXCreateContext(dpy, vinfo, None, True))) { + fatalError("could not create rendering context"); + } + + cmap = XCreateColormap(dpy, RootWindow(dpy, vinfo->screen), vinfo->visual, AllocNone); + winattr.colormap = cmap; + winattr.border_pixel = 0; + winattr.event_mask = ExposureMask|ButtonPressMask|StructureNotifyMask; + win = XCreateWindow(dpy, RootWindow(dpy, vinfo->screen),0,0,300,300,0, + vinfo->depth, InputOutput, vinfo->visual, + CWBorderPixel|CWColormap|CWEventMask, &winattr); + XSetStandardProperties(dpy, win, "glxsimple", "glxsimple", None, argv, argc, NULL); + + glXMakeCurrent(dpy, win, ctx); + XMapWindow(dpy, win); + + glEnable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10.0); + + int keepRunning = 1; + while (keepRunning) { + while (XPending(dpy)) { + XNextEvent(dpy, &event); + switch (event.type) { + case ButtonPress: + switch (event.xbutton.button) { + case 1: xAngle += 10.0; break; + case 2: yAngle += 10.0; break; + case 3: zAngle += 10.0; break; + } + break; + case ConfigureNotify: + glViewport(0, 0, event.xconfigure.width, event.xconfigure.height); + case Expose: + // needRedraw = True; + break; + } + } + } + + printf("ok\n"); + return 0; +} diff --git a/main1.c b/main1.c @@ -1,3 +1,4 @@ +/* basic vertex+fragment shaders */ #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/main2.c b/main2.c @@ -1,162 +1,197 @@ -/* tri.c - Minimal X11 + GL/GLU + GLX program drawing one triangle with shaders. - Build: - gcc -o tri tri.c -lX11 -lGL -lGLU - Run: - ./tri -*/ -#define GL_GLEXT_PROTOTYPES 1 +/* tesselation */ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> +#include <math.h> +#include <X11/X.h> #include <X11/Xlib.h> -#include <X11/Xutil.h> +#define GL_GLEXT_PROTOTYPES 1 #include <GL/gl.h> -#include <GL/glu.h> #include <GL/glx.h> +#include <GL/glu.h> -static const char *vert_src = -"#version 120\n" /* GLSL 1.10 for wide compatibility */ -"attribute vec3 pos;" -"void main() { gl_Position = vec4(pos, 1.0); }"; +static const GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; -static const char *frag_src = -"#version 120\n" -"void main() { gl_FragColor = vec4(0.8, 0.4, 0.2, 1.0); }"; +static const double current_ts() { + struct timespec ts; + timespec_get(&ts, TIME_UTC); + return (double)ts.tv_sec + (double)ts.tv_nsec/1e9; +} -static GLuint compile_shader(GLenum type, const char *src) { - GLuint s = glCreateShader(type); - glShaderSource(s, 1, &src, NULL); - glCompileShader(s); +static double t_started; + +//@todo move shaders to separate files +static const GLchar *vertexSrc = " \n\ +#version 420 \n\ +in vec2 position; \n\ +in vec3 inColor; \n\ +out vec3 color; \n\ +void main() { \n\ + gl_Position = vec4(position, 0.0, 1.0); \n\ + color = inColor; \n\ +} \n\ +"; + +static const GLchar *fragmentSrc = " \n\ +#version 420 \n\ +uniform double iTime; \n\ +in vec3 color; \n\ +out vec4 outColor; \n\ +void main() { \n\ + float c1 = abs(sin(float(iTime))); \n\ + float c2 = abs(cos(float(iTime))); \n\ + outColor = vec4(color+c1-c2, 1.0); \n\ +} \n\ +"; + +static GLuint mkShader(GLenum type, const GLchar *src) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); GLint ok = 0; - glGetShaderiv(s, GL_COMPILE_STATUS, &ok); + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); if (!ok) { - char buf[1024]; - GLsizei len = 0; - glGetShaderInfoLog(s, sizeof(buf)-1, &len, buf); - fprintf(stderr, "Shader compile error: %.*s\n", (int)len, buf); - exit(1); + static char buf[512] = {0}; + glGetShaderInfoLog(shader, sizeof(buf)-1, NULL, buf); + fprintf(stderr, "Shader %d compile error: %s\n", (int)type, buf); } - return s; + return shader; } -static GLuint link_program(GLuint vs, GLuint fs) { - GLuint p = glCreateProgram(); - glAttachShader(p, vs); - glAttachShader(p, fs); - glBindAttribLocation(p, 0, "pos"); /* ensure attribute location 0 for simplicity */ - glLinkProgram(p); - GLint ok = 0; - glGetProgramiv(p, GL_LINK_STATUS, &ok); - if (!ok) { - char buf[1024]; - GLsizei len = 0; - glGetProgramInfoLog(p, sizeof(buf)-1, &len, buf); - fprintf(stderr, "Program link error: %.*s\n", (int)len, buf); - exit(1); - } - return p; +static GLuint linkProgram(GLuint vertex, GLuint fragment) { + GLuint shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertex); + glAttachShader(shaderProgram, fragment); + glBindAttribLocation(shaderProgram, 0, "position"); + glBindFragDataLocation(shaderProgram, 0, "outColor"); + glLinkProgram(shaderProgram); + return shaderProgram; +} + +void __attribute__((constructor)) start() { + printf("start()\n"); + t_started = current_ts(); } -int main(void) { +void __attribute((destructor)) end() { + printf("end()\n"); +} + +int main(int argc, char *argv[]) { Display *dpy = XOpenDisplay(NULL); - if (!dpy) { - fprintf(stderr, "Unable to open X display\n"); - return 1; + XSetWindowAttributes swa; + Window win; + XWindowAttributes gwa; + XEvent xev; + + + if (dpy == NULL) { + printf("\n\tcannot connect to X server\n\n"); + exit(0); } - /* Choose a visual */ - static int att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; - XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), att); - if (!vi) { - fprintf(stderr, "No appropriate visual found\n"); - return 1; + Window root = DefaultRootWindow(dpy); + XVisualInfo *vi = glXChooseVisual(dpy, 0, attr); + + if (vi == NULL) { + printf("\n\tno appropriate visual found\n\n"); + exit(0); + } else { + printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */ } - Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); - XSetWindowAttributes swa; + Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone); swa.colormap = cmap; - swa.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask; - - Window win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), - 0, 0, 640, 480, 0, vi->depth, InputOutput, - vi->visual, CWColormap | CWEventMask, &swa); - XStoreName(dpy, win, "Minimal GL Triangle"); + swa.event_mask = ExposureMask | KeyPressMask; + win = XCreateWindow(dpy, root, 0, 0, 500, 500, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa); XMapWindow(dpy, win); - - /* Create GLX context */ + XStoreName(dpy, win, "OPENGL"); GLXContext ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE); - if (!ctx) { - fprintf(stderr, "Failed to create GLX context\n"); - return 1; - } glXMakeCurrent(dpy, win, ctx); - /* Compile shaders and link program */ - GLuint vs = compile_shader(GL_VERTEX_SHADER, vert_src); - GLuint fs = compile_shader(GL_FRAGMENT_SHADER, frag_src); - GLuint prog = link_program(vs, fs); + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); - /* Triangle vertices (preset) */ - const GLfloat verts[] = { - 0.0f, 0.6f, 0.0f, - -0.6f, -0.4f, 0.0f, - 0.6f, -0.4f, 0.0f + // [x, y, r, g, b] + static const GLfloat vertices[] = { + 0.01f, 0.01f, 1.0f, 0.0f, 0.0f, + 0.8f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.8f, 0.0f, 0.0f, 1.0f, + + -0.01f, -0.01f, 0.0f, 0.0f, 1.0f, + -0.8f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, -0.8f, 1.0f, 0.0f, 0.0f, + + 0.3f, 0.3f, 1.0f, 0.0f, 0.0f, + 0.3f, 0.6f, 1.0f, 0.0f, 0.0f, + 0.6f, 0.3f, 1.0f, 0.0f, 0.0f, + 0.6f, 0.6f, 1.0f, 0.0f, 0.0f + }; + + static const GLuint elements[] = { + 0, 1, 5, + 3, 2, 4, + 6, 7, 8, + 7, 8, 9 }; - /* Create simple VBO */ - GLuint vbo = 0; + GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + GLuint ebo; + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); - /* Set up GL state */ - glViewport(0, 0, 640, 480); - glClearColor(0.15f, 0.18f, 0.20f, 1.0f); + GLuint vertex = mkShader(GL_VERTEX_SHADER, vertexSrc); + GLuint fragment = mkShader(GL_FRAGMENT_SHADER, fragmentSrc); + GLuint shaderPrg = linkProgram(vertex, fragment); - /* Main loop */ - int running = 1; - while (running) { + while (1) { while (XPending(dpy)) { - XEvent xe; - XNextEvent(dpy, &xe); - if (xe.type == Expose) { - /* ignore */ - } else if (xe.type == ConfigureNotify) { - XConfigureEvent *ce = (XConfigureEvent*)&xe; + XEvent xev; + XNextEvent(dpy, &xev); + if (xev.type == Expose) { + XGetWindowAttributes(dpy, win, &gwa); + glViewport(0, 0, gwa.width, gwa.height); + } else if (xev.type == KeyPress) { + printf("btn:%d\n", xev.xbutton.button); + if (xev.xbutton.button==24||xev.xbutton.button==9) { + glXMakeCurrent(dpy, None, NULL); + glXDestroyContext(dpy, ctx); + XDestroyWindow(dpy, win); + XCloseDisplay(dpy); + exit(0); + } + } else if (xev.type == ConfigureNotify) { + XConfigureEvent *ce = (XConfigureEvent *)&xev; glViewport(0, 0, ce->width, ce->height); - } else if (xe.type == KeyPress) { - running = 0; /* exit on any key */ - } else if (xe.type == DestroyNotify) { - running = 0; } } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearColor(0.1f, 0.1f, 0.15f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(prog); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime"); + glUniform1d(iTime, current_ts()-t_started); + //printf("%f\n", fabsf(sinf(current_ts()-t_started))); - glDrawArrays(GL_TRIANGLES, 0, 3); + glUseProgram(shaderPrg); - glDisableVertexAttribArray(0); - glUseProgram(0); + GLint position = glGetAttribLocation(shaderPrg, "position"); + glEnableVertexAttribArray(position); + glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), 0); + GLint color = glGetAttribLocation(shaderPrg, "inColor"); + glEnableVertexAttribArray(color); + glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void *)(2*sizeof(GLfloat))); + glDrawElements(GL_TRIANGLES, sizeof(elements), GL_UNSIGNED_INT, 0); glXSwapBuffers(dpy, win); - /* Simple CPU-side sleep to limit spin (not required) */ - usleep(1000 * 16); + usleep(1000*16); } - - /* Cleanup */ - glDeleteBuffers(1, &vbo); - glDeleteProgram(prog); - glDeleteShader(vs); - glDeleteShader(fs); - glXMakeCurrent(dpy, None, NULL); - glXDestroyContext(dpy, ctx); - XDestroyWindow(dpy, win); - XCloseDisplay(dpy); - return 0; }