opengl_x11

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

sphere.c (11065B)


      1 /* 3D sphere */
      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> // tesselator
     14 #include "../cglm/include/cglm/cglm.h"
     15 #include "astc.h"
     16 
     17 #define RANDOM(x) (rand() % (x))
     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 // I can push that to the local variables but want to keep the array on stack for now.
     31 #define STACKS 128
     32 #define SECTORS 128
     33 
     34 static const double current_ts() {
     35     struct timespec ts;
     36     timespec_get(&ts, TIME_UTC);
     37     return (double)ts.tv_sec + (double)ts.tv_nsec/1e9;
     38 }
     39 
     40 static double t_started;
     41 
     42 //@todo maybe move shaders to separate files
     43 static const GLchar *vertexSrc = R"(
     44 #version 420
     45 layout(location=0) in vec3 position;
     46 layout(location=1) in vec2 aTexCoord;
     47 out vec2 texCoord;
     48 uniform mat4 model;
     49 uniform mat4 view;
     50 uniform mat4 projection;
     51 void main() {
     52     gl_Position = projection * view * model * vec4(position, 1.0);
     53     texCoord = aTexCoord;
     54 }
     55 )";
     56 
     57 static const GLchar *fragmentSrc = R"(
     58 #version 420
     59 uniform double iTime;
     60 uniform sampler2D ourTex;
     61 out vec4 outColor;
     62 in vec2 texCoord;
     63 void main() {
     64     //outColor = vec4(0.1f, 0.5f, 0.2f, 0.0f);
     65     outColor = texture(ourTex, texCoord);
     66 }
     67 )";
     68 
     69 static GLuint mkShader(GLenum type, const GLchar *src) {
     70     GLuint shader = glCreateShader(type);
     71     glShaderSource(shader, 1, &src, NULL);
     72     glCompileShader(shader);
     73     GLint ok = 0;
     74     glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
     75     if (!ok) {
     76         static char buf[512] = {0};
     77         glGetShaderInfoLog(shader, sizeof(buf)-1, NULL, buf);
     78         fprintf(stderr, "Shader %d compile error: %s\n", (int)type, buf);
     79     }
     80     return shader;
     81 }
     82 
     83 static GLuint linkProgram(GLuint vertex, GLuint fragment) {
     84     GLuint shaderProgram = glCreateProgram();
     85     glAttachShader(shaderProgram, vertex);
     86     glAttachShader(shaderProgram, fragment);
     87     glBindAttribLocation(shaderProgram, 0, "position");
     88     glBindAttribLocation(shaderProgram, 1, "aTexCoord");
     89     glLinkProgram(shaderProgram);
     90     return shaderProgram;
     91 }
     92 
     93 void __attribute__((constructor)) start() {
     94     printf("start()\n");
     95 
     96     // just a playground
     97     vec4 vector = {1.0f, 0.0f, 0.0f, 1.0f};
     98     mat4 trans;
     99     glm_mat4_identity(trans);
    100     vec3 t = {1.0f, 1.0f, 0.0f};
    101     glm_translate(trans, t);
    102     vec4 out;
    103     glm_mat4_mulv(trans, vector, out);
    104     glm_vec4_print(out, stdout);
    105 
    106     mat4 trans1;
    107     glm_mat4_identity(trans1);
    108     glm_rotate(trans1, glm_rad(90.0f), (vec3){0.0, 0.0, 1.0});
    109     glm_scale(trans1, (vec3){0.5, 0.5, 0.5});
    110     glm_mat4_print(trans1, stdout);
    111 
    112     t_started = current_ts();
    113 
    114     srand(time(0));
    115 }
    116 
    117 void __attribute((destructor)) end() {
    118     printf("end()\n");
    119 }
    120 
    121 void generateSphere(float radius, int stacks, int sectors, GLfloat outVertices[]) {
    122     float stackStep = M_PI/stacks;
    123     float sectorStep = (2.f*M_PI)/sectors;
    124     int offset = 0;
    125     for (int i=0;i<=stacks;++i) {
    126         float stackAngle = M_PI_2 - (float)i*stackStep;
    127         float xy = radius*cosf(stackAngle);
    128         float z = radius*sinf(stackAngle);
    129         for (int j=0;j<=sectors;++j) {
    130             float sectorAngle = (float)j*sectorStep;
    131             float x = xy*cosf(sectorAngle);
    132             float y = xy*sinf(sectorAngle);
    133             float u = (float)j / sectors;
    134             float v = (float)i / stacks;
    135             outVertices[offset++] = x;
    136             outVertices[offset++] = y;
    137             outVertices[offset++] = z;
    138             outVertices[offset++] = u;
    139             outVertices[offset++] = v;
    140         }
    141     }
    142 }
    143 
    144 void generateElements(int stacks, int sectors, GLuint outElements[]) {
    145     uint32_t offset = 0;
    146     for (int i=0;i<stacks;++i) {
    147         int k1 = i*(sectors+1);
    148         int k2 = k1+sectors+1;
    149         for (int j=0;j<sectors;++j,++k1,++k2) {
    150             if (i!=0) {
    151                 outElements[offset++] = k1;
    152                 outElements[offset++] = k2;
    153                 outElements[offset++] = k1+1;
    154             }
    155             if (i!=(stacks-1)) {
    156                 outElements[offset++] = k1+1;
    157                 outElements[offset++] = k2;
    158                 outElements[offset++] = k2+1;
    159             }
    160         }
    161     }
    162     printf("elements offset: %lu\n", offset);
    163 }
    164 
    165 int main(int argc, char *argv[]) {
    166     Display *dpy = XOpenDisplay(NULL);
    167     XSetWindowAttributes swa;
    168     Window win;
    169     XWindowAttributes gwa;
    170     GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
    171 
    172     if (dpy == NULL) {
    173         printf("\n\tcannot connect to X server\n\n");
    174         exit(0);
    175     }
    176 
    177     Window root = DefaultRootWindow(dpy);
    178     XVisualInfo *vi = glXChooseVisual(dpy, 0, attr);
    179 
    180     if (vi == NULL) {
    181         printf("\n\tno appropriate visual found\n\n");
    182         exit(0);
    183     } else {
    184         printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */
    185     }
    186 
    187     Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    188     swa.colormap = cmap;
    189     swa.event_mask = ExposureMask | KeyPressMask;
    190     win = XCreateWindow(dpy, root, 0, 0, 800, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
    191     XMapWindow(dpy, win);
    192     XStoreName(dpy, win, "OPENGL");
    193     GLXContext ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    194     glXMakeCurrent(dpy, win, ctx);
    195 
    196     GLuint vao;
    197     glGenVertexArrays(1, &vao);
    198     glBindVertexArray(vao);
    199 
    200     const float radius = .9f;
    201     // x,y,z,u,v
    202     GLfloat vertices[(STACKS+1)*(SECTORS+1)*5];
    203     GLuint elements[(STACKS-1)*(SECTORS)*6];
    204     generateSphere(radius, STACKS, SECTORS, vertices);
    205     generateElements(STACKS, SECTORS, elements);
    206 
    207     printf("%4lu vertices\n%4lu elements\n", LEN(vertices), LEN(elements));
    208 
    209     vec3 positions[1] = {{0,0,0}};
    210 
    211     glShadeModel(GL_SMOOTH);
    212     glEnable(GL_MULTISAMPLE);
    213     glEnable(GL_DEPTH_TEST);
    214     glEnable(GL_CULL_FACE);
    215     glEnable(GL_LINE_SMOOTH);
    216     glEnable(GL_POLYGON_SMOOTH);
    217     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    218     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    219     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
    220 
    221     GLuint vbo;
    222     glGenBuffers(1, &vbo);
    223     glBindBuffer(GL_ARRAY_BUFFER, vbo);
    224     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    225 
    226     GLuint ebo;
    227     glGenBuffers(1, &ebo);
    228     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    229     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
    230 
    231     GLuint vertex = mkShader(GL_VERTEX_SHADER, vertexSrc);
    232     GLuint fragment = mkShader(GL_FRAGMENT_SHADER, fragmentSrc);
    233     GLuint shaderPrg = linkProgram(vertex, fragment);
    234 
    235     GLint prgStatus;
    236     glGetProgramiv(shaderPrg, GL_LINK_STATUS, &prgStatus);
    237     printf("shader link status: %s\n", prgStatus == GL_TRUE ? "ok" : "error");
    238 
    239     GLuint tex = mkTextureAstc("mars.astc");
    240 
    241     GLint position = glGetAttribLocation(shaderPrg, "position");
    242     glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void *)0);
    243     glEnableVertexAttribArray(position);
    244     GLint aTexCoord = glGetAttribLocation(shaderPrg, "aTexCoord");
    245     glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void *)(3*sizeof(GLfloat)));
    246     glEnableVertexAttribArray(aTexCoord);
    247 
    248     mat4 model;
    249     glm_mat4_identity(model);
    250     glm_rotate(model, glm_rad(-55.f), (vec3){1.f, 0.f, 0.f});
    251     mat4 view;
    252     glm_mat4_identity(view);
    253     glm_translate(view, (vec3){0.f, 0.f, -3.f});
    254     mat4 projection;
    255     glm_perspective(glm_rad(45.f), 4.f/3.f, 0.1f, 100.f, projection);
    256 
    257     glm_mat4_print(model, stdout);
    258     glm_mat4_print(view, stdout);
    259     glm_mat4_print(projection, stdout);
    260 
    261     float speeds[1];
    262     for (int i=0; i<LEN(speeds); ++i) {
    263         speeds[i] = RANDOM(90);
    264     }
    265     assert(LEN(positions)==LEN(speeds));
    266 
    267     while (1) {
    268         while (XPending(dpy)) {
    269             XEvent xev;
    270             XNextEvent(dpy, &xev);
    271             if (xev.type == Expose) {
    272                 XGetWindowAttributes(dpy, win, &gwa);
    273                 glViewport(0, 0, gwa.width, gwa.height);
    274             } else if (xev.type == KeyPress) {
    275                 printf("btn:%3d\n", xev.xbutton.button);
    276                 if (xev.xbutton.button==24||xev.xbutton.button==9) {
    277                     glXMakeCurrent(dpy, None, NULL);
    278                     glXDestroyContext(dpy, ctx);
    279                     XDestroyWindow(dpy, win);
    280                     XCloseDisplay(dpy);
    281                     exit(0);
    282                 }
    283             } else if (xev.type == ConfigureNotify) {
    284                 XConfigureEvent *ce = (XConfigureEvent *)&xev;
    285                 glViewport(0, 0, ce->width, ce->height);
    286             }
    287         }
    288 
    289         double t = current_ts()-t_started;
    290 
    291         glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
    292         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    293 
    294         GLfloat iTime = glGetUniformLocation(shaderPrg, "iTime");
    295         glUniform1d(iTime, t);
    296         //printf("%f\n", fabsf(sinf(current_ts()-t_started)));
    297 
    298         //glm_rotate(model, glm_rad(1.f), (vec3){0.5f, 1.f, 0.f});
    299         //GLuint loc_model = glGetUniformLocation(shaderPrg, "model");
    300         //glUniformMatrix4fv(loc_model, 1, GL_FALSE, model[0]);
    301         GLuint loc_view = glGetUniformLocation(shaderPrg, "view");
    302         glUniformMatrix4fv(loc_view, 1, GL_FALSE, view[0]);
    303         GLuint loc_projection = glGetUniformLocation(shaderPrg, "projection");
    304         glUniformMatrix4fv(loc_projection, 1, GL_FALSE, projection[0]);
    305 
    306         glUseProgram(shaderPrg);
    307         // ultra useful debug
    308         glLineWidth(1.0f);
    309         glPointSize(4.0f);
    310         //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    311 
    312         for (int i=0; i<LEN(positions); ++i) {
    313             mat4 model;
    314             glm_mat4_identity(model);
    315             glm_translate(model, positions[i]);
    316             GLfloat angle = 20.f * i + speeds[i]*t;
    317             glm_rotate(model, glm_rad(angle), (vec3){ 1.f, 0.3f, 0.5f });
    318             GLuint loc_model = glGetUniformLocation(shaderPrg, "model");
    319             glUniformMatrix4fv(loc_model, 1, GL_FALSE, model[0]);
    320 
    321             //glDrawArrays(GL_POINTS, 0, LEN(vertices));
    322             glDrawElements(GL_TRIANGLES, LEN(elements), GL_UNSIGNED_INT, 0);
    323         }
    324 
    325         glXSwapBuffers(dpy, win);
    326         usleep(1000*7); // 144hz
    327     }
    328 }