eqemu

annotate src/main.cc @ 11:2b559dc24c7b

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