eqemu

annotate src/main.cc @ 7:e9ab4861536d

added glow
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 18 Jul 2014 04:24:53 +0300
parents 977bc1cb055b
children fca1f126d23b
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@4 3 #include <float.h>
nuclear@0 4 #include <assert.h>
nuclear@0 5 #include <errno.h>
nuclear@0 6 #include <unistd.h>
nuclear@0 7 #include <sys/select.h>
nuclear@0 8 #include <GL/glew.h>
nuclear@0 9 #include <X11/Xlib.h>
nuclear@0 10 #include <GL/glx.h>
nuclear@1 11 #include "dev.h"
nuclear@4 12 #include "scene.h"
nuclear@7 13 #include "timer.h"
nuclear@7 14 #include "fblur.h"
nuclear@7 15
nuclear@7 16
nuclear@7 17 enum {
nuclear@7 18 REGULAR_PASS,
nuclear@7 19 GLOW_PASS
nuclear@7 20 };
nuclear@0 21
nuclear@0 22 static bool init();
nuclear@0 23 static void cleanup();
nuclear@0 24 static void display();
nuclear@7 25 static void draw_scene(int pass = REGULAR_PASS);
nuclear@7 26 static void post_glow(void);
nuclear@0 27 static void keyb(int key, bool pressed);
nuclear@0 28 static void mouse(int bn, bool pressed, int x, int y);
nuclear@0 29 static void motion(int x, int y);
nuclear@4 30 static Ray calc_pick_ray(int x, int y);
nuclear@7 31 static int next_pow2(int x);
nuclear@0 32
nuclear@0 33 static Window create_window(const char *title, int xsz, int ysz);
nuclear@0 34 static void process_events();
nuclear@0 35 static int translate_keysym(KeySym sym);
nuclear@0 36
nuclear@2 37 static int proc_args(int argc, char **argv);
nuclear@2 38
nuclear@0 39 static Display *dpy;
nuclear@0 40 static Window win;
nuclear@0 41 static GLXContext ctx;
nuclear@0 42 static Atom xa_wm_prot, xa_wm_del_win;
nuclear@0 43
nuclear@0 44 static int win_width, win_height;
nuclear@0 45
nuclear@4 46 static bool draw_pending;
nuclear@0 47 static bool win_mapped;
nuclear@0 48
nuclear@2 49 static int fakefd = -1;
nuclear@2 50 static char *fake_devpath;
nuclear@2 51
nuclear@4 52 static float cam_theta, cam_phi, cam_dist = 140;
nuclear@4 53 static Scene *scn;
nuclear@4 54
nuclear@4 55 enum { BN_TICKET, BN_NEXT, NUM_BUTTONS };
nuclear@6 56 static const char *button_names[] = { "button1", "button2" };
nuclear@4 57 static Object *button_obj[NUM_BUTTONS];
nuclear@6 58 static Object *disp_obj[2];
nuclear@6 59 static Object *led_obj[2];
nuclear@6 60 static Vector3 led_on_emissive;
nuclear@4 61
nuclear@7 62 static bool opt_use_glow = true;
nuclear@7 63 #define GLOW_SZ_DIV 3
nuclear@7 64 static unsigned int glow_tex;
nuclear@7 65 static int glow_tex_xsz, glow_tex_ysz, glow_xsz, glow_ysz;
nuclear@7 66 static int glow_iter = 1;
nuclear@7 67 static int blur_size = 5;
nuclear@7 68 unsigned char *glow_framebuf;
nuclear@7 69
nuclear@7 70
nuclear@2 71 int main(int argc, char **argv)
nuclear@0 72 {
nuclear@2 73 if(proc_args(argc, argv) == -1) {
nuclear@2 74 return 1;
nuclear@2 75 }
nuclear@0 76 if(!init()) {
nuclear@0 77 return 1;
nuclear@0 78 }
nuclear@0 79 atexit(cleanup);
nuclear@0 80
nuclear@0 81 int xfd = ConnectionNumber(dpy);
nuclear@0 82
nuclear@4 83 // run once through pending events before going into the select loop
nuclear@4 84 process_events();
nuclear@4 85
nuclear@0 86 for(;;) {
nuclear@0 87 fd_set rd;
nuclear@0 88 FD_ZERO(&rd);
nuclear@0 89
nuclear@0 90 FD_SET(xfd, &rd);
nuclear@2 91 FD_SET(fakefd, &rd);
nuclear@0 92
nuclear@4 93 struct timeval noblock = {0, 0};
nuclear@2 94 int maxfd = xfd > fakefd ? xfd : fakefd;
nuclear@4 95 while(select(maxfd + 1, &rd, 0, 0, draw_pending ? &noblock : 0) == -1 && errno == EINTR);
nuclear@0 96
nuclear@0 97 if(FD_ISSET(xfd, &rd)) {
nuclear@0 98 process_events();
nuclear@0 99 }
nuclear@2 100 if(FD_ISSET(fakefd, &rd)) {
nuclear@2 101 proc_dev_input();
nuclear@2 102 }
nuclear@0 103
nuclear@4 104 if(draw_pending) {
nuclear@7 105 draw_pending = false;
nuclear@0 106 display();
nuclear@0 107 }
nuclear@0 108 }
nuclear@0 109 return 0;
nuclear@0 110 }
nuclear@0 111
nuclear@0 112 static bool init()
nuclear@0 113 {
nuclear@2 114 if(fake_devpath) {
nuclear@2 115 if((fakefd = start_dev(fake_devpath)) == -1) {
nuclear@2 116 return false;
nuclear@2 117 }
nuclear@2 118 }
nuclear@1 119
nuclear@0 120 if(!(dpy = XOpenDisplay(0))) {
nuclear@0 121 fprintf(stderr, "failed to connect to the X server!\n");
nuclear@0 122 return false;
nuclear@0 123 }
nuclear@0 124
nuclear@7 125 if(!(win = create_window("equeue device emulator", 512, 512))) {
nuclear@0 126 return false;
nuclear@0 127 }
nuclear@0 128
nuclear@4 129 glewInit();
nuclear@4 130
nuclear@4 131 scn = new Scene;
nuclear@4 132 if(!scn->load("data/device.obj")) {
nuclear@4 133 fprintf(stderr, "failed to load device 3D model\n");
nuclear@4 134 return false;
nuclear@4 135 }
nuclear@4 136
nuclear@4 137 for(int i=0; i<NUM_BUTTONS; i++) {
nuclear@4 138 button_obj[i] = scn->get_object(button_names[i]);
nuclear@4 139 if(!button_obj[i]) {
nuclear@4 140 fprintf(stderr, "invalid 3D model\n");
nuclear@4 141 return false;
nuclear@4 142 }
nuclear@4 143 BSphere &bs = button_obj[i]->get_mesh()->get_bounds();
nuclear@4 144 bs.set_radius(bs.get_radius() * 1.5);
nuclear@4 145 }
nuclear@4 146
nuclear@6 147 disp_obj[0] = scn->get_object("7seg0");
nuclear@6 148 disp_obj[1] = scn->get_object("7seg1");
nuclear@6 149 if(!disp_obj[0] || !disp_obj[1]) {
nuclear@6 150 fprintf(stderr, "invalid 3D model\n");
nuclear@6 151 return false;
nuclear@6 152 }
nuclear@6 153 scn->remove_object(disp_obj[0]);
nuclear@6 154 scn->remove_object(disp_obj[1]);
nuclear@6 155
nuclear@6 156 led_obj[0] = scn->get_object("led1");
nuclear@6 157 led_obj[1] = scn->get_object("led2");
nuclear@6 158 if(!led_obj[0] || !led_obj[1]) {
nuclear@6 159 fprintf(stderr, "invalid 3D model\n");
nuclear@6 160 return false;
nuclear@6 161 }
nuclear@6 162 scn->remove_object(led_obj[0]);
nuclear@6 163 scn->remove_object(led_obj[1]);
nuclear@6 164 led_on_emissive = led_obj[0]->mtl.emissive;
nuclear@6 165
nuclear@7 166 // create the glow texture
nuclear@7 167 glGenTextures(1, &glow_tex);
nuclear@7 168 glBindTexture(GL_TEXTURE_2D, glow_tex);
nuclear@7 169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@7 170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@7 171 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@7 172
nuclear@4 173 glEnable(GL_DEPTH_TEST);
nuclear@4 174 glEnable(GL_CULL_FACE);
nuclear@4 175 glEnable(GL_LIGHTING);
nuclear@4 176 glEnable(GL_LIGHT0);
nuclear@4 177
nuclear@4 178 glClearColor(0.1, 0.1, 0.1, 1);
nuclear@4 179
nuclear@0 180 return true;
nuclear@0 181 }
nuclear@0 182
nuclear@0 183 static void cleanup()
nuclear@0 184 {
nuclear@4 185 delete scn;
nuclear@4 186
nuclear@1 187 stop_dev();
nuclear@1 188
nuclear@0 189 if(!dpy) return;
nuclear@0 190
nuclear@0 191 if(win) {
nuclear@0 192 XDestroyWindow(dpy, win);
nuclear@0 193 }
nuclear@0 194 XCloseDisplay(dpy);
nuclear@0 195 }
nuclear@0 196
nuclear@6 197 #define DIGIT_USZ (1.0 / 11.0)
nuclear@7 198 #define MIN_REDRAW_INTERVAL (1000 / 40) /* 40fps */
nuclear@6 199
nuclear@0 200 static void display()
nuclear@0 201 {
nuclear@0 202 glMatrixMode(GL_MODELVIEW);
nuclear@0 203 glLoadIdentity();
nuclear@4 204 glTranslatef(0, 0, -cam_dist);
nuclear@4 205 glRotatef(cam_phi, 1, 0, 0);
nuclear@4 206 glRotatef(cam_theta, 0, 1, 0);
nuclear@4 207
nuclear@4 208 float lpos[] = {-7, 5, 10, 0};
nuclear@4 209 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
nuclear@4 210
nuclear@7 211 if(opt_use_glow) {
nuclear@7 212 glViewport(0, 0, glow_xsz, glow_ysz);
nuclear@7 213
nuclear@7 214 glClearColor(0, 0, 0, 1);
nuclear@7 215 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@7 216
nuclear@7 217 draw_scene(GLOW_PASS);
nuclear@7 218
nuclear@7 219 glReadPixels(0, 0, glow_xsz, glow_ysz, GL_RGBA, GL_UNSIGNED_BYTE, glow_framebuf);
nuclear@7 220 glViewport(0, 0, win_width, win_height);
nuclear@7 221 }
nuclear@7 222
nuclear@7 223 glClearColor(0.05, 0.05, 0.05, 1);
nuclear@7 224 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@7 225
nuclear@7 226 draw_scene();
nuclear@7 227
nuclear@7 228 if(opt_use_glow) {
nuclear@7 229 for(int i=0; i<glow_iter; i++) {
nuclear@7 230 fast_blur(BLUR_BOTH, blur_size, (uint32_t*)glow_framebuf, glow_xsz, glow_ysz);
nuclear@7 231 glBindTexture(GL_TEXTURE_2D, glow_tex);
nuclear@7 232 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, glow_xsz, glow_ysz, GL_RGBA, GL_UNSIGNED_BYTE, glow_framebuf);
nuclear@7 233
nuclear@7 234 post_glow();
nuclear@7 235 }
nuclear@7 236 }
nuclear@7 237
nuclear@7 238 //if(get_led_state(0)) {
nuclear@7 239 // continuously redraw until the left LED times out
nuclear@7 240 draw_pending = true;
nuclear@7 241 //}
nuclear@7 242
nuclear@7 243 glXSwapBuffers(dpy, win);
nuclear@7 244 assert(glGetError() == GL_NO_ERROR);
nuclear@7 245
nuclear@7 246 /*static long prev_msec;
nuclear@7 247 long msec = get_msec();
nuclear@7 248 long dt = msec - prev_msec;
nuclear@7 249
nuclear@7 250 if(dt < MIN_REDRAW_INTERVAL) {
nuclear@7 251 wait_for(MIN_REDRAW_INTERVAL - dt);
nuclear@7 252 }
nuclear@7 253 prev_msec = get_msec();*/
nuclear@7 254 }
nuclear@7 255
nuclear@7 256 static void draw_scene(int pass)
nuclear@7 257 {
nuclear@7 258 if(pass != GLOW_PASS) {
nuclear@7 259 scn->render();
nuclear@7 260 }
nuclear@0 261
nuclear@6 262 // shift the textures and modify the materials to make the display match our state
nuclear@6 263 for(int i=0; i<2; i++) {
nuclear@7 264 // 7seg
nuclear@6 265 int digit = get_display_number();
nuclear@6 266 for(int j=0; j<i; j++) {
nuclear@6 267 digit /= 10;
nuclear@6 268 }
nuclear@6 269 digit %= 10;
nuclear@6 270
nuclear@6 271 float uoffs = DIGIT_USZ + DIGIT_USZ * digit;
nuclear@6 272
nuclear@6 273 disp_obj[i]->mtl.tex_offset[TEX_DIFFUSE] = Vector2(uoffs, 0);
nuclear@6 274 disp_obj[i]->render();
nuclear@6 275
nuclear@6 276 // LEDs
nuclear@6 277 if(get_led_state(i)) {
nuclear@6 278 led_obj[i]->mtl.emissive = led_on_emissive;
nuclear@6 279 } else {
nuclear@6 280 led_obj[i]->mtl.emissive = Vector3(0, 0, 0);
nuclear@6 281 }
nuclear@6 282 led_obj[i]->render();
nuclear@6 283 }
nuclear@7 284 }
nuclear@6 285
nuclear@7 286 static void post_glow(void)
nuclear@7 287 {
nuclear@7 288 float max_s = (float)glow_xsz / (float)glow_tex_xsz;
nuclear@7 289 float max_t = (float)glow_ysz / (float)glow_tex_ysz;
nuclear@7 290
nuclear@7 291 glPushAttrib(GL_ENABLE_BIT);
nuclear@7 292
nuclear@7 293 glBlendFunc(GL_ONE, GL_ONE);
nuclear@7 294 glEnable(GL_BLEND);
nuclear@7 295 glDisable(GL_CULL_FACE);
nuclear@7 296 glDisable(GL_LIGHTING);
nuclear@7 297 glDisable(GL_DEPTH_TEST);
nuclear@7 298
nuclear@7 299 glMatrixMode(GL_MODELVIEW);
nuclear@7 300 glPushMatrix();
nuclear@7 301 glLoadIdentity();
nuclear@7 302 glMatrixMode(GL_PROJECTION);
nuclear@7 303 glPushMatrix();
nuclear@7 304 glLoadIdentity();
nuclear@7 305
nuclear@7 306 glEnable(GL_TEXTURE_2D);
nuclear@7 307 glBindTexture(GL_TEXTURE_2D, glow_tex);
nuclear@7 308
nuclear@7 309 glBegin(GL_QUADS);
nuclear@7 310 glColor4f(1, 1, 1, 1);
nuclear@7 311 glTexCoord2f(0, 0);
nuclear@7 312 glVertex2f(-1, -1);
nuclear@7 313 glTexCoord2f(max_s, 0);
nuclear@7 314 glVertex2f(1, -1);
nuclear@7 315 glTexCoord2f(max_s, max_t);
nuclear@7 316 glVertex2f(1, 1);
nuclear@7 317 glTexCoord2f(0, max_t);
nuclear@7 318 glVertex2f(-1, 1);
nuclear@7 319 glEnd();
nuclear@7 320
nuclear@7 321 glPopMatrix();
nuclear@7 322 glMatrixMode(GL_MODELVIEW);
nuclear@7 323 glPopMatrix();
nuclear@7 324
nuclear@7 325 glPopAttrib();
nuclear@0 326 }
nuclear@0 327
nuclear@7 328
nuclear@0 329 static void reshape(int x, int y)
nuclear@0 330 {
nuclear@0 331 glViewport(0, 0, x, y);
nuclear@0 332
nuclear@0 333 glMatrixMode(GL_PROJECTION);
nuclear@0 334 glLoadIdentity();
nuclear@4 335 gluPerspective(50.0, (float)x / (float)y, 1.0, 1000.0);
nuclear@4 336
nuclear@4 337 win_width = x;
nuclear@4 338 win_height = y;
nuclear@7 339
nuclear@7 340 if(opt_use_glow) {
nuclear@7 341 glow_xsz = x / GLOW_SZ_DIV;
nuclear@7 342 glow_ysz = y / GLOW_SZ_DIV;
nuclear@7 343 printf("glow image size: %dx%d\n", glow_xsz, glow_ysz);
nuclear@7 344
nuclear@7 345 delete [] glow_framebuf;
nuclear@7 346 glow_framebuf = new unsigned char[glow_xsz * glow_ysz * 4];
nuclear@7 347
nuclear@7 348 glow_tex_xsz = next_pow2(glow_xsz);
nuclear@7 349 glow_tex_ysz = next_pow2(glow_ysz);
nuclear@7 350 glBindTexture(GL_TEXTURE_2D, glow_tex);
nuclear@7 351 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glow_tex_xsz, glow_tex_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@7 352 }
nuclear@0 353 }
nuclear@0 354
nuclear@0 355 static void keyb(int key, bool pressed)
nuclear@0 356 {
nuclear@0 357 if(pressed) {
nuclear@0 358 switch(key) {
nuclear@0 359 case 27:
nuclear@0 360 exit(0);
nuclear@0 361 }
nuclear@0 362 }
nuclear@0 363 }
nuclear@0 364
nuclear@4 365 static bool bnstate[32];
nuclear@4 366 static int prev_x, prev_y;
nuclear@4 367
nuclear@0 368 static void mouse(int bn, bool pressed, int x, int y)
nuclear@0 369 {
nuclear@4 370 bnstate[bn] = pressed;
nuclear@4 371 prev_x = x;
nuclear@4 372 prev_y = y;
nuclear@4 373
nuclear@4 374 if(bn == 0 && pressed) {
nuclear@4 375 // do picking
nuclear@4 376 Ray ray = calc_pick_ray(x, win_height - y);
nuclear@4 377
nuclear@4 378 HitPoint minhit;
nuclear@4 379 minhit.t = FLT_MAX;
nuclear@4 380 int hit_found = -1;
nuclear@4 381
nuclear@4 382 for(int i=0; i<NUM_BUTTONS; i++) {
nuclear@4 383 HitPoint hit;
nuclear@4 384 if(button_obj[i]->get_mesh()->get_bounds().intersect(ray, &hit) && hit.t < minhit.t) {
nuclear@4 385 minhit = hit;
nuclear@4 386 hit_found = i;
nuclear@4 387 }
nuclear@4 388 }
nuclear@4 389
nuclear@4 390 if(hit_found != -1) {
nuclear@4 391 switch(hit_found) {
nuclear@4 392 case BN_TICKET:
nuclear@4 393 issue_ticket();
nuclear@4 394 printf("issue ticket\n");
nuclear@4 395 break;
nuclear@4 396
nuclear@4 397 case BN_NEXT:
nuclear@4 398 next_customer();
nuclear@4 399 printf("next customer\n");
nuclear@4 400 break;
nuclear@4 401 }
nuclear@4 402 draw_pending = true;
nuclear@4 403 }
nuclear@4 404 }
nuclear@0 405 }
nuclear@0 406
nuclear@0 407 static void motion(int x, int y)
nuclear@0 408 {
nuclear@4 409 int dx = x - prev_x;
nuclear@4 410 int dy = y - prev_y;
nuclear@4 411 prev_x = x;
nuclear@4 412 prev_y = y;
nuclear@4 413
nuclear@4 414 if(bnstate[0]) {
nuclear@4 415 cam_theta += dx * 0.5;
nuclear@4 416 cam_phi += dy * 0.5;
nuclear@4 417 if(cam_phi < -90) cam_phi = -90;
nuclear@4 418 if(cam_phi > 90) cam_phi = 90;
nuclear@6 419
nuclear@6 420 } else if(bnstate[2]) {
nuclear@4 421 cam_dist += dy * 0.5;
nuclear@4 422 if(cam_dist < 0.0) cam_dist = 0.0;
nuclear@6 423
nuclear@6 424 } else {
nuclear@6 425 float xoffs = 2.0 * x / win_width - 1.0;
nuclear@6 426 float yoffs = 2.0 * y / win_height - 1.0;
nuclear@6 427 cam_theta = -xoffs * 15.0 * (win_width / win_height);
nuclear@6 428 cam_phi = -yoffs * 15.0;
nuclear@4 429 }
nuclear@6 430 draw_pending = true;
nuclear@4 431 }
nuclear@4 432
nuclear@4 433 static Ray calc_pick_ray(int x, int y)
nuclear@4 434 {
nuclear@4 435 double mv[16], proj[16];
nuclear@4 436 int vp[4];
nuclear@4 437 double resx, resy, resz;
nuclear@4 438 Ray ray;
nuclear@4 439
nuclear@4 440 glGetDoublev(GL_MODELVIEW_MATRIX, mv);
nuclear@4 441 glGetDoublev(GL_PROJECTION_MATRIX, proj);
nuclear@4 442 glGetIntegerv(GL_VIEWPORT, vp);
nuclear@4 443
nuclear@4 444 gluUnProject(x, y, 0, mv, proj, vp, &resx, &resy, &resz);
nuclear@4 445 ray.origin = Vector3(resx, resy, resz);
nuclear@4 446
nuclear@4 447 gluUnProject(x, y, 1, mv, proj, vp, &resx, &resy, &resz);
nuclear@4 448 ray.dir = normalize(Vector3(resx, resy, resz) - ray.origin);
nuclear@4 449
nuclear@4 450 return ray;
nuclear@0 451 }
nuclear@0 452
nuclear@7 453 static int next_pow2(int x)
nuclear@7 454 {
nuclear@7 455 x--;
nuclear@7 456 x = (x >> 1) | x;
nuclear@7 457 x = (x >> 2) | x;
nuclear@7 458 x = (x >> 4) | x;
nuclear@7 459 x = (x >> 8) | x;
nuclear@7 460 x = (x >> 16) | x;
nuclear@7 461 return x + 1;
nuclear@7 462 }
nuclear@7 463
nuclear@0 464 static Window create_window(const char *title, int xsz, int ysz)
nuclear@0 465 {
nuclear@0 466 int scr = DefaultScreen(dpy);
nuclear@0 467 Window root = RootWindow(dpy, scr);
nuclear@0 468
nuclear@0 469 int glxattr[] = {
nuclear@0 470 GLX_RGBA,
nuclear@0 471 GLX_RED_SIZE, 8,
nuclear@0 472 GLX_GREEN_SIZE, 8,
nuclear@0 473 GLX_BLUE_SIZE, 8,
nuclear@0 474 GLX_DEPTH_SIZE, 24,
nuclear@0 475 GLX_DOUBLEBUFFER,
nuclear@0 476 #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample)
nuclear@0 477 GLX_SAMPLE_BUFFERS_ARB, 1,
nuclear@0 478 GLX_SAMPLES_ARB, 1,
nuclear@0 479 #endif
nuclear@0 480 None
nuclear@0 481 };
nuclear@0 482
nuclear@0 483 XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr);
nuclear@0 484 if(!vis) {
nuclear@0 485 fprintf(stderr, "failed to find a suitable visual\n");
nuclear@0 486 return 0;
nuclear@0 487 }
nuclear@0 488
nuclear@0 489 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
nuclear@0 490 fprintf(stderr, "failed to create OpenGL context\n");
nuclear@0 491 XFree(vis);
nuclear@0 492 return -1;
nuclear@0 493 }
nuclear@0 494
nuclear@0 495 XSetWindowAttributes xattr;
nuclear@0 496 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
nuclear@0 497 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
nuclear@0 498 unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel;
nuclear@0 499
nuclear@0 500 Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
nuclear@0 501 vis->visual, xattr_mask, &xattr);
nuclear@0 502 if(!win) {
nuclear@0 503 fprintf(stderr, "failed to create window\n");
nuclear@0 504 glXDestroyContext(dpy, ctx);
nuclear@0 505 XFree(vis);
nuclear@0 506 return -1;
nuclear@0 507 }
nuclear@0 508 XFree(vis);
nuclear@0 509
nuclear@0 510 unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask |
nuclear@0 511 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
nuclear@6 512 PointerMotionMask;
nuclear@0 513 XSelectInput(dpy, win, evmask);
nuclear@0 514
nuclear@0 515 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
nuclear@0 516 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
nuclear@0 517 XSetWMProtocols(dpy, win, &xa_wm_del_win, 1);
nuclear@0 518
nuclear@0 519 XClassHint hint;
nuclear@0 520 hint.res_name = hint.res_class = (char*)"equeue_win";
nuclear@0 521 XSetClassHint(dpy, win, &hint);
nuclear@0 522
nuclear@0 523 XTextProperty wm_name;
nuclear@0 524 XStringListToTextProperty((char**)&title, 1, &wm_name);
nuclear@0 525 XSetWMName(dpy, win, &wm_name);
nuclear@0 526 XSetWMIconName(dpy, win, &wm_name);
nuclear@0 527 XFree(wm_name.value);
nuclear@0 528
nuclear@0 529 XMapWindow(dpy, win);
nuclear@0 530 glXMakeCurrent(dpy, win, ctx);
nuclear@0 531
nuclear@0 532 return win;
nuclear@0 533 }
nuclear@0 534
nuclear@0 535 static void process_events()
nuclear@0 536 {
nuclear@0 537 XEvent ev;
nuclear@0 538
nuclear@0 539 while(XPending(dpy)) {
nuclear@0 540 XNextEvent(dpy, &ev);
nuclear@0 541 switch(ev.type) {
nuclear@0 542 case MapNotify:
nuclear@0 543 win_mapped = true;
nuclear@0 544 break;
nuclear@0 545
nuclear@0 546 case UnmapNotify:
nuclear@0 547 win_mapped = false;
nuclear@0 548 break;
nuclear@0 549
nuclear@0 550 case Expose:
nuclear@0 551 if(win_mapped && ev.xexpose.count == 0) {
nuclear@6 552 draw_pending = true;
nuclear@0 553 }
nuclear@0 554 break;
nuclear@0 555
nuclear@0 556 case MotionNotify:
nuclear@0 557 motion(ev.xmotion.x, ev.xmotion.y);
nuclear@0 558 break;
nuclear@0 559
nuclear@0 560 case ButtonPress:
nuclear@0 561 mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y);
nuclear@0 562 break;
nuclear@0 563
nuclear@0 564 case ButtonRelease:
nuclear@0 565 mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y);
nuclear@0 566 break;
nuclear@0 567
nuclear@0 568 case KeyPress:
nuclear@0 569 {
nuclear@0 570 KeySym sym = XLookupKeysym(&ev.xkey, 0);
nuclear@0 571 keyb(translate_keysym(sym), true);
nuclear@0 572 }
nuclear@0 573 break;
nuclear@0 574
nuclear@0 575 case KeyRelease:
nuclear@0 576 {
nuclear@0 577 KeySym sym = XLookupKeysym(&ev.xkey, 0);
nuclear@0 578 keyb(translate_keysym(sym), false);
nuclear@0 579 }
nuclear@0 580 break;
nuclear@0 581
nuclear@0 582 case ConfigureNotify:
nuclear@0 583 {
nuclear@0 584 int xsz = ev.xconfigure.width;
nuclear@0 585 int ysz = ev.xconfigure.height;
nuclear@0 586
nuclear@0 587 if(xsz != win_width || ysz != win_height) {
nuclear@0 588 win_width = xsz;
nuclear@0 589 win_height = ysz;
nuclear@0 590 reshape(xsz, ysz);
nuclear@0 591 }
nuclear@0 592 }
nuclear@0 593 break;
nuclear@0 594
nuclear@0 595 case ClientMessage:
nuclear@0 596 if(ev.xclient.message_type == xa_wm_prot) {
nuclear@0 597 if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) {
nuclear@0 598 exit(0);
nuclear@0 599 }
nuclear@0 600 }
nuclear@0 601 break;
nuclear@0 602
nuclear@0 603 default:
nuclear@0 604 break;
nuclear@0 605 }
nuclear@0 606
nuclear@0 607 }
nuclear@0 608 }
nuclear@0 609
nuclear@0 610 static int translate_keysym(KeySym sym)
nuclear@0 611 {
nuclear@0 612 switch(sym) {
nuclear@0 613 case XK_BackSpace:
nuclear@0 614 return '\b';
nuclear@0 615 case XK_Tab:
nuclear@0 616 return '\t';
nuclear@0 617 case XK_Linefeed:
nuclear@0 618 return '\r';
nuclear@0 619 case XK_Return:
nuclear@0 620 return '\n';
nuclear@0 621 case XK_Escape:
nuclear@0 622 return 27;
nuclear@0 623 default:
nuclear@0 624 break;
nuclear@0 625 }
nuclear@0 626 return (int)sym;
nuclear@0 627 }
nuclear@2 628
nuclear@2 629 static int proc_args(int argc, char **argv)
nuclear@2 630 {
nuclear@2 631 for(int i=1; i<argc; i++) {
nuclear@2 632 if(argv[i][0] == '-') {
nuclear@2 633 fprintf(stderr, "unexpected option: %s\n", argv[i]);
nuclear@2 634 return -1;
nuclear@2 635
nuclear@2 636 } else {
nuclear@2 637 if(fake_devpath) {
nuclear@2 638 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
nuclear@2 639 return -1;
nuclear@2 640 }
nuclear@2 641 fake_devpath = argv[i];
nuclear@2 642 }
nuclear@2 643 }
nuclear@2 644 if(!fake_devpath) {
nuclear@2 645 fprintf(stderr, "no device path specified, running standalone\n");
nuclear@2 646 }
nuclear@2 647 return 0;
nuclear@2 648 }