diff options
Diffstat (limited to 'debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx')
-rw-r--r-- | debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx b/debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx new file mode 100644 index 00000000..40615660 --- /dev/null +++ b/debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx @@ -0,0 +1,153 @@ +/************************************************************************ + + Virtual Trackball for manipulating objects on the screen. + + This code is based on the virtual trackball mechanism developed by + Gavin Bell of Silicon Graphics. + + $Id: trackball.cxx 427 2004-09-27 04:45:31Z garland $ + + ************************************************************************/ + +#include <gfx/gfx.h> +#include <gfx/gl.h> +#include <gfx/trackball.h> + +namespace gfx +{ + +static +float proj_to_sphere(float r, float x, float y) +{ + // This is a magic number taken from the SGI trackball. + // + const float MAGIC_RLIMIT = 0.70710678118654752440f; + + // Project (x,y) onto a sphere of radius r or a hyperbolic sheet + // if the point is far enough away from the origin. + // + float d = sqrt(x*x + y*y); + if (d < r * MAGIC_RLIMIT ) + { + // Inside sphere + return sqrt(r*r - d*d); + } + else + { + // On hyperbola + float t = r * MAGIC_RLIMIT; + return t*t / d; + } +} + +// +// This is the core routine that actually simulates the action of the +// trackball. It projects the given coordinates onto the trackball +// surface, and computes an appropriate rotation. +// +// NOTE: This uses the combined spherical/hyperbolic trackball surface +// used in the SGI trackball. +// +void trackball(Quat& q, float p1x, float p1y, float p2x, float p2y) +{ + if (p1x == p2x && p1y == p2y) + { + q = Quat::ident(); + return; + } + + // This is a magic number taken from the SGI trackball source. + // Here is the original explanation of this constant: + // + // This size should really be based on the distance from the + // center of rotation to the point on the object underneath + // the mouse. That point would then track the mouse as + // closely as possible. This is a simple example, though, so + // that is left as an Exercise for the Programmer. + // + const float TRACKBALLSIZE = 0.8f; + + // Project the window coordinates onto the trackball surface. + // + Vec3 p1(p1x,p1y,proj_to_sphere(TRACKBALLSIZE,p1x,p1y)); + Vec3 p2(p2x,p2y,proj_to_sphere(TRACKBALLSIZE,p2x,p2y)); + + // And how much do we rotate? + // + float t = norm(p1-p2) / (2.0*TRACKBALLSIZE); + if (t > 1.0) t = 1.0; + if (t < -1.0) t = -1.0; + + // Convert this axis/angle rotation to a quaternion. + // + q = axis_to_quat(p2^p1, 2.0*asin(t)); +} + +static +void add_quats(const Quat& q1, const Quat& q2, Quat& dest) +{ + dest = q2*q1; + unitize(dest); +} + +//////////////////////////////////////////////////////////////////////// +// +// Encapsulate the standard interface of the trackball to simplify +// its use in most applications. +// + +Trackball::Trackball() +{ +} + +void Trackball::update_animation() +{ + add_quats(lastquat, curquat, curquat); +} + +bool Trackball::mouse_up(int *where, int which) +{ + return false; +} + +bool Trackball::mouse_down(int *where, int which) +{ + if( which==1 ) + lastquat = Quat::ident(); + + return false; +} + +bool Trackball::mouse_drag(int *where, int *last, int which) +{ + float vp[4]; + glGetFloatv(GL_VIEWPORT, vp); + float W=vp[2], H=vp[3]; + + float diam = 2*radius; + + if( which==1 ) + { + trackball(lastquat, + (2.0 * last[0] - W)/W, + (H - 2.0 * last[1])/H, + (2.0 * where[0] - W)/W, + (H - 2.0 * where[1])/H); + add_quats(lastquat, curquat, curquat); + } + else if( which==2 ) + { + trans[0] += diam * (where[0] - last[0]) / W; + trans[1] += diam * (last[1] - where[1]) / H; + } + else if( which==3 ) + { + trans[2] += 0.02*diam*(where[1] - last[1]); + } + else + return false; + + return true; +} + +} // namespace gfx |