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 }