X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fgltrackball.c;h=f3e02fd34f10d741682dc857b48bfe911b5d6ff9;hp=ee54cf91d2432f4a541774a742621d77286a54c4;hb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e;hpb=dba664f31aa87285db4d76cf8c5e66335299703a diff --git a/hacks/glx/gltrackball.c b/hacks/glx/gltrackball.c index ee54cf91..f3e02fd3 100644 --- a/hacks/glx/gltrackball.c +++ b/hacks/glx/gltrackball.c @@ -1,4 +1,4 @@ -/* gltrackball, Copyright (c) 2002-2012 Jamie Zawinski +/* gltrackball, Copyright (c) 2002-2014 Jamie Zawinski * GL-flavored wrapper for trackball.c * * Permission to use, copy, modify, distribute, and sell this software and its @@ -18,32 +18,52 @@ # include "config.h" #endif -#ifndef HAVE_COCOA +#ifdef HAVE_COCOA +# include "jwxyz.h" +#else /* !HAVE_COCOA -- real X11 */ +# include +# include # include -#endif +#endif /* !HAVE_COCOA */ #ifdef HAVE_JWZGLES # include "jwzgles.h" #endif /* HAVE_JWZGLES */ +# define Button4 4 /* WTF */ +# define Button5 5 +# define Button6 6 +# define Button7 7 + #include "trackball.h" #include "gltrackball.h" -extern double current_device_rotation (void); /* Bah, it's in fps.h */ +/* Bah, copied from ../fps.h */ +#ifdef USE_IPHONE + extern double current_device_rotation (void); +#else +# define current_device_rotation() (0) +#endif + struct trackball_state { - int x, y; + int ow, oh; + double x, y; + double dx, dy, ddx, ddy; GLfloat q[4]; + int button_down_p; + int ignore_device_rotation_p; }; /* Returns a trackball_state object, which encapsulates the stuff necessary to make dragging the mouse on the window of a GL program do the right thing. */ trackball_state * -gltrackball_init (void) +gltrackball_init (int ignore_device_rotation_p) { trackball_state *ts = (trackball_state *) calloc (1, sizeof (*ts)); if (!ts) return 0; + ts->ignore_device_rotation_p = ignore_device_rotation_p; trackball (ts->q, 0, 0, 0, 0); return ts; } @@ -58,6 +78,41 @@ gltrackball_reset (trackball_state *ts) } +/* Device rotation interacts very strangely with mouse positions. + I'm not entirely sure this is the right fix. + */ +static void +adjust_for_device_rotation (trackball_state *ts, + double *x, double *y, double *w, double *h) +{ + int rot = (int) current_device_rotation(); + int swap; + + if (ts->ignore_device_rotation_p) return; + + while (rot <= -180) rot += 360; + while (rot > 180) rot -= 360; + + if (rot > 135 || rot < -135) /* 180 */ + { + *x = *w - *x; + *y = *h - *y; + } + else if (rot > 45) /* 90 */ + { + swap = *x; *x = *y; *y = swap; + swap = *w; *w = *h; *h = swap; + *x = *w - *x; + } + else if (rot < -45) /* 270 */ + { + swap = *x; *x = *y; *y = swap; + swap = *w; *w = *h; *h = swap; + *y = *h - *y; + } +} + + /* Begin tracking the mouse: Call this when the mouse button goes down. x and y are the mouse position relative to the window. w and h are the size of the window. @@ -67,26 +122,76 @@ gltrackball_start (trackball_state *ts, int x, int y, int w, int h) { ts->x = x; ts->y = y; + ts->button_down_p = 1; + ts->dx = ts->ddx = 0; + ts->dy = ts->ddy = 0; } -/* Track the mouse: Call this each time the mouse moves with the button down. - x and y are the new mouse position relative to the window. - w and h are the size of the window. +/* Stop tracking the mouse: Call this when the mouse button goes up. */ void -gltrackball_track (trackball_state *ts, int x, int y, int w, int h) +gltrackball_stop (trackball_state *ts) +{ + ts->button_down_p = 0; +} + +static void +gltrackball_track_1 (trackball_state *ts, + double x, double y, + int w, int h) { + double X = x; + double Y = y; + double W = w, W2 = w; + double H = h, H2 = h; float q2[4]; - trackball (q2, - (2.0 * ts->x - w) / w, - (h - 2.0 * ts->y) / h, - (2.0 * x - w) / w, - (h - 2.0 * y) / h); + double ox = ts->x; + double oy = ts->y; + ts->x = x; ts->y = y; + + adjust_for_device_rotation (ts, &ox, &oy, &W, &H); + adjust_for_device_rotation (ts, &X, &Y, &W2, &H2); + + trackball (q2, + (2 * ox - W) / W, + (H - 2 * oy) / H, + (2 * X - W) / W, + (H - 2 * Y) / H); + add_quats (q2, ts->q, ts->q); } + +/* Track the mouse: Call this each time the mouse moves with the button down. + x and y are the new mouse position relative to the window. + w and h are the size of the window. + */ +void +gltrackball_track (trackball_state *ts, int x, int y, int w, int h) +{ + double dampen = 0.01; /* This keeps it going for about 3 sec */ + ts->dx = x - ts->x; + ts->dy = y - ts->y; + ts->ddx = ts->dx * dampen; + ts->ddy = ts->dy * dampen; + ts->ow = w; + ts->oh = h; + gltrackball_track_1 (ts, x, y, w, h); +} + + +static void +gltrackball_dampen (double *n, double *dn) +{ + int pos = (*n > 0); + *n -= *dn; + if (pos != (*n > 0)) + *n = *dn = 0; +} + + /* Execute the rotations current encapsulated in the trackball_state: this does something analagous to glRotatef(). */ @@ -94,16 +199,26 @@ void gltrackball_rotate (trackball_state *ts) { GLfloat m[4][4]; + if (!ts->button_down_p && + (ts->ddx != 0 || + ts->ddy != 0)) + { + /* Apply inertia: keep moving in the same direction as the last move. */ + gltrackball_track_1 (ts, + ts->x + ts->dx, + ts->y + ts->dy, + ts->ow, ts->oh); + + /* Dampen inertia: gradually stop spinning. */ + gltrackball_dampen (&ts->dx, &ts->ddx); + gltrackball_dampen (&ts->dy, &ts->ddy); + } + build_rotmatrix (m, ts->q); glMultMatrixf (&m[0][0]); } -# define Button4 4 /* X11/Xlib.h */ -# define Button5 5 -# define Button6 6 -# define Button7 7 - /* Call this when a mouse-wheel click is detected. Clicks act like horizontal or vertical drags. Percent is the length of the drag as a percentage of the screen size. @@ -154,3 +269,52 @@ gltrackball_get_quaternion (trackball_state *ts, float q[4]) for (i=0; i<4; i++) q[i] = ts->q[i]; } + + +/* A utility function for event-handler functions: + Handles the various motion and click events related to trackballs. + Returns True if the event was handled. + */ +Bool +gltrackball_event_handler (XEvent *event, + trackball_state *ts, + int window_width, int window_height, + Bool *button_down_p) +{ + if (event->xany.type == ButtonPress && + event->xbutton.button == Button1) + { + *button_down_p = True; + gltrackball_start (ts, + event->xbutton.x, event->xbutton.y, + window_width, window_height); + return True; + } + else if (event->xany.type == ButtonRelease && + event->xbutton.button == Button1) + { + *button_down_p = False; + gltrackball_stop (ts); + return True; + } + else if (event->xany.type == ButtonPress && + (event->xbutton.button == Button4 || + event->xbutton.button == Button5 || + event->xbutton.button == Button6 || + event->xbutton.button == Button7)) + { + gltrackball_mousewheel (ts, event->xbutton.button, 10, + !!event->xbutton.state); + return True; + } + else if (event->xany.type == MotionNotify && + *button_down_p) + { + gltrackball_track (ts, + event->xmotion.x, event->xmotion.y, + window_width, window_height); + return True; + } + + return False; +}