File indexing completed on 2024-05-12 04:05:52
0001 /** KempoApi: The Turloc Toolkit *****************************/ 0002 /** * * **/ 0003 /** ** ** Filename: ArcBall.cpp **/ 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 #include "ArcBall.h" // ArcBall header 0021 0022 #include <cstdio> 0023 0024 //Arcball sphere constants: 0025 //Diameter is 2.0f 0026 //Radius is 1.0f 0027 //Radius squared is 1.0f 0028 0029 void ArcBall_t::_mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const 0030 { 0031 Point2fT TempPt; 0032 GLfloat length; 0033 0034 //Copy parameter into temp point 0035 TempPt = *NewPt; 0036 0037 //Adjust point coords and scale down to range of [-1 ... 1] 0038 TempPt.s.X = (TempPt.s.X * this->AdjustWidth) - 1.0f; 0039 TempPt.s.Y = 1.0f - (TempPt.s.Y * this->AdjustHeight); 0040 0041 //Compute the square of the length of the vector to the point from the center 0042 length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y); 0043 0044 //If the point is mapped outside of the sphere... (length > radius squared) 0045 if (length > 1.0f) 0046 { 0047 GLfloat norm; 0048 0049 //Compute a normalizing factor (radius / sqrt(length)) 0050 norm = 1.0f / FuncSqrt(length); 0051 0052 //Return the "normalized" vector, a point on the sphere 0053 NewVec->s.X = TempPt.s.X * norm; 0054 NewVec->s.Y = TempPt.s.Y * norm; 0055 NewVec->s.Z = 0.0f; 0056 } 0057 else //Else it's on the inside 0058 { 0059 //Return a vector to a point mapped inside the sphere sqrt(radius squared - length) 0060 NewVec->s.X = TempPt.s.X; 0061 NewVec->s.Y = TempPt.s.Y; 0062 NewVec->s.Z = FuncSqrt(1.0f - length); 0063 } 0064 } 0065 0066 //Create/Destroy 0067 ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight) 0068 { 0069 //Clear initial values 0070 this->StVec.s.X = 0071 this->StVec.s.Y = 0072 this->StVec.s.Z = 0073 0074 this->EnVec.s.X = 0075 this->EnVec.s.Y = 0076 this->EnVec.s.Z = 0.0f; 0077 0078 //Set initial bounds 0079 this->setBounds(NewWidth, NewHeight); 0080 } 0081 0082 //Mouse down 0083 void ArcBall_t::click(const Point2fT* NewPt) 0084 { 0085 //Map the point to the sphere 0086 this->_mapToSphere(NewPt, &this->StVec); 0087 } 0088 0089 //Mouse drag, calculate rotation 0090 void ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot) 0091 { 0092 //Map the point to the sphere 0093 this->_mapToSphere(NewPt, &this->EnVec); 0094 0095 //Return the quaternion equivalent to the rotation 0096 if (NewRot) 0097 { 0098 Vector3fT Perp; 0099 0100 //Compute the vector perpendicular to the begin and end vectors 0101 Vector3fCross(&Perp, &this->StVec, &this->EnVec); 0102 0103 //Compute the length of the perpendicular vector 0104 if (Vector3fLength(&Perp) > Epsilon) //if its non-zero 0105 { 0106 //We're ok, so return the perpendicular vector as the transform after all 0107 NewRot->s.X = Perp.s.X; 0108 NewRot->s.Y = Perp.s.Y; 0109 NewRot->s.Z = Perp.s.Z; 0110 //In the quaternion values, w is cosine (theta / 2), where theta is rotation angle 0111 NewRot->s.W= Vector3fDot(&this->StVec, &this->EnVec); 0112 } 0113 else //if its zero 0114 { 0115 //The begin and end vectors coincide, so return an identity transform 0116 NewRot->s.X = 0117 NewRot->s.Y = 0118 NewRot->s.Z = 0119 NewRot->s.W = 0.0f; 0120 } 0121 } 0122 } 0123