1 #define GL_GLEXT_PROTOTYPES
10 typedef struct GeometryCorrection
13 float keystone_vertical;
15 float curvature_depth;
16 float vertical_center;
20 typedef struct InteractiveView
23 GLXContext glx_context;
25 Atom geometry_data_atom;
32 static unsigned short frustum_indices[] = { 2, 1, 3, 0, 1, 0xFFFF, 3, 4, 2, 0, 4, 0xFFFF };
33 static float view_matrix[] =
35 0.70711f, 0.23570f, -0.66667f, 0.0f,
36 0.0f, 0.94281f, 0.33333f, 0.0f,
37 0.70711f, -0.23570f, 0.66667f, 0.0f,
38 -0.2f, 0.0f, -2.0f, 1.0f
40 static float projection_matrix[] =
42 2.0f, 0.0f, 0.0f, 0.0f,
43 0.0f, 2.6667f, 0.0f, 0.0f,
44 0.0f, 0.0f, -1.1f, -1.0f,
45 0.0f, 0.0f, -1.05f, 0.0f
48 static const char *vshader_src =
50 "uniform mat4 view;\n"
54 " gl_Position = view*vertex;\n"
57 static const char *gshader_src =
59 "layout(triangles) in;\n"
60 "layout(triangle_strip, max_vertices=3) out;\n"
61 "uniform mat4 projection;\n"
65 " vec3 v0 = gl_in[0].gl_Position.xyz;\n"
66 " vec3 v1 = gl_in[1].gl_Position.xyz;\n"
67 " vec3 v2 = gl_in[2].gl_Position.xyz;\n"
68 " vec3 tri_normal = normalize(cross(v1-v0, v2-v0));\n"
69 " for(int i=0; i<3; ++i)\n"
71 " normal = tri_normal;\n"
72 " gl_Position = projection*gl_in[i].gl_Position;\n"
78 static const char *fshader_src =
81 "out vec4 frag_color;\n"
84 " frag_color = vec4(vec3(0.5+clamp(normal.z, 0.0, 1.0)*0.5), 1.0);\n"
87 static const char *flat_vshader_src =
89 "uniform mat4 view;\n"
90 "uniform mat4 projection;\n"
94 " gl_Position = projection*view*vertex;\n"
97 static const char *flat_fshader_src =
99 "uniform vec4 color;\n"
100 "out vec4 frag_color;\n"
103 " frag_color = color;\n"
107 void reset_correction(GeometryCorrection *correction)
109 correction->keystone_vertical = 0.0f;
110 correction->curvature_type = 1;
111 correction->curvature_depth = 0.0f;
112 correction->vertical_center = 0.5f;
113 correction->perspective = 1.0f;
116 GeometryCorrection *get_corrections(Display *display)
120 Atom correction_atom;
123 unsigned long overflow;
124 unsigned long names_length;
126 unsigned long values_length;
128 unsigned ncorrections;
130 GeometryCorrection *corrections;
133 root = DefaultRootWindow(display);
134 monitors_atom = XInternAtom(display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
135 correction_atom = XInternAtom(display, "_MSP_GEOMETRY_CORRECTION", False);
137 XGetWindowProperty(display, root, monitors_atom, 0, 64, False, XA_STRING,
138 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
139 if(prop_type!=XA_STRING || prop_format!=8)
142 XGetWindowProperty(display, root, correction_atom, 0, 64, False, XA_INTEGER,
143 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
144 if(prop_type!=XA_INTEGER || prop_format!=16)
150 ncorrections = (names_length>0);
151 for(i=0; i<names_length; ++i)
154 if(ncorrections*5>values_length)
155 ncorrections = values_length/5;
156 corrections = (GeometryCorrection *)malloc((ncorrections+1)*sizeof(GeometryCorrection));
159 for(i=0; i<ncorrections; ++i)
163 namelen = strlen(name_ptr);
164 corrections[i].monitor_name = (char *)malloc(namelen+1);
165 strcpy(corrections[i].monitor_name, name_ptr);
167 corrections[i].keystone_vertical = values[i*5]/4096.0f;
168 corrections[i].curvature_type = values[i*5+1];
169 corrections[i].curvature_depth = values[i*5+2]/4096.0f;
170 corrections[i].vertical_center = values[i*5+3]/4096.0f;
171 corrections[i].perspective = values[i*5+4]/4096.0f;
173 name_ptr += namelen+1;
176 corrections[ncorrections].monitor_name = NULL;
184 void set_corrections(Display *display, GeometryCorrection *corrections)
186 unsigned ncorrections;
194 Atom correction_atom;
198 for(i=0; corrections[i].monitor_name; ++i)
201 total_len += strlen(corrections[i].monitor_name);
204 names = (char *)malloc(total_len+ncorrections);
205 values = (short *)malloc(ncorrections*5*sizeof(short));
207 for(i=0; i<ncorrections; ++i)
209 strcpy(name_ptr, corrections[i].monitor_name);
210 name_ptr += strlen(name_ptr)+1;
212 values[i*5] = corrections[i].keystone_vertical*4096;
213 values[i*5+1] = corrections[i].curvature_type;
214 values[i*5+2] = corrections[i].curvature_depth*4096;
215 values[i*5+3] = corrections[i].vertical_center*4096;
216 values[i*5+4] = corrections[i].perspective*4096;
219 root = DefaultRootWindow(display);
220 monitors_atom = XInternAtom(display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
221 correction_atom = XInternAtom(display, "_MSP_GEOMETRY_CORRECTION", False);
222 XChangeProperty(display, root, monitors_atom, XA_STRING, 8, PropModeReplace, (unsigned char *)names, total_len+ncorrections-1);
223 XChangeProperty(display, root, correction_atom, XA_INTEGER, 16, PropModeReplace, (unsigned char *)values, ncorrections*5);
229 unsigned create_shader(GLenum type, const char *src)
233 shader = glCreateShader(type);
234 glShaderSource(shader, 1, &src, NULL);
235 glCompileShader(shader);
240 unsigned create_program(unsigned *shaders, unsigned nshaders)
245 program = glCreateProgram();
246 for(i=0; i<nshaders; ++i)
247 glAttachShader(program, shaders[i]);
248 glLinkProgram(program);
250 glUseProgram(program);
251 glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, view_matrix);
252 glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, projection_matrix);
257 int initialize_view(Display *display, InteractiveView *view)
263 GLXFBConfig *configs;
266 XSetWindowAttributes win_attr;
269 if(!glXQueryVersion(display, &major_ver, &minor_ver) || major_ver<1 || (major_ver==1 && minor_ver<4))
273 attribs[i++] = GLX_DOUBLEBUFFER;
275 attribs[i++] = GLX_DEPTH_SIZE;
279 configs = glXChooseFBConfig(display, DefaultScreen(display), attribs, &nconfigs);
280 if(!configs || !nconfigs)
283 vi = glXGetVisualFromFBConfig(display, configs[0]);
284 root = DefaultRootWindow(display);
285 win_attr.colormap = XCreateColormap(display, root, vi->visual, AllocNone);
286 view->window = XCreateWindow(display, root, 0, 0, 1024, 768, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
287 XStoreName(display, view->window, "Geometry correction control");
288 XMapWindow(display, view->window);
290 view->glx_window = glXCreateWindow(display, configs[0], view->window, NULL);
291 view->glx_context = glXCreateNewContext(display, configs[0], GLX_RGBA_TYPE, NULL, True);
292 glXMakeContextCurrent(display, view->glx_window, view->glx_window, view->glx_context);
297 view->shaders[0] = create_shader(GL_VERTEX_SHADER, vshader_src);
298 view->shaders[1] = create_shader(GL_GEOMETRY_SHADER, gshader_src);
299 view->shaders[2] = create_shader(GL_FRAGMENT_SHADER, fshader_src);
300 view->programs[0] = create_program(view->shaders, 3);
301 view->shaders[3] = create_shader(GL_VERTEX_SHADER, flat_vshader_src);
302 view->shaders[4] = create_shader(GL_FRAGMENT_SHADER, flat_fshader_src);
303 view->programs[1] = create_program(view->shaders+3, 2);
304 glUniform4f(glGetUniformLocation(view->programs[1], "color"), 0.0f, 0.6f, 1.0f, 1.0f);
306 glGenBuffers(2, view->buffers);
307 glBindBuffer(GL_ARRAY_BUFFER, view->buffers[0]);
308 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), NULL);
309 glEnableVertexAttribArray(0);
310 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, view->buffers[1]);
312 glEnable(GL_PRIMITIVE_RESTART);
313 glPrimitiveRestartIndex(0xFFFF);
315 glEnable(GL_DEPTH_TEST);
316 glDepthFunc(GL_LEQUAL);
318 view->geometry_data_atom = XInternAtom(display, "_MSP_GEOMETRY_CORRECTION_DATA", False);
319 XSelectInput(display, view->window, KeyPressMask|ExposureMask);
324 void request_geometry_data(Display *display, InteractiveView *view, GeometryCorrection *target)
326 XChangeProperty(display, view->window, view->geometry_data_atom, XA_STRING, 8, PropModeReplace, (unsigned char *)target->monitor_name, strlen(target->monitor_name));
327 XConvertSelection(display, view->geometry_data_atom, view->geometry_data_atom, view->geometry_data_atom, view->window, CurrentTime);
330 void update_view(Display *display, InteractiveView *view, XSelectionEvent *event)
334 unsigned long overflow;
335 unsigned long data_length;
336 short *geometry_data;
337 unsigned tessellation;
341 unsigned short *index_data;
345 XGetWindowProperty(display, event->requestor, event->property, 0, 32262, False, XA_INTEGER,
346 &prop_type, &prop_format, &data_length, &overflow, (unsigned char **)&geometry_data);
348 tessellation = geometry_data[0];
349 nvertices = 5+(tessellation+1)*(tessellation+1);
351 vertex_data = (float *)malloc(nvertices*3*sizeof(float));
352 for(i=0; i<nvertices*3; ++i)
353 vertex_data[i] = geometry_data[1+i]/4096.0f;
355 view->nelements = tessellation*((tessellation+1)*2+1)-1;
357 nindices = 12+view->nelements;
358 index_data = (unsigned short *)malloc(nindices*sizeof(unsigned short));
359 memcpy(index_data, frustum_indices, sizeof(frustum_indices));
361 for(y=0; y<(int)tessellation; ++y)
364 index_data[i++] = 0xFFFF;
365 for(x=0; x<=(int)tessellation; ++x)
367 index_data[i++] = 5+(y+1)*(tessellation+1)+x;
368 index_data[i++] = 5+y*(tessellation+1)+x;
372 glBufferData(GL_ARRAY_BUFFER, nvertices*3*sizeof(float), vertex_data, GL_STATIC_DRAW);
373 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nindices*sizeof(unsigned short), index_data, GL_STATIC_DRAW);
377 XFree(geometry_data);
380 int interactive(Display *display, GeometryCorrection *corrections, GeometryCorrection *target)
382 InteractiveView view;
386 initialize_view(display, &view);
387 request_geometry_data(display, &view, target);
397 XNextEvent(display, &event);
403 keysym = XLookupKeysym(&event.xkey, 0);
404 if(keysym==XK_Escape)
409 else if(update_pending)
411 else if(keysym==XK_q)
412 target->keystone_vertical += 1.0f/64;
413 else if(keysym==XK_a)
414 target->keystone_vertical -= 1.0f/64;
415 else if(keysym==XK_w)
416 target->curvature_depth += 1.0f/256;
417 else if(keysym==XK_s)
418 target->curvature_depth -= 1.0f/256;
419 else if(keysym==XK_e)
420 target->vertical_center += 1.0f/32;
421 else if(keysym==XK_d)
422 target->vertical_center -= 1.0f/32;
423 else if(keysym==XK_r)
424 target->perspective += 1.0f/16;
425 else if(keysym==XK_f)
426 target->perspective -= 1.0f/16;
427 else if(keysym==XK_z)
428 target->curvature_type = target->curvature_type%2+1;
429 else if(keysym==XK_0)
430 reset_correction(target);
434 set_corrections(display, corrections);
435 request_geometry_data(display, &view, target);
439 case SelectionNotify:
440 if(event.xselection.property==view.geometry_data_atom)
442 update_view(display, &view, &event.xselection);
454 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
455 glUseProgram(view.programs[0]);
456 glDrawElements(GL_TRIANGLE_STRIP, view.nelements, GL_UNSIGNED_SHORT, (void *)(12*sizeof(unsigned short)));
457 glUseProgram(view.programs[1]);
458 glDrawElements(GL_LINE_STRIP, 11, GL_UNSIGNED_SHORT, NULL);
459 glXSwapBuffers(display, view.glx_window);
466 int main(int argc, char **argv)
469 GeometryCorrection *corrections;
472 if(argc!=2 && argc!=7)
474 fprintf(stderr, "Usage: %s <monitor> [<keystone> <curvature> <depth> <vcenter> <perspective>]\n", argv[0]);
478 display = XOpenDisplay(NULL);
480 corrections = get_corrections(display);
483 for(i=0; corrections[i].monitor_name; ++i)
484 if(!strcmp(corrections[i].monitor_name, argv[1]))
490 if(!corrections || !corrections[i].monitor_name)
494 corrections = (GeometryCorrection *)realloc(corrections, (i+2)*sizeof(GeometryCorrection));
495 namelen = strlen(argv[1]);
496 corrections[i].monitor_name = (char *)malloc(namelen+1);
497 strcpy(corrections[i].monitor_name, argv[1]);
498 corrections[i+1].monitor_name = NULL;
499 reset_correction(&corrections[i]);
503 interactive(display, corrections, &corrections[i]);
506 if(!strcmp(argv[3], "cylindrical"))
507 corrections[i].curvature_type = 1;
508 else if(!strcmp(argv[3], "spherical"))
509 corrections[i].curvature_type = 2;
512 fprintf(stderr, "Invalid curvature\n");
515 corrections[i].keystone_vertical = strtod(argv[2], NULL);
516 corrections[i].curvature_depth = strtod(argv[4], NULL);
517 corrections[i].vertical_center = strtod(argv[5], NULL);
518 corrections[i].perspective = strtod(argv[6], NULL);
520 set_corrections(display, corrections);
523 XCloseDisplay(display);
524 for(i=0; corrections[i].monitor_name; ++i)
525 free(corrections[i].monitor_name);