File indexing completed on 2024-05-12 04:05:53

0001 /** KempoApi: The Turloc Toolkit *****************************/
0002 /** *    *                                                  **/
0003 /** **  **  Filename: ArcBall.h                             **/
0004 /**   **    Version:  Common                                **/
0005 /**   **                                                    **/
0006 /**                                                         **/
0007 /**  Arcball class for mouse manipulation.                  **/
0008 /**                                                         **/
0009 /**                                                         **/
0010 /**                                                         **/
0011 /**                                                         **/
0012 /**                              (C) 1999-2003 Tatewake.com **/
0013 /**   History:                                              **/
0014 /**   08/17/2003 - (TJG) - Creation                         **/
0015 /**   09/23/2003 - (TJG) - Bug fix and optimization         **/
0016 /**   09/25/2003 - (TJG) - Version for NeHe Basecode users  **/
0017 /**                                                         **/
0018 /*************************************************************/
0019 
0020 #ifndef _ArcBall_h
0021 #define _ArcBall_h
0022 
0023 #include <QtSystemDetection>
0024 
0025 #ifdef Q_OS_MAC
0026 #include <OpenGL/gl.h>
0027 #include <OpenGL/glu.h>
0028 #elif defined(Q_OS_WIN)
0029 #include <windows.h>
0030 #include <GL/gl.h>                                                                                             // Header File For The OpenGL32 Library
0031 #include <GL/glu.h>                                                                                            // Header File For The GLu32 Library
0032 #else
0033 #include <GL/gl.h>                                                                                             // Header File For The OpenGL32 Library
0034 #include <GL/glu.h>                                                                                            // Header File For The GLu32 Library
0035 #endif
0036 
0037 #include <math.h>                                               // Needed for sqrtf
0038 
0039 // 8<--Snip here if you have your own math types/funcs-->8 
0040 
0041 //Only support assertions in debug builds
0042 #ifdef _DEBUG
0043 # include "assert.h"
0044 #else
0045 #  ifdef assert
0046 #    undef assert
0047 #  endif
0048 # define assert(x) { }
0049 #endif
0050 
0051 //Math types derived from the KempoApi tMath library
0052     typedef union Tuple2f_t
0053     {
0054         struct
0055         {
0056             GLfloat X, Y;
0057         } s;
0058 
0059         GLfloat T[2];
0060     } Tuple2fT;      //A generic 2-element tuple that is represented by single-precision floating point x,y coordinates. 
0061 
0062     typedef union Tuple3f_t
0063     {
0064         struct
0065         {
0066             GLfloat X, Y, Z;
0067         } s;
0068 
0069         GLfloat T[3];
0070     } Tuple3fT;      //A generic 3-element tuple that is represented by single precision-floating point x,y,z coordinates. 
0071 
0072     typedef union Tuple4f_t
0073     {
0074         struct
0075         {
0076             GLfloat X, Y, Z, W;
0077         } s;
0078 
0079         GLfloat T[4];
0080     } Tuple4fT;      //A 4-element tuple represented by single-precision floating point x,y,z,w coordinates. 
0081 
0082     typedef union Matrix3f_t
0083     {
0084             struct
0085             {
0086                 //column major
0087                 union { GLfloat M00; GLfloat XX; GLfloat SX; };  //XAxis.X and Scale X
0088                 union { GLfloat M10; GLfloat XY;             };  //XAxis.Y
0089                 union { GLfloat M20; GLfloat XZ;             };  //XAxis.Z
0090                 union { GLfloat M01; GLfloat YX;             };  //YAxis.X
0091                 union { GLfloat M11; GLfloat YY; GLfloat SY; };  //YAxis.Y and Scale Y
0092                 union { GLfloat M21; GLfloat YZ;             };  //YAxis.Z
0093                 union { GLfloat M02; GLfloat ZX;             };  //ZAxis.X
0094                 union { GLfloat M12; GLfloat ZY;             };  //ZAxis.Y
0095                 union { GLfloat M22; GLfloat ZZ; GLfloat SZ; };  //ZAxis.Z and Scale Z
0096             } s;
0097             GLfloat M[9];
0098     } Matrix3fT;     //A single precision floating point 3 by 3 matrix. 
0099 
0100     typedef union Matrix4f_t
0101     {
0102             struct
0103             {
0104                 //column major
0105                 union { GLfloat M00; GLfloat XX; GLfloat SX; };  //XAxis.X and Scale X
0106                 union { GLfloat M10; GLfloat XY;             };  //XAxis.Y
0107                 union { GLfloat M20; GLfloat XZ;             };  //XAxis.Z
0108                 union { GLfloat M30; GLfloat XW;             };  //XAxis.W
0109                 union { GLfloat M01; GLfloat YX;             };  //YAxis.X
0110                 union { GLfloat M11; GLfloat YY; GLfloat SY; };  //YAxis.Y and Scale Y
0111                 union { GLfloat M21; GLfloat YZ;             };  //YAxis.Z
0112                 union { GLfloat M31; GLfloat YW;             };  //YAxis.W
0113                 union { GLfloat M02; GLfloat ZX;             };  //ZAxis.X
0114                 union { GLfloat M12; GLfloat ZY;             };  //ZAxis.Y
0115                 union { GLfloat M22; GLfloat ZZ; GLfloat SZ; };  //ZAxis.Z and Scale Z
0116                 union { GLfloat M32; GLfloat ZW;             };  //ZAxis.W
0117                 union { GLfloat M03; GLfloat TX;             };  //Trans.X
0118                 union { GLfloat M13; GLfloat TY;             };  //Trans.Y
0119                 union { GLfloat M23; GLfloat TZ;             };  //Trans.Z
0120                 union { GLfloat M33; GLfloat TW; GLfloat SW; };  //Trans.W and Scale W
0121             } s;
0122             GLfloat M[16];
0123     } Matrix4fT;     //A single precision floating point 4 by 4 matrix. 
0124 
0125 
0126 //"Inherited" types
0127 #define Point2fT    Tuple2fT   //A 2 element point that is represented by single precision floating point x,y coordinates. 
0128 
0129 #define Quat4fT     Tuple4fT   //A 4 element unit quaternion represented by single precision floating point x,y,z,w coordinates. 
0130 
0131 #define Vector2fT   Tuple2fT   //A 2-element vector that is represented by single-precision floating point x,y coordinates. 
0132 #define Vector3fT   Tuple3fT   //A 3-element vector that is represented by single-precision floating point x,y,z coordinates. 
0133 
0134 //Custom math, or speed overrides
0135 #define FuncSqrt    sqrtf
0136 
0137 //utility macros
0138 //assuming IEEE-754(GLfloat), which i believe has max precision of 7 bits
0139 # define Epsilon 1.0e-5
0140 
0141 //Math functions
0142 
0143     /**
0144      * Sets the value of this tuple to the vector sum of itself and tuple t1.
0145      * @param t1  the other tuple
0146      */
0147     inline
0148     static void Point2fAdd(Point2fT* NewObj, const Tuple2fT* t1)
0149     {
0150         assert(NewObj && t1);
0151 
0152         NewObj->s.X += t1->s.X;
0153         NewObj->s.Y += t1->s.Y;
0154     }
0155 
0156     /**
0157       * Sets the value of this tuple to the vector difference of itself and tuple t1 (this = this - t1).
0158       * @param t1 the other tuple
0159       */
0160     inline
0161     static void Point2fSub(Point2fT* NewObj, const Tuple2fT* t1)
0162     {
0163         assert(NewObj && t1);
0164 
0165         NewObj->s.X -= t1->s.X;
0166         NewObj->s.Y -= t1->s.Y;
0167     }
0168 
0169     /**
0170       * Sets this vector to be the vector cross product of vectors v1 and v2.
0171       * @param v1 the first vector
0172       * @param v2 the second vector
0173       */
0174     inline
0175     static void Vector3fCross(Vector3fT* NewObj, const Vector3fT* v1, const Vector3fT* v2)
0176     {
0177         Vector3fT Result; //safe not to initialize
0178 
0179         assert(NewObj && v1 && v2);
0180 
0181         // store on stack once for aliasing-safty
0182         // i.e. safe when a.cross(a, b)
0183 
0184         Result.s.X = (v1->s.Y * v2->s.Z) - (v1->s.Z * v2->s.Y);
0185         Result.s.Y = (v1->s.Z * v2->s.X) - (v1->s.X * v2->s.Z);
0186         Result.s.Z = (v1->s.X * v2->s.Y) - (v1->s.Y * v2->s.X);
0187 
0188         //copy result back
0189         *NewObj = Result;
0190     }
0191 
0192     /**
0193       * Computes the dot product of the this vector and vector v1.
0194       * @param  v1 the other vector
0195       */
0196     inline
0197     static GLfloat Vector3fDot(const Vector3fT* NewObj, const Vector3fT* v1)
0198     {
0199         assert(NewObj && v1);
0200 
0201         return  (NewObj->s.X * v1->s.X) +
0202                 (NewObj->s.Y * v1->s.Y) +
0203                 (NewObj->s.Z * v1->s.Z);
0204     }
0205 
0206     /**
0207       * Returns the squared length of this vector.
0208       * @return the squared length of this vector
0209       */
0210     inline
0211     static GLfloat Vector3fLengthSquared(const Vector3fT* NewObj)
0212     {
0213         assert(NewObj);
0214 
0215         return  (NewObj->s.X * NewObj->s.X) +
0216                 (NewObj->s.Y * NewObj->s.Y) +
0217                 (NewObj->s.Z * NewObj->s.Z);
0218     }
0219 
0220     /**
0221       * Returns the length of this vector.
0222       * @return the length of this vector
0223       */
0224     inline
0225     static GLfloat Vector3fLength(const Vector3fT* NewObj)
0226     {
0227         assert(NewObj);
0228 
0229         return FuncSqrt(Vector3fLengthSquared(NewObj));
0230     }
0231 
0232     inline
0233     static void Matrix3fSetZero(Matrix3fT* NewObj)
0234     {
0235         NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 = 
0236         NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 = 
0237         NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = 0.0f;
0238     }
0239 
0240     /**
0241      * Sets this Matrix3 to identity.
0242      */
0243     inline
0244     static void Matrix3fSetIdentity(Matrix3fT* NewObj)
0245     {
0246         Matrix3fSetZero(NewObj);
0247 
0248         //then set diagonal as 1
0249         NewObj->s.M00 = 
0250         NewObj->s.M11 = 
0251         NewObj->s.M22 = 1.0f;
0252     }
0253 
0254     /**
0255       * Sets the value of this matrix to the matrix conversion of the
0256       * quaternion argument. 
0257       * @param q1 the quaternion to be converted 
0258       */
0259     //$hack this can be optimized some(if s == 0)
0260     inline
0261     static void Matrix3fSetRotationFromQuat4f(Matrix3fT* NewObj, const Quat4fT* q1)
0262     {
0263         GLfloat n, s;
0264         GLfloat xs, ys, zs;
0265         GLfloat wx, wy, wz;
0266         GLfloat xx, xy, xz;
0267         GLfloat yy, yz, zz;
0268 
0269         assert(NewObj && q1);
0270 
0271         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);
0272         s = (n > 0.0f) ? (2.0f / n) : 0.0f;
0273 
0274         xs = q1->s.X * s;  ys = q1->s.Y * s;  zs = q1->s.Z * s;
0275         wx = q1->s.W * xs; wy = q1->s.W * ys; wz = q1->s.W * zs;
0276         xx = q1->s.X * xs; xy = q1->s.X * ys; xz = q1->s.X * zs;
0277         yy = q1->s.Y * ys; yz = q1->s.Y * zs; zz = q1->s.Z * zs;
0278 
0279         NewObj->s.XX = 1.0f - (yy + zz); NewObj->s.YX =         xy - wz;  NewObj->s.ZX =         xz + wy;
0280         NewObj->s.XY =         xy + wz;  NewObj->s.YY = 1.0f - (xx + zz); NewObj->s.ZY =         yz - wx;
0281         NewObj->s.XZ =         xz - wy;  NewObj->s.YZ =         yz + wx;  NewObj->s.ZZ = 1.0f - (xx + yy);
0282     }
0283 
0284     /**
0285      * Sets the value of this matrix to the result of multiplying itself
0286      * with matrix m1. 
0287      * @param m1 the other matrix 
0288      */
0289     inline
0290     static void Matrix3fMulMatrix3f(Matrix3fT* NewObj, const Matrix3fT* m1)
0291     {
0292         Matrix3fT Result; //safe not to initialize
0293 
0294         assert(NewObj && m1);
0295 
0296         // alias-safe way.
0297         Result.s.M00 = (NewObj->s.M00 * m1->s.M00) + (NewObj->s.M01 * m1->s.M10) + (NewObj->s.M02 * m1->s.M20);
0298         Result.s.M01 = (NewObj->s.M00 * m1->s.M01) + (NewObj->s.M01 * m1->s.M11) + (NewObj->s.M02 * m1->s.M21);
0299         Result.s.M02 = (NewObj->s.M00 * m1->s.M02) + (NewObj->s.M01 * m1->s.M12) + (NewObj->s.M02 * m1->s.M22);
0300 
0301         Result.s.M10 = (NewObj->s.M10 * m1->s.M00) + (NewObj->s.M11 * m1->s.M10) + (NewObj->s.M12 * m1->s.M20);
0302         Result.s.M11 = (NewObj->s.M10 * m1->s.M01) + (NewObj->s.M11 * m1->s.M11) + (NewObj->s.M12 * m1->s.M21);
0303         Result.s.M12 = (NewObj->s.M10 * m1->s.M02) + (NewObj->s.M11 * m1->s.M12) + (NewObj->s.M12 * m1->s.M22);
0304 
0305         Result.s.M20 = (NewObj->s.M20 * m1->s.M00) + (NewObj->s.M21 * m1->s.M10) + (NewObj->s.M22 * m1->s.M20);
0306         Result.s.M21 = (NewObj->s.M20 * m1->s.M01) + (NewObj->s.M21 * m1->s.M11) + (NewObj->s.M22 * m1->s.M21);
0307         Result.s.M22 = (NewObj->s.M20 * m1->s.M02) + (NewObj->s.M21 * m1->s.M12) + (NewObj->s.M22 * m1->s.M22);
0308 
0309         //copy result back to this
0310         *NewObj = Result;
0311     }
0312 
0313     inline
0314     static void Matrix4fSetRotationScaleFromMatrix4f(Matrix4fT* NewObj, const Matrix4fT* m1)
0315     {
0316         assert(NewObj && m1);
0317 
0318         NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;
0319         NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;
0320         NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ;
0321     }
0322 
0323     /**
0324       * Performs SVD on this matrix and gets scale and rotation.
0325       * Rotation is placed into rot3, and rot4.
0326       * @param rot3 the rotation factor(Matrix3d). if null, ignored
0327       * @param rot4 the rotation factor(Matrix4) only upper 3x3 elements are changed. if null, ignored
0328       * @return scale factor
0329       */
0330     inline
0331     static GLfloat Matrix4fSVD(const Matrix4fT* NewObj, Matrix3fT* rot3, Matrix4fT* rot4)
0332     {
0333         GLfloat s, n;
0334 
0335         assert(NewObj);
0336 
0337         // this is a simple svd.
0338         // Not complete but fast and reasonable.
0339         // See comment in Matrix3d.
0340 
0341         s = FuncSqrt(
0342                 ( (NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) + 
0343                   (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) +
0344                   (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ) ) / 3.0f );
0345 
0346         if (rot3)   //if pointer not null
0347         {
0348             //this->getRotationScale(rot3);
0349             rot3->s.XX = NewObj->s.XX; rot3->s.XY = NewObj->s.XY; rot3->s.XZ = NewObj->s.XZ;
0350             rot3->s.YX = NewObj->s.YX; rot3->s.YY = NewObj->s.YY; rot3->s.YZ = NewObj->s.YZ;
0351             rot3->s.ZX = NewObj->s.ZX; rot3->s.ZY = NewObj->s.ZY; rot3->s.ZZ = NewObj->s.ZZ;
0352 
0353             // zero-div may occur.
0354 
0355             n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) +
0356                                       (NewObj->s.XY * NewObj->s.XY) +
0357                                       (NewObj->s.XZ * NewObj->s.XZ) );
0358             rot3->s.XX *= n;
0359             rot3->s.XY *= n;
0360             rot3->s.XZ *= n;
0361 
0362             n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) +
0363                                       (NewObj->s.YY * NewObj->s.YY) +
0364                                       (NewObj->s.YZ * NewObj->s.YZ) );
0365             rot3->s.YX *= n;
0366             rot3->s.YY *= n;
0367             rot3->s.YZ *= n;
0368 
0369             n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) +
0370                                       (NewObj->s.ZY * NewObj->s.ZY) +
0371                                       (NewObj->s.ZZ * NewObj->s.ZZ) );
0372             rot3->s.ZX *= n;
0373             rot3->s.ZY *= n;
0374             rot3->s.ZZ *= n;
0375         }
0376 
0377         if (rot4)   //if pointer not null
0378         {
0379             if (rot4 != NewObj)
0380             {
0381                 Matrix4fSetRotationScaleFromMatrix4f(rot4, NewObj);  // private method
0382             }
0383 
0384             // zero-div may occur.
0385 
0386             n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) +
0387                                       (NewObj->s.XY * NewObj->s.XY) +
0388                                       (NewObj->s.XZ * NewObj->s.XZ) );
0389             rot4->s.XX *= n;
0390             rot4->s.XY *= n;
0391             rot4->s.XZ *= n;
0392 
0393             n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) +
0394                                       (NewObj->s.YY * NewObj->s.YY) +
0395                                       (NewObj->s.YZ * NewObj->s.YZ) );
0396             rot4->s.YX *= n;
0397             rot4->s.YY *= n;
0398             rot4->s.YZ *= n;
0399 
0400             n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) +
0401                                       (NewObj->s.ZY * NewObj->s.ZY) +
0402                                       (NewObj->s.ZZ * NewObj->s.ZZ) );
0403             rot4->s.ZX *= n;
0404             rot4->s.ZY *= n;
0405             rot4->s.ZZ *= n;
0406         }
0407 
0408         return s;
0409     }
0410 
0411     inline
0412     static void Matrix4fSetRotationScaleFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1)
0413     {
0414         assert(NewObj && m1);
0415 
0416         NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;
0417         NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;
0418         NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ;
0419     }
0420 
0421     inline
0422     static void Matrix4fMulRotationScale(Matrix4fT* NewObj, GLfloat scale)
0423     {
0424         assert(NewObj);
0425 
0426         NewObj->s.XX *= scale; NewObj->s.YX *= scale; NewObj->s.ZX *= scale;
0427         NewObj->s.XY *= scale; NewObj->s.YY *= scale; NewObj->s.ZY *= scale;
0428         NewObj->s.XZ *= scale; NewObj->s.YZ *= scale; NewObj->s.ZZ *= scale;
0429     }
0430 
0431     /**
0432       * Sets the rotational component (upper 3x3) of this matrix to the matrix
0433       * values in the T precision Matrix3d argument; the other elements of
0434       * this matrix are unchanged; a singular value decomposition is performed
0435       * on this object's upper 3x3 matrix to factor out the scale, then this
0436       * object's upper 3x3 matrix components are replaced by the passed rotation
0437       * components, and then the scale is reapplied to the rotational
0438       * components.
0439       * @param m1 T precision 3x3 matrix
0440       */
0441     inline
0442     static void Matrix4fSetRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1)
0443     {
0444         GLfloat scale;
0445 
0446         assert(NewObj && m1);
0447 
0448         scale = Matrix4fSVD(NewObj, nullptr, nullptr);
0449 
0450         Matrix4fSetRotationScaleFromMatrix3f(NewObj, m1);
0451         Matrix4fMulRotationScale(NewObj, scale);
0452     }
0453 
0454 // 8<--Snip here if you have your own math types/funcs-->8 
0455 
0456     typedef class ArcBall_t
0457     {
0458         protected:
0459             inline
0460             void _mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const;
0461 
0462         public:
0463             //Create/Destroy
0464                     ArcBall_t(GLfloat NewWidth, GLfloat NewHeight);
0465                    ~ArcBall_t() { /* nothing to do */ }
0466 
0467             //Set new bounds
0468             inline
0469             void    setBounds(GLfloat NewWidth, GLfloat NewHeight)
0470             {
0471                 assert((NewWidth > 1.0f) && (NewHeight > 1.0f));
0472 
0473                 //Set adjustment factor for width/height
0474                 this->AdjustWidth  = 1.0f / ((NewWidth  - 1.0f) * 0.5f);
0475                 this->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
0476             }
0477 
0478             //Mouse down
0479             void    click(const Point2fT* NewPt);
0480 
0481             //Mouse drag, calculate rotation
0482             void    drag(const Point2fT* NewPt, Quat4fT* NewRot);
0483 
0484         protected:
0485             Vector3fT   StVec;          //Saved click vector
0486             Vector3fT   EnVec;          //Saved drag vector
0487             GLfloat     AdjustWidth;    //Mouse bounds width
0488             GLfloat     AdjustHeight;   //Mouse bounds height
0489 
0490     } ArcBallT;
0491 
0492 #endif
0493