opengl_x11

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

commit 00c137be510c733070cfcf3c0ea6b57d00e19b18
parent 977c6aa28ffeb094a56bf6d091686a164fa102ed
Author: bsandro <email@bsandro.tech>
Date:   Thu, 20 Nov 2025 21:29:20 +0200

kept practice file with transformation matrices

Diffstat:
Dcube.c | 388-------------------------------------------------------------------------------
Atrans.c | 388+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 388 insertions(+), 388 deletions(-)

diff --git a/cube.c b/cube.c @@ -1,388 +0,0 @@ -/* 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/trans.c b/trans.c @@ -0,0 +1,388 @@ +/* transformation matrices */ +#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.f; + + 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 + } +}