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