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