/* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * This code derived from TI Explorer Lisp code by Joe Keane, Fritz Mueller, * and Jamie Zawinski. */ #include #include "screenhack.h" #define POINT_COUNT 16 #define LINE_COUNT 32 #define ANGLE_SCALE 0.001 struct line_info { char li_ip; char li_iq; char li_color; char li_pad; }; struct point_state { short old_x, old_y; short new_x, new_y; }; struct hyper_state { char hs_stop; char hs_icon; char hs_resize; char hs_redraw; Display *hs_display; Window hs_window; float hs_two_observer_z; float hs_offset_x; float hs_offset_y; float hs_unit_scale; int hs_delay; GC hs_color_gcs[8]; GC black_gc; #if 0 double hs_angle_xy; double hs_angle_xz; double hs_angle_yz; double hs_angle_xw; double hs_angle_yw; double hs_angle_zw; #endif double hs_cos_xy, hs_sin_xy; double hs_cos_xz, hs_sin_xz; double hs_cos_yz, hs_sin_yz; double hs_cos_xw, hs_sin_xw; double hs_cos_yw, hs_sin_yw; double hs_cos_zw, hs_sin_zw; double hs_ref_ax, hs_ref_ay, hs_ref_az, hs_ref_aw; double hs_ref_bx, hs_ref_by, hs_ref_bz, hs_ref_bw; double hs_ref_cx, hs_ref_cy, hs_ref_cz, hs_ref_cw; double hs_ref_dx, hs_ref_dy, hs_ref_dz, hs_ref_dw; struct point_state hs_points[POINT_COUNT]; int roted; }; static const struct line_info line_table[LINE_COUNT]; static const char *hypercube_defaults[] = { "*observer-z: 3.0", "*delay: 10000", "*xy: 3", "*xz: 5", "*yw: 10", "*yz: 0", "*xw: 0", "*zw: 0", ".background: black", ".foreground: white", "*fpsSolid: true", "*color0: magenta", "*color3: #FF0093", "*color1: yellow", "*color2: #FF9300", "*color4: green", "*color7: #00FFD0", "*color5: #8080FF", "*color6: #00D0FF", 0 }; static XrmOptionDescRec hypercube_options [] = { { "-color0", ".color0", XrmoptionSepArg, 0 }, { "-color1", ".color1", XrmoptionSepArg, 0 }, { "-color2", ".color2", XrmoptionSepArg, 0 }, { "-color3", ".color3", XrmoptionSepArg, 0 }, { "-color4", ".color4", XrmoptionSepArg, 0 }, { "-color5", ".color5", XrmoptionSepArg, 0 }, { "-color6", ".color6", XrmoptionSepArg, 0 }, { "-color7", ".color7", XrmoptionSepArg, 0 }, { "-xw", ".xw", XrmoptionSepArg, 0 }, { "-xy", ".xy", XrmoptionSepArg, 0 }, { "-xz", ".xz", XrmoptionSepArg, 0 }, { "-yw", ".yw", XrmoptionSepArg, 0 }, { "-yz", ".yz", XrmoptionSepArg, 0 }, { "-zw", ".zw", XrmoptionSepArg, 0 }, { "-observer-z", ".observer-z", XrmoptionSepArg, 0 }, { "-delay", ".delay", XrmoptionSepArg, 0 }, { 0, 0, 0, 0 } }; static void set_sizes (struct hyper_state *hs, int width, int height); static void * hypercube_init (Display *dpy, Window win) { XGCValues gcv; Colormap cmap; unsigned long bg_pixel; int delay; float observer_z; struct hyper_state *hs = (struct hyper_state *) calloc (1, sizeof(*hs)); hs->hs_display = dpy; hs->hs_window = win; observer_z = get_float_resource (dpy, "observer-z", "Float"); if (observer_z < 1.125) observer_z = 1.125; /* hs->hs_observer_z = observer_z; */ hs->hs_two_observer_z = 2.0 * observer_z; { XWindowAttributes wa; XGetWindowAttributes (dpy, win, &wa); cmap = wa.colormap; set_sizes (hs, wa.width, wa.height); } delay = get_integer_resource (dpy, "delay", "Integer"); hs->hs_delay = delay; bg_pixel = get_pixel_resource (dpy, cmap, "background", "Background"); if (mono_p) { GC black_gc; unsigned long fg_pixel; GC white_gc; gcv.function = GXcopy; gcv.foreground = bg_pixel; black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); fg_pixel = get_pixel_resource (dpy, cmap, "foreground", "Foreground"); gcv.foreground = fg_pixel ^ bg_pixel; white_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); hs->hs_color_gcs[0] = black_gc; hs->hs_color_gcs[1] = white_gc; } else { int col; gcv.function = GXcopy; gcv.foreground = get_pixel_resource (dpy, cmap, "background", "Background"); hs->black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); for (col = 0; col < 8; col++) { char buffer[16]; unsigned long fg_pixel; GC color_gc; sprintf (buffer, "color%d", col); fg_pixel = get_pixel_resource (dpy, cmap, buffer, "Foreground"); gcv.foreground = fg_pixel; color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv); hs->hs_color_gcs[col] = color_gc; } } hs->hs_ref_ax = 1.0, hs->hs_ref_ay = 0.0, hs->hs_ref_az = 0.0, hs->hs_ref_aw = 0.0; hs->hs_ref_bx = 0.0, hs->hs_ref_by = 1.0, hs->hs_ref_bz = 0.0, hs->hs_ref_bw = 0.0; hs->hs_ref_cx = 0.0, hs->hs_ref_cy = 0.0, hs->hs_ref_cz = 1.0, hs->hs_ref_cw = 0.0; hs->hs_ref_dx = 0.0, hs->hs_ref_dy = 0.0, hs->hs_ref_dz = 0.0, hs->hs_ref_dw = 1.0; { double xy; double xz; double yz; double xw; double yw; double zw; double cos_xy, sin_xy; double cos_xz, sin_xz; double cos_yz, sin_yz; double cos_xw, sin_xw; double cos_yw, sin_yw; double cos_zw, sin_zw; xy = get_float_resource (dpy, "xy", "Float") * ANGLE_SCALE; xz = get_float_resource (dpy, "xz", "Float") * ANGLE_SCALE; yz = get_float_resource (dpy, "yz", "Float") * ANGLE_SCALE; xw = get_float_resource (dpy, "xw", "Float") * ANGLE_SCALE; yw = get_float_resource (dpy, "yw", "Float") * ANGLE_SCALE; zw = get_float_resource (dpy, "zw", "Float") * ANGLE_SCALE; cos_xy = cos (xy), sin_xy = sin (xy); hs->hs_cos_xy = cos_xy, hs->hs_sin_xy = sin_xy; cos_xz = cos (xz), sin_xz = sin (xz); hs->hs_cos_xz = cos_xz, hs->hs_sin_xz = sin_xz; cos_yz = cos (yz), sin_yz = sin (yz); hs->hs_cos_yz = cos_yz, hs->hs_sin_yz = sin_yz; cos_xw = cos (xw), sin_xw = sin (xw); hs->hs_cos_xw = cos_xw, hs->hs_sin_xw = sin_xw; cos_yw = cos (yw), sin_yw = sin (yw); hs->hs_cos_yw = cos_yw, hs->hs_sin_yw = sin_yw; cos_zw = cos (zw), sin_zw = sin (zw); hs->hs_cos_zw = cos_zw, hs->hs_sin_zw = sin_zw; } return hs; } static unsigned long hypercube_draw (Display *dpy, Window window, void *closure) { struct hyper_state *hs = (struct hyper_state *) closure; int this_delay = hs->hs_delay; #ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ XClearWindow (dpy, window); #endif { int icon; int resize; char moved[POINT_COUNT]; int redraw; int stop; icon = hs->hs_icon; resize = hs->hs_resize; if (icon || !(hs->roted | resize)) goto skip1; { float observer_z; float unit_scale; float offset_x; float offset_y; double az, bz, cz, dz; double sum_z; double ax, bx, cx, dx; double sum_x; double ay, by, cy, dy; double sum_y; struct point_state *ps; int old_x; int old_y; double mul; double xf; double yf; int new_x; int new_y; int mov; #define compute(as,bs,cs,ds,i) \ az = hs->hs_ref_az; bz = hs->hs_ref_bz; cz = hs->hs_ref_cz; dz = hs->hs_ref_dz; \ ax = hs->hs_ref_ax; bx = hs->hs_ref_bx; cx = hs->hs_ref_cx; dx = hs->hs_ref_dx; \ ay = hs->hs_ref_ay; by = hs->hs_ref_by; cy = hs->hs_ref_cy; dy = hs->hs_ref_dy; \ sum_z = as az bs bz cs cz ds dz; \ observer_z = hs->hs_two_observer_z; \ unit_scale = hs->hs_unit_scale; \ sum_x = as ax bs bx cs cx ds dx; \ sum_y = as ay bs by cs cy ds dy; \ ps = &hs->hs_points[i]; \ mul = unit_scale / (observer_z - sum_z); \ offset_x = hs->hs_offset_x; \ offset_y = hs->hs_offset_y; \ old_x = ps->new_x; \ old_y = ps->new_y; \ xf = sum_x * mul + offset_x; \ yf = sum_y * mul + offset_y; \ new_x = (int)rint(xf); \ new_y = (int)rint(yf); \ ps->old_x = old_x; \ ps->old_y = old_y; \ ps->new_x = new_x; \ ps->new_y = new_y; \ mov = old_x != new_x || old_y != new_y; \ moved[i] = mov; compute (-, -, -, -, 0); compute (-, -, -, +, 1); compute (-, -, +, -, 2); compute (-, -, +, +, 3); compute (-, +, -, -, 4); compute (-, +, -, +, 5); compute (-, +, +, -, 6); compute (-, +, +, +, 7); compute (+, -, -, -, 8); compute (+, -, -, +, 9); compute (+, -, +, -, 10); compute (+, -, +, +, 11); compute (+, +, -, -, 12); compute (+, +, -, +, 13); compute (+, +, +, -, 14); compute (+, +, +, +, 15); } skip1: icon = hs->hs_icon; redraw = hs->hs_redraw; if (icon || !(hs->roted | redraw)) goto skip2; { int lc; const struct line_info *lip; int mono; Window win; lc = LINE_COUNT; lip = &line_table[0]; mono = mono_p; win = hs->hs_window; while (--lc >= 0) { int ip; int iq; int col; struct point_state *sp; struct point_state *sq; int mov_p; int mov_q; GC erase_gc; GC draw_gc; int p_x; int p_y; int q_x; int q_y; ip = lip->li_ip; iq = lip->li_iq; col = lip->li_color; lip++; mov_p = moved[ip]; mov_q = moved[iq]; if (!(redraw | mov_p | mov_q)) continue; sp = &hs->hs_points[ip]; sq = &hs->hs_points[iq]; if (mono) { erase_gc = hs->hs_color_gcs[0]; draw_gc = hs->hs_color_gcs[1]; } else { erase_gc = hs->black_gc; draw_gc = hs->hs_color_gcs[col]; } if (!redraw) { p_x = sp->old_x; p_y = sp->old_y; q_x = sq->old_x; q_y = sq->old_y; XDrawLine (dpy, win, erase_gc, p_x, p_y, q_x, q_y); } p_x = sp->new_x; p_y = sp->new_y; q_x = sq->new_x; q_y = sq->new_y; XDrawLine (dpy, win, draw_gc, p_x, p_y, q_x, q_y); } } skip2: stop = hs->hs_stop; hs->roted = 0; if (stop) goto skip3; hs->roted = 1; { double cos_a; double sin_a; double old_u; double old_v; double new_u; double new_v; /* If you get error messages about the following forms, and you think you're using an ANSI C conforming compiler, then you're mistaken. Possibly you're mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa. Regardless, your system is broken; it's not a bug in this program. */ #if defined(__STDC__) || defined(__ANSI_CPP__) #define rotate(name,dim0,dim1) \ old_u = hs->hs_ref_##name##dim0; \ old_v = hs->hs_ref_##name##dim1; \ new_u = old_u * cos_a + old_v * sin_a; \ new_v = old_v * cos_a - old_u * sin_a; \ hs->hs_ref_##name##dim0 = new_u; \ hs->hs_ref_##name##dim1 = new_v; #define rotates(dim0,dim1) \ if (hs->hs_sin_##dim0##dim1 != 0) { \ cos_a = hs->hs_cos_##dim0##dim1; \ sin_a = hs->hs_sin_##dim0##dim1; \ rotate(a,dim0,dim1); \ rotate(b,dim0,dim1); \ rotate(c,dim0,dim1); \ rotate(d,dim0,dim1); \ } #else /* !__STDC__, courtesy of Andreas Luik */ #define rotate(name,dim0,dim1) \ old_u = hs->hs_ref_/**/name/**/dim0; \ old_v = hs->hs_ref_/**/name/**/dim1; \ new_u = old_u * cos_a + old_v * sin_a; \ new_v = old_v * cos_a - old_u * sin_a; \ hs->hs_ref_/**/name/**/dim0 = new_u; \ hs->hs_ref_/**/name/**/dim1 = new_v; #define rotates(dim0,dim1) \ if (hs->hs_sin_/**/dim0/**/dim1 != 0) { \ cos_a = hs->hs_cos_/**/dim0/**/dim1; \ sin_a = hs->hs_sin_/**/dim0/**/dim1; \ rotate(a,dim0,dim1); \ rotate(b,dim0,dim1); \ rotate(c,dim0,dim1); \ rotate(d,dim0,dim1); \ } #endif /* !__STDC__ */ rotates (x,y); rotates (x,z); rotates (y,z); rotates (x,w); rotates (y,w); rotates (z,w); } skip3: /* stop = hs->hs_stop; */ if (stop && this_delay < 10000) this_delay = 10000; } return this_delay; } static Bool hypercube_event (Display *dpy, Window window, void *closure, XEvent *e) { struct hyper_state *hs = (struct hyper_state *) closure; if (e->type == ButtonPress && e->xbutton.button == 2) { hs->hs_stop = !hs->hs_stop; return True; } return False; } static void hypercube_reshape (Display *dpy, Window window, void *closure, unsigned int w, unsigned int h) { struct hyper_state *hs = (struct hyper_state *) closure; set_sizes (hs, w, h); XClearWindow (dpy, window); } static void set_sizes (struct hyper_state *hs, int width, int height) { double observer_z; int min_dim; double var; double offset_x; double offset_y; double unit_scale; observer_z = 0.5 * hs->hs_two_observer_z; min_dim = width < height ? width : height; var = sqrt(observer_z * observer_z - 1.0); offset_x = 0.5 * (double)(width - 1); offset_y = 0.5 * (double)(height - 1); unit_scale = 0.4 * min_dim * var; hs->hs_offset_x = (float)offset_x; hs->hs_offset_y = (float)offset_y; hs->hs_unit_scale = (float)unit_scale; } /* data */ static const struct line_info line_table[LINE_COUNT] = { { 0, 1, 0, }, { 0, 2, 0, }, { 1, 3, 0, }, { 2, 3, 0, }, { 4, 5, 1, }, { 4, 6, 1, }, { 5, 7, 1, }, { 6, 7, 1, }, { 0, 4, 4, }, { 0, 8, 4, }, { 4, 12, 4, }, { 8, 12, 4, }, { 1, 5, 5, }, { 1, 9, 5, }, { 5, 13, 5, }, { 9, 13, 5, }, { 2, 6, 6, }, { 2, 10, 6, }, { 6, 14, 6, }, { 10, 14, 6, }, { 3, 7, 7, }, { 3, 11, 7, }, { 7, 15, 7, }, { 11, 15, 7, }, { 8, 9, 2, }, { 8, 10, 2, }, { 9, 11, 2, }, { 10, 11, 2, }, { 12, 13, 3, }, { 12, 14, 3, }, { 13, 15, 3, }, { 14, 15, 3, }, }; static void hypercube_free (Display *dpy, Window window, void *closure) { struct hyper_state *hs = (struct hyper_state *) closure; int i; XFreeGC (dpy, hs->black_gc); for (i = 0; i < 8; i++) if (hs->hs_color_gcs[i]) XFreeGC (dpy, hs->hs_color_gcs[i]); free (hs); } XSCREENSAVER_MODULE ("HyperCube", hypercube)