opengl_x11

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

commit 32fffec98c6be4a6a302f39bd99dc72863718ce1
parent 67612dc61659fa60a2b9579f377b5f8f8e78279f
Author: bsandro <email@bsandro.tech>
Date:   Sun, 23 Nov 2025 16:01:32 +0200

sphere that doesn't look like sphere yet

Diffstat:
Asphere.c | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 273 insertions(+), 0 deletions(-)

diff --git a/sphere.c b/sphere.c @@ -0,0 +1,273 @@ +/* 3D cube */ +#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> +#define GL_GLEXT_PROTOTYPES 1 +#include <GL/gl.h> +#include <GL/glx.h> +#include <GL/glu.h> +#include "../cglm/include/cglm/cglm.h" + +#define RANDOM(x) (rand() % (x)) +#define LEN(x) (sizeof(x)/sizeof(x[0])) + +#define GL_CHECK(x) \ +x; \ +{ \ + GLenum glError = glGetError(); \ + if (glError!=GL_NO_ERROR) { \ + printf("glGetError() = %i (%#.8x) at %s:%i\n", glError, glError, __FILE__, __LINE__); \ + exit(EXIT_FAILURE); \ + } \ +} + +static const double current_ts() { + struct timespec ts; + timespec_get(&ts, TIME_UTC); + return (double)ts.tv_sec + (double)ts.tv_nsec/1e9; +} + +static double t_started; + +//@todo maybe move shaders to separate files +static const GLchar *vertexSrc = R"( +#version 420 +layout(location=0) in vec3 position; +layout(location=1) in vec2 aTexCoord; +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +void main() { + gl_Position = projection * view * model * vec4(position, 1.0); +} +)"; + +static const GLchar *fragmentSrc = R"( +#version 420 +uniform double iTime; +out vec4 outColor; +void main() { + outColor = vec4(0.1f, 0.5f, 0.2f, 0.0f); +} +)"; + +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"); + glBindAttribLocation(shaderProgram, 1, "aTexCoord"); + glLinkProgram(shaderProgram); + return shaderProgram; +} + +void __attribute__((constructor)) start() { + printf("start()\n"); + + // just a playground + vec4 vector = {1.0f, 0.0f, 0.0f, 1.0f}; + mat4 trans; + glm_mat4_identity(trans); + vec3 t = {1.0f, 1.0f, 0.0f}; + glm_translate(trans, t); + vec4 out; + glm_mat4_mulv(trans, vector, out); + glm_vec4_print(out, stdout); + + mat4 trans1; + glm_mat4_identity(trans1); + glm_rotate(trans1, glm_rad(90.0f), (vec3){0.0, 0.0, 1.0}); + glm_scale(trans1, (vec3){0.5, 0.5, 0.5}); + glm_mat4_print(trans1, stdout); + + t_started = current_ts(); + + srand(time(0)); +} + +void __attribute((destructor)) end() { + printf("end()\n"); +} + +void generateSphere(float radius, int stacks, int sectors, GLfloat outVertices[]) { + float stackStep = M_PI/stacks; + float sectorStep = 2.f*M_PI/sectors; + // deliberate <= + for (int i=0;i<=stacks;++i) { + float stackAngle = M_PI_2 - (float)i*stackStep; + float xy = radius*cosf(stackAngle); + float z = radius = sinf(stackAngle); + for (int j=0;j<=sectors;++j) { + float sectorAngle = (float)j*sectorStep; + float x = xy*cosf(sectorAngle); + float y = xy*sinf(sectorAngle); + int offset = i*sectors*3+j*3; + assert(offset<(stacks+1)*(sectors+1)*3); + outVertices[offset] = x; + outVertices[offset+1] = y; + outVertices[offset+2] = z; + } + } +} + +int main(int argc, char *argv[]) { + Display *dpy = XOpenDisplay(NULL); + XSetWindowAttributes swa; + Window win; + XWindowAttributes gwa; + GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; + + if (dpy == NULL) { + printf("\n\tcannot connect to X server\n\n"); + exit(0); + } + + 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, root, vi->visual, AllocNone); + swa.colormap = cmap; + swa.event_mask = ExposureMask | KeyPressMask; + win = XCreateWindow(dpy, root, 0, 0, 800, 600, 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); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + +#define stacks 50 +#define sectors 50 + // x,y,z + GLfloat vertices[(stacks+1)*(sectors+1)*3]; + generateSphere(10.f, stacks, sectors, vertices); + // + + vec3 positions[1] = {{0,0,0}}; + + glEnable(GL_DEPTH_TEST); + + 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); + + GLint prgStatus; + glGetProgramiv(shaderPrg, GL_LINK_STATUS, &prgStatus); + printf("shader link status: %s\n", prgStatus == GL_TRUE ? "ok" : "error"); + + GLint position = glGetAttribLocation(shaderPrg, "position"); + glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (void *)0); + glEnableVertexAttribArray(position); + + mat4 model; + glm_mat4_identity(model); + glm_rotate(model, glm_rad(-55.f), (vec3){1.f, 0.f, 0.f}); + mat4 view; + glm_mat4_identity(view); + glm_translate(view, (vec3){0.f, 0.f, -3.f}); + mat4 projection; + glm_perspective(glm_rad(55.f), 4.f/3.f, 0.1f, 100.f, projection); + + glm_mat4_print(model, stdout); + glm_mat4_print(view, stdout); + glm_mat4_print(projection, stdout); + + float speeds[1]; + for (int i=0; i<LEN(speeds); ++i) { + speeds[i] = RANDOM(90); + } + assert(LEN(positions)==LEN(speeds)); + + while (1) { + while (XPending(dpy)) { + 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:%3d\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); + } + } + + double t = current_ts()-t_started; + + glClearColor(0.1f, 0.1f, 0.15f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime"); + glUniform1d(iTime, t); + //printf("%f\n", fabsf(sinf(current_ts()-t_started))); + + //glm_rotate(model, glm_rad(1.f), (vec3){0.5f, 1.f, 0.f}); + //GLuint loc_model = glGetUniformLocation(shaderPrg, "model"); + //glUniformMatrix4fv(loc_model, 1, GL_FALSE, model[0]); + GLuint loc_view = glGetUniformLocation(shaderPrg, "view"); + glUniformMatrix4fv(loc_view, 1, GL_FALSE, view[0]); + GLuint loc_projection = glGetUniformLocation(shaderPrg, "projection"); + glUniformMatrix4fv(loc_projection, 1, GL_FALSE, projection[0]); + + glUseProgram(shaderPrg); + // ultra useful debug + glLineWidth(4.0f); + glPointSize(8.0f); + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + for (int i=0; i<LEN(positions); ++i) { + mat4 model; + glm_mat4_identity(model); + glm_translate(model, positions[i]); + GLfloat angle = 20.f * i + speeds[i]*t; + glm_rotate(model, glm_rad(angle), (vec3){ 1.f, 0.3f, 0.5f }); + GLuint loc_model = glGetUniformLocation(shaderPrg, "model"); + glUniformMatrix4fv(loc_model, 1, GL_FALSE, model[0]); + glDrawArrays(GL_POINTS, 0, LEN(vertices)); + } + + glXSwapBuffers(dpy, win); + usleep(1000*7); // 144hz + } +}