opengl_x11

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

cube.c (11604B)


      1 /* 3D cube */
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <time.h>
      6 #include <unistd.h>
      7 #include <math.h>
      8 #include <X11/X.h>
      9 #include <X11/Xlib.h>
     10 #define GL_GLEXT_PROTOTYPES 1
     11 #include <GL/gl.h>
     12 #include <GL/glx.h>
     13 #include <GL/glu.h>
     14 #include "../cglm/include/cglm/cglm.h"
     15 #include "astc.h"
     16 #define STB_IMAGE_IMPLEMENTATION
     17 #include "stb_image.h"
     18 
     19 #define RANDOM(x) (rand() % (x))
     20 #define LEN(x) (sizeof(x)/sizeof(x[0]))
     21 
     22 #define GL_CHECK(x)                                                                           \
     23 x;                                                                                            \
     24 {                                                                                             \
     25     GLenum glError = glGetError();                                                            \
     26     if (glError!=GL_NO_ERROR) {                                                               \
     27         printf("glGetError() = %i (%#.8x) at %s:%i\n", glError, glError, __FILE__, __LINE__); \
     28         exit(EXIT_FAILURE);                                                                   \
     29     }                                                                                         \
     30 }
     31 
     32 static const double current_ts() {
     33     struct timespec ts;
     34     timespec_get(&ts, TIME_UTC);
     35     return (double)ts.tv_sec + (double)ts.tv_nsec/1e9;
     36 }
     37 
     38 static double t_started;
     39 
     40 //@todo maybe move shaders to separate files
     41 static const GLchar *vertexSrc = R"(
     42 #version 420
     43 layout(location=0) in vec3 position;
     44 layout(location=1) in vec2 aTexCoord;
     45 out vec2 texCoord;
     46 uniform mat4 model;
     47 uniform mat4 view;
     48 uniform mat4 projection;
     49 void main() {
     50     gl_Position = projection * view * model * vec4(position, 1.0);
     51     texCoord = aTexCoord;
     52 }
     53 )";
     54 
     55 static const GLchar *fragmentSrc = R"(
     56 #version 420
     57 uniform double iTime;
     58 uniform sampler2D ourTex;
     59 out vec4 outColor;
     60 in vec2 texCoord;
     61 void main() {
     62     outColor = texture(ourTex, texCoord);
     63 }
     64 )";
     65 
     66 static GLuint mkShader(GLenum type, const GLchar *src) {
     67     GLuint shader = glCreateShader(type);
     68     glShaderSource(shader, 1, &src, NULL);
     69     glCompileShader(shader);
     70     GLint ok = 0;
     71     glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
     72     if (!ok) {
     73         static char buf[512] = {0};
     74         glGetShaderInfoLog(shader, sizeof(buf)-1, NULL, buf);
     75         fprintf(stderr, "Shader %d compile error: %s\n", (int)type, buf);
     76     }
     77     return shader;
     78 }
     79 
     80 static GLuint linkProgram(GLuint vertex, GLuint fragment) {
     81     GLuint shaderProgram = glCreateProgram();
     82     glAttachShader(shaderProgram, vertex);
     83     glAttachShader(shaderProgram, fragment);
     84     glBindAttribLocation(shaderProgram, 0, "position");
     85     glBindAttribLocation(shaderProgram, 1, "aTexCoord");
     86     glLinkProgram(shaderProgram);
     87     return shaderProgram;
     88 }
     89 
     90 void __attribute__((constructor)) start() {
     91     printf("start()\n");
     92 
     93     // just a playground
     94     vec4 vector = {1.0f, 0.0f, 0.0f, 1.0f};
     95     mat4 trans;
     96     glm_mat4_identity(trans);
     97     vec3 t = {1.0f, 1.0f, 0.0f};
     98     glm_translate(trans, t);
     99     vec4 out;
    100     glm_mat4_mulv(trans, vector, out);
    101     glm_vec4_print(out, stdout);
    102 
    103     mat4 trans1;
    104     glm_mat4_identity(trans1);
    105     glm_rotate(trans1, glm_rad(90.0f), (vec3){0.0, 0.0, 1.0});
    106     glm_scale(trans1, (vec3){0.5, 0.5, 0.5});
    107     glm_mat4_print(trans1, stdout);
    108 
    109     t_started = current_ts();
    110 
    111     srand(time(0));
    112 }
    113 
    114 void __attribute((destructor)) end() {
    115     printf("end()\n");
    116 }
    117 
    118 int main(int argc, char *argv[]) {
    119     const char *tex_fname;
    120     if (argc>1) {
    121         tex_fname = argv[1];
    122         int len = strlen(tex_fname);
    123         // ".astc" extension = 5 bytes
    124         if (len<ASTC_LEN || strncmp(tex_fname+len-ASTC_LEN, ASTC_EXT, ASTC_LEN)!=0) {
    125             printf("only .astc textures are supported\n");
    126             exit(-1);
    127         }
    128     } else {
    129         tex_fname = "hina.astc";
    130     }
    131     printf("texture file: %s\n", tex_fname);
    132 
    133     Display *dpy = XOpenDisplay(NULL);
    134     XSetWindowAttributes swa;
    135     Window win;
    136     XWindowAttributes gwa;
    137     GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
    138 
    139     if (dpy == NULL) {
    140         printf("\n\tcannot connect to X server\n\n");
    141         exit(0);
    142     }
    143 
    144     Window root = DefaultRootWindow(dpy);
    145     XVisualInfo *vi = glXChooseVisual(dpy, 0, attr);
    146 
    147     if (vi == NULL) {
    148         printf("\n\tno appropriate visual found\n\n");
    149         exit(0);
    150     } else {
    151         printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */
    152     }
    153 
    154     Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    155     swa.colormap = cmap;
    156     swa.event_mask = ExposureMask | KeyPressMask;
    157     win = XCreateWindow(dpy, root, 0, 0, 800, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
    158     XMapWindow(dpy, win);
    159     XStoreName(dpy, win, "OPENGL");
    160     GLXContext ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    161     glXMakeCurrent(dpy, win, ctx);
    162 
    163     // USEFUL DEBUG INFO
    164     //@todo validate ASTC support
    165     /*GLint extn;
    166     GL_CHECK(glGetIntegerv(GL_NUM_EXTENSIONS, &extn));
    167     printf("%d GL Extensions:\n", extn);
    168     for (GLint i=0; i<extn; ++i) {
    169         printf("\t%s\n", glGetStringi(GL_EXTENSIONS, i));
    170     }*/
    171 
    172     GLuint vao;
    173     glGenVertexArrays(1, &vao);
    174     glBindVertexArray(vao);
    175 
    176     // @todo geh some astc stuff I haven't figured out
    177     const GLfloat c = 0.099f;
    178 
    179     // x,y,tx,ty
    180     static const GLfloat vertices[] = {
    181         -0.5f, -0.5f, -0.5f,  0.0f+c, 0.0f+c,
    182          0.5f, -0.5f, -0.5f,  1.0f-c, 0.0f+c,
    183          0.5f,  0.5f, -0.5f,  1.0f-c, 1.0f-c,
    184          0.5f,  0.5f, -0.5f,  1.0f-c, 1.0f-c,
    185         -0.5f,  0.5f, -0.5f,  0.0f+c, 1.0f-c,
    186         -0.5f, -0.5f, -0.5f,  0.0f+c, 0.0f+c,
    187 
    188         -0.5f, -0.5f,  0.5f,  0.0f+c, 0.0f+c,
    189          0.5f, -0.5f,  0.5f,  1.0f-c, 0.0f+c,
    190          0.5f,  0.5f,  0.5f,  1.0f-c, 1.0f-c,
    191          0.5f,  0.5f,  0.5f,  1.0f-c, 1.0f-c,
    192         -0.5f,  0.5f,  0.5f,  0.0f+c, 1.0f-c,
    193         -0.5f, -0.5f,  0.5f,  0.0f+c, 0.0f+c,
    194 
    195         -0.5f,  0.5f,  0.5f,  1.0f-c, 0.0f+c,
    196         -0.5f,  0.5f, -0.5f,  1.0f-c, 1.0f-c,
    197         -0.5f, -0.5f, -0.5f,  0.0f+c, 1.0f-c,
    198         -0.5f, -0.5f, -0.5f,  0.0f+c, 1.0f-c,
    199         -0.5f, -0.5f,  0.5f,  0.0f+c, 0.0f+c,
    200         -0.5f,  0.5f,  0.5f,  1.0f-c, 0.0f+c,
    201 
    202          0.5f,  0.5f,  0.5f,  1.0f-c, 0.0f+c,
    203          0.5f,  0.5f, -0.5f,  1.0f-c, 1.0f-c,
    204          0.5f, -0.5f, -0.5f,  0.0f+c, 1.0f-c,
    205          0.5f, -0.5f, -0.5f,  0.0f+c, 1.0f-c,
    206          0.5f, -0.5f,  0.5f,  0.0f+c, 0.0f+c,
    207          0.5f,  0.5f,  0.5f,  1.0f-c, 0.0f+c,
    208 
    209         -0.5f, -0.5f, -0.5f,  0.0f+c, 1.0f-c,
    210          0.5f, -0.5f, -0.5f,  1.0f-c, 1.0f-c,
    211          0.5f, -0.5f,  0.5f,  1.0f-c, 0.0f+c,
    212          0.5f, -0.5f,  0.5f,  1.0f-c, 0.0f+c,
    213         -0.5f, -0.5f,  0.5f,  0.0f+c, 0.0f+c,
    214         -0.5f, -0.5f, -0.5f,  0.0f+c, 1.0f-c,
    215 
    216         -0.5f,  0.5f, -0.5f,  0.0f+c, 1.0f-c,
    217          0.5f,  0.5f, -0.5f,  1.0f-c, 1.0f-c,
    218          0.5f,  0.5f,  0.5f,  1.0f-c, 0.0f+c,
    219          0.5f,  0.5f,  0.5f,  1.0f-c, 0.0f+c,
    220         -0.5f,  0.5f,  0.5f,  0.0f+c, 0.0f+c,
    221         -0.5f,  0.5f, -0.5f,  0.0f+c, 1.0f-c
    222     };
    223 
    224     vec3 cubePositions[] = {
    225         { 0.0f,  0.0f,  0.0f  },
    226         { 2.0f,  5.0f, -15.0f },
    227         {-1.5f, -2.2f, -2.5f  },
    228         {-3.8f, -2.0f, -12.3f },
    229         { 2.4f, -0.4f, -3.5f  },
    230         {-1.7f,  3.0f, -7.5f  },
    231         { 1.3f, -2.0f, -2.5f  },
    232         { 1.5f,  2.0f, -2.5f  },
    233         { 1.5f,  0.2f, -1.5f  },
    234         {-1.3f,  1.0f, -1.5f  }
    235     };
    236 
    237     glEnable(GL_DEPTH_TEST);
    238 
    239     GLuint vbo;
    240     glGenBuffers(1, &vbo);
    241     glBindBuffer(GL_ARRAY_BUFFER, vbo);
    242     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    243 
    244     GLuint vertex = mkShader(GL_VERTEX_SHADER, vertexSrc);
    245     GLuint fragment = mkShader(GL_FRAGMENT_SHADER, fragmentSrc);
    246     GLuint shaderPrg = linkProgram(vertex, fragment);
    247 
    248     GLint prgStatus;
    249     glGetProgramiv(shaderPrg, GL_LINK_STATUS, &prgStatus);
    250     printf("shader link status: %s\n", prgStatus == GL_TRUE ? "ok" : "error");
    251 
    252     // texture - the only line that matters it seems!
    253     GLuint tex = mkTextureAstc(tex_fname);
    254     GLint position = glGetAttribLocation(shaderPrg, "position");
    255     glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void *)0);
    256     glEnableVertexAttribArray(position);
    257     GLint aTexCoord = glGetAttribLocation(shaderPrg, "aTexCoord");
    258     glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void *)(3*sizeof(GLfloat)));
    259     glEnableVertexAttribArray(aTexCoord);
    260 
    261     mat4 model;
    262     glm_mat4_identity(model);
    263     glm_rotate(model, glm_rad(-55.f), (vec3){1.f, 0.f, 0.f});
    264     mat4 view;
    265     glm_mat4_identity(view);
    266     glm_translate(view, (vec3){0.f, 0.f, -3.f});
    267     mat4 projection;
    268     glm_perspective(glm_rad(45.f), 4.f/3.f, 0.1f, 100.f, projection);
    269 
    270     glm_mat4_print(model, stdout);
    271     glm_mat4_print(view, stdout);
    272     glm_mat4_print(projection, stdout);
    273 
    274     float speeds[10];
    275     for (int i=0; i<LEN(speeds); ++i) {
    276         speeds[i] = RANDOM(360);
    277     }
    278     assert(LEN(cubePositions)==LEN(speeds));
    279 
    280     while (1) {
    281         while (XPending(dpy)) {
    282             XEvent xev;
    283             XNextEvent(dpy, &xev);
    284             if (xev.type == Expose) {
    285                 XGetWindowAttributes(dpy, win, &gwa);
    286                 glViewport(0, 0, gwa.width, gwa.height);
    287             } else if (xev.type == KeyPress) {
    288                 printf("btn:%3d\n", xev.xbutton.button);
    289                 if (xev.xbutton.button==24||xev.xbutton.button==9) {
    290                     glXMakeCurrent(dpy, None, NULL);
    291                     glXDestroyContext(dpy, ctx);
    292                     XDestroyWindow(dpy, win);
    293                     XCloseDisplay(dpy);
    294                     exit(0);
    295                 }
    296             } else if (xev.type == ConfigureNotify) {
    297                 XConfigureEvent *ce = (XConfigureEvent *)&xev;
    298                 glViewport(0, 0, ce->width, ce->height);
    299             }
    300         }
    301 
    302         double t = current_ts()-t_started;
    303 
    304         glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
    305         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    306 
    307         GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime");
    308         glUniform1d(iTime, t);
    309         //printf("%f\n", fabsf(sinf(current_ts()-t_started)));
    310 
    311         //glm_rotate(model, glm_rad(1.f), (vec3){0.5f, 1.f, 0.f});
    312         //GLuint loc_model = glGetUniformLocation(shaderPrg, "model");
    313         //glUniformMatrix4fv(loc_model, 1, GL_FALSE, model[0]);
    314         GLuint loc_view = glGetUniformLocation(shaderPrg, "view");
    315         glUniformMatrix4fv(loc_view, 1, GL_FALSE, view[0]);
    316         GLuint loc_projection = glGetUniformLocation(shaderPrg, "projection");
    317         glUniformMatrix4fv(loc_projection, 1, GL_FALSE, projection[0]);
    318 
    319         glUseProgram(shaderPrg);
    320         // if I remove next 3 lines the texture is still being rendered, curious
    321         glUniform1i(tex, 0);
    322         glActiveTexture(GL_TEXTURE0);
    323         glBindTexture(GL_TEXTURE_2D, tex);
    324         // ultra useful debug
    325         //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    326 
    327         for (int i=0; i<LEN(cubePositions); ++i) {
    328             mat4 model;
    329             glm_mat4_identity(model);
    330             glm_translate(model, cubePositions[i]);
    331             GLfloat angle = 20.f * i + speeds[i]*t;
    332             glm_rotate(model, glm_rad(angle), (vec3){ 1.f, 0.3f, 0.5f });
    333             GLuint loc_model = glGetUniformLocation(shaderPrg, "model");
    334             glUniformMatrix4fv(loc_model, 1, GL_FALSE, model[0]);
    335             glDrawArrays(GL_TRIANGLES, 0, LEN(vertices));
    336         }
    337 
    338         glXSwapBuffers(dpy, win);
    339         usleep(1000*7); // 144hz
    340     }
    341 }