summaryrefslogtreecommitdiffstats
path: root/debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx')
-rw-r--r--debian/fireflies/fireflies-2.08/libgfx/src/trackball.cxx153
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