// update current arcball rotation void arcball_move(int mx, int my) { if(ab_planar) { ab_curr = planar_coords((GLdouble)mx,(GLdouble)my); if(ab_curr.equals(ab_start)) return; // d is motion since the last position vec d = ab_curr - ab_start; GLfloat angle = d.length() * 0.5; GLfloat cosa = cos( angle ); GLfloat sina = sin( angle ); // p is perpendicular to d vec p = ((ab_out*d.x)-(ab_up*d.y)).unit() * sina; quaternion(ab_next,p.x,p.y,p.z,cosa); quatnext(ab_quat,ab_last,ab_next); // planar style only ever relates to the last point quatcopy(ab_last,ab_quat); ab_start = ab_curr; } else { ab_curr = sphere_coords((GLdouble)mx,(GLdouble)my); if(ab_curr.equals(ab_start)) { // avoid potential rare divide by tiny quatcopy(ab_quat,ab_last); return; } // use a dot product to get the angle between them // use a cross product to get the vector to rotate around GLfloat cos2a = ab_start*ab_curr; GLfloat sina = sqrt((1.0 - cos2a)*0.5); GLfloat cosa = sqrt((1.0 + cos2a)*0.5); vec cross = (ab_start^ab_curr).unit() * sina; quaternion(ab_next,cross.x,cross.y,cross.z,cosa); // update the rotation matrix quatnext(ab_quat,ab_last,ab_next); } }