From fcc21bf22fb603e0073cef98dc4ff002bdb7cce7 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 14 Dec 2015 21:46:07 +0200 Subject: [PATCH] Implement an interactive adjustment mode to the control program --- Makefile | 2 +- source/control.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 333 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 43c845f..a46b9e2 100644 --- a/Makefile +++ b/Makefile @@ -4,4 +4,4 @@ geometrycompositor: source/main.c gcc -o $@ $< -Wall -Wextra -Werror -std=c90 -pedantic -ggdb -lm -lX11 -lXcomposite -lXdamage -lXext -lXrandr -lGL geometrycontrol: source/control.c - gcc -o $@ $< -Wall -Wextra -Werror -std=c90 -pedantic -ggdb -lX11 + gcc -o $@ $< -Wall -Wextra -Werror -std=c90 -pedantic -ggdb -lX11 -lGL diff --git a/source/control.c b/source/control.c index f0c3357..3ead1e2 100644 --- a/source/control.c +++ b/source/control.c @@ -1,8 +1,11 @@ +#define GL_GLEXT_PROTOTYPES #include #include #include #include #include +#include +#include typedef struct GeometryCorrection { @@ -13,6 +16,93 @@ typedef struct GeometryCorrection float perspective; } GeometryCorrection; +typedef struct InteractiveView +{ + Window window; + GLXContext glx_context; + GLXWindow glx_window; + Atom geometry_data_atom; + unsigned shaders[5]; + unsigned programs[2]; + unsigned buffers[2]; + unsigned nelements; +} InteractiveView; + +static unsigned short frustum_indices[] = { 2, 1, 3, 0, 1, 0xFFFF, 3, 4, 2, 0, 4, 0xFFFF }; +static float view_matrix[] = +{ + 0.70711f, 0.40825f, -0.57735f, 0.0f, + 0.0f, 0.81650f, 0.57735f, 0.0f, + 0.70711f, -0.40725f, 0.57735f, 0.0f, + -0.2f, 0.0f, -2.5f, 1.0f +}; +static float projection_matrix[] = +{ + 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.6667f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.1f, -1.0f, + 0.0f, 0.0f, -1.05f, 0.0f +}; + +static const char *vshader_src = + "#version 150\n" + "uniform mat4 view;\n" + "in vec4 vertex;\n" + "void main()\n" + "{\n" + " gl_Position = view*vertex;\n" + "}\n"; + +static const char *gshader_src = + "#version 150\n" + "layout(triangles) in;\n" + "layout(triangle_strip, max_vertices=3) out;\n" + "uniform mat4 projection;\n" + "out vec3 normal;\n" + "void main()\n" + "{\n" + " vec3 v0 = gl_in[0].gl_Position.xyz;\n" + " vec3 v1 = gl_in[1].gl_Position.xyz;\n" + " vec3 v2 = gl_in[2].gl_Position.xyz;\n" + " vec3 tri_normal = normalize(cross(v1-v0, v2-v0));\n" + " for(int i=0; i<3; ++i)\n" + " {\n" + " normal = tri_normal;\n" + " gl_Position = projection*gl_in[i].gl_Position;\n" + " EmitVertex();\n" + " }\n" + " EndPrimitive();\n" + "}\n"; + +static const char *fshader_src = + "#version 150\n" + "in vec3 normal;\n" + "out vec4 frag_color;\n" + "void main()\n" + "{\n" + " frag_color = vec4(vec3(0.5+clamp(normal.z, 0.0, 1.0)*0.5), 1.0);\n" + "}\n"; + +static const char *flat_vshader_src = + "#version 150\n" + "uniform mat4 view;\n" + "uniform mat4 projection;\n" + "in vec4 vertex;\n" + "void main()\n" + "{\n" + " gl_Position = projection*view*vertex;\n" + "}\n"; + +static const char *flat_fshader_src = + "#version 150\n" + "uniform vec4 color;\n" + "out vec4 frag_color;\n" + "void main()\n" + "{\n" + " frag_color = color;\n" + "}\n"; + + GeometryCorrection *get_corrections(Display *display) { Window root; @@ -124,15 +214,242 @@ void set_corrections(Display *display, GeometryCorrection *corrections) free(values); } +unsigned create_shader(GLenum type, const char *src) +{ + unsigned shader; + + shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + + return shader; +} + +unsigned create_program(unsigned *shaders, unsigned nshaders) +{ + unsigned program; + unsigned i; + + program = glCreateProgram(); + for(i=0; ivisual, AllocNone); + view->window = XCreateWindow(display, root, 0, 0, 1024, 768, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr); + XStoreName(display, view->window, "Geometry correction control"); + XMapWindow(display, view->window); + + view->glx_window = glXCreateWindow(display, configs[0], view->window, NULL); + view->glx_context = glXCreateNewContext(display, configs[0], GLX_RGBA_TYPE, NULL, True); + glXMakeContextCurrent(display, view->glx_window, view->glx_window, view->glx_context); + + XFree(configs); + XFree(vi); + + view->shaders[0] = create_shader(GL_VERTEX_SHADER, vshader_src); + view->shaders[1] = create_shader(GL_GEOMETRY_SHADER, gshader_src); + view->shaders[2] = create_shader(GL_FRAGMENT_SHADER, fshader_src); + view->programs[0] = create_program(view->shaders, 3); + view->shaders[3] = create_shader(GL_VERTEX_SHADER, flat_vshader_src); + view->shaders[4] = create_shader(GL_FRAGMENT_SHADER, flat_fshader_src); + view->programs[1] = create_program(view->shaders+3, 2); + glUniform4f(glGetUniformLocation(view->programs[1], "color"), 0.0f, 0.6f, 1.0f, 1.0f); + + glGenBuffers(2, view->buffers); + glBindBuffer(GL_ARRAY_BUFFER, view->buffers[0]); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), NULL); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, view->buffers[1]); + + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex(0xFFFF); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + view->geometry_data_atom = XInternAtom(display, "_MSP_GEOMETRY_CORRECTION_DATA", False); + XSelectInput(display, view->window, KeyPressMask|ExposureMask); + + return 1; +} + +void request_geometry_data(Display *display, InteractiveView *view, GeometryCorrection *target) +{ + XChangeProperty(display, view->window, view->geometry_data_atom, XA_STRING, 8, PropModeReplace, (unsigned char *)target->monitor_name, strlen(target->monitor_name)); + XConvertSelection(display, view->geometry_data_atom, view->geometry_data_atom, view->geometry_data_atom, view->window, CurrentTime); +} + +void update_view(Display *display, InteractiveView *view, XSelectionEvent *event) +{ + Atom prop_type; + int prop_format; + unsigned long overflow; + unsigned long data_length; + short *geometry_data; + unsigned tessellation; + unsigned nvertices; + float *vertex_data; + unsigned nindices; + unsigned short *index_data; + unsigned i; + int x, y; + + XGetWindowProperty(display, event->requestor, event->property, 0, 32262, False, XA_INTEGER, + &prop_type, &prop_format, &data_length, &overflow, (unsigned char **)&geometry_data); + + tessellation = geometry_data[0]; + nvertices = 5+(tessellation+1)*(tessellation+1); + + vertex_data = (float *)malloc(nvertices*3*sizeof(float)); + for(i=0; inelements = tessellation*((tessellation+1)*2+1)-1; + + nindices = 12+view->nelements; + index_data = (unsigned short *)malloc(nindices*sizeof(unsigned short)); + memcpy(index_data, frustum_indices, sizeof(frustum_indices)); + i = 12; + for(y=0; y<(int)tessellation; ++y) + { + if(y>0) + index_data[i++] = 0xFFFF; + for(x=0; x<=(int)tessellation; ++x) + { + index_data[i++] = 5+(y+1)*(tessellation+1)+x; + index_data[i++] = 5+y*(tessellation+1)+x; + } + } + + glBufferData(GL_ARRAY_BUFFER, nvertices*3*sizeof(float), vertex_data, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nindices*sizeof(unsigned short), index_data, GL_STATIC_DRAW); + + free(vertex_data); + free(index_data); + XFree(geometry_data); +} + +int interactive(Display *display, GeometryCorrection *corrections, GeometryCorrection *target) +{ + InteractiveView view; + int update_pending; + int done; + + initialize_view(display, &view); + request_geometry_data(display, &view, target); + + done = 0; + update_pending = 0; + while(!done) + { + XEvent event; + KeySym keysym; + + XNextEvent(display, &event); + + switch(event.type) + { + case KeyPress: + keysym = XLookupKeysym(&event.xkey, 0); + if(keysym==XK_Escape) + { + done = 1; + break; + } + else if(update_pending) + break; + else if(keysym==XK_q) + target->keystone_vertical += 1.0f/64; + else if(keysym==XK_a) + target->keystone_vertical -= 1.0f/64; + else if(keysym==XK_w) + target->cylinder_depth += 1.0f/256; + else if(keysym==XK_s) + target->cylinder_depth -= 1.0f/256; + else if(keysym==XK_e) + target->vertical_center += 1.0f/32; + else if(keysym==XK_d) + target->vertical_center -= 1.0f/32; + else if(keysym==XK_r) + target->perspective += 1.0f/16; + else if(keysym==XK_f) + target->perspective -= 1.0f/16; + else + break; + + set_corrections(display, corrections); + request_geometry_data(display, &view, target); + update_pending = 1; + + break; + case SelectionNotify: + if(event.xselection.property==view.geometry_data_atom) + { + update_view(display, &view, &event.xselection); + update_pending = 0; + } + break; + default: + printf("event %d\n", event.type); + break; + } + + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + glUseProgram(view.programs[0]); + glDrawElements(GL_TRIANGLE_STRIP, view.nelements, GL_UNSIGNED_SHORT, (void *)(12*sizeof(unsigned short))); + glUseProgram(view.programs[1]); + glDrawElements(GL_LINE_STRIP, 11, GL_UNSIGNED_SHORT, NULL); + glXSwapBuffers(display, view.glx_window); + } + + return 0; +} + int main(int argc, char **argv) { Display *display; GeometryCorrection *corrections; unsigned i; - if(argc!=6) + if(argc!=2 && argc!=6) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s [ ]\n", argv[0]); return 1; } @@ -159,14 +476,22 @@ int main(int argc, char **argv) corrections[i+1].monitor_name = NULL; } - corrections[i].keystone_vertical = strtod(argv[2], NULL); - corrections[i].cylinder_depth = strtod(argv[3], NULL); - corrections[i].vertical_center = strtod(argv[4], NULL); - corrections[i].perspective = strtod(argv[5], NULL); + if(argc==2) + interactive(display, corrections, &corrections[i]); + else if(argc==6) + { + corrections[i].keystone_vertical = strtod(argv[2], NULL); + corrections[i].cylinder_depth = strtod(argv[3], NULL); + corrections[i].vertical_center = strtod(argv[4], NULL); + corrections[i].perspective = strtod(argv[5], NULL); - set_corrections(display, corrections); + set_corrections(display, corrections); + } XCloseDisplay(display); + for(i=0; corrections[i].monitor_name; ++i) + free(corrections[i].monitor_name); + free(corrections); return 0; } -- 2.45.2