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:
| A | sphere.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
+ }
+}