Code:
void MArcBall::End(void)
{
this->m_LastRotMatrix = this->m_CurrentRotMatrix;
}
void MArcBall::SetBounds(int NewWidth, int NewHeight)
{
if((NewWidth > 1) && (NewHeight > 1))
{
this->AdjustWidth = 1 / (NewWidth / 2);
this->AdjustHeight = 1 / (NewHeight / 2);
}
}
void MArcBall::Click(int x, int y)
{
this->m_RotationAxis.SetIdentity();
this->m_CurrentRotMatrix.SetIdentity();
this->MapToSphere(x, y, &this->m_Start);
}
void MArcBall::MapToSphere(int mx, int my, MVector* NewVec)
{
double lengthsquared, x, y;
//Adjust point coords and scale down to range of [-1 ... 1]
NewVec->SetX((mx * this->AdjustWidth) - 1);
NewVec->SetY(1 - (my * this->AdjustHeight));
x = NewVec->GetX();
y = NewVec->GetY();
//Compute the square of the length of the vector to the point from the center
lengthsquared = (x * x) + (y * y);
//If the point is mapped outside of the sphere... (length > radius squared)
if (lengthsquared > 1.0f)
{
double norm = 1.0f / sqrt(lengthsquared);
//Return the "normalized" vector, a point on the sphere
//yes, i know, bad coding practice here, but i've been too lazy to write a function for this
NewVec->m_matrix.m_quat.m_matrix[0][0] *= norm;
NewVec->m_matrix.m_quat.m_matrix[1][0] *= norm;
NewVec->m_matrix.m_quat.m_matrix[2][0] = 0.0f;
}
else //Else it's on the inside
{
//Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
NewVec->m_matrix.m_quat.m_matrix[2][0] = sqrt(1 - lengthsquared);
}
}
void MArcBall::Drag(int mx, int my)
{
//Map the point to the sphere
this->MapToSphere(mx, my, &this->m_End);
MVector Axis = this->m_Start.Cross(this->m_End);
//Compute the length of the perpendicular vector
if (Axis.Length() > 0) //if its non-zero
{
//We're ok, so return the perpendicular vector as the transform after all
this->m_RotationAxis.Set(
Axis.GetX(),
Axis.GetY(),
Axis.GetZ(),
this->m_Start.Dot(this->m_End)
);
}
else //if its zero
{
//The begin and end vectors coincide, so return an identity transform
this->m_RotationAxis.SetIdentity();
}
this->MQuatToMMatrix();
this->m_CurrentRotMatrix *= this->m_LastRotMatrix;
this->MakeTransformMatrix();
PrintData();
}
void MArcBall::MQuatToMMatrix(void)
{
double w = m_RotationAxis.GetW();
double x = m_RotationAxis.GetX();
double y = m_RotationAxis.GetY();
double z = m_RotationAxis.GetZ();
double Nq = x*x + y*y + z*z + w*w;
double s = (Nq > 0.0f) ? (2.0f / Nq) : 0.0f;
double xs = x*s, ys = y*s, zs = z*s;
double wx = w*xs, wy = w*ys, wz = w*zs;
double xx = x*xs, xy = x*ys, xz = x*zs;
double yy = y*ys, yz = y*zs, zz = z*zs;
m_CurrentRotMatrix.Set(0,0,1.0f - (yy + zz));
m_CurrentRotMatrix.Set(1,0,(xy - wz));
m_CurrentRotMatrix.Set(2,0,(xz + wy));
m_CurrentRotMatrix.Set(0,1,(xy + wz));
m_CurrentRotMatrix.Set(1,1,1.0f - (xx + zz));
m_CurrentRotMatrix.Set(2,1,(yz - wx));
m_CurrentRotMatrix.Set(0,2,(xz - wy));
m_CurrentRotMatrix.Set(1,2,(yz + wx));
m_CurrentRotMatrix.Set(2,2,1.0f - (xx + yy));
}
//not this
void MArcBall::MakeTransformMatrix(void)
{
this->m_Rotate[0] = this->m_CurrentRotMatrix.Get(0,0); this->m_Rotate[4] = this->m_CurrentRotMatrix.Get(0,1); this->m_Rotate[8] = this->m_CurrentRotMatrix.Get(0,2);
this->m_Rotate[1] = this->m_CurrentRotMatrix.Get(1,0); this->m_Rotate[5] = this->m_CurrentRotMatrix.Get(1,1); this->m_Rotate[9] = this->m_CurrentRotMatrix.Get(1,2);
this->m_Rotate[2] = this->m_CurrentRotMatrix.Get(2,0); this->m_Rotate[6] = this->m_CurrentRotMatrix.Get(2,1); this->m_Rotate[10] = this->m_CurrentRotMatrix.Get(2,2);
this->m_Rotate[3] =
this->m_Rotate[7] =
this->m_Rotate[11] =
this->m_Rotate[12] =
this->m_Rotate[13] =
this->m_Rotate[14] = 0;
this->m_Rotate[15] = 1;
}
}