#include #include #include #include #include #define GL_GLEXT_PROTOTYPES #ifndef GLUT #include #include #include #else #include #include #include #endif #include "util.h" #ifndef GLUT EGLDisplay dpy; #endif GLuint vbo; GLint proj_uniform, tex_uniform, tex2_uniform, pixelsize_uniform, search_rect_uniform, barrier_uniform; GLuint texture; GLuint texture2; int width, height; GLuint program; GdkPixbuf *pixbuf; int x1, y1; int mwidth, mheight; static int init_shaders() { GLuint v, f; GError *error; gsize length; gchar *p; char msg[512]; GLfloat vertices[4 * 5]; GLint status; g_file_get_contents("wimmel.vert", &p, &length, &error); v = glCreateShader(GL_VERTEX_SHADER); glShaderSource(v, 1, (const GLchar **) &p, NULL); glCompileShader(v); glGetShaderiv(v, GL_COMPILE_STATUS, &status); g_free(p); if (!status) { glGetShaderInfoLog(v, sizeof msg, NULL, msg); fprintf(stderr, "vertex shader info: %s\n", msg); return -1; } g_file_get_contents("wimmel.frag", &p, &length, &error); f = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(f, 1, (const GLchar **) &p, NULL); glCompileShader(f); glGetShaderiv(f, GL_COMPILE_STATUS, &status); g_free(p); if (!status) { glGetShaderInfoLog(f, sizeof msg, NULL, msg); fprintf(stderr, "fragment shader info: %s\n", msg); return -1; } program = glCreateProgram(); glAttachShader(program, v); glAttachShader(program, f); glBindAttribLocation(program, 0, "position"); glBindAttribLocation(program, 1, "texcoord"); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &status); if (!status) { glGetProgramInfoLog(program, sizeof msg, NULL, msg); fprintf(stderr, "link info: %s\n", msg); return -1; } glUseProgram(program); proj_uniform = glGetUniformLocation(program, "proj"); tex_uniform = glGetUniformLocation(program, "tex"); tex2_uniform = glGetUniformLocation(program, "tex2"); pixelsize_uniform = glGetUniformLocation(program, "pixelsize"); search_rect_uniform = glGetUniformLocation(program, "srect"); barrier_uniform = glGetUniformLocation(program, "barrier"); vertices[ 0] = 0.0; vertices[ 1] = 0.0; vertices[ 2] = 0.0; vertices[ 3] = 0.0; vertices[ 4] = 0.0; vertices[ 5] = 0.0; vertices[ 6] = 1.0; vertices[ 7] = 0.0; vertices[ 8] = 0.0; vertices[ 9] = 1.0; vertices[10] = 1.0; vertices[11] = 0.0; vertices[12] = 0.0; vertices[13] = 1.0; vertices[14] = 0.0; vertices[15] = 1.0; vertices[16] = 1.0; vertices[17] = 0.0; vertices[18] = 1.0; vertices[19] = 1.0; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); return 0; } static inline int align(int value, int alignment) { return (value + alignment - 1) & ~(alignment - 1); } guchar * monochrome(GdkPixbuf *p) { int x, y, width, height, nch; guchar *d, *data; width = gdk_pixbuf_get_width(p); height = gdk_pixbuf_get_height(p); nch = gdk_pixbuf_get_n_channels(p); data = malloc(width * height); if (!data) return NULL; for (y = 0; y < height; ++y) { d = gdk_pixbuf_get_pixels(p) + y * gdk_pixbuf_get_rowstride(p); for (x = 0; x < width; ++x, d += nch) { data[y*width + x] = MAX(d[0], MAX(d[1], d[2])); } } return data; } static void create_texture(GdkPixbuf *pixbuf, GLuint *texture, int i) { guchar *data; int width, height; glActiveTexture(GL_TEXTURE0 + i); glGenTextures(1, texture); glBindTexture(GL_TEXTURE_2D, *texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); data = monochrome(pixbuf); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); free(data); } static void draw(void) { float pixelsize[] = { 1.0 / width, 1.0 / height }; static GLfloat proj[16] = { 2., 0., 0., 0., 0., -2., 0., 0., 0., 0., 1., 0., -1., 1., 0., 1. }; float search[4]; int barrier = mwidth * mheight / 2; glClear(GL_COLOR_BUFFER_BIT); glUniformMatrix4fv(proj_uniform, 1, GL_FALSE, proj); glUniform1i(tex_uniform, 0); glUniform1i(tex2_uniform, 1); glUniform2fv(pixelsize_uniform, 1, pixelsize); search[0] = 1.0 * x1 / width; search[1] = 1.0 * y1 / height; search[2] = 1.0 * mwidth / width; search[3] = 1.0 * mheight / height; glUniform4fv(search_rect_uniform, 1, search); glUniform1i(barrier_uniform, barrier); glDisable(GL_BLEND); glBindBuffer(GL_ARRAY_BUFFER, vbo); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), NULL); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (GLfloat *)0 + 3); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glFinish(); printf("finished\n"); } static void init_gl(int argc, char **argv) { GLuint fb, rb; #ifndef GLUT EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; #if 0 EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint pbuf_attribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, #if 0 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, #endif EGL_NONE }; EGLSurface surf; EGLConfig conf; EGLint num_conf; #endif EGLContext ctx; dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(dpy, NULL, NULL); eglBindAPI(EGL_OPENGL_ES_API); #if 0 if (!eglChooseConfig(dpy, attribs, &conf, 1, &num_conf) || !num_conf) { printf("eglChooseConfig() failed\n"); exit(EXIT_FAILURE); } #endif ctx = eglCreateContext(dpy, NULL, EGL_NO_CONTEXT, ctx_attribs); if (ctx == NULL) { fprintf(stderr, "failed to create context\n"); exit(EXIT_FAILURE); } if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) { fprintf(stderr, "failed to make context current\n"); exit(EXIT_FAILURE); } #if 0 ctx = eglCreateContext(dpy, conf, EGL_NO_CONTEXT, ctx_attribs); if (ctx == NULL) { fprintf(stderr, "failed to create context\n"); exit(EXIT_FAILURE); } surf = eglCreatePbufferSurface(dpy, conf, pbuf_attribs); if (!surf) { fprintf(stderr, "failed to create pbuffer surface\n"); exit(EXIT_FAILURE); } if (!eglMakeCurrent(dpy, surf, surf, ctx)) { fprintf(stderr, "failed to make context current\n"); exit(EXIT_FAILURE); } #endif #else glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA /*| GLUT_DEPTH */ | GLUT_DOUBLE); glutInitWindowSize(1,1); int window = glutCreateWindow("wimmel"); glutDestroyWindow(window); #endif glGenFramebuffers(1, &fb); glGenRenderbuffers(1, &rb); glBindFramebuffer(GL_FRAMEBUFFER, fb); glBindRenderbuffer(GL_RENDERBUFFER, rb); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, width, height); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { fprintf(stderr, "Framebuffer not complete\n"); exit(EXIT_FAILURE); } } int main(int argc, char **argv) { gint stride; guchar *buffer; GdkPixbuf *match; g_type_init(); if (argc <= 5) return 1; pixbuf = gdk_pixbuf_new_from_file(argv[1], NULL); if (!pixbuf) return 1; width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); init_gl(argc, argv); x1 = atoi(argv[2]); y1 = atoi(argv[3]); mwidth = atoi(argv[4]); mheight = atoi(argv[5]); init_shaders(); create_texture(pixbuf, &texture, 0); match = gdk_pixbuf_new_subpixbuf(pixbuf, x1, y1, mwidth, mheight); create_texture(match, &texture2, 1); g_object_unref(match); glViewport(0,0,width,height); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); draw(); glPixelStorei(GL_PACK_ALIGNMENT, 1); stride = width * sizeof(GLushort); buffer = malloc(stride * height); #ifndef GLUT if (!strstr((char *) glGetString(GL_EXTENSIONS), "GL_EXT_read_format_bgra")) { fprintf(stderr, "GL_EXT_read_format_bgra not available\n"); exit(EXIT_FAILURE); } #endif glReadPixels(0, 0, width, height, GL_BGRA_EXT, #ifdef GL_EXT_read_format_bgra GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, #else GL_UNSIGNED_SHORT_4_4_4_4_REV, #endif buffer); for (int j = 0; j < height; ++j) { GLushort *row = (GLushort *) (buffer + (height - 1 - j) * stride); for (int i = 0; i < width; ++i) { if (row[i] & 0x0f) { color_t color = COLOR(255, 0, 0, 0); for (int k = i; k < i+mwidth; k++) { put_pixel(pixbuf, POINT(k, j), color); put_pixel(pixbuf, POINT(k, j+mheight), color); } for (int n = j; n < j+mheight; n++) { put_pixel(pixbuf, POINT(i, n), color); put_pixel(pixbuf, POINT(i+mwidth, n), color); } } } } gdk_pixbuf_save(pixbuf, "output_gl.tiff", "tiff", NULL, NULL); free(buffer); g_object_unref(pixbuf); #ifndef GLUT eglTerminate(dpy); #endif return 0; }