]> git.tdb.fi Git - geometrycompositor.git/commitdiff
Implement an interactive adjustment mode to the control program
authorMikko Rasa <tdb@tdb.fi>
Mon, 14 Dec 2015 19:46:07 +0000 (21:46 +0200)
committerMikko Rasa <tdb@tdb.fi>
Mon, 14 Dec 2015 20:57:16 +0000 (22:57 +0200)
Makefile
source/control.c

index 43c845fcbc05824a6ede889a1197e3aea3665d2e..a46b9e26d64161b6860141534297442fbe011416 100644 (file)
--- 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
index f0c3357fc8018fb74ba33f4445597b6fa57f3a5a..3ead1e2118a293660716592b802b20a615602b4e 100644 (file)
@@ -1,8 +1,11 @@
+#define GL_GLEXT_PROTOTYPES
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
 
 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; i<nshaders; ++i)
+               glAttachShader(program, shaders[i]);
+       glLinkProgram(program);
+
+       glUseProgram(program);
+       glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, view_matrix);
+       glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, projection_matrix);
+
+       return program;
+}
+
+int initialize_view(Display *display, InteractiveView *view)
+{
+       int major_ver;
+       int minor_ver;
+       int attribs[5];
+       unsigned i;
+       GLXFBConfig *configs;
+       int nconfigs;
+       XVisualInfo *vi;
+       XSetWindowAttributes win_attr;
+       Window root;
+
+       if(!glXQueryVersion(display, &major_ver, &minor_ver) || major_ver<1 || (major_ver==1 && minor_ver<4))
+               return 0;
+
+       i = 0;
+       attribs[i++] = GLX_DOUBLEBUFFER;
+       attribs[i++] = True;
+       attribs[i++] = GLX_DEPTH_SIZE;
+       attribs[i++] = 16;
+       attribs[i] = None;
+
+       configs = glXChooseFBConfig(display, DefaultScreen(display), attribs, &nconfigs);
+       if(!configs || !nconfigs)
+               return 0;
+
+       vi = glXGetVisualFromFBConfig(display, configs[0]);
+       root = DefaultRootWindow(display);
+       win_attr.colormap = XCreateColormap(display, root, vi->visual, 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; i<nvertices*3; ++i)
+               vertex_data[i] = geometry_data[1+i]/10000.0f;
+
+       view->nelements = 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 <monitor> <keystone> <cylinder> <vcenter> <perspective>\n", argv[0]);
+               fprintf(stderr, "Usage: %s <monitor> [<keystone> <cylinder> <vcenter> <perspective>]\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;
 }