src/opengl/ArcBall.h

00001 
00018 /*************************************************************/
00019 
00020 #ifndef _ArcBall_h
00021 #define _ArcBall_h
00022 #include <stdlib.h>
00023 // 8<--Snip here if you have your own math types/funcs-->8 
00024 
00025 //Only support assertions in debug builds
00026 #ifdef _DEBUG
00027 # include "assert.h"
00028 #else
00029 # define assert(x) { }
00030 #endif
00031 
00032 //Math types derived from the KempoApi tMath library
00033     typedef union Tuple2f_t
00034     {
00035         struct
00036         {
00037             GLfloat X, Y;
00038         } s;
00039 
00040         GLfloat T[2];
00041     } Tuple2fT;      //A generic 2-element tuple that is represented by single-precision floating point x,y coordinates. 
00042 
00043     typedef union Tuple3f_t
00044     {
00045         struct
00046         {
00047             GLfloat X, Y, Z;
00048         } s;
00049 
00050         GLfloat T[3];
00051     } Tuple3fT;      //A generic 3-element tuple that is represented by single precision-floating point x,y,z coordinates. 
00052 
00053     typedef union Tuple4f_t
00054     {
00055         struct
00056         {
00057             GLfloat X, Y, Z, W;
00058         } s;
00059 
00060         GLfloat T[4];
00061     } Tuple4fT;      //A 4-element tuple represented by single-precision floating point x,y,z,w coordinates. 
00062 
00063     typedef union Matrix3f_t
00064     {
00065             struct
00066             {
00067                 //column major
00068                 union { GLfloat M00; GLfloat XX; GLfloat SX; };  //XAxis.X and Scale X
00069                 union { GLfloat M10; GLfloat XY;             };  //XAxis.Y
00070                 union { GLfloat M20; GLfloat XZ;             };  //XAxis.Z
00071                 union { GLfloat M01; GLfloat YX;             };  //YAxis.X
00072                 union { GLfloat M11; GLfloat YY; GLfloat SY; };  //YAxis.Y and Scale Y
00073                 union { GLfloat M21; GLfloat YZ;             };  //YAxis.Z
00074                 union { GLfloat M02; GLfloat ZX;             };  //ZAxis.X
00075                 union { GLfloat M12; GLfloat ZY;             };  //ZAxis.Y
00076                 union { GLfloat M22; GLfloat ZZ; GLfloat SZ; };  //ZAxis.Z and Scale Z
00077             } s;
00078             GLfloat M[9];
00079     } Matrix3fT;     //A single precision floating point 3 by 3 matrix. 
00080 
00081     typedef union Matrix4f_t
00082     {
00083             struct
00084             {
00085                 //column major
00086                 union { GLfloat M00; GLfloat XX; GLfloat SX; };  //XAxis.X and Scale X
00087                 union { GLfloat M10; GLfloat XY;             };  //XAxis.Y
00088                 union { GLfloat M20; GLfloat XZ;             };  //XAxis.Z
00089                 union { GLfloat M30; GLfloat XW;             };  //XAxis.W
00090                 union { GLfloat M01; GLfloat YX;             };  //YAxis.X
00091                 union { GLfloat M11; GLfloat YY; GLfloat SY; };  //YAxis.Y and Scale Y
00092                 union { GLfloat M21; GLfloat YZ;             };  //YAxis.Z
00093                 union { GLfloat M31; GLfloat YW;             };  //YAxis.W
00094                 union { GLfloat M02; GLfloat ZX;             };  //ZAxis.X
00095                 union { GLfloat M12; GLfloat ZY;             };  //ZAxis.Y
00096                 union { GLfloat M22; GLfloat ZZ; GLfloat SZ; };  //ZAxis.Z and Scale Z
00097                 union { GLfloat M32; GLfloat ZW;             };  //ZAxis.W
00098                 union { GLfloat M03; GLfloat TX;             };  //Trans.X
00099                 union { GLfloat M13; GLfloat TY;             };  //Trans.Y
00100                 union { GLfloat M23; GLfloat TZ;             };  //Trans.Z
00101                 union { GLfloat M33; GLfloat TW; GLfloat SW; };  //Trans.W and Scale W
00102             } s;
00103             GLfloat M[16];
00104     } Matrix4fT;     //A single precision floating point 4 by 4 matrix. 
00105 
00106 
00107 //"Inherited" types
00108 #define Point2fT    Tuple2fT   //A 2 element point that is represented by single precision floating point x,y coordinates. 
00109 
00110 #define Quat4fT     Tuple4fT   //A 4 element unit quaternion represented by single precision floating point x,y,z,w coordinates. 
00111 
00112 #define Vector2fT   Tuple2fT   //A 2-element vector that is represented by single-precision floating point x,y coordinates. 
00113 #define Vector3fT   Tuple3fT   //A 3-element vector that is represented by single-precision floating point x,y,z coordinates. 
00114 
00115 //Custom math, or speed overrides
00116 #define FuncSqrt    sqrtf
00117 
00118 //utility macros
00119 //assuming IEEE-754(GLfloat), which i believe has max precision of 7 bits
00120 # define Epsilon 1.0e-5
00121 
00122 //Math functions
00123 
00128     inline
00129     static void Point2fAdd(Point2fT* NewObj, const Tuple2fT* t1)
00130     {
00131         assert(NewObj && t1);
00132 
00133         NewObj->s.X += t1->s.X;
00134         NewObj->s.Y += t1->s.Y;
00135     }
00136 
00141     inline
00142     static void Point2fSub(Point2fT* NewObj, const Tuple2fT* t1)
00143     {
00144         assert(NewObj && t1);
00145 
00146         NewObj->s.X -= t1->s.X;
00147         NewObj->s.Y -= t1->s.Y;
00148     }
00149 
00155     inline
00156     static void Vector3fCross(Vector3fT* NewObj, const Vector3fT* v1, const Vector3fT* v2)
00157     {
00158         Vector3fT Result; //safe not to initialize
00159 
00160         assert(NewObj && v1 && v2);
00161 
00162         // store on stack once for aliasing-safty
00163         // i.e. safe when a.cross(a, b)
00164 
00165         Result.s.X = (v1->s.Y * v2->s.Z) - (v1->s.Z * v2->s.Y);
00166         Result.s.Y = (v1->s.Z * v2->s.X) - (v1->s.X * v2->s.Z);
00167         Result.s.Z = (v1->s.X * v2->s.Y) - (v1->s.Y * v2->s.X);
00168 
00169         //copy result back
00170         *NewObj = Result;
00171     }
00172 
00177     inline
00178     static GLfloat Vector3fDot(const Vector3fT* NewObj, const Vector3fT* v1)
00179     {
00180         assert(NewObj && v1);
00181 
00182         return  (NewObj->s.X * v1->s.X) +
00183                 (NewObj->s.Y * v1->s.Y) +
00184                 (NewObj->s.Z * v1->s.Z);
00185     }
00186 
00191     inline
00192     static GLfloat Vector3fLengthSquared(const Vector3fT* NewObj)
00193     {
00194         assert(NewObj);
00195 
00196         return  (NewObj->s.X * NewObj->s.X) +
00197                 (NewObj->s.Y * NewObj->s.Y) +
00198                 (NewObj->s.Z * NewObj->s.Z);
00199     }
00200 
00205     inline
00206     static GLfloat Vector3fLength(const Vector3fT* NewObj)
00207     {
00208         assert(NewObj);
00209 
00210         return FuncSqrt(Vector3fLengthSquared(NewObj));
00211     }
00212 
00213     inline
00214     static void Matrix3fSetZero(Matrix3fT* NewObj)
00215     {
00216         NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 = 
00217         NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 = 
00218         NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = 0.0f;
00219     }
00220 
00224     inline
00225     static void Matrix3fSetIdentity(Matrix3fT* NewObj)
00226     {
00227         Matrix3fSetZero(NewObj);
00228 
00229         //then set diagonal as 1
00230         NewObj->s.M00 = 
00231         NewObj->s.M11 = 
00232         NewObj->s.M22 = 1.0f;
00233     }
00234 
00240     //$hack this can be optimized some(if s == 0)
00241     inline
00242     static void Matrix3fSetRotationFromQuat4f(Matrix3fT* NewObj, const Quat4fT* q1)
00243     {
00244         GLfloat n, s;
00245         GLfloat xs, ys, zs;
00246         GLfloat wx, wy, wz;
00247         GLfloat xx, xy, xz;
00248         GLfloat yy, yz, zz;
00249 
00250         assert(NewObj && q1);
00251 
00252         n = (q1->s.X * q1->s.X) + (q1->s.Y * q1->s.Y) + (q1->s.Z * q1->s.Z) + (q1->s.W * q1->s.W);
00253         s = (n > 0.0f) ? (2.0f / n) : 0.0f;
00254 
00255         xs = q1->s.X * s;  ys = q1->s.Y * s;  zs = q1->s.Z * s;
00256         wx = q1->s.W * xs; wy = q1->s.W * ys; wz = q1->s.W * zs;
00257         xx = q1->s.X * xs; xy = q1->s.X * ys; xz = q1->s.X * zs;
00258         yy = q1->s.Y * ys; yz = q1->s.Y * zs; zz = q1->s.Z * zs;
00259 
00260         NewObj->s.XX = 1.0f - (yy + zz); NewObj->s.YX =         xy - wz;  NewObj->s.ZX =         xz + wy;
00261         NewObj->s.XY =         xy + wz;  NewObj->s.YY = 1.0f - (xx + zz); NewObj->s.ZY =         yz - wx;
00262         NewObj->s.XZ =         xz - wy;  NewObj->s.YZ =         yz + wx;  NewObj->s.ZZ = 1.0f - (xx + yy);
00263     }
00264 
00270     inline
00271     static void Matrix3fMulMatrix3f(Matrix3fT* NewObj, const Matrix3fT* m1)
00272     {
00273         Matrix3fT Result; //safe not to initialize
00274 
00275         assert(NewObj && m1);
00276 
00277         // alias-safe way.
00278         Result.s.M00 = (NewObj->s.M00 * m1->s.M00) + (NewObj->s.M01 * m1->s.M10) + (NewObj->s.M02 * m1->s.M20);
00279         Result.s.M01 = (NewObj->s.M00 * m1->s.M01) + (NewObj->s.M01 * m1->s.M11) + (NewObj->s.M02 * m1->s.M21);
00280         Result.s.M02 = (NewObj->s.M00 * m1->s.M02) + (NewObj->s.M01 * m1->s.M12) + (NewObj->s.M02 * m1->s.M22);
00281 
00282         Result.s.M10 = (NewObj->s.M10 * m1->s.M00) + (NewObj->s.M11 * m1->s.M10) + (NewObj->s.M12 * m1->s.M20);
00283         Result.s.M11 = (NewObj->s.M10 * m1->s.M01) + (NewObj->s.M11 * m1->s.M11) + (NewObj->s.M12 * m1->s.M21);
00284         Result.s.M12 = (NewObj->s.M10 * m1->s.M02) + (NewObj->s.M11 * m1->s.M12) + (NewObj->s.M12 * m1->s.M22);
00285 
00286         Result.s.M20 = (NewObj->s.M20 * m1->s.M00) + (NewObj->s.M21 * m1->s.M10) + (NewObj->s.M22 * m1->s.M20);
00287         Result.s.M21 = (NewObj->s.M20 * m1->s.M01) + (NewObj->s.M21 * m1->s.M11) + (NewObj->s.M22 * m1->s.M21);
00288         Result.s.M22 = (NewObj->s.M20 * m1->s.M02) + (NewObj->s.M21 * m1->s.M12) + (NewObj->s.M22 * m1->s.M22);
00289 
00290         //copy result back to this
00291         *NewObj = Result;
00292     }
00293 
00294     inline
00295     static void Matrix4fSetRotationScaleFromMatrix4f(Matrix4fT* NewObj, const Matrix4fT* m1)
00296     {
00297         assert(NewObj && m1);
00298 
00299         NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;
00300         NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;
00301         NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ;
00302     }
00303 
00311     inline
00312     static GLfloat Matrix4fSVD(const Matrix4fT* NewObj, Matrix3fT* rot3, Matrix4fT* rot4)
00313     {
00314         GLfloat s, n;
00315 
00316         assert(NewObj);
00317 
00318         // this is a simple svd.
00319         // Not complete but fast and reasonable.
00320         // See comment in Matrix3d.
00321 
00322         s = FuncSqrt(
00323                 ( (NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) + 
00324                   (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) +
00325                   (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ) ) / 3.0f );
00326 
00327         if (rot3)   //if pointer not null
00328         {
00329             //this->getRotationScale(rot3);
00330             rot3->s.XX = NewObj->s.XX; rot3->s.XY = NewObj->s.XY; rot3->s.XZ = NewObj->s.XZ;
00331             rot3->s.YX = NewObj->s.YX; rot3->s.YY = NewObj->s.YY; rot3->s.YZ = NewObj->s.YZ;
00332             rot3->s.ZX = NewObj->s.ZX; rot3->s.ZY = NewObj->s.ZY; rot3->s.ZZ = NewObj->s.ZZ;
00333 
00334             // zero-div may occur.
00335 
00336             n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) +
00337                                       (NewObj->s.XY * NewObj->s.XY) +
00338                                       (NewObj->s.XZ * NewObj->s.XZ) );
00339             rot3->s.XX *= n;
00340             rot3->s.XY *= n;
00341             rot3->s.XZ *= n;
00342 
00343             n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) +
00344                                       (NewObj->s.YY * NewObj->s.YY) +
00345                                       (NewObj->s.YZ * NewObj->s.YZ) );
00346             rot3->s.YX *= n;
00347             rot3->s.YY *= n;
00348             rot3->s.YZ *= n;
00349 
00350             n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) +
00351                                       (NewObj->s.ZY * NewObj->s.ZY) +
00352                                       (NewObj->s.ZZ * NewObj->s.ZZ) );
00353             rot3->s.ZX *= n;
00354             rot3->s.ZY *= n;
00355             rot3->s.ZZ *= n;
00356         }
00357 
00358         if (rot4)   //if pointer not null
00359         {
00360             if (rot4 != NewObj)
00361             {
00362                 Matrix4fSetRotationScaleFromMatrix4f(rot4, NewObj);  // private method
00363             }
00364 
00365             // zero-div may occur.
00366 
00367             n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) +
00368                                       (NewObj->s.XY * NewObj->s.XY) +
00369                                       (NewObj->s.XZ * NewObj->s.XZ) );
00370             rot4->s.XX *= n;
00371             rot4->s.XY *= n;
00372             rot4->s.XZ *= n;
00373 
00374             n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) +
00375                                       (NewObj->s.YY * NewObj->s.YY) +
00376                                       (NewObj->s.YZ * NewObj->s.YZ) );
00377             rot4->s.YX *= n;
00378             rot4->s.YY *= n;
00379             rot4->s.YZ *= n;
00380 
00381             n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) +
00382                                       (NewObj->s.ZY * NewObj->s.ZY) +
00383                                       (NewObj->s.ZZ * NewObj->s.ZZ) );
00384             rot4->s.ZX *= n;
00385             rot4->s.ZY *= n;
00386             rot4->s.ZZ *= n;
00387         }
00388 
00389         return s;
00390     }
00391 
00392     inline
00393     static void Matrix4fSetRotationScaleFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1)
00394     {
00395         assert(NewObj && m1);
00396 
00397         NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;
00398         NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;
00399         NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ;
00400     }
00401 
00402     inline
00403     static void Matrix4fMulRotationScale(Matrix4fT* NewObj, GLfloat scale)
00404     {
00405         assert(NewObj);
00406 
00407         NewObj->s.XX *= scale; NewObj->s.YX *= scale; NewObj->s.ZX *= scale;
00408         NewObj->s.XY *= scale; NewObj->s.YY *= scale; NewObj->s.ZY *= scale;
00409         NewObj->s.XZ *= scale; NewObj->s.YZ *= scale; NewObj->s.ZZ *= scale;
00410     }
00411 
00422     inline
00423     static void Matrix4fSetRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1)
00424     {
00425         GLfloat scale;
00426 
00427         assert(NewObj && m1);
00428 
00429         scale = Matrix4fSVD(NewObj, NULL, NULL);
00430 
00431         Matrix4fSetRotationScaleFromMatrix3f(NewObj, m1);
00432         Matrix4fMulRotationScale(NewObj, scale);
00433     }
00434 
00435 // 8<--Snip here if you have your own math types/funcs-->8 
00436 
00437     typedef class ArcBall_t
00438     {
00439         protected:
00440             inline
00441             void _mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const;
00442 
00443         public:
00444             //Create/Destroy
00445                     ArcBall_t(GLfloat NewWidth, GLfloat NewHeight);
00446                    ~ArcBall_t() { /* nothing to do */ };
00447 
00448             //Set new bounds
00449             inline
00450             void    setBounds(GLfloat NewWidth, GLfloat NewHeight)
00451             {
00452                 assert((NewWidth > 1.0f) && (NewHeight > 1.0f));
00453 
00454                 //Set adjustment factor for width/height
00455                 this->AdjustWidth  = 1.0f / ((NewWidth  - 1.0f) * 0.5f);
00456                 this->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
00457             }
00458 
00459             //Mouse down
00460             void    click(const Point2fT* NewPt);
00461 
00462             //Mouse drag, calculate rotation
00463             void    drag(const Point2fT* NewPt, Quat4fT* NewRot);
00464 
00465         protected:
00466             Vector3fT   StVec;          //Saved click vector
00467             Vector3fT   EnVec;          //Saved drag vector
00468             GLfloat     AdjustWidth;    //Mouse bounds width
00469             GLfloat     AdjustHeight;   //Mouse bounds height
00470 
00471     } ArcBallT;
00472 
00473 #endif
00474 

Generated on Wed Apr 11 16:50:50 2007 for open_prospect by  doxygen 1.4.6