opengl_x11

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

obj2d.c (8313B)


      1 /* 2d object from single vertex */
      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 
     15 #define SIZE_W 800
     16 #define SIZE_H 800
     17 
     18 #define LEN(x) (sizeof(x)/sizeof(x[0]))
     19 
     20 #define GL_CHECK(x)                                                                           \
     21 x;                                                                                            \
     22 {                                                                                             \
     23     GLenum glError = glGetError();                                                            \
     24     if (glError!=GL_NO_ERROR) {                                                               \
     25         printf("glGetError() = %i (%#.8x) at %s:%i\n", glError, glError, __FILE__, __LINE__); \
     26         exit(EXIT_FAILURE);                                                                   \
     27     }                                                                                         \
     28 }
     29 
     30 static double current_ts() {
     31     struct timespec ts;
     32     timespec_get(&ts, TIME_UTC);
     33     return (double)ts.tv_sec + (double)ts.tv_nsec/1e9;
     34 }
     35 
     36 static double t_started;
     37 
     38 static const GLchar *vertexSrc = R"(
     39 #version 420
     40 in vec2 position;
     41 in vec3 color;
     42 out vec3 dotColor;
     43 void main() {
     44     gl_Position = vec4(position, 0.0, 1.0);
     45     dotColor = color;
     46 }
     47 )";
     48 
     49 static const GLchar *geometrySrc = R"(
     50 #version 420
     51 layout(points) in;
     52 layout(line_strip,max_vertices=6) out;
     53 in vec3 dotColor[];
     54 uniform double iTime;
     55 out vec3 fColor;
     56 
     57 mat2 rotate(float a) {
     58     float s = sin(a);
     59     float c = cos(a);
     60     return mat2(c, -s,
     61                 s,  c);
     62 }
     63 
     64 void main() {
     65     fColor = dotColor[0];
     66     vec4 p = gl_in[0].gl_Position;
     67     vec4 p1 = p+vec4(-0.1, -0.1, 0.0, 0.0);
     68     p1 = vec4(p.xy+rotate(float(iTime))*(p1.xy - p.xy), 0.0, 1.0);
     69     gl_Position = p1;
     70     EmitVertex();
     71     gl_Position = p+vec4(0.1, -0.1, 0.0, 0.0);
     72     gl_Position = vec4(p.xy+rotate(float(iTime))*(gl_Position.xy - p.xy), 0.0, 1.0);
     73     EmitVertex();
     74     gl_Position = p+vec4(0.1, 0.1, 0.0, 0.0);
     75     gl_Position = vec4(p.xy+rotate(float(iTime))*(gl_Position.xy - p.xy), 0.0, 1.0);
     76     EmitVertex();
     77     gl_Position = p+vec4(-0.1, 0.1, 0.0, 0.0);
     78     gl_Position = vec4(p.xy+rotate(float(iTime))*(gl_Position.xy - p.xy), 0.0, 1.0);
     79     EmitVertex();
     80     gl_Position = p1;
     81     EmitVertex();
     82     EndPrimitive();
     83 }
     84 )";
     85 
     86 static const GLchar *fragmentSrc = R"(
     87 #version 420
     88 uniform double iTime;
     89 in vec3 fColor;
     90 out vec4 outColor;
     91 void main() {
     92     vec3 color = fColor;
     93     if (gl_FragCoord.x < 300) {
     94         color.g = 1.0f;
     95     }
     96     outColor = vec4(color, 1.0);
     97 }
     98 )";
     99 
    100 static GLuint mkShader(GLenum type, const GLchar *src) {
    101     GLuint shader = glCreateShader(type);
    102     glShaderSource(shader, 1, &src, NULL);
    103     glCompileShader(shader);
    104     GLint ok = 0;
    105     glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
    106     if (!ok) {
    107         static char buf[512] = {0};
    108         glGetShaderInfoLog(shader, sizeof(buf)-1, NULL, buf);
    109         fprintf(stderr, "Shader %d compile error: %s\n", (int)type, buf);
    110     }
    111     return shader;
    112 }
    113 
    114 static GLuint linkProgram(GLuint vertex, GLuint geometry, GLuint fragment) {
    115     GLuint shaderProgram = glCreateProgram();
    116     glAttachShader(shaderProgram, vertex);
    117     glAttachShader(shaderProgram, geometry);
    118     glAttachShader(shaderProgram, fragment);
    119     //glBindAttribLocation(shaderProgram, 0, "position");
    120     //glBindAttribLocation(shaderProgram, 1, "color");
    121     glLinkProgram(shaderProgram);
    122     return shaderProgram;
    123 }
    124 
    125 void __attribute__((constructor)) start() {
    126     printf("start()\n");
    127     t_started = current_ts();
    128 }
    129 
    130 void __attribute((destructor)) end() {
    131     printf("end()\n");
    132 }
    133 
    134 struct vec2 {
    135     float x;
    136     float y;
    137 };
    138 
    139 struct vec2 rand_shift(void) {
    140     int xs = (rand()%2)==0?1:-1;
    141     int ys = (rand()%2)==0?1:-1;
    142     int x = xs*rand()%20;
    143     int y = ys*rand()%20;
    144     return (struct vec2){ .x=(float)x/10000.f, .y=(float)y/10000.f};
    145 }
    146 
    147 int main(void) {
    148     srand(time(0));
    149     Display *dpy = XOpenDisplay(NULL);
    150     XSetWindowAttributes swa;
    151     Window win;
    152     XWindowAttributes gwa;
    153     GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
    154 
    155     if (dpy == NULL) {
    156         printf("\n\tcannot connect to X server\n\n");
    157         exit(0);
    158     }
    159 
    160     Window root = DefaultRootWindow(dpy);
    161     XVisualInfo *vi = glXChooseVisual(dpy, 0, attr);
    162 
    163     if (vi == NULL) {
    164         printf("\n\tno appropriate visual found\n\n");
    165         exit(0);
    166     } else {
    167         printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */
    168     }
    169 
    170     Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    171     swa.colormap = cmap;
    172     swa.event_mask = ExposureMask | KeyPressMask;
    173     win = XCreateWindow(dpy, root, 0, 0, SIZE_W, SIZE_H, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
    174     XMapWindow(dpy, win);
    175     XStoreName(dpy, win, "OPENGL");
    176     GLXContext ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    177     glXMakeCurrent(dpy, win, ctx);
    178 
    179     // USEFUL DEBUG INFO
    180     //@todo validate ASTC support
    181     /*GLint extn;
    182     GL_CHECK(glGetIntegerv(GL_NUM_EXTENSIONS, &extn));
    183     printf("%d GL Extensions:\n", extn);
    184     for (GLint i=0; i<extn; ++i) {
    185         printf("\t%s\n", glGetStringi(GL_EXTENSIONS, i));
    186     }*/
    187 
    188     GLuint vao;
    189     glGenVertexArrays(1, &vao);
    190     glBindVertexArray(vao);
    191 
    192     // x,y, color(r,g,b)
    193     GLfloat vertices[][5] = {
    194         {-0.3, -0.5, 1.f, 0.f, 0.f},
    195         { 0.6, -0.1, 0.f, 1.f, 0.f},
    196         { 0.4,  0.4, 0.f, 0.f, 1.f},
    197         {-0.5,  0.6, 1.f, 1.f, 0.f}
    198     };
    199 
    200     GLuint vbo;
    201     glGenBuffers(1, &vbo);
    202     glBindBuffer(GL_ARRAY_BUFFER, vbo);
    203     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
    204 
    205     GLuint vertex = mkShader(GL_VERTEX_SHADER, vertexSrc);
    206     GLuint geometry = mkShader(GL_GEOMETRY_SHADER, geometrySrc);
    207     GLuint fragment = mkShader(GL_FRAGMENT_SHADER, fragmentSrc);
    208     GLuint shaderPrg = linkProgram(vertex, geometry, fragment);
    209 
    210     GLint prgStatus;
    211     glGetProgramiv(shaderPrg, GL_LINK_STATUS, &prgStatus);
    212     printf("shader link status: %s\n", prgStatus == GL_TRUE ? "ok" : "error");
    213 
    214     GLint position = glGetAttribLocation(shaderPrg, "position");
    215     glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void *)0);
    216     glEnableVertexAttribArray(position);
    217     GLint color = glGetAttribLocation(shaderPrg, "color");
    218     glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(2*sizeof(GLfloat)));
    219     glEnableVertexAttribArray(color);
    220 
    221     glLineWidth(1.f);
    222     glPointSize(4.f);
    223 
    224     while (1) {
    225         while (XPending(dpy)) {
    226             XEvent xev;
    227             XNextEvent(dpy, &xev);
    228             if (xev.type == Expose) {
    229                 XGetWindowAttributes(dpy, win, &gwa);
    230                 glViewport(0, 0, gwa.width, gwa.height);
    231             } else if (xev.type == KeyPress) {
    232                 printf("btn:%3d\n", xev.xbutton.button);
    233                 if (xev.xbutton.button==24||xev.xbutton.button==9) {
    234                     glXMakeCurrent(dpy, None, NULL);
    235                     glXDestroyContext(dpy, ctx);
    236                     XDestroyWindow(dpy, win);
    237                     XCloseDisplay(dpy);
    238                     exit(0);
    239                 }
    240             } else if (xev.type == ConfigureNotify) {
    241                 XConfigureEvent *ce = (XConfigureEvent *)&xev;
    242                 glViewport(0, 0, ce->width, ce->height);
    243             }
    244         }
    245         for (size_t i=0;i<LEN(vertices);++i) {
    246             struct vec2 shift = rand_shift();
    247             vertices[i][0] += shift.x;
    248             vertices[i][1] += shift.y;
    249         }
    250         glNamedBufferData(vbo, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
    251 
    252         glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
    253         glClear(GL_COLOR_BUFFER_BIT);
    254 
    255         GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime");
    256         glUniform1d(iTime, current_ts()-t_started);
    257         //printf("%f\n", fabsf(sinf(current_ts()-t_started)));
    258 
    259         glUseProgram(shaderPrg);
    260         glDrawArrays(GL_POINTS, 0, LEN(vertices));
    261 
    262         glXSwapBuffers(dpy, win);
    263         usleep(1000*7); // 144hz
    264     }
    265 }