diff options
-rw-r--r-- | wimmel.frag | 27 | ||||
-rw-r--r-- | wimmel.vert | 10 | ||||
-rw-r--r-- | wimmel_gl.c | 243 |
3 files changed, 280 insertions, 0 deletions
diff --git a/wimmel.frag b/wimmel.frag new file mode 100644 index 0000000..d4cb7ef --- /dev/null +++ b/wimmel.frag @@ -0,0 +1,27 @@ +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform vec2 pixelsize; +uniform vec4 search_rect; +uniform int barrier; + +void +main() +{ + float i, j; + float width = search_rect[2]; + float height = search_rect[3]; + int diff = 0; + + for (i = 0.0; i < width && diff < barrier; i += pixelsize.x) { + for (j = 0.0; j < height && diff < barrier; j += pixelsize.y) { + vec4 match = texture2D(tex, search_rect.xy + vec2(i,j)); + vec4 orig = texture2D(tex, v_texcoord + vec2(i,j)); + + diff += int(any(greaterThan(abs(orig - match), vec4(0.2)))); + } + } + + gl_FragColor = vec4(float(diff < barrier), 0.0, 0.0, 0.0); +} + +// vim:ft=c: diff --git a/wimmel.vert b/wimmel.vert new file mode 100644 index 0000000..fe26ecc --- /dev/null +++ b/wimmel.vert @@ -0,0 +1,10 @@ +uniform mat4 proj; +attribute vec4 position; +attribute vec2 texcoord; +varying vec2 v_texcoord; + +void main() +{ + gl_Position = proj * position; + v_texcoord = texcoord; +} diff --git a/wimmel_gl.c b/wimmel_gl.c new file mode 100644 index 0000000..4d6456e --- /dev/null +++ b/wimmel_gl.c @@ -0,0 +1,243 @@ +#include <glib.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#define GL_GLEXT_PROTOTYPES +#include <GL/glut.h> +#include <GL/gl.h> +#include <GL/glext.h> + +int window = 0; +GLuint vbo; +GLint proj_uniform, tex_uniform, pixelsize_uniform, + search_rect_uniform, barrier_uniform; +GLuint texture; +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"); + pixelsize_uniform = glGetUniformLocation(program, "pixelsize"); + search_rect_uniform = glGetUniformLocation(program, "search_rect"); + 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 void +keypress(unsigned char key, int x, int y) +{ + switch (key) { + case 27: + glutDestroyWindow(window); + exit(0); + break; + } +} + +static void +resize(int w, int h) +{ + glViewport(0, 0, w, h); +} + +static void +create_texture(GdkPixbuf *pixbuf) +{ + void *data; + GLenum format; + + 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); + + data = gdk_pixbuf_get_pixels(pixbuf); + + if (gdk_pixbuf_get_has_alpha(pixbuf)) + format = GL_RGBA; + else + format = GL_RGB; + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, + width, height, 0, + format, GL_UNSIGNED_BYTE, 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; + static int frames = 0; + static int last_time = 0; + int elapsed = glutGet(GLUT_ELAPSED_TIME); + + ++frames; + if ((elapsed - last_time) >= 5000) { + printf("fps: %d\n", frames / 5); + last_time = elapsed; + frames = 0; + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUniformMatrix4fv(proj_uniform, 1, GL_FALSE, proj); + glUniform1i(tex_uniform, 0); + 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); + + glBindTexture(GL_TEXTURE_2D, texture); + 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); + + glutSwapBuffers(); + printf("finished\n"); + +} + +int +main(int argc, char **argv) +{ + g_type_init(); + + glutInit(&argc, argv); + if (argc <= 1) + return 1; + + glutInitDisplayMode(GLUT_RGBA /*| GLUT_DEPTH */ | GLUT_DOUBLE); + + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + + 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); + + x1 = atoi(argv[2]); + y1 = atoi(argv[3]); + mwidth = atoi(argv[4]); + mheight = atoi(argv[5]); + + glutInitWindowSize(width, height); + window = glutCreateWindow("wimmel"); + + glutDisplayFunc(draw); + glutKeyboardFunc(keypress); + glutReshapeFunc(resize); + + init_shaders(); + create_texture(pixbuf); + glViewport(0,0,width,height); + + glutMainLoop(); + + return 0; +} |