opengl_x11

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

commit 6edbbe11040624e99fdec37abbc8784b4f674241
Author: bsandro <email@bsandro.tech>
Date:   Mon,  6 Oct 2025 14:45:17 +0300

init

Diffstat:
AMakefile | 12++++++++++++
Amain1.c | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain2.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 330 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,12 @@ +all: + ${CC} main1.c -std=c99 -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 -lGL -lGLU -lX11 -Wl,--gc-sections -o test1 + +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 + +clean: + rm ./test1 + +run: min + ./test1 diff --git a/main1.c b/main1.c @@ -0,0 +1,156 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#define GL_GLEXT_PROTOTYPES 1 +#include <GL/gl.h> +#include <GL/glx.h> +#include <GL/glu.h> + +Display *dpy; +Window root; +GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; +XVisualInfo *vi; +XSetWindowAttributes swa; +Window win; +XWindowAttributes gwa; +XEvent xev; + +static const GLchar *vertexSrc = " \n\ +#version 150 core \n\ +in vec3 position; \n\ +void main() { \n\ + gl_Position = vec4(position, 1.0); \n\ +} \n\ +"; + +static const GLchar *fragmentSrc = " \n\ +#version 150 core \n\ +out vec4 outColor; \n\ +void main() { \n\ + outColor = vec4(0.7, 0.5, 0.3, 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(shader, GL_COMPILE_STATUS, &ok); + if (!ok) { + static char buf[512] = {0}; + glGetShaderInfoLog(shader, sizeof(buf)-1, NULL, buf); + fprintf(stderr, "Shader %d compile error: %s\n", (int)type, buf); + } + return shader; +} + +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 DrawThing() { + glClearColor(0.1f, 0.1f, 0.15f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + /*glBegin(GL_TRIANGLES); + // Vertex data + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(-0.3f, 0.0f, 0.0f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex3f(0.3f, 0.1f, 0.0f); + glColor3f(1.0f, 0.0f, 1.0f); + glVertex3f(0.0f, 0.8f, 0.0f); + glEnd(); + + glBegin(GL_POLYGON); + glColor3f(0.8f, 0.0f, 0.0f); + glVertex3f(0.5f, 0.5f, 0.5f); + glVertex3f(0.1f, 0.1f, 0.1f); + glVertex3f(-0.1f, -0.1f, 0.1f); + glVertex3f(0.4f, 0.0f, 0.0f); + glVertex3f(-0.4f, 0.0f, 0.3f); + glEnd();*/ + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLfloat vertices[] = { + 0.0f, 0.0f, 0.0f, + 0.4f, 0.0f, 0.0f, + 0.0f, 0.4f, 0.0f + }; + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + GLuint vertex = mkShader(GL_VERTEX_SHADER, vertexSrc); + GLuint fragment = mkShader(GL_FRAGMENT_SHADER, fragmentSrc); + GLuint shaderPrg = linkProgram(vertex, fragment); + glUseProgram(shaderPrg); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)0); + glDrawArrays(GL_TRIANGLES, 0, 3); + glDisableVertexAttribArray(0); + glUseProgram(0); +} + +int main(int argc, char *argv[]) { + dpy = XOpenDisplay(NULL); + + if (dpy == NULL) { + printf("\n\tcannot connect to X server\n\n"); + exit(0); + } + + root = DefaultRootWindow(dpy); + vi = glXChooseVisual(dpy, 0, att); + + 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, root, vi->visual, AllocNone); + swa.colormap = cmap; + 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); + XStoreName(dpy, win, "OPENGL"); + GLXContext ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE); + glXMakeCurrent(dpy, win, ctx); + float p = .0f; + while (1) { + // while (XPending(dpy)) ??? + XNextEvent(dpy, &xev); + if (xev.type == Expose) { + XGetWindowAttributes(dpy, win, &gwa); + glViewport(0, 0, gwa.width, gwa.height); + DrawThing(); + glXSwapBuffers(dpy, win); + } 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); + } + } + } +} diff --git a/main2.c b/main2.c @@ -0,0 +1,162 @@ +/* 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 +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <GL/gl.h> +#include <GL/glu.h> +#include <GL/glx.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 char *frag_src = +"#version 120\n" +"void main() { gl_FragColor = vec4(0.8, 0.4, 0.2, 1.0); }"; + +static GLuint compile_shader(GLenum type, const char *src) { + GLuint s = glCreateShader(type); + glShaderSource(s, 1, &src, NULL); + glCompileShader(s); + GLint ok = 0; + glGetShaderiv(s, 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); + } + return s; +} + +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; +} + +int main(void) { + Display *dpy = XOpenDisplay(NULL); + if (!dpy) { + fprintf(stderr, "Unable to open X display\n"); + return 1; + } + + /* 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; + } + + Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); + XSetWindowAttributes swa; + 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"); + XMapWindow(dpy, win); + + /* Create GLX context */ + 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); + + /* Triangle vertices (preset) */ + const GLfloat verts[] = { + 0.0f, 0.6f, 0.0f, + -0.6f, -0.4f, 0.0f, + 0.6f, -0.4f, 0.0f + }; + + /* Create simple VBO */ + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + + /* Set up GL state */ + glViewport(0, 0, 640, 480); + glClearColor(0.15f, 0.18f, 0.20f, 1.0f); + + /* Main loop */ + int running = 1; + while (running) { + while (XPending(dpy)) { + XEvent xe; + XNextEvent(dpy, &xe); + if (xe.type == Expose) { + /* ignore */ + } else if (xe.type == ConfigureNotify) { + XConfigureEvent *ce = (XConfigureEvent*)&xe; + 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); + + glUseProgram(prog); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(0); + glUseProgram(0); + + glXSwapBuffers(dpy, win); + /* Simple CPU-side sleep to limit spin (not required) */ + 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; +}