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 }