nuclear@0: #include nuclear@0: #include nuclear@4: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@1: #include "dev.h" nuclear@4: #include "scene.h" nuclear@7: #include "timer.h" nuclear@7: #include "fblur.h" nuclear@7: nuclear@7: nuclear@7: enum { nuclear@7: REGULAR_PASS, nuclear@7: GLOW_PASS nuclear@7: }; nuclear@0: nuclear@11: void post_redisplay(); nuclear@0: static bool init(); nuclear@0: static void cleanup(); nuclear@0: static void display(); nuclear@7: static void draw_scene(int pass = REGULAR_PASS); nuclear@7: static void post_glow(void); nuclear@0: static void keyb(int key, bool pressed); nuclear@0: static void mouse(int bn, bool pressed, int x, int y); nuclear@0: static void motion(int x, int y); nuclear@4: static Ray calc_pick_ray(int x, int y); nuclear@7: static int next_pow2(int x); nuclear@0: nuclear@0: static Window create_window(const char *title, int xsz, int ysz); nuclear@0: static void process_events(); nuclear@0: static int translate_keysym(KeySym sym); nuclear@0: nuclear@2: static int proc_args(int argc, char **argv); nuclear@2: nuclear@0: static Display *dpy; nuclear@0: static Window win; nuclear@0: static GLXContext ctx; nuclear@0: static Atom xa_wm_prot, xa_wm_del_win; nuclear@0: nuclear@0: static int win_width, win_height; nuclear@0: nuclear@4: static bool draw_pending; nuclear@0: static bool win_mapped; nuclear@0: nuclear@2: static int fakefd = -1; nuclear@2: static char *fake_devpath; nuclear@2: nuclear@4: static float cam_theta, cam_phi, cam_dist = 140; nuclear@4: static Scene *scn; nuclear@4: nuclear@4: enum { BN_TICKET, BN_NEXT, NUM_BUTTONS }; nuclear@6: static const char *button_names[] = { "button1", "button2" }; nuclear@4: static Object *button_obj[NUM_BUTTONS]; nuclear@6: static Object *disp_obj[2]; nuclear@6: static Object *led_obj[2]; nuclear@6: static Vector3 led_on_emissive; nuclear@4: nuclear@7: static bool opt_use_glow = true; nuclear@7: #define GLOW_SZ_DIV 3 nuclear@7: static unsigned int glow_tex; nuclear@7: static int glow_tex_xsz, glow_tex_ysz, glow_xsz, glow_ysz; nuclear@7: static int glow_iter = 1; nuclear@7: static int blur_size = 5; nuclear@7: unsigned char *glow_framebuf; nuclear@7: nuclear@7: nuclear@2: int main(int argc, char **argv) nuclear@0: { nuclear@2: if(proc_args(argc, argv) == -1) { nuclear@2: return 1; nuclear@2: } nuclear@0: if(!init()) { nuclear@0: return 1; nuclear@0: } nuclear@0: atexit(cleanup); nuclear@0: nuclear@0: int xfd = ConnectionNumber(dpy); nuclear@0: nuclear@4: // run once through pending events before going into the select loop nuclear@4: process_events(); nuclear@4: nuclear@0: for(;;) { nuclear@0: fd_set rd; nuclear@0: FD_ZERO(&rd); nuclear@0: nuclear@0: FD_SET(xfd, &rd); nuclear@2: FD_SET(fakefd, &rd); nuclear@0: nuclear@4: struct timeval noblock = {0, 0}; nuclear@2: int maxfd = xfd > fakefd ? xfd : fakefd; nuclear@9: while(!XPending(dpy) && select(maxfd + 1, &rd, 0, 0, draw_pending ? &noblock : 0) == -1 && errno == EINTR); nuclear@0: nuclear@9: if(XPending(dpy) || FD_ISSET(xfd, &rd)) { nuclear@0: process_events(); nuclear@0: } nuclear@2: if(FD_ISSET(fakefd, &rd)) { nuclear@2: proc_dev_input(); nuclear@2: } nuclear@0: nuclear@4: if(draw_pending) { nuclear@7: draw_pending = false; nuclear@0: display(); nuclear@0: } nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@11: void post_redisplay() nuclear@11: { nuclear@11: draw_pending = true; nuclear@11: } nuclear@11: nuclear@0: static bool init() nuclear@0: { nuclear@2: if(fake_devpath) { nuclear@2: if((fakefd = start_dev(fake_devpath)) == -1) { nuclear@2: return false; nuclear@2: } nuclear@2: } nuclear@1: nuclear@0: if(!(dpy = XOpenDisplay(0))) { nuclear@0: fprintf(stderr, "failed to connect to the X server!\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@7: if(!(win = create_window("equeue device emulator", 512, 512))) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@4: glewInit(); nuclear@4: nuclear@4: scn = new Scene; nuclear@4: if(!scn->load("data/device.obj")) { nuclear@4: fprintf(stderr, "failed to load device 3D model\n"); nuclear@4: return false; nuclear@4: } nuclear@4: nuclear@4: for(int i=0; iget_object(button_names[i]); nuclear@4: if(!button_obj[i]) { nuclear@4: fprintf(stderr, "invalid 3D model\n"); nuclear@4: return false; nuclear@4: } nuclear@4: BSphere &bs = button_obj[i]->get_mesh()->get_bounds(); nuclear@4: bs.set_radius(bs.get_radius() * 1.5); nuclear@4: } nuclear@4: nuclear@6: disp_obj[0] = scn->get_object("7seg0"); nuclear@6: disp_obj[1] = scn->get_object("7seg1"); nuclear@6: if(!disp_obj[0] || !disp_obj[1]) { nuclear@6: fprintf(stderr, "invalid 3D model\n"); nuclear@6: return false; nuclear@6: } nuclear@6: scn->remove_object(disp_obj[0]); nuclear@6: scn->remove_object(disp_obj[1]); nuclear@6: nuclear@6: led_obj[0] = scn->get_object("led1"); nuclear@6: led_obj[1] = scn->get_object("led2"); nuclear@6: if(!led_obj[0] || !led_obj[1]) { nuclear@6: fprintf(stderr, "invalid 3D model\n"); nuclear@6: return false; nuclear@6: } nuclear@6: scn->remove_object(led_obj[0]); nuclear@6: scn->remove_object(led_obj[1]); nuclear@6: led_on_emissive = led_obj[0]->mtl.emissive; nuclear@6: nuclear@7: // create the glow texture nuclear@7: glGenTextures(1, &glow_tex); nuclear@7: glBindTexture(GL_TEXTURE_2D, glow_tex); nuclear@7: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@7: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@7: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); nuclear@7: nuclear@4: glEnable(GL_DEPTH_TEST); nuclear@4: glEnable(GL_CULL_FACE); nuclear@4: glEnable(GL_LIGHTING); nuclear@4: glEnable(GL_LIGHT0); nuclear@4: nuclear@4: glClearColor(0.1, 0.1, 0.1, 1); nuclear@4: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: static void cleanup() nuclear@0: { nuclear@4: delete scn; nuclear@4: nuclear@1: stop_dev(); nuclear@1: nuclear@0: if(!dpy) return; nuclear@0: nuclear@0: if(win) { nuclear@0: XDestroyWindow(dpy, win); nuclear@0: } nuclear@0: XCloseDisplay(dpy); nuclear@0: } nuclear@0: nuclear@6: #define DIGIT_USZ (1.0 / 11.0) nuclear@7: #define MIN_REDRAW_INTERVAL (1000 / 40) /* 40fps */ nuclear@6: nuclear@0: static void display() nuclear@0: { nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@4: glTranslatef(0, 0, -cam_dist); nuclear@4: glRotatef(cam_phi, 1, 0, 0); nuclear@4: glRotatef(cam_theta, 0, 1, 0); nuclear@4: nuclear@4: float lpos[] = {-7, 5, 10, 0}; nuclear@4: glLightfv(GL_LIGHT0, GL_POSITION, lpos); nuclear@4: nuclear@7: if(opt_use_glow) { nuclear@7: glViewport(0, 0, glow_xsz, glow_ysz); nuclear@7: nuclear@7: glClearColor(0, 0, 0, 1); nuclear@7: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@7: nuclear@7: draw_scene(GLOW_PASS); nuclear@7: nuclear@7: glReadPixels(0, 0, glow_xsz, glow_ysz, GL_RGBA, GL_UNSIGNED_BYTE, glow_framebuf); nuclear@7: glViewport(0, 0, win_width, win_height); nuclear@7: } nuclear@7: nuclear@7: glClearColor(0.05, 0.05, 0.05, 1); nuclear@7: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@7: nuclear@7: draw_scene(); nuclear@7: nuclear@7: if(opt_use_glow) { nuclear@7: for(int i=0; irender(); nuclear@7: } nuclear@0: nuclear@6: // shift the textures and modify the materials to make the display match our state nuclear@6: for(int i=0; i<2; i++) { nuclear@7: // 7seg nuclear@6: int digit = get_display_number(); nuclear@6: for(int j=0; jmtl.tex_offset[TEX_DIFFUSE] = Vector2(uoffs, 0); nuclear@6: disp_obj[i]->render(); nuclear@6: nuclear@6: // LEDs nuclear@6: if(get_led_state(i)) { nuclear@6: led_obj[i]->mtl.emissive = led_on_emissive; nuclear@6: } else { nuclear@6: led_obj[i]->mtl.emissive = Vector3(0, 0, 0); nuclear@6: } nuclear@6: led_obj[i]->render(); nuclear@6: } nuclear@7: } nuclear@6: nuclear@7: static void post_glow(void) nuclear@7: { nuclear@7: float max_s = (float)glow_xsz / (float)glow_tex_xsz; nuclear@7: float max_t = (float)glow_ysz / (float)glow_tex_ysz; nuclear@7: nuclear@7: glPushAttrib(GL_ENABLE_BIT); nuclear@7: nuclear@7: glBlendFunc(GL_ONE, GL_ONE); nuclear@7: glEnable(GL_BLEND); nuclear@7: glDisable(GL_CULL_FACE); nuclear@7: glDisable(GL_LIGHTING); nuclear@7: glDisable(GL_DEPTH_TEST); nuclear@7: nuclear@7: glMatrixMode(GL_MODELVIEW); nuclear@7: glPushMatrix(); nuclear@7: glLoadIdentity(); nuclear@7: glMatrixMode(GL_PROJECTION); nuclear@7: glPushMatrix(); nuclear@7: glLoadIdentity(); nuclear@7: nuclear@7: glEnable(GL_TEXTURE_2D); nuclear@7: glBindTexture(GL_TEXTURE_2D, glow_tex); nuclear@7: nuclear@7: glBegin(GL_QUADS); nuclear@7: glColor4f(1, 1, 1, 1); nuclear@7: glTexCoord2f(0, 0); nuclear@7: glVertex2f(-1, -1); nuclear@7: glTexCoord2f(max_s, 0); nuclear@7: glVertex2f(1, -1); nuclear@7: glTexCoord2f(max_s, max_t); nuclear@7: glVertex2f(1, 1); nuclear@7: glTexCoord2f(0, max_t); nuclear@7: glVertex2f(-1, 1); nuclear@7: glEnd(); nuclear@7: nuclear@7: glPopMatrix(); nuclear@7: glMatrixMode(GL_MODELVIEW); nuclear@7: glPopMatrix(); nuclear@7: nuclear@7: glPopAttrib(); nuclear@0: } nuclear@0: nuclear@7: nuclear@0: static void reshape(int x, int y) nuclear@0: { nuclear@0: glViewport(0, 0, x, y); nuclear@0: nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glLoadIdentity(); nuclear@4: gluPerspective(50.0, (float)x / (float)y, 1.0, 1000.0); nuclear@4: nuclear@4: win_width = x; nuclear@4: win_height = y; nuclear@7: nuclear@7: if(opt_use_glow) { nuclear@7: glow_xsz = x / GLOW_SZ_DIV; nuclear@7: glow_ysz = y / GLOW_SZ_DIV; nuclear@7: printf("glow image size: %dx%d\n", glow_xsz, glow_ysz); nuclear@7: nuclear@7: delete [] glow_framebuf; nuclear@7: glow_framebuf = new unsigned char[glow_xsz * glow_ysz * 4]; nuclear@7: nuclear@7: glow_tex_xsz = next_pow2(glow_xsz); nuclear@7: glow_tex_ysz = next_pow2(glow_ysz); nuclear@7: glBindTexture(GL_TEXTURE_2D, glow_tex); nuclear@7: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glow_tex_xsz, glow_tex_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); nuclear@7: } nuclear@0: } nuclear@0: nuclear@0: static void keyb(int key, bool pressed) nuclear@0: { nuclear@0: if(pressed) { nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@4: static bool bnstate[32]; nuclear@4: static int prev_x, prev_y; nuclear@4: nuclear@0: static void mouse(int bn, bool pressed, int x, int y) nuclear@0: { nuclear@4: bnstate[bn] = pressed; nuclear@4: prev_x = x; nuclear@4: prev_y = y; nuclear@4: nuclear@4: if(bn == 0 && pressed) { nuclear@4: // do picking nuclear@4: Ray ray = calc_pick_ray(x, win_height - y); nuclear@4: nuclear@4: HitPoint minhit; nuclear@4: minhit.t = FLT_MAX; nuclear@4: int hit_found = -1; nuclear@4: nuclear@4: for(int i=0; iget_mesh()->get_bounds().intersect(ray, &hit) && hit.t < minhit.t) { nuclear@4: minhit = hit; nuclear@4: hit_found = i; nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: if(hit_found != -1) { nuclear@4: switch(hit_found) { nuclear@4: case BN_TICKET: nuclear@4: issue_ticket(); nuclear@4: printf("issue ticket\n"); nuclear@4: break; nuclear@4: nuclear@4: case BN_NEXT: nuclear@4: next_customer(); nuclear@4: printf("next customer\n"); nuclear@4: break; nuclear@4: } nuclear@4: draw_pending = true; nuclear@4: } nuclear@4: } nuclear@0: } nuclear@0: nuclear@0: static void motion(int x, int y) nuclear@0: { nuclear@4: int dx = x - prev_x; nuclear@4: int dy = y - prev_y; nuclear@4: prev_x = x; nuclear@4: prev_y = y; nuclear@4: nuclear@4: if(bnstate[0]) { nuclear@4: cam_theta += dx * 0.5; nuclear@4: cam_phi += dy * 0.5; nuclear@4: if(cam_phi < -90) cam_phi = -90; nuclear@4: if(cam_phi > 90) cam_phi = 90; nuclear@6: nuclear@6: } else if(bnstate[2]) { nuclear@4: cam_dist += dy * 0.5; nuclear@4: if(cam_dist < 0.0) cam_dist = 0.0; nuclear@6: nuclear@6: } else { nuclear@6: float xoffs = 2.0 * x / win_width - 1.0; nuclear@6: float yoffs = 2.0 * y / win_height - 1.0; nuclear@6: cam_theta = -xoffs * 15.0 * (win_width / win_height); nuclear@6: cam_phi = -yoffs * 15.0; nuclear@4: } nuclear@6: draw_pending = true; nuclear@4: } nuclear@4: nuclear@4: static Ray calc_pick_ray(int x, int y) nuclear@4: { nuclear@4: double mv[16], proj[16]; nuclear@4: int vp[4]; nuclear@4: double resx, resy, resz; nuclear@4: Ray ray; nuclear@4: nuclear@4: glGetDoublev(GL_MODELVIEW_MATRIX, mv); nuclear@4: glGetDoublev(GL_PROJECTION_MATRIX, proj); nuclear@4: glGetIntegerv(GL_VIEWPORT, vp); nuclear@4: nuclear@4: gluUnProject(x, y, 0, mv, proj, vp, &resx, &resy, &resz); nuclear@4: ray.origin = Vector3(resx, resy, resz); nuclear@4: nuclear@4: gluUnProject(x, y, 1, mv, proj, vp, &resx, &resy, &resz); nuclear@4: ray.dir = normalize(Vector3(resx, resy, resz) - ray.origin); nuclear@4: nuclear@4: return ray; nuclear@0: } nuclear@0: nuclear@7: static int next_pow2(int x) nuclear@7: { nuclear@7: x--; nuclear@7: x = (x >> 1) | x; nuclear@7: x = (x >> 2) | x; nuclear@7: x = (x >> 4) | x; nuclear@7: x = (x >> 8) | x; nuclear@7: x = (x >> 16) | x; nuclear@7: return x + 1; nuclear@7: } nuclear@7: nuclear@0: static Window create_window(const char *title, int xsz, int ysz) nuclear@0: { nuclear@0: int scr = DefaultScreen(dpy); nuclear@0: Window root = RootWindow(dpy, scr); nuclear@0: nuclear@0: int glxattr[] = { nuclear@0: GLX_RGBA, nuclear@0: GLX_RED_SIZE, 8, nuclear@0: GLX_GREEN_SIZE, 8, nuclear@0: GLX_BLUE_SIZE, 8, nuclear@0: GLX_DEPTH_SIZE, 24, nuclear@0: GLX_DOUBLEBUFFER, nuclear@0: #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) nuclear@0: GLX_SAMPLE_BUFFERS_ARB, 1, nuclear@0: GLX_SAMPLES_ARB, 1, nuclear@0: #endif nuclear@0: None nuclear@0: }; nuclear@0: nuclear@0: XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr); nuclear@0: if(!vis) { nuclear@0: fprintf(stderr, "failed to find a suitable visual\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { nuclear@0: fprintf(stderr, "failed to create OpenGL context\n"); nuclear@0: XFree(vis); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: XSetWindowAttributes xattr; nuclear@0: xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); nuclear@0: xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); nuclear@0: unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel; nuclear@0: nuclear@0: Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, nuclear@0: vis->visual, xattr_mask, &xattr); nuclear@0: if(!win) { nuclear@0: fprintf(stderr, "failed to create window\n"); nuclear@0: glXDestroyContext(dpy, ctx); nuclear@0: XFree(vis); nuclear@0: return -1; nuclear@0: } nuclear@0: XFree(vis); nuclear@0: nuclear@0: unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask | nuclear@0: KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | nuclear@11: PointerMotionMask | LeaveWindowMask; nuclear@0: XSelectInput(dpy, win, evmask); nuclear@0: nuclear@0: xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); nuclear@0: xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); nuclear@0: XSetWMProtocols(dpy, win, &xa_wm_del_win, 1); nuclear@0: nuclear@0: XClassHint hint; nuclear@0: hint.res_name = hint.res_class = (char*)"equeue_win"; nuclear@0: XSetClassHint(dpy, win, &hint); nuclear@0: nuclear@0: XTextProperty wm_name; nuclear@0: XStringListToTextProperty((char**)&title, 1, &wm_name); nuclear@0: XSetWMName(dpy, win, &wm_name); nuclear@0: XSetWMIconName(dpy, win, &wm_name); nuclear@0: XFree(wm_name.value); nuclear@0: nuclear@0: XMapWindow(dpy, win); nuclear@0: glXMakeCurrent(dpy, win, ctx); nuclear@0: nuclear@0: return win; nuclear@0: } nuclear@0: nuclear@0: static void process_events() nuclear@0: { nuclear@0: XEvent ev; nuclear@0: nuclear@0: while(XPending(dpy)) { nuclear@0: XNextEvent(dpy, &ev); nuclear@0: switch(ev.type) { nuclear@0: case MapNotify: nuclear@0: win_mapped = true; nuclear@0: break; nuclear@0: nuclear@0: case UnmapNotify: nuclear@0: win_mapped = false; nuclear@0: break; nuclear@0: nuclear@0: case Expose: nuclear@0: if(win_mapped && ev.xexpose.count == 0) { nuclear@6: draw_pending = true; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case MotionNotify: nuclear@0: motion(ev.xmotion.x, ev.xmotion.y); nuclear@0: break; nuclear@0: nuclear@0: case ButtonPress: nuclear@0: mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y); nuclear@0: break; nuclear@0: nuclear@0: case ButtonRelease: nuclear@0: mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y); nuclear@0: break; nuclear@0: nuclear@0: case KeyPress: nuclear@0: { nuclear@0: KeySym sym = XLookupKeysym(&ev.xkey, 0); nuclear@0: keyb(translate_keysym(sym), true); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case KeyRelease: nuclear@0: { nuclear@0: KeySym sym = XLookupKeysym(&ev.xkey, 0); nuclear@0: keyb(translate_keysym(sym), false); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ConfigureNotify: nuclear@0: { nuclear@0: int xsz = ev.xconfigure.width; nuclear@0: int ysz = ev.xconfigure.height; nuclear@0: nuclear@0: if(xsz != win_width || ysz != win_height) { nuclear@0: win_width = xsz; nuclear@0: win_height = ysz; nuclear@0: reshape(xsz, ysz); nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ClientMessage: nuclear@0: if(ev.xclient.message_type == xa_wm_prot) { nuclear@0: if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) { nuclear@0: exit(0); nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@11: case LeaveNotify: nuclear@11: if(ev.xcrossing.mode == NotifyNormal) { nuclear@11: cam_theta = cam_phi = 0; nuclear@11: draw_pending = true; nuclear@11: } nuclear@11: break; nuclear@11: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static int translate_keysym(KeySym sym) nuclear@0: { nuclear@0: switch(sym) { nuclear@0: case XK_BackSpace: nuclear@0: return '\b'; nuclear@0: case XK_Tab: nuclear@0: return '\t'; nuclear@0: case XK_Linefeed: nuclear@0: return '\r'; nuclear@0: case XK_Return: nuclear@0: return '\n'; nuclear@0: case XK_Escape: nuclear@0: return 27; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: return (int)sym; nuclear@0: } nuclear@2: nuclear@2: static int proc_args(int argc, char **argv) nuclear@2: { nuclear@2: for(int i=1; i