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 }