opengl_x11

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

texture.c (8695B)


      1 /* textures */
      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 #define STB_IMAGE_IMPLEMENTATION
     15 #include "stb_image.h"
     16 #include "astc.h"
     17 
     18 #define GL_CHECK(x)                                                                           \
     19 x;                                                                                            \
     20 {                                                                                             \
     21     GLenum glError = glGetError();                                                            \
     22     if (glError!=GL_NO_ERROR) {                                                               \
     23         printf("glGetError() = %i (%#.8x) at %s:%i\n", glError, glError, __FILE__, __LINE__); \
     24         exit(EXIT_FAILURE);                                                                   \
     25     }                                                                                         \
     26 }
     27 
     28 static const double current_ts() {
     29     struct timespec ts;
     30     timespec_get(&ts, TIME_UTC);
     31     return (double)ts.tv_sec + (double)ts.tv_nsec/1e9;
     32 }
     33 
     34 static double t_started;
     35 
     36 //@todo move shaders to separate files
     37 static const GLchar *vertexSrc = R"(
     38 #version 420
     39 layout(location=0) in vec2 position;
     40 layout(location=1) in vec2 aTexCoord;
     41 out vec2 texCoord;
     42 void main() {
     43     gl_Position = vec4(position, 0.0, 1.0);
     44     texCoord = aTexCoord;
     45 }
     46 )";
     47 
     48 static const GLchar *fragmentSrc = R"(
     49 #version 420
     50 uniform double iTime;
     51 uniform sampler2D ourTex;
     52 out vec4 outColor;
     53 in vec2 texCoord;
     54 void main() {
     55     vec3 color;
     56     color.r = 0.2;
     57     color.g = 0.6;
     58     color.b = 0.1;
     59     float c1 = abs(sin(float(iTime)));
     60     float c2 = abs(cos(float(iTime)));
     61     vec4 modColor = vec4(color+c1-c2, 1.0);
     62     outColor = texture(ourTex, texCoord) + modColor;
     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 static GLuint mkTexture(const char *filename) {
     91     GLuint tex;
     92     glGenTextures(1, &tex);
     93     glBindTexture(GL_TEXTURE_2D, tex);
     94     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     95     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     96     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
     97     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     98     int w, h, numchan;
     99     //stbi_set_flip_vertically_on_load(1);
    100     uint8_t *data = stbi_load(filename, &w, &h, &numchan, 3);
    101     if (data) {
    102         printf("texture %dx%d %dbpp\n", w, h, numchan*8);
    103         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    104         glGenerateMipmap(GL_TEXTURE_2D);
    105         glEnable(GL_TEXTURE_2D);
    106         stbi_image_free(data);
    107     } else {
    108         printf("Failed to load texture %s: %s\n", filename, stbi_failure_reason());
    109     }
    110     return tex;
    111 }
    112 
    113 void __attribute__((constructor)) start() {
    114     printf("start()\n");
    115     t_started = current_ts();
    116 }
    117 
    118 void __attribute((destructor)) end() {
    119     printf("end()\n");
    120 }
    121 
    122 int main(int argc, char *argv[]) {
    123     const char *tex_fname;
    124     bool is_astc = false;
    125     if (argc>1) {
    126         tex_fname = argv[1];
    127         int len = strlen(tex_fname);
    128         // ".astc" extension = 5 bytes
    129         is_astc = (len>ASTC_LEN&&strncmp(tex_fname+len-ASTC_LEN, ASTC_EXT, ASTC_LEN)==0);
    130     } else {
    131         tex_fname = "hina.astc";
    132         is_astc = true;
    133     }
    134     printf("texture file: %s (%s)\n", tex_fname, is_astc ? "astc" : "plain");
    135 
    136     Display *dpy = XOpenDisplay(NULL);
    137     XSetWindowAttributes swa;
    138     Window win;
    139     XWindowAttributes gwa;
    140     GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
    141 
    142     if (dpy == NULL) {
    143         printf("\n\tcannot connect to X server\n\n");
    144         exit(0);
    145     }
    146 
    147     Window root = DefaultRootWindow(dpy);
    148     XVisualInfo *vi = glXChooseVisual(dpy, 0, attr);
    149 
    150     if (vi == NULL) {
    151         printf("\n\tno appropriate visual found\n\n");
    152         exit(0);
    153     } else {
    154         printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */
    155     }
    156 
    157     Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    158     swa.colormap = cmap;
    159     swa.event_mask = ExposureMask | KeyPressMask;
    160     win = XCreateWindow(dpy, root, 0, 0, 500, 500, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
    161     XMapWindow(dpy, win);
    162     XStoreName(dpy, win, "OPENGL");
    163     GLXContext ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    164     glXMakeCurrent(dpy, win, ctx);
    165 
    166     // USEFUL DEBUG INFO
    167     //@todo validate ASTC support
    168     /*GLint extn;
    169     GL_CHECK(glGetIntegerv(GL_NUM_EXTENSIONS, &extn));
    170     printf("%d GL Extensions:\n", extn);
    171     for (GLint i=0; i<extn; ++i) {
    172         printf("\t%s\n", glGetStringi(GL_EXTENSIONS, i));
    173     }*/
    174 
    175     GLuint vao;
    176     glGenVertexArrays(1, &vao);
    177     glBindVertexArray(vao);
    178 
    179     // @todo geh
    180     const GLfloat c = 0; //0.099f;
    181 
    182     // x,y,tx,ty
    183     static const GLfloat vertices[] = {
    184         -0.5, -0.5, 0+c, 1-c,
    185          0.5, -0.5, 1-c, 1-c,
    186          0.5,  0.5, 1-c, 0+c,
    187         -0.5,  0.5, 0+c, 0+c
    188     };
    189     static const GLuint elements[] = {
    190         0, 1, 2,
    191         2, 3, 0
    192     };
    193 
    194     GLuint vbo;
    195     glGenBuffers(1, &vbo);
    196     glBindBuffer(GL_ARRAY_BUFFER, vbo);
    197     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    198 
    199     GLuint ebo;
    200     glGenBuffers(1, &ebo);
    201     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    202     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
    203 
    204     GLuint vertex = mkShader(GL_VERTEX_SHADER, vertexSrc);
    205     GLuint fragment = mkShader(GL_FRAGMENT_SHADER, fragmentSrc);
    206     GLuint shaderPrg = linkProgram(vertex, fragment);
    207 
    208     GLint prgStatus;
    209     glGetProgramiv(shaderPrg, GL_LINK_STATUS, &prgStatus);
    210     printf("shader link status: %s\n", prgStatus == GL_TRUE ? "ok" : "error");
    211 
    212     // texture
    213     GLuint tex = is_astc ? mkTextureAstc(tex_fname) : mkTexture(tex_fname);
    214     GLint position = glGetAttribLocation(shaderPrg, "position");
    215     glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void *)0);
    216     glEnableVertexAttribArray(position);
    217     GLint aTexCoord = glGetAttribLocation(shaderPrg, "aTexCoord");
    218     glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));
    219     glEnableVertexAttribArray(aTexCoord);
    220 
    221     while (1) {
    222         while (XPending(dpy)) {
    223             XEvent xev;
    224             XNextEvent(dpy, &xev);
    225             if (xev.type == Expose) {
    226                 XGetWindowAttributes(dpy, win, &gwa);
    227                 glViewport(0, 0, gwa.width, gwa.height);
    228             } else if (xev.type == KeyPress) {
    229                 printf("btn:%3d\n", xev.xbutton.button);
    230                 if (xev.xbutton.button==24||xev.xbutton.button==9) {
    231                     glXMakeCurrent(dpy, None, NULL);
    232                     glXDestroyContext(dpy, ctx);
    233                     XDestroyWindow(dpy, win);
    234                     XCloseDisplay(dpy);
    235                     exit(0);
    236                 }
    237             } else if (xev.type == ConfigureNotify) {
    238                 XConfigureEvent *ce = (XConfigureEvent *)&xev;
    239                 glViewport(0, 0, ce->width, ce->height);
    240             }
    241         }
    242 
    243         glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
    244         glClear(GL_COLOR_BUFFER_BIT);
    245 
    246         GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime");
    247         glUniform1d(iTime, current_ts()-t_started);
    248         //printf("%f\n", fabsf(sinf(current_ts()-t_started)));
    249 
    250         glUseProgram(shaderPrg);
    251         glUniform1i(tex, 0);
    252         glActiveTexture(GL_TEXTURE0);
    253         glBindTexture(GL_TEXTURE_2D, tex);
    254         glDrawElements(GL_TRIANGLES, sizeof(elements)/sizeof(elements[0]), GL_UNSIGNED_INT, 0);
    255 
    256         glXSwapBuffers(dpy, win);
    257         usleep(1000*7); // 144hz
    258     }
    259 }