llmaniprotate.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llmaniprotate.h"
00035 
00036 // library includes
00037 #include "llmath.h"
00038 #include "llgl.h"
00039 #include "v4color.h"
00040 #include "llprimitive.h"
00041 #include "llview.h"
00042 #include "llfontgl.h"
00043 
00044 // viewer includes
00045 #include "llagent.h"
00046 #include "llbox.h"
00047 #include "llbutton.h"
00048 #include "llviewercontrol.h"
00049 #include "llcriticaldamp.h"
00050 #include "llhoverview.h"
00051 #include "llfloatertools.h"
00052 #include "llselectmgr.h"
00053 #include "llstatusbar.h"
00054 #include "llui.h"
00055 #include "llvoavatar.h"
00056 #include "llviewborder.h"
00057 #include "llviewercamera.h"
00058 #include "llviewerobject.h"
00059 #include "llviewerobject.h"
00060 #include "llviewerwindow.h"
00061 #include "llworld.h"
00062 #include "pipeline.h"
00063 #include "viewer.h"
00064 #include "lldrawable.h"
00065 #include "llglheaders.h"
00066 
00067 const F32 RADIUS_PIXELS = 100.f;                // size in screen space
00068 const F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS;
00069 const F32 WIDTH_PIXELS = 8;
00070 const S32 CIRCLE_STEPS = 100;
00071 const F32 DELTA = F_TWO_PI / CIRCLE_STEPS;
00072 const F32 SIN_DELTA = sin( DELTA );
00073 const F32 COS_DELTA = cos( DELTA );
00074 const F32 MAX_MANIP_SELECT_DISTANCE = 100.f;
00075 const F32 SNAP_ANGLE_INCREMENT = 5.625f;
00076 const F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT;
00077 const F32 SNAP_GUIDE_RADIUS_1 = 2.8f;
00078 const F32 SNAP_GUIDE_RADIUS_2 = 2.4f;
00079 const F32 SNAP_GUIDE_RADIUS_3 = 2.2f;
00080 const F32 SNAP_GUIDE_RADIUS_4 = 2.1f;
00081 const F32 SNAP_GUIDE_RADIUS_5 = 2.05f;
00082 const F32 SNAP_GUIDE_INNER_RADIUS = 2.f;
00083 const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 80.f * DEG_TO_RAD );
00084 const F32 SELECTED_MANIPULATOR_SCALE = 1.05f;
00085 const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
00086 
00087 extern void handle_reset_rotation(void*);  // in LLViewerWindow
00088 
00089 LLManipRotate::LLManipRotate( LLToolComposite* composite )
00090 :       LLManip( "Rotate", composite ),
00091         mRotationCenter(),
00092         mCenterScreen(),
00093         mRotation(),
00094         mMouseDown(),
00095         mMouseCur(),
00096         mRadiusMeters(0.f),
00097         mCenterToCam(),
00098         mCenterToCamNorm(),
00099         mCenterToCamMag(0.f),
00100         mCenterToProfilePlane(),
00101         mCenterToProfilePlaneMag(0.f),
00102         mManipPart( LL_NO_PART ),
00103         mSendUpdateOnMouseUp( FALSE ),
00104         mSmoothRotate( FALSE ),
00105         mCamEdgeOn(FALSE),
00106         mManipulatorScales(1.f, 1.f, 1.f, 1.f)
00107 { }
00108 
00109 void LLManipRotate::handleSelect()
00110 {
00111         // *FIX: put this in mouseDown?
00112         gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
00113         gFloaterTools->setStatusText("rotate");
00114         LLManip::handleSelect();
00115 }
00116 
00117 void LLManipRotate::handleDeselect()
00118 {
00119         mHighlightedPart = LL_NO_PART;
00120         mManipPart = LL_NO_PART;
00121         LLManip::handleDeselect();
00122 }
00123 
00124 void LLManipRotate::render()
00125 {
00126         LLGLSUIDefault gls_ui;
00127         LLGLSNoTexture gls_no_texture;
00128         LLGLDepthTest gls_depth(GL_TRUE);
00129         LLGLEnable gl_blend(GL_BLEND);
00130         LLGLEnable gls_alpha_test(GL_ALPHA_TEST);
00131         
00132         // You can rotate if you can move
00133         LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(TRUE);
00134         if( !first_object )
00135         {
00136                 return;
00137         }
00138 
00139         if( !updateVisiblity() )
00140         {
00141                 return;
00142         }
00143 
00144         glMatrixMode(GL_MODELVIEW);
00145         glPushMatrix();
00146         if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
00147         {
00148                 F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
00149                 glScalef(zoom, zoom, zoom);
00150         }
00151 
00152 
00153         LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
00154 
00155         LLColor4 highlight_outside( 1.f, 1.f, 0.f, 1.f );
00156         LLColor4 highlight_inside( 0.7f, 0.7f, 0.f, 0.5f );
00157         F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
00158 
00159         glPushMatrix();
00160         {
00161                 // are we in the middle of a constrained drag?
00162                 if (mManipPart >= LL_ROT_X && mManipPart <= LL_ROT_Z)
00163                 {
00164                         renderSnapGuides();
00165                 }
00166                 else
00167                 {
00168                         LLGLEnable cull_face(GL_CULL_FACE);
00169                         LLGLDepthTest gls_depth(GL_FALSE);
00170                         glPushMatrix();
00171                         {
00172                                 // Draw "sphere" (intersection of sphere with tangent cone that has apex at camera)
00173                                 glTranslatef( mCenterToProfilePlane.mV[VX], mCenterToProfilePlane.mV[VY], mCenterToProfilePlane.mV[VZ] );
00174                                 glTranslatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
00175 
00176                                 // Inverse change of basis vectors
00177                                 LLVector3 forward = mCenterToCamNorm;
00178                                 LLVector3 left = gAgent.getUpAxis() % forward;
00179                                 left.normVec();
00180                                 LLVector3 up = forward % left;
00181 
00182                                 LLVector4 a(-forward);
00183                                 a.mV[3] = 0;
00184                                 LLVector4 b(up);
00185                                 b.mV[3] = 0;
00186                                 LLVector4 c(left);
00187                                 c.mV[3] = 0;
00188                                 LLMatrix4 mat;
00189                                 mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f));
00190 
00191                                 glMultMatrixf( &mat.mMatrix[0][0] );
00192 
00193                                 glRotatef( -90, 0.f, 1.f, 0.f);
00194                                 LLColor4 color;
00195                                 if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
00196                                 {
00197                                         color.setVec(0.8f, 0.8f, 0.8f, 0.8f);
00198                                         glScalef(mManipulatorScales.mV[VW], mManipulatorScales.mV[VW], mManipulatorScales.mV[VW]);
00199                                 }
00200                                 else
00201                                 {
00202                                         color.setVec( 0.7f, 0.7f, 0.7f, 0.6f );
00203                                 }
00204                                 gl_washer_2d(mRadiusMeters + width_meters, mRadiusMeters, CIRCLE_STEPS, color, color);
00205 
00206 
00207                                 if (mManipPart == LL_NO_PART)
00208                                 {
00209                                         glColor4f( 0.7f, 0.7f, 0.7f, 0.3f );
00210                                         gl_circle_2d( 0, 0,  mRadiusMeters, CIRCLE_STEPS, TRUE );
00211                                 }
00212                                 
00213                                 GLdouble plane_eqn[] = { 0, 0, 1, 0 };
00214                                 glClipPlane( GL_CLIP_PLANE0, plane_eqn );
00215                         }
00216                         glPopMatrix();
00217                 }
00218 
00219                 glTranslatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
00220 
00221                 LLQuaternion rot;
00222                 F32 angle_radians, x, y, z;
00223 
00224                 LLVector3 grid_origin;
00225                 LLVector3 grid_scale;
00226                 LLQuaternion grid_rotation;
00227 
00228                 gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale);
00229 
00230                 grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
00231                 glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
00232 
00233 
00234                 if (mManipPart == LL_ROT_Z)
00235                 {
00236                         mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00237                         glPushMatrix();
00238                         {
00239                                 // selected part
00240                                 glScalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]);
00241                                 renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f) , LLColor4( 0.f, 0.f, 1.f, 0.3f ));
00242                         }
00243                         glPopMatrix();
00244                 }
00245                 else if (mManipPart == LL_ROT_Y)
00246                 {
00247                         mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00248                         glPushMatrix();
00249                         {
00250                                 glRotatef( 90.f, 1.f, 0.f, 0.f );
00251                                 glScalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]);
00252                                 renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f), LLColor4( 0.f, 1.f, 0.f, 0.3f));
00253                         }
00254                         glPopMatrix();
00255                 }
00256                 else if (mManipPart == LL_ROT_X)
00257                 {
00258                         mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00259                         glPushMatrix();
00260                         {
00261                                 glRotatef( 90.f, 0.f, 1.f, 0.f );
00262                                 glScalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]);
00263                                 renderActiveRing( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f), LLColor4( 1.f, 0.f, 0.f, 0.3f));
00264                         }
00265                         glPopMatrix();
00266                 }
00267                 else if (mManipPart == LL_ROT_ROLL)
00268                 {
00269                         mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00270                 }
00271                 else if (mManipPart == LL_NO_PART)
00272                 {
00273                         if (mHighlightedPart == LL_NO_PART)
00274                         {
00275                                 mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00276                         }
00277 
00278                         LLGLEnable cull_face(GL_CULL_FACE);
00279                         LLGLEnable clip_plane0(GL_CLIP_PLANE0);
00280                         LLGLDepthTest gls_depth(GL_FALSE);
00281 
00282                         // First pass: centers. Second pass: sides.
00283                         for( S32 i=0; i<2; i++ )
00284                         {
00285                                 glPushMatrix();
00286                                 {
00287                                         if (mHighlightedPart == LL_ROT_Z)
00288                                         {
00289                                                 mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00290                                                 glScalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]);
00291                                                 // hovering over part
00292                                                 gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f ), LLColor4( 0.f, 0.f, 1.f, 0.5f ), CIRCLE_STEPS, i);
00293                                         }
00294                                         else
00295                                         {
00296                                                 // default
00297                                                 gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 0.8f, 0.8f ), LLColor4( 0.f, 0.f, 0.8f, 0.4f ), CIRCLE_STEPS, i);
00298                                         }
00299                                 }
00300                                 glPopMatrix();
00301 
00302                                 glPushMatrix();
00303                                 {
00304                                         glRotatef( 90.f, 1.f, 0.f, 0.f );
00305                                         if (mHighlightedPart == LL_ROT_Y)
00306                                         {
00307                                                 mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00308                                                 glScalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]);
00309                                                 // hovering over part
00310                                                 gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f ), LLColor4( 0.f, 1.f, 0.f, 0.5f ), CIRCLE_STEPS, i);
00311                                         }
00312                                         else
00313                                         {
00314                                                 // default
00315                                                 gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.8f, 0.f, 0.8f ), LLColor4( 0.f, 0.8f, 0.f, 0.4f ), CIRCLE_STEPS, i);
00316                                         }                                               
00317                                 }
00318                                 glPopMatrix();
00319 
00320                                 glPushMatrix();
00321                                 {
00322                                         glRotatef( 90.f, 0.f, 1.f, 0.f );
00323                                         if (mHighlightedPart == LL_ROT_X)
00324                                         {
00325                                                 mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00326                                                 glScalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]);
00327         
00328                                                 // hovering over part
00329                                                 gl_ring( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f ), LLColor4( 1.f, 0.f, 0.f, 0.5f ), CIRCLE_STEPS, i);
00330                                         }
00331                                         else
00332                                         {
00333                                                 // default
00334                                                 gl_ring( mRadiusMeters, width_meters, LLColor4( 0.8f, 0.f, 0.f, 0.8f ), LLColor4( 0.8f, 0.f, 0.f, 0.4f ), CIRCLE_STEPS, i);
00335                                         }
00336                                 }
00337                                 glPopMatrix();
00338 
00339                                 if (mHighlightedPart == LL_ROT_ROLL)
00340                                 {
00341                                         mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00342                                 }
00343                         }
00344                 }
00345         }
00346         glPopMatrix();
00347         glPopMatrix();
00348 
00349         LLVector3 euler_angles;
00350         LLQuaternion object_rot = first_object->getRotationEdit();
00351         object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]), &(euler_angles.mV[VZ]));
00352         euler_angles *= RAD_TO_DEG;
00353         euler_angles.mV[VX] = llround(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f);
00354         euler_angles.mV[VY] = llround(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f);
00355         euler_angles.mV[VZ] = llround(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f);
00356 
00357         renderXYZ(euler_angles);
00358 }
00359 
00360 BOOL LLManipRotate::handleMouseDown(S32 x, S32 y, MASK mask)
00361 {
00362         BOOL    handled = FALSE;
00363 
00364         LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(TRUE);
00365         if( first_object )
00366         {
00367                 LLViewerObject* hit_obj = gViewerWindow->lastObjectHit();
00368                 if( hit_obj && mHighlightedPart != LL_NO_PART )
00369                 {
00370                         handled = handleMouseDownOnPart( x, y, mask );
00371                 }
00372         }
00373 
00374         return handled;
00375 }
00376 
00377 // Assumes that one of the parts of the manipulator was hit.
00378 BOOL LLManipRotate::handleMouseDownOnPart( S32 x, S32 y, MASK mask )
00379 {
00380         BOOL can_rotate = canAffectSelection();
00381         if (!can_rotate)
00382         {
00383                 return FALSE;
00384         }
00385 
00386         highlightManipulators(x, y);
00387         S32 hit_part = mHighlightedPart;
00388         // we just started a drag, so save initial object positions
00389         gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_ROTATE);
00390 
00391         // save selection center
00392         mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() ); //gSelectMgr->getSelectionCenterGlobal();
00393 
00394         mManipPart = (EManipPart)hit_part;
00395         LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
00396 
00397         if( mManipPart == LL_ROT_GENERAL)
00398         {
00399                 mMouseDown = intersectMouseWithSphere( x, y, center, mRadiusMeters);
00400         }
00401         else
00402         {
00403                 // Project onto the plane of the ring
00404                 LLVector3 axis = getConstraintAxis();
00405 
00406                 F32 axis_onto_cam = llabs( axis * mCenterToCamNorm );
00407                 const F32 AXIS_ONTO_CAM_TOL = cos( 85.f * DEG_TO_RAD );
00408                 if( axis_onto_cam < AXIS_ONTO_CAM_TOL )
00409                 {
00410                         LLVector3 up_from_axis = mCenterToCamNorm % axis;
00411                         up_from_axis.normVec();
00412                         LLVector3 cur_intersection;
00413                         getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam);
00414                         cur_intersection -= center;
00415                         mMouseDown = projected_vec(cur_intersection, up_from_axis);
00416                         F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
00417                         F32 mouse_dist_sqrd = mMouseDown.magVecSquared();
00418                         if (mouse_dist_sqrd > 0.0001f)
00419                         {
00420                                 mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - 
00421                                                                         mouse_dist_sqrd);
00422                         }
00423                         LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, axis);
00424                         mMouseDown += mouse_depth * projected_center_to_cam;
00425 
00426                 }
00427                 else
00428                 {
00429                         mMouseDown = findNearestPointOnRing( x, y, center, axis ) - center;
00430                         mMouseDown.normVec();
00431                 }
00432         }
00433 
00434         mMouseCur = mMouseDown;
00435 
00436         // Route future Mouse messages here preemptively.  (Release on mouse up.)
00437         setMouseCapture( TRUE );
00438         gSelectMgr->enableSilhouette(FALSE);
00439         return TRUE;
00440 }
00441 
00442 
00443 LLVector3 LLManipRotate::findNearestPointOnRing( S32 x, S32 y, const LLVector3& center, const LLVector3& axis )
00444 {
00445         // Project the delta onto the ring and rescale it by the radius so that it's _on_ the ring.
00446         LLVector3 proj_onto_ring;
00447         getMousePointOnPlaneAgent(proj_onto_ring, x, y, center, axis);
00448         proj_onto_ring -= center;
00449         proj_onto_ring.normVec();
00450 
00451         return center + proj_onto_ring * mRadiusMeters;
00452 }
00453 
00454 BOOL LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask)
00455 {
00456         // first, perform normal processing in case this was a quick-click
00457         handleHover(x, y, mask);
00458 
00459         if( hasMouseCapture() )
00460         {
00461                 mManipPart = LL_NO_PART;
00462 
00463                 // Might have missed last update due to timing.
00464                 gSelectMgr->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION );
00465                 gSelectMgr->enableSilhouette(TRUE);
00466                 //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
00467 
00468                 gSelectMgr->updateSelectionCenter();
00469                 gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
00470         }
00471 
00472         return LLManip::handleMouseUp(x, y, mask);
00473 }
00474 
00475 
00476 BOOL LLManipRotate::handleHover(S32 x, S32 y, MASK mask)
00477 {
00478         if( hasMouseCapture() )
00479         {
00480                 if( mObjectSelection->isEmpty() )
00481                 {
00482                         // Somehow the object got deselected while we were dragging it.
00483                         setMouseCapture( FALSE );
00484                 }
00485                 else
00486                 {
00487                         drag(x, y);
00488                 }
00489 
00490                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (active)" << llendl;             
00491         }
00492         else
00493         {
00494                 highlightManipulators(x, y);
00495                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (inactive)" << llendl;           
00496         }
00497 
00498         gViewerWindow->setCursor(UI_CURSOR_TOOLROTATE);
00499         return TRUE;
00500 }
00501 
00502 
00503 LLVector3 LLManipRotate::projectToSphere( F32 x, F32 y, BOOL* on_sphere ) 
00504 {
00505         F32 z = 0.f;
00506         F32 dist_squared = x*x + y*y;
00507 
00508         *on_sphere = dist_squared <= SQ_RADIUS;
00509     if( *on_sphere )
00510         {    
00511         z = sqrt(SQ_RADIUS - dist_squared);
00512     }
00513         return LLVector3( x, y, z );
00514 }
00515 
00516 extern U32 gFrameCount;
00517 
00518 // Freeform rotation
00519 void LLManipRotate::drag( S32 x, S32 y )
00520 {
00521         if( !updateVisiblity() )
00522         {
00523                 return;
00524         }
00525 
00526         if( mManipPart == LL_ROT_GENERAL )
00527         {
00528                 mRotation = dragUnconstrained(x, y);
00529         }
00530         else
00531         {
00532                 mRotation = dragConstrained(x, y);
00533         }
00534 
00535         BOOL damped = mSmoothRotate;
00536         mSmoothRotate = FALSE;
00537 
00538         for (LLObjectSelection::iterator iter = mObjectSelection->begin();
00539                  iter != mObjectSelection->end(); iter++)
00540         {
00541                 LLSelectNode* selectNode = *iter;
00542                 LLViewerObject* object = selectNode->getObject();
00543 
00544                 // have permission to move and object is root of selection or individually selected
00545                 if (object->permMove() && (object->isRootEdit() || selectNode->mIndividualSelection))
00546                 {
00547                         if (!object->isRootEdit())
00548                         {
00549                                 // child objects should not update if parent is selected
00550                                 LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
00551                                 if (editable_root->isSelected())
00552                                 {
00553                                         // we will be moved properly by our parent, so skip
00554                                         continue;
00555                                 }
00556                         }
00557 
00558                         LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
00559                         std::vector<LLVector3> child_positions;
00560                         std::vector<LLQuaternion> child_rotations;
00561                         if (object->isRootEdit() && selectNode->mIndividualSelection)
00562                         {
00563                                 for (U32 i = 0; i < object->mChildList.size(); i++)
00564                                 {
00565                                         LLViewerObject* childp = object->mChildList[i];
00566                                         child_positions.push_back(childp->getPositionEdit());
00567                                         child_rotations.push_back(childp->getRotationEdit());
00568                                 }
00569                         }
00570 
00571                         if (object->getParent() && object->mDrawable.notNull())
00572                         {
00573                                 LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
00574                                 invParentRotation.transQuat();
00575 
00576                                 object->setRotation(new_rot * invParentRotation, damped);
00577                                 rebuild(object);
00578                         }
00579                         else
00580                         {
00581                                 object->setRotation(new_rot, damped);
00582                                 rebuild(object);
00583                         }
00584 
00585                         // for individually selected roots, we need to counterrotate all the children
00586                         if (object->isRootEdit() && selectNode->mIndividualSelection)
00587                         {
00588                                 //RN: must do non-damped updates on these objects so relative rotation appears constant
00589                                 // instead of having two competing slerps making the child objects appear to "wobble"
00590                                 for (U32 i = 0; i < object->mChildList.size(); i++)
00591                                 {
00592                                         LLViewerObject* childp = object->mChildList[i];
00593                                         LLVector3 child_offset = ((child_positions[i] - object->getPositionEdit()) * ~object->getRotationEdit()) - childp->getPosition();
00594                                         if (!childp->isSelected() && childp->mDrawable.notNull())
00595                                         {
00596                                                 childp->setRotation(child_rotations[i] * ~object->getRotationEdit());
00597                                                 childp->setPosition((child_positions[i] - object->getPositionEdit()) * ~object->getRotationEdit());
00598                                                 rebuild(childp);
00599                                         }
00600                                 }
00601                         }
00602                 }
00603         }
00604 
00605         // update positions
00606         for (LLObjectSelection::iterator iter = mObjectSelection->begin();
00607                  iter != mObjectSelection->end(); iter++)
00608         {
00609                 LLSelectNode* selectNode = *iter;
00610                 LLViewerObject* object = selectNode->getObject();
00611 
00612                 // to avoid cumulative position changes we calculate the objects new position using its saved position
00613                 if (object && object->permMove())
00614                 {
00615                         LLVector3 center   = gAgent.getPosAgentFromGlobal( mRotationCenter );
00616 
00617                         LLVector3 old_position;
00618                         LLVector3 new_position;
00619 
00620                         if (object->isAttachment() && object->mDrawable.notNull())
00621                         { 
00622                                 // need to work in drawable space to handle selected items from multiple attachments 
00623                                 // (which have no shared frame of reference other than their render positions)
00624                                 LLXform* parent_xform = object->mDrawable->getXform()->getParent();
00625                                 new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
00626                                 old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
00627                         }
00628                         else
00629                         {
00630                                 new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal );
00631                                 old_position = object->getPositionAgent();
00632                         }
00633 
00634                         new_position = (new_position - center) * mRotation;             // new relative rotated position
00635                         new_position += center;
00636                         
00637                         if (object->isRootEdit() && !object->isAttachment())
00638                         {
00639                                 LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
00640                                 new_pos_global = gWorldp->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
00641                                 new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
00642                         }
00643 
00644                         // for individually selected child objects
00645                         if (!object->isRootEdit() && selectNode->mIndividualSelection)
00646                         {
00647                                 LLViewerObject* parentp = (LLViewerObject*)object->getParent();
00648                                 if (!parentp->isSelected())
00649                                 {
00650                                         if (object->isAttachment() && object->mDrawable.notNull())
00651                                         {
00652                                                 // find position relative to render position of parent
00653                                                 object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
00654                                                 rebuild(object);
00655                                         }
00656                                         else
00657                                         {
00658                                                 object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
00659                                                 rebuild(object);
00660                                         }
00661                                 }
00662                         }
00663                         else if (object->isRootEdit())
00664                         {
00665                                 if (object->isAttachment() && object->mDrawable.notNull())
00666                                 {
00667                                         LLXform* parent_xform = object->mDrawable->getXform()->getParent();
00668                                         object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
00669                                         rebuild(object);
00670                                 }
00671                                 else
00672                                 {
00673                                         object->setPositionAgent(new_position);
00674                                         rebuild(object);
00675                                 }
00676                         }
00677 
00678                         // for individually selected roots, we need to counter-translate all unselected children
00679                         if (object->isRootEdit() && selectNode->mIndividualSelection)
00680                         {
00681                                 // only offset by parent's translation as we've already countered parent's rotation
00682                                 LLVector3 child_offset;
00683                                 if (object->isAttachment() && object->mDrawable.notNull())
00684                                 {
00685                                         LLXform* attachment_point_xform = object->mDrawable->getXform()->getParent();
00686                                         LLQuaternion parent_rotation = object->getRotation() * attachment_point_xform->getWorldRotation();
00687                                         child_offset = LLVector3(old_position - new_position) * ~parent_rotation;
00688                                 }
00689                                 else
00690                                 {
00691                                         child_offset = LLVector3(old_position - new_position) * ~object->getRenderRotation();
00692                                 }
00693 
00694                                 rebuild(object);
00695                                 for (U32 i = 0; i < object->mChildList.size(); i++)
00696                                 {
00697                                         LLViewerObject* childp = object->mChildList[i];
00698                                         if (!childp->isSelected() && childp->mDrawable.notNull())
00699                                         {
00700                                                 childp->setPosition(childp->getPosition() + child_offset);
00701                                                 rebuild(childp);
00702                                         }
00703                                 }
00704                         }
00705                 }
00706         }
00707 
00708         // store changes to override updates
00709         for (LLObjectSelection::iterator iter = gSelectMgr->getSelection()->begin();
00710                  iter != gSelectMgr->getSelection()->end(); iter++)
00711         {
00712                 LLSelectNode* selectNode = *iter;
00713                 LLViewerObject*cur = selectNode->getObject();
00714                 if( cur->permModify() && cur->permMove() && !cur->isAvatar())
00715                 {
00716                         selectNode->mLastRotation = cur->getRotation();
00717                         selectNode->mLastPositionLocal = cur->getPosition();
00718                 }
00719         }       
00720 
00721         gSelectMgr->updateSelectionCenter();
00722 
00723         // RN: just clear focus so camera doesn't follow spurious object updates
00724         gAgent.clearFocusObject();
00725         dialog_refresh_all();
00726 }
00727 
00728 void LLManipRotate::renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color)
00729 {
00730         LLGLEnable cull_face(GL_CULL_FACE);
00731         {
00732                 gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, FALSE);
00733                 gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, TRUE);
00734         }
00735         {
00736                 LLGLDepthTest gls_depth(GL_FALSE);
00737                 gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, FALSE);
00738                 gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, TRUE);
00739         }
00740 }
00741 
00742 void LLManipRotate::renderSnapGuides()
00743 {
00744         LLVector3 grid_origin;
00745         LLVector3 grid_scale;
00746         LLQuaternion grid_rotation;
00747         LLVector3 constraint_axis = getConstraintAxis();
00748 
00749         gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale);
00750 
00751         if (!gSavedSettings.getBOOL("SnapEnabled"))
00752         {
00753                 return;
00754         }
00755 
00756         LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
00757         LLVector3 cam_at_axis;
00758         if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
00759         {
00760                 cam_at_axis.setVec(1.f, 0.f, 0.f);
00761         }
00762         else
00763         {
00764                 cam_at_axis = center - gAgent.getCameraPositionAgent();
00765                 cam_at_axis.normVec();
00766         }
00767 
00768         LLVector3 world_snap_axis;
00769         LLVector3 test_axis = constraint_axis;
00770 
00771         BOOL constrain_to_ref_object = FALSE;
00772         if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject())
00773         {
00774                 test_axis = test_axis * ~grid_rotation;
00775         }
00776         else if (gSelectMgr->getGridMode() == GRID_MODE_REF_OBJECT)
00777         {
00778                 test_axis = test_axis * ~grid_rotation;
00779                 constrain_to_ref_object = TRUE;
00780         }
00781 
00782         test_axis.abs();
00783 
00784         // find closest global/reference axis to local constraint axis;
00785         if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
00786         {
00787                 world_snap_axis = LLVector3::y_axis;
00788         }
00789         else if (test_axis.mV[VY] > test_axis.mV[VZ])
00790         {
00791                 world_snap_axis = LLVector3::z_axis;
00792         }
00793         else
00794         {
00795                 world_snap_axis = LLVector3::x_axis;
00796         }
00797 
00798         LLVector3 projected_snap_axis = world_snap_axis;
00799         if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject())
00800         {
00801                 projected_snap_axis = projected_snap_axis * grid_rotation;
00802         }
00803         else if (constrain_to_ref_object)
00804         {
00805                 projected_snap_axis = projected_snap_axis * grid_rotation;
00806         }
00807 
00808         // project world snap axis onto constraint plane
00809         projected_snap_axis -= projected_vec(projected_snap_axis, constraint_axis);
00810         projected_snap_axis.normVec();
00811 
00812         S32 num_rings = mCamEdgeOn ? 2 : 1;
00813         for (S32 ring_num = 0; ring_num < num_rings; ring_num++)
00814         {
00815                 LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
00816 
00817                 if (mCamEdgeOn)
00818                 {
00819                         // draw two opposing rings
00820                         if (ring_num == 0)
00821                         {
00822                                 center += constraint_axis * mRadiusMeters * 0.5f;
00823                         }
00824                         else
00825                         {
00826                                 center -= constraint_axis * mRadiusMeters * 0.5f;
00827                         }
00828                 }
00829 
00830                 LLGLDepthTest gls_depth(GL_FALSE);
00831                 for (S32 pass = 0; pass < 3; pass++)
00832                 {
00833                         // render snap guide ring
00834                         glPushMatrix();
00835                         
00836                         LLQuaternion snap_guide_rot;
00837                         F32 angle_radians, x, y, z;
00838                         snap_guide_rot.shortestArc(LLVector3::z_axis, getConstraintAxis());
00839                         snap_guide_rot.getAngleAxis(&angle_radians, &x, &y, &z);
00840                         glTranslatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
00841                         glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
00842 
00843                         LLColor4 line_color = setupSnapGuideRenderPass(pass);
00844 
00845                         glColor4fv(line_color.mV);
00846 
00847                         if (mCamEdgeOn)
00848                         {
00849                                 // render an arc
00850                                 LLVector3 edge_normal = cam_at_axis % constraint_axis;
00851                                 edge_normal.normVec();
00852                                 LLVector3 x_axis_snap = LLVector3::x_axis * snap_guide_rot;
00853                                 LLVector3 y_axis_snap = LLVector3::y_axis * snap_guide_rot;
00854 
00855                                 F32 end_angle = atan2(y_axis_snap * edge_normal, x_axis_snap * edge_normal);
00856                                 //F32 start_angle = angle_between((-1.f * LLVector3::x_axis) * snap_guide_rot, edge_normal);
00857                                 F32 start_angle = end_angle - F_PI;
00858                                 gl_arc_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, FALSE, start_angle, end_angle);
00859                         }
00860                         else
00861                         {
00862                                 gl_circle_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, FALSE);
00863                         }
00864                         glPopMatrix();
00865 
00866                         for (S32 i = 0; i < 64; i++)
00867                         {
00868                                 BOOL render_text = TRUE;
00869                                 F32 deg = 5.625f * (F32)i;
00870                                 LLVector3 inner_point;
00871                                 LLVector3 outer_point;
00872                                 LLVector3 text_point;
00873                                 LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis);
00874                                 glBegin(GL_LINES);
00875                                 {
00876                                         inner_point = (projected_snap_axis * mRadiusMeters * SNAP_GUIDE_INNER_RADIUS * rot) + center;
00877                                         F32 tick_length = 0.f;
00878                                         if (i % 16 == 0)
00879                                         {
00880                                                 tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_1 - SNAP_GUIDE_INNER_RADIUS);
00881                                         }
00882                                         else if (i % 8 == 0)
00883                                         {
00884                                                 tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_2 - SNAP_GUIDE_INNER_RADIUS);
00885                                         }
00886                                         else if (i % 4 == 0)
00887                                         {
00888                                                 tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_3 - SNAP_GUIDE_INNER_RADIUS);
00889                                         }
00890                                         else if (i % 2 == 0)
00891                                         {
00892                                                 tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_4 - SNAP_GUIDE_INNER_RADIUS);
00893                                         }
00894                                         else
00895                                         {
00896                                                 tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_5 - SNAP_GUIDE_INNER_RADIUS);
00897                                         }
00898                                         
00899                                         if (mCamEdgeOn)
00900                                         {
00901                                                 // don't draw ticks that are on back side of circle
00902                                                 F32 dot = cam_at_axis * (projected_snap_axis * rot);
00903                                                 if (dot > 0.f)
00904                                                 {
00905                                                         outer_point = inner_point;
00906                                                         render_text = FALSE;
00907                                                 }
00908                                                 else
00909                                                 {
00910                                                         if (ring_num == 0)
00911                                                         {
00912                                                                 outer_point = inner_point + (constraint_axis * tick_length) * rot;
00913                                                         }
00914                                                         else
00915                                                         {
00916                                                                 outer_point = inner_point - (constraint_axis * tick_length) * rot;
00917                                                         }
00918                                                 }
00919                                         }
00920                                         else
00921                                         {
00922                                                 outer_point = inner_point + (projected_snap_axis * tick_length) * rot;
00923                                         }
00924 
00925                                         text_point = outer_point + (projected_snap_axis * mRadiusMeters * 0.1f) * rot;
00926 
00927                                         glVertex3fv(inner_point.mV);
00928                                         glVertex3fv(outer_point.mV);
00929                                 }
00930                                 glEnd();
00931 
00932                                 //RN: text rendering does own shadow pass, so only render once
00933                                 if (pass == 1 && render_text && i % 16 == 0)
00934                                 {
00935                                         if (world_snap_axis.mV[VX])
00936                                         {
00937                                                 if (i == 0)
00938                                                 {
00939                                                         renderTickText(text_point, mObjectSelection->isAttachment() ? "Forward" : "East", LLColor4::white);
00940                                                 }
00941                                                 else if (i == 16)
00942                                                 {
00943                                                         if (constraint_axis.mV[VZ] > 0.f)
00944                                                         {
00945                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Left" : "North", LLColor4::white);
00946                                                         }
00947                                                         else
00948                                                         {
00949                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Right" : "South", LLColor4::white);
00950                                                         }
00951                                                 }
00952                                                 else if (i == 32)
00953                                                 {
00954                                                         renderTickText(text_point, mObjectSelection->isAttachment() ? "Back" : "West", LLColor4::white);
00955                                                 }
00956                                                 else
00957                                                 {
00958                                                         if (constraint_axis.mV[VZ] > 0.f)
00959                                                         {
00960                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Right" : "South", LLColor4::white);
00961                                                         }
00962                                                         else
00963                                                         {
00964                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Left" : "North", LLColor4::white);
00965                                                         }
00966                                                 }
00967                                         }
00968                                         else if (world_snap_axis.mV[VY])
00969                                         {
00970                                                 if (i == 0)
00971                                                 {
00972                                                         renderTickText(text_point, mObjectSelection->isAttachment() ? "Left" : "North", LLColor4::white);
00973                                                 }
00974                                                 else if (i == 16)
00975                                                 {
00976                                                         if (constraint_axis.mV[VX] > 0.f)
00977                                                         {
00978                                                                 renderTickText(text_point, "Up", LLColor4::white);
00979                                                         }
00980                                                         else
00981                                                         {
00982                                                                 renderTickText(text_point, "Down", LLColor4::white);
00983                                                         }
00984                                                 }
00985                                                 else if (i == 32)
00986                                                 {
00987                                                         renderTickText(text_point, mObjectSelection->isAttachment() ? "Right" : "South", LLColor4::white);
00988                                                 }
00989                                                 else
00990                                                 {
00991                                                         if (constraint_axis.mV[VX] > 0.f)
00992                                                         {
00993                                                                 renderTickText(text_point, "Down", LLColor4::white);
00994                                                         }
00995                                                         else
00996                                                         {
00997                                                                 renderTickText(text_point, "Up", LLColor4::white);
00998                                                         }
00999                                                 }
01000                                         }
01001                                         else if (world_snap_axis.mV[VZ])
01002                                         {
01003                                                 if (i == 0)
01004                                                 {
01005                                                         renderTickText(text_point, "Up", LLColor4::white);
01006                                                 }
01007                                                 else if (i == 16)
01008                                                 {
01009                                                         if (constraint_axis.mV[VY] > 0.f)
01010                                                         {
01011                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Forward" : "East", LLColor4::white);
01012                                                         }
01013                                                         else
01014                                                         {
01015                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Back" : "West", LLColor4::white);
01016                                                         }
01017                                                 }
01018                                                 else if (i == 32)
01019                                                 {
01020                                                         renderTickText(text_point, "Down", LLColor4::white);
01021                                                 }
01022                                                 else
01023                                                 {
01024                                                         if (constraint_axis.mV[VY] > 0.f)
01025                                                         {
01026                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Back" : "West", LLColor4::white);
01027                                                         }
01028                                                         else
01029                                                         {
01030                                                                 renderTickText(text_point, mObjectSelection->isAttachment() ? "Forward" : "East", LLColor4::white);
01031                                                         }
01032                                                 }
01033                                         }
01034                                 }
01035                                 glColor4fv(line_color.mV);
01036                         }
01037 
01038                         // now render projected object axis
01039                         if (mInSnapRegime)
01040                         {
01041                                 LLVector3 object_axis;
01042                                 getObjectAxisClosestToMouse(object_axis);
01043 
01044                                 // project onto constraint plane
01045                                 LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(TRUE);
01046                                 object_axis = object_axis * first_node->getObject()->getRenderRotation();
01047                                 object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
01048                                 object_axis.normVec();
01049                                 object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center;
01050                                 LLVector3 line_start = center;
01051 
01052                                 glBegin(GL_LINES);
01053                                 {
01054                                         glVertex3fv(line_start.mV);
01055                                         glVertex3fv(object_axis.mV);
01056                                 }
01057                                 glEnd();
01058 
01059                                 // draw snap guide arrow
01060                                 glBegin(GL_TRIANGLES);
01061                                 {
01062                                         LLVector3 arrow_dir;
01063                                         LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
01064                                         arrow_span.normVec();
01065 
01066                                         arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
01067                                         arrow_dir.normVec();
01068                                         if (ring_num == 1)
01069                                         {
01070                                                 arrow_dir *= -1.f;
01071                                         }
01072                                         glVertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
01073                                         glVertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
01074                                         glVertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
01075                                 }
01076                                 glEnd();
01077 
01078                                 {
01079                                         LLGLDepthTest gls_depth(GL_TRUE);
01080                                         glBegin(GL_LINES);
01081                                         {
01082                                                 glVertex3fv(line_start.mV);
01083                                                 glVertex3fv(object_axis.mV);
01084                                         }
01085                                         glEnd();
01086 
01087                                         // draw snap guide arrow
01088                                         glBegin(GL_TRIANGLES);
01089                                         {
01090                                                 LLVector3 arrow_dir;
01091                                                 LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
01092                                                 arrow_span.normVec();
01093 
01094                                                 arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
01095                                                 arrow_dir.normVec();
01096                                                 if (ring_num == 1)
01097                                                 {
01098                                                         arrow_dir *= -1.f;
01099                                                 }
01100 
01101                                                 glVertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
01102                                                 glVertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
01103                                                 glVertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
01104                                         }
01105                                         glEnd();
01106                                 }
01107                         }
01108                 }
01109         }
01110 }
01111 
01112 // Returns TRUE if center of sphere is visible.  Also sets a bunch of member variables that are used later (e.g. mCenterToCam)
01113 BOOL LLManipRotate::updateVisiblity()
01114 {
01115         // Don't want to recalculate the center of the selection during a drag.
01116         // Due to packet delays, sometimes half the objects in the selection have their
01117         // new position and half have their old one.  This creates subtle errors in the
01118         // computed center position for that frame.  Unfortunately, these errors
01119         // accumulate.  The result is objects seem to "fly apart" during rotations.
01120         // JC - 03.26.2002
01121         if (!hasMouseCapture())
01122         {
01123                 mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() );//gSelectMgr->getSelectionCenterGlobal();
01124         }
01125 
01126         BOOL visible = FALSE;
01127 
01128         LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
01129         if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01130         {
01131                 mCenterToCam = LLVector3(-1.f / gAgent.getAvatarObject()->mHUDCurZoom, 0.f, 0.f);
01132                 mCenterToCamNorm = mCenterToCam;
01133                 mCenterToCamMag = mCenterToCamNorm.normVec();
01134 
01135                 mRadiusMeters = RADIUS_PIXELS / (F32) gCamera->getViewHeightInPixels();
01136                 mRadiusMeters /= gAgent.getAvatarObject()->mHUDCurZoom;
01137 
01138                 mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
01139                 mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
01140 
01141                 mCenterScreen.set((S32)((0.5f - mRotationCenter.mdV[VY]) / gAgent.getAvatarObject()->mHUDCurZoom * gViewerWindow->getWindowWidth()),
01142                                                         (S32)((mRotationCenter.mdV[VZ] + 0.5f) / gAgent.getAvatarObject()->mHUDCurZoom * gViewerWindow->getWindowHeight()));
01143                 visible = TRUE;
01144         }
01145         else
01146         {
01147                 visible = gCamera->projectPosAgentToScreen(center, mCenterScreen );
01148                 if( visible )
01149                 {
01150                         mCenterToCam = gAgent.getCameraPositionAgent() - center;
01151                         mCenterToCamNorm = mCenterToCam;
01152                         mCenterToCamMag = mCenterToCamNorm.normVec();
01153                         LLVector3 cameraAtAxis = gCamera->getAtAxis();
01154                         cameraAtAxis.normVec();
01155 
01156                         F32 z_dist = -1.f * (mCenterToCam * cameraAtAxis);
01157 
01158                         // Don't drag manip if object too far away
01159                         if (gSavedSettings.getBOOL("LimitSelectDistance"))
01160                         {
01161                                 F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
01162                                 if (dist_vec(gAgent.getPositionAgent(), center) > max_select_distance)
01163                                 {
01164                                         visible = FALSE;
01165                                 }
01166                         }
01167                         
01168                         if (mCenterToCamMag > 0.001f)
01169                         {
01170                                 F32 fraction_of_fov = RADIUS_PIXELS / (F32) gCamera->getViewHeightInPixels();
01171                                 F32 apparent_angle = fraction_of_fov * gCamera->getView();  // radians
01172                                 mRadiusMeters = z_dist * tan(apparent_angle);
01173 
01174                                 mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
01175                                 mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
01176                         }
01177                         else
01178                         {
01179                                 visible = FALSE;
01180                         }
01181                 }
01182         }
01183 
01184         mCamEdgeOn = FALSE;
01185         F32 axis_onto_cam = mManipPart >= LL_ROT_X ? llabs( getConstraintAxis() * mCenterToCamNorm ) : 0.f;
01186         if( axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE )
01187         {
01188                 mCamEdgeOn = TRUE;
01189         }
01190 
01191         return visible;
01192 }
01193 
01194 LLQuaternion LLManipRotate::dragUnconstrained( S32 x, S32 y )
01195 {
01196         LLVector3 cam = gAgent.getCameraPositionAgent();
01197         LLVector3 center =  gAgent.getPosAgentFromGlobal( mRotationCenter );
01198 
01199         mMouseCur = intersectMouseWithSphere( x, y, center, mRadiusMeters);
01200 
01201         F32 delta_x = (F32)(mCenterScreen.mX - x);
01202         F32 delta_y = (F32)(mCenterScreen.mY - y);
01203 
01204         F32 dist_from_sphere_center = sqrt(delta_x * delta_x + delta_y * delta_y);
01205 
01206         LLVector3 axis = mMouseDown % mMouseCur;
01207         axis.normVec();
01208         F32 angle = acos(mMouseDown * mMouseCur);
01209         LLQuaternion sphere_rot( angle, axis );
01210 
01211         if (is_approx_zero(1.f - mMouseDown * mMouseCur))
01212         {
01213                 return LLQuaternion::DEFAULT;
01214         }
01215         else if (dist_from_sphere_center < RADIUS_PIXELS)
01216         {
01217                 return sphere_rot;
01218         }
01219         else
01220         {
01221                 LLVector3 intersection;
01222                 getMousePointOnPlaneAgent( intersection, x, y, center + mCenterToProfilePlane, mCenterToCamNorm );
01223 
01224                 // amount dragging in sphere from center to periphery would rotate object
01225                 F32 in_sphere_angle = F_PI_BY_TWO;
01226                 F32 dist_to_tangent_point = mRadiusMeters;
01227                 if( !is_approx_zero( mCenterToProfilePlaneMag ) )
01228                 {
01229                         dist_to_tangent_point = sqrt( mRadiusMeters * mRadiusMeters - mCenterToProfilePlaneMag * mCenterToProfilePlaneMag );
01230                         in_sphere_angle = atan2( dist_to_tangent_point, mCenterToProfilePlaneMag );
01231                 }
01232 
01233                 LLVector3 profile_center_to_intersection = intersection - (center + mCenterToProfilePlane);
01234                 F32 dist_to_intersection = profile_center_to_intersection.normVec();
01235                 F32 angle = (-1.f + dist_to_intersection / dist_to_tangent_point) * in_sphere_angle;
01236 
01237                 LLVector3 axis;
01238                 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01239                 {
01240                         axis = LLVector3(-1.f, 0.f, 0.f) % profile_center_to_intersection;
01241                 }
01242                 else
01243                 {
01244                         axis = (cam - center) % profile_center_to_intersection;
01245                         axis.normVec();
01246                 }
01247                 return sphere_rot * LLQuaternion( angle, axis );
01248         }
01249 }
01250 
01251 LLVector3 LLManipRotate::getConstraintAxis()
01252 {
01253         LLVector3 axis;
01254         if( LL_ROT_ROLL == mManipPart )
01255         {
01256                 axis = mCenterToCamNorm;
01257         }
01258         else
01259         {
01260                 S32 axis_dir = mManipPart - LL_ROT_X;
01261                 if ((axis_dir >= 0) && (axis_dir < 3))
01262                 {
01263                         axis.mV[axis_dir] = 1.f;
01264                 }
01265                 else
01266                 {
01267 #ifndef LL_RELEASE_FOR_DOWNLOAD
01268                         llerrs << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl
01269 #else
01270                         llwarns << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl
01271 #endif
01272                         axis.mV[0] = 1.f;
01273                 }
01274 
01275                 LLVector3 grid_origin;
01276                 LLVector3 grid_scale;
01277                 LLQuaternion grid_rotation;
01278 
01279                 gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale);
01280 
01281                 LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(TRUE);
01282                 if (first_node)
01283                 {
01284                         // *FIX: get agent local attachment grid working
01285                         // Put rotation into frame of first selected root object
01286                         axis = axis * grid_rotation;
01287                 }
01288         }
01289 
01290         return axis;
01291 }
01292 
01293 LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y )
01294 {
01295         LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(TRUE);
01296         LLVector3 constraint_axis = getConstraintAxis();
01297         LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
01298 
01299         F32 angle = 0.f;
01300 
01301         // build snap axes
01302         LLVector3 grid_origin;
01303         LLVector3 grid_scale;
01304         LLQuaternion grid_rotation;
01305 
01306         gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale);
01307 
01308         LLVector3 axis1;
01309         LLVector3 axis2;
01310 
01311         LLVector3 test_axis = constraint_axis;
01312         if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject())
01313         {
01314                 test_axis = test_axis * ~grid_rotation;
01315         }
01316         else if (gSelectMgr->getGridMode() == GRID_MODE_REF_OBJECT)
01317         {
01318                 test_axis = test_axis * ~grid_rotation;
01319         }
01320         test_axis.abs();
01321 
01322         // find closest global axis to constraint axis;
01323         if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
01324         {
01325                 axis1 = LLVector3::y_axis;
01326         }
01327         else if (test_axis.mV[VY] > test_axis.mV[VZ])
01328         {
01329                 axis1 = LLVector3::z_axis;
01330         }
01331         else
01332         {
01333                 axis1 = LLVector3::x_axis;
01334         }
01335 
01336         if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject())
01337         {
01338                 axis1 = axis1 * grid_rotation;
01339         }
01340         else if (gSelectMgr->getGridMode() == GRID_MODE_REF_OBJECT)
01341         {
01342                 axis1 = axis1 * grid_rotation;
01343         }
01344 
01345         //project axis onto constraint plane
01346         axis1 -= (axis1 * constraint_axis) * constraint_axis;
01347         axis1.normVec();
01348 
01349         // calculate third and final axis
01350         axis2 = constraint_axis % axis1;
01351 
01352         //F32 axis_onto_cam = llabs( constraint_axis * mCenterToCamNorm );
01353         if( mCamEdgeOn )
01354         {
01355                 // We're looking at the ring edge-on.
01356                 LLVector3 snap_plane_center = (center + (constraint_axis * mRadiusMeters * 0.5f));
01357                 LLVector3 cam_to_snap_plane;
01358                 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01359                 {
01360                         cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
01361                 }
01362                 else
01363                 {
01364                         cam_to_snap_plane = snap_plane_center - gAgent.getCameraPositionAgent();
01365                         cam_to_snap_plane.normVec();
01366                 }
01367 
01368                 LLVector3 projected_mouse;
01369                 BOOL hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
01370                 projected_mouse -= snap_plane_center;
01371 
01372                 S32 snap_plane = 0;
01373 
01374                 F32 dot = cam_to_snap_plane * constraint_axis;
01375                 if (llabs(dot) < 0.01f)
01376                 {
01377                         // looking at ring edge on, project onto view plane and check if mouse is past ring
01378                         getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
01379                         projected_mouse -= snap_plane_center;
01380                         dot = projected_mouse * constraint_axis;
01381                         if (projected_mouse * constraint_axis > 0)
01382                         {
01383                                 snap_plane = 1;
01384                         }
01385                         projected_mouse -= dot * constraint_axis;
01386                 }
01387                 else if (dot > 0.f)
01388                 {
01389                         // look for mouse position outside and in front of snap circle
01390                         if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
01391                         {
01392                                 snap_plane = 1;
01393                         }
01394                 }
01395                 else
01396                 {
01397                         // look for mouse position inside or in back of snap circle
01398                         if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
01399                         {
01400                                 snap_plane = 1;
01401                         }
01402                 }
01403 
01404                 if (snap_plane == 0)
01405                 {
01406                         // try other plane
01407                         snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f));
01408                         if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01409                         {
01410                                 cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
01411                         }
01412                         else
01413                         {
01414                                 cam_to_snap_plane = snap_plane_center - gAgent.getCameraPositionAgent();
01415                                 cam_to_snap_plane.normVec();
01416                         }
01417 
01418                         hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
01419                         projected_mouse -= snap_plane_center;
01420 
01421                         dot = cam_to_snap_plane * constraint_axis;
01422                         if (llabs(dot) < 0.01f)
01423                         {
01424                                 // looking at ring edge on, project onto view plane and check if mouse is past ring
01425                                 getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
01426                                 projected_mouse -= snap_plane_center;
01427                                 dot = projected_mouse * constraint_axis;
01428                                 if (projected_mouse * constraint_axis < 0)
01429                                 {
01430                                         snap_plane = 2;
01431                                 }
01432                                 projected_mouse -= dot * constraint_axis;
01433                         }
01434                         else if (dot < 0.f)
01435                         {
01436                                 // look for mouse position outside and in front of snap circle
01437                                 if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
01438                                 {
01439                                         snap_plane = 2;
01440                                 }
01441                         }
01442                         else
01443                         {
01444                                 // look for mouse position inside or in back of snap circle
01445                                 if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
01446                                 {
01447                                         snap_plane = 2;
01448                                 }
01449                         }
01450                 }
01451 
01452                 if (snap_plane > 0)
01453                 {
01454                         LLVector3 cam_at_axis;
01455                         if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01456                         {
01457                                 cam_at_axis.setVec(1.f, 0.f, 0.f);
01458                         }
01459                         else
01460                         {
01461                                 cam_at_axis = snap_plane_center - gAgent.getCameraPositionAgent();
01462                                 cam_at_axis.normVec();
01463                         }
01464 
01465                         // first, project mouse onto screen plane at point tangent to rotation radius. 
01466                         getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis);
01467                         // project that point onto rotation plane
01468                         projected_mouse -= snap_plane_center;
01469                         projected_mouse -= projected_vec(projected_mouse, constraint_axis);
01470 
01471                         F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec());
01472                         F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
01473                         if (llabs(mouse_lateral_dist) > 0.01f)
01474                         {
01475                                 mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - 
01476                                                                         (mouse_lateral_dist * mouse_lateral_dist));
01477                         }
01478                         LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis);
01479                         projected_mouse -= mouse_depth * projected_camera_at;
01480 
01481                         if (!mInSnapRegime)
01482                         {
01483                                 mSmoothRotate = TRUE;
01484                         }
01485                         mInSnapRegime = TRUE;
01486                         // 0 to 360 deg
01487                         F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
01488                         
01489                         F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
01490                         //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
01491 
01492                         LLVector3 object_axis;
01493                         getObjectAxisClosestToMouse(object_axis);
01494                         object_axis = object_axis * first_object_node->mSavedRotation;
01495 
01496                         // project onto constraint plane
01497                         object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
01498                         object_axis.normVec();
01499 
01500                         if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
01501                         {
01502                                 F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
01503                                 angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
01504                         }
01505                         else
01506                         {
01507                                 angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
01508                         }
01509                         return LLQuaternion( -angle, constraint_axis );
01510                 }
01511                 else
01512                 {
01513                         if (mInSnapRegime)
01514                         {
01515                                 mSmoothRotate = TRUE;
01516                         }
01517                         mInSnapRegime = FALSE;
01518 
01519                         LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis;
01520                         up_from_axis.normVec();
01521                         LLVector3 cur_intersection;
01522                         getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam);
01523                         cur_intersection -= center;
01524                         mMouseCur = projected_vec(cur_intersection, up_from_axis);
01525                         F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
01526                         F32 mouse_dist_sqrd = mMouseCur.magVecSquared();
01527                         if (mouse_dist_sqrd > 0.0001f)
01528                         {
01529                                 mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - 
01530                                                                         mouse_dist_sqrd);
01531                         }
01532                         LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, constraint_axis);
01533                         mMouseCur += mouse_depth * projected_center_to_cam;
01534 
01535                         F32 dist = (cur_intersection * up_from_axis) - (mMouseDown * up_from_axis);
01536                         angle = dist / (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * -F_PI_BY_TWO;
01537                 }
01538         }
01539         else
01540         {
01541                 LLVector3 projected_mouse;
01542                 getMousePointOnPlaneAgent(projected_mouse, x, y, center, constraint_axis);
01543                 projected_mouse -= center;
01544                 mMouseCur = projected_mouse;
01545                 mMouseCur.normVec();
01546 
01547                 if (!first_object_node)
01548                 {
01549                         return LLQuaternion::DEFAULT;
01550                 }
01551 
01552                 if (gSavedSettings.getBOOL("SnapEnabled") && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters)
01553                 {
01554                         if (!mInSnapRegime)
01555                         {
01556                                 mSmoothRotate = TRUE;
01557                         }
01558                         mInSnapRegime = TRUE;
01559                         // 0 to 360 deg
01560                         F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
01561                         
01562                         F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
01563                         //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
01564 
01565                         LLVector3 object_axis;
01566                         getObjectAxisClosestToMouse(object_axis);
01567                         object_axis = object_axis * first_object_node->mSavedRotation;
01568 
01569                         // project onto constraint plane
01570                         object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
01571                         object_axis.normVec();
01572 
01573                         if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
01574                         {
01575                                 F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
01576                                 angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
01577                         }
01578                         else
01579                         {
01580                                 angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
01581                         }
01582                         return LLQuaternion( -angle, constraint_axis );
01583                 }
01584                 else
01585                 {
01586                         if (mInSnapRegime)
01587                         {
01588                                 mSmoothRotate = TRUE;
01589                         }
01590                         mInSnapRegime = FALSE;
01591                 }
01592 
01593                 angle = acos(mMouseCur * mMouseDown);
01594 
01595                 F32 dir = (mMouseDown % mMouseCur) * constraint_axis;  // cross product
01596                 if( dir < 0.f )
01597                 {
01598                         angle *= -1.f;
01599                 }
01600         }
01601 
01602         F32 rot_step = gSavedSettings.getF32("RotationStep");
01603         F32 step_size = DEG_TO_RAD * rot_step;
01604         angle -= fmod(angle, step_size);
01605                 
01606         return LLQuaternion( angle, constraint_axis );
01607 }
01608 
01609 
01610 
01611 LLVector3 LLManipRotate::intersectMouseWithSphere( S32 x, S32 y, const LLVector3& sphere_center, F32 sphere_radius)
01612 {
01613         LLVector3 ray_pt;
01614         LLVector3 ray_dir;
01615         mouseToRay( x, y, &ray_pt, &ray_dir);
01616         return intersectRayWithSphere( ray_pt, ray_dir, sphere_center, sphere_radius );
01617 }
01618 
01619 LLVector3 LLManipRotate::intersectRayWithSphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius)
01620 {
01621         LLVector3 ray_pt_to_center = sphere_center - ray_pt;
01622         F32 center_distance = ray_pt_to_center.normVec();
01623 
01624         F32 dot = ray_dir * ray_pt_to_center;
01625 
01626         if (dot == 0.f)
01627         {
01628                 return LLVector3::zero;
01629         }
01630 
01631         // point which ray hits plane centered on sphere origin, facing ray origin
01632         LLVector3 intersection_sphere_plane = ray_pt + (ray_dir * center_distance / dot); 
01633         // vector from sphere origin to the point, normalized to sphere radius
01634         LLVector3 sphere_center_to_intersection = (intersection_sphere_plane - sphere_center) / sphere_radius;
01635 
01636         F32 dist_squared = sphere_center_to_intersection.magVecSquared();
01637         LLVector3 result;
01638 
01639         if (dist_squared > 1.f)
01640         {
01641                 result = sphere_center_to_intersection;
01642                 result.normVec();
01643         }
01644         else
01645         {
01646                 result = sphere_center_to_intersection - ray_dir * sqrt(1.f - dist_squared);
01647         }
01648 
01649         return result;
01650 }
01651 
01652 // Utility function.  Should probably be moved to another class.
01653 //static
01654 void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_dir )
01655 {
01656         if (gSelectMgr->getSelection()->getSelectType() == SELECT_TYPE_HUD)
01657         {
01658                 F32 mouse_x = (((F32)x / gViewerWindow->getWindowWidth()) - 0.5f) / gAgent.getAvatarObject()->mHUDCurZoom;
01659                 F32 mouse_y = ((((F32)y) / gViewerWindow->getWindowHeight()) - 0.5f) / gAgent.getAvatarObject()->mHUDCurZoom;
01660 
01661                 *ray_pt = LLVector3(-1.f, -mouse_x, mouse_y);
01662                 *ray_dir = LLVector3(1.f, 0.f, 0.f);
01663         }
01664         else
01665         {
01666                 *ray_pt = gAgent.getCameraPositionAgent();
01667                 gCamera->projectScreenToPosAgent(x, y, ray_dir);
01668                 *ray_dir -= *ray_pt;
01669                 ray_dir->normVec();
01670         }
01671 }
01672 
01673 void LLManipRotate::highlightManipulators( S32 x, S32 y )
01674 {
01675         mHighlightedPart = LL_NO_PART;
01676 
01677         //LLBBox bbox = gSelectMgr->getBBoxOfSelection();
01678         LLViewerObject *first_object = mObjectSelection->getFirstMoveableObject(TRUE);
01679         
01680         if (!first_object)
01681         {
01682                 return;
01683         }
01684         
01685         LLQuaternion object_rot = first_object->getRenderRotation();
01686         LLVector3 rotation_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
01687         LLVector3 mouse_dir_x;
01688         LLVector3 mouse_dir_y;
01689         LLVector3 mouse_dir_z;
01690         LLVector3 intersection_roll;
01691 
01692         LLVector3 grid_origin;
01693         LLVector3 grid_scale;
01694         LLQuaternion grid_rotation;
01695 
01696         gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale);
01697 
01698         LLVector3 rot_x_axis = LLVector3::x_axis * grid_rotation;
01699         LLVector3 rot_y_axis = LLVector3::y_axis * grid_rotation;
01700         LLVector3 rot_z_axis = LLVector3::z_axis * grid_rotation;
01701 
01702         F32 proj_rot_x_axis = llabs(rot_x_axis * mCenterToCamNorm);
01703         F32 proj_rot_y_axis = llabs(rot_y_axis * mCenterToCamNorm);
01704         F32 proj_rot_z_axis = llabs(rot_z_axis * mCenterToCamNorm);
01705 
01706         F32 min_select_distance = 0.f;
01707         F32 cur_select_distance = 0.f;
01708 
01709         // test x
01710         getMousePointOnPlaneAgent(mouse_dir_x, x, y, rotation_center, rot_x_axis);
01711         mouse_dir_x -= rotation_center;
01712         // push intersection point out when working at obtuse angle to make ring easier to hit
01713         mouse_dir_x *= 1.f + (1.f - llabs(rot_x_axis * mCenterToCamNorm)) * 0.1f;
01714 
01715         // test y
01716         getMousePointOnPlaneAgent(mouse_dir_y, x, y, rotation_center, rot_y_axis);
01717         mouse_dir_y -= rotation_center;
01718         mouse_dir_y *= 1.f + (1.f - llabs(rot_y_axis * mCenterToCamNorm)) * 0.1f;
01719 
01720         // test z
01721         getMousePointOnPlaneAgent(mouse_dir_z, x, y, rotation_center, rot_z_axis);
01722         mouse_dir_z -= rotation_center;
01723         mouse_dir_z *= 1.f + (1.f - llabs(rot_z_axis * mCenterToCamNorm)) * 0.1f;
01724 
01725         // test roll
01726         getMousePointOnPlaneAgent(intersection_roll, x, y, rotation_center, mCenterToCamNorm);
01727         intersection_roll -= rotation_center;
01728 
01729         F32 dist_x = mouse_dir_x.normVec();
01730         F32 dist_y = mouse_dir_y.normVec();
01731         F32 dist_z = mouse_dir_z.normVec();
01732 
01733         F32 distance_threshold = (MAX_MANIP_SELECT_DISTANCE * mRadiusMeters) / gViewerWindow->getWindowHeight();
01734 
01735         if (llabs(dist_x - mRadiusMeters) * llmax(0.05f, proj_rot_x_axis) < distance_threshold)
01736         {
01737                 // selected x
01738                 cur_select_distance = dist_x * mouse_dir_x * mCenterToCamNorm;
01739                 if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance))
01740                 {
01741                         min_select_distance = cur_select_distance;
01742                         mHighlightedPart = LL_ROT_X;
01743                 }
01744         }
01745         if (llabs(dist_y - mRadiusMeters) * llmax(0.05f, proj_rot_y_axis) < distance_threshold)
01746         {
01747                 // selected y
01748                 cur_select_distance = dist_y * mouse_dir_y * mCenterToCamNorm;
01749                 if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance))
01750                 {
01751                         min_select_distance = cur_select_distance;
01752                         mHighlightedPart = LL_ROT_Y;
01753                 }
01754         }
01755         if (llabs(dist_z - mRadiusMeters) * llmax(0.05f, proj_rot_z_axis) < distance_threshold)
01756         {
01757                 // selected z
01758                 cur_select_distance = dist_z * mouse_dir_z * mCenterToCamNorm;
01759                 if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance))
01760                 {
01761                         min_select_distance = cur_select_distance;
01762                         mHighlightedPart = LL_ROT_Z;
01763                 }
01764         }
01765 
01766         // test for edge-on intersections
01767         if (proj_rot_x_axis < 0.05f)
01768         {
01769                 if ((proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_x_axis) < distance_threshold) && dist_y < mRadiusMeters) ||
01770                         (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_x_axis) < distance_threshold) && dist_z < mRadiusMeters))
01771                 {
01772                         mHighlightedPart = LL_ROT_X;
01773                 }
01774         }
01775 
01776         if (proj_rot_y_axis < 0.05f)
01777         {
01778                 if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_y_axis) < distance_threshold) && dist_x < mRadiusMeters) ||
01779                         (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_y_axis) < distance_threshold) && dist_z < mRadiusMeters))
01780                 {
01781                         mHighlightedPart = LL_ROT_Y;
01782                 }
01783         }
01784 
01785         if (proj_rot_z_axis < 0.05f)
01786         {
01787                 if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_z_axis) < distance_threshold) && dist_x < mRadiusMeters) ||
01788                         (proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_z_axis) < distance_threshold) && dist_y < mRadiusMeters))
01789                 {
01790                         mHighlightedPart = LL_ROT_Z;
01791                 }
01792         }
01793 
01794         // test for roll
01795         if (mHighlightedPart == LL_NO_PART)
01796         {
01797                 F32 roll_distance = intersection_roll.magVec();
01798                 F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
01799 
01800                 // use larger distance threshold for roll as it is checked only if something else wasn't highlighted
01801                 if (llabs(roll_distance - (mRadiusMeters + (width_meters * 2.f))) < distance_threshold * 2.f)
01802                 {
01803                         mHighlightedPart = LL_ROT_ROLL;
01804                 }
01805                 else if (roll_distance < mRadiusMeters)
01806                 {
01807                         mHighlightedPart = LL_ROT_GENERAL;
01808                 }
01809         }
01810 }
01811 
01812 S32 LLManipRotate::getObjectAxisClosestToMouse(LLVector3& object_axis)
01813 {
01814         LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(TRUE);
01815 
01816         if (!first_object_node)
01817         {
01818                 object_axis.clearVec();
01819                 return -1;
01820         }
01821 
01822         LLQuaternion obj_rotation = first_object_node->mSavedRotation;
01823         LLVector3 mouse_down_object = mMouseDown * ~obj_rotation;
01824         LLVector3 mouse_down_abs = mouse_down_object;
01825         mouse_down_abs.abs();
01826 
01827         S32 axis_index = 0;
01828         if (mouse_down_abs.mV[VX] > mouse_down_abs.mV[VY] && mouse_down_abs.mV[VX] > mouse_down_abs.mV[VZ])
01829         {
01830                 if (mouse_down_object.mV[VX] > 0.f)
01831                 {
01832                         object_axis = LLVector3::x_axis;
01833                 }
01834                 else
01835                 {
01836                         object_axis = LLVector3::x_axis_neg;
01837                 }
01838                 axis_index = VX;
01839         }
01840         else if (mouse_down_abs.mV[VY] > mouse_down_abs.mV[VZ])
01841         {
01842                 if (mouse_down_object.mV[VY] > 0.f)
01843                 {
01844                         object_axis = LLVector3::y_axis;
01845                 }
01846                 else
01847                 {
01848                         object_axis = LLVector3::y_axis_neg;
01849                 }
01850                 axis_index = VY;
01851         }
01852         else
01853         {
01854                 if (mouse_down_object.mV[VZ] > 0.f)
01855                 {
01856                         object_axis = LLVector3::z_axis;
01857                 }
01858                 else
01859                 {
01860                         object_axis = LLVector3::z_axis_neg;
01861                 }
01862                 axis_index = VZ;
01863         }
01864 
01865         return axis_index;
01866 }
01867 
01868 //virtual
01869 BOOL LLManipRotate::canAffectSelection()
01870 {
01871         BOOL can_rotate = mObjectSelection->getObjectCount() != 0;
01872         if (can_rotate)
01873         {
01874                 struct f : public LLSelectedObjectFunctor
01875                 {
01876                         virtual bool apply(LLViewerObject* objectp)
01877                         {
01878                                 return objectp->permMove() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));
01879                         }
01880                 } func;
01881                 can_rotate = mObjectSelection->applyToObjects(&func);
01882         }
01883         return can_rotate;
01884 }
01885 

Generated on Thu Jul 1 06:08:49 2010 for Second Life Viewer by  doxygen 1.4.7