commit 977c6aa28ffeb094a56bf6d091686a164fa102ed
parent 90cd65b3f5846304ddb7e4d40baaef5998ecf1cb
Author: bsandro <email@bsandro.tech>
Date: Wed, 19 Nov 2025 00:22:00 +0200
rotating stuff
Diffstat:
4 files changed, 388 insertions(+), 0 deletions(-)
diff --git a/cube.c b/cube.c
@@ -0,0 +1,388 @@
+/* textures */
+#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 STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+#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); \
+ } \
+}
+
+#define ASTC_EXT ".astc"
+#define ASTC_LEN 5
+
+/* ASTC header declaration. */
+typedef struct
+{
+ uint8_t magic[4];
+ uint8_t blockdim_x;
+ uint8_t blockdim_y;
+ uint8_t blockdim_z;
+ uint8_t xsize[3];
+ uint8_t ysize[3];
+ uint8_t zsize[3];
+} astc_header;
+
+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 move shaders to separate files
+static const GLchar *vertexSrc = R"(
+#version 420
+layout(location=0) in vec2 position;
+layout(location=1) in vec2 aTexCoord;
+out vec2 texCoord;
+uniform mat4 trans;
+void main() {
+ mat4 t;
+ t[0][0]=1.0f;
+ t[1][1]=1.0f;
+ t[2][2]=1.0f;
+ t[3][3]=1.0f;
+ gl_Position = trans * vec4(position, 0.0, 1.0);
+ texCoord = aTexCoord;
+}
+)";
+
+static const GLchar *fragmentSrc = R"(
+#version 420
+uniform double iTime;
+uniform sampler2D ourTex;
+uniform mat4 trans;
+out vec4 outColor;
+in vec2 texCoord;
+void main() {
+ vec3 color;
+ color.r = 0.2;
+ color.g = 0.6;
+ color.b = 0.1;
+ float c1 = abs(sin(float(iTime)));
+ float c2 = abs(cos(float(iTime)));
+ vec4 modColor = vec4(color+c1-c2, 1.0);
+ outColor = texture(ourTex, texCoord) + modColor;
+}
+)";
+
+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;
+}
+
+static GLuint mkTexture(const char *filename) {
+ GLuint tex;
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ int w, h, numchan;
+ //stbi_set_flip_vertically_on_load(1);
+ uint8_t *data = stbi_load(filename, &w, &h, &numchan, 3);
+ if (data) {
+ printf("texture %dx%d %dbpp\n", w, h, numchan*8);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_2D);
+ stbi_image_free(data);
+ } else {
+ printf("Failed to load texture %s: %s\n", filename, stbi_failure_reason());
+ }
+ return tex;
+}
+
+#define CHECK_ASTC_FORMAT(bx, by) if (x==bx&&y==by) return GL_COMPRESSED_RGBA_ASTC_##bx##x##by##_KHR;
+
+GLenum get_astc_format(uint8_t x, uint8_t y) {
+ CHECK_ASTC_FORMAT(4,4)
+ CHECK_ASTC_FORMAT(5,4)
+ CHECK_ASTC_FORMAT(5,5)
+ CHECK_ASTC_FORMAT(6,5)
+ CHECK_ASTC_FORMAT(6,6)
+ CHECK_ASTC_FORMAT(8,5)
+ CHECK_ASTC_FORMAT(8,6)
+ CHECK_ASTC_FORMAT(8,8)
+ CHECK_ASTC_FORMAT(10,5)
+ CHECK_ASTC_FORMAT(10,6)
+ CHECK_ASTC_FORMAT(10,8)
+ CHECK_ASTC_FORMAT(10,10)
+ CHECK_ASTC_FORMAT(12,10)
+ CHECK_ASTC_FORMAT(12,12)
+
+ printf("invalid ASTC block size\n");
+ exit(-1);
+}
+
+static GLuint mkTextureAstc(const char *filename) {
+ FILE *f = fopen(filename, "rb");
+ if (f==NULL) {
+ printf("error loading file %s\n", filename);
+ exit(EXIT_FAILURE);
+ }
+
+ fseek(f, 0, SEEK_END);
+ int64_t fsize = ftell(f);
+ rewind(f);
+
+ printf("astc file size: %lld bytes\n", fsize);
+
+ uint8_t *data = malloc(fsize);
+ if (fread(data, 1, fsize, f) != fsize) {
+ printf("error reading file %s\n", filename);
+ exit(EXIT_FAILURE);
+ }
+
+ const astc_header *astc_data = (astc_header *)data;
+ printf("astc block: %dx%d\n", astc_data->blockdim_x, astc_data->blockdim_y);
+ GLenum astc_format = get_astc_format(astc_data->blockdim_x, astc_data->blockdim_y);
+ /* Merge x,y,z-sizes from 3 chars into one integer value. */
+ GLsizei xsize = astc_data->xsize[0] + (astc_data->xsize[1] << 8) + (astc_data->xsize[2] << 16);
+ GLsizei ysize = astc_data->ysize[0] + (astc_data->ysize[1] << 8) + (astc_data->ysize[2] << 16);
+ GLsizei zsize = astc_data->zsize[0] + (astc_data->zsize[1] << 8) + (astc_data->zsize[2] << 16);
+
+ printf("astc dimensions: %dx%d\n", xsize, ysize);
+
+ /* Compute number of blocks in each direction. */
+ GLsizei xblocks = (xsize + astc_data->blockdim_x - 1) / astc_data->blockdim_x;
+ GLsizei yblocks = (ysize + astc_data->blockdim_y - 1) / astc_data->blockdim_y;
+ GLsizei zblocks = (zsize + astc_data->blockdim_z - 1) / astc_data->blockdim_z;
+
+ // maybe we can do just fsize-16 here
+ GLsizei astc_size = xblocks * yblocks * zblocks << 4;
+
+ printf("astc data size: %lld bytes\n", astc_size);
+
+ GLuint tex;
+ GL_CHECK(glGenTextures(1, &tex));
+ GL_CHECK(glBindTexture(GL_TEXTURE_2D, tex));
+ GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); // GL_REPEAT
+ GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)); // GL_CLAMP_TO_EDGE
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+ GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+ GL_CHECK(glCompressedTexImage2D(GL_TEXTURE_2D, 0, astc_format, xsize, ysize, 0, astc_size, (const GLvoid *)astc_data));
+ //GL_CHECK(glGenerateMipmap(GL_TEXTURE_2D));
+ GL_CHECK(glEnable(GL_TEXTURE_2D));
+
+ fclose(f);
+ free(data);
+ return tex;
+}
+
+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();
+}
+
+void __attribute((destructor)) end() {
+ printf("end()\n");
+}
+
+int main(int argc, char *argv[]) {
+ const char *tex_fname;
+ bool is_astc = false;
+ if (argc>1) {
+ tex_fname = argv[1];
+ int len = strlen(tex_fname);
+ // ".astc" extension = 5 bytes
+ is_astc = (len>ASTC_LEN&&strncmp(tex_fname+len-ASTC_LEN, ASTC_EXT, ASTC_LEN)==0);
+ } else {
+ tex_fname = "hina.astc";
+ is_astc = true;
+ }
+ printf("texture file: %s (%s)\n", tex_fname, is_astc ? "astc" : "plain");
+
+ 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, 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);
+
+ // USEFUL DEBUG INFO
+ //@todo validate ASTC support
+ /*GLint extn;
+ GL_CHECK(glGetIntegerv(GL_NUM_EXTENSIONS, &extn));
+ printf("%d GL Extensions:\n", extn);
+ for (GLint i=0; i<extn; ++i) {
+ printf("\t%s\n", glGetStringi(GL_EXTENSIONS, i));
+ }*/
+
+ GLuint vao;
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+
+ // @todo geh
+ const GLfloat c = 0; //0.099f;
+
+ // x,y,tx,ty
+ static const GLfloat vertices[] = {
+ -0.5, -0.5, 0+c, 1-c,
+ 0.5, -0.5, 1-c, 1-c,
+ 0.5, 0.5, 1-c, 0+c,
+ -0.5, 0.5, 0+c, 0+c
+ };
+ static const GLuint elements[] = {
+ 0, 1, 2,
+ 2, 3, 0
+ };
+
+ GLuint vbo;
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ 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);
+
+ 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");
+
+ // texture
+ GLuint tex = is_astc ? mkTextureAstc(tex_fname) : mkTexture(tex_fname);
+ GLint position = glGetAttribLocation(shaderPrg, "position");
+ glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void *)0);
+ glEnableVertexAttribArray(position);
+ GLint aTexCoord = glGetAttribLocation(shaderPrg, "aTexCoord");
+ glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));
+ glEnableVertexAttribArray(aTexCoord);
+
+ mat4 trans;
+ glm_mat4_identity(trans);
+ //glm_rotate(trans, glm_rad(90.0f), (vec3){0.0, 0.0, 1.0});
+ glm_scale(trans, (vec3){1.2, 1.2, 1.2});
+ glm_mat4_print(trans, stdout);
+
+ float rotation = 1.5f;
+
+ 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);
+ }
+ }
+
+ glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime");
+ glUniform1d(iTime, current_ts()-t_started);
+ //printf("%f\n", fabsf(sinf(current_ts()-t_started)));
+
+ glm_rotate(trans, glm_rad(rotation), (vec3){0.0, 0.0, 1.0});
+ GLuint transform = glGetUniformLocation(shaderPrg, "trans");
+ glUniformMatrix4fv(transform, 1, GL_FALSE, trans[0]);
+
+ glUseProgram(shaderPrg);
+ glUniform1i(tex, 0);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glDrawElements(GL_TRIANGLES, sizeof(elements)/sizeof(elements[0]), GL_UNSIGNED_INT, 0);
+
+ glXSwapBuffers(dpy, win);
+ usleep(1000*7); // 144hz
+ }
+}
diff --git a/doge_icon.astc b/doge_icon.astc
Binary files differ.
diff --git a/icon2.astc b/icon2.astc
Binary files differ.
diff --git a/pickle_icon.astc b/pickle_icon.astc
Binary files differ.