llmanipscale.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llmanipscale.h"
00035 
00036 // library includes
00037 #include "llmath.h"
00038 #include "v3math.h"
00039 #include "llquaternion.h"
00040 #include "llgl.h"
00041 #include "llglimmediate.h"
00042 #include "v4color.h"
00043 #include "llprimitive.h"
00044 
00045 // viewer includes
00046 #include "llagent.h"
00047 #include "llbbox.h"
00048 #include "llbox.h"
00049 #include "llviewercontrol.h"
00050 #include "llcriticaldamp.h"
00051 #include "lldrawable.h"
00052 #include "llfloatertools.h"
00053 #include "llglheaders.h"
00054 #include "llselectmgr.h"
00055 #include "llstatusbar.h"
00056 #include "llui.h"
00057 #include "llviewercamera.h"
00058 #include "llviewerobject.h"
00059 #include "llviewerwindow.h"
00060 #include "llhudrender.h"
00061 #include "llworld.h"
00062 #include "v2math.h"
00063 #include "llvoavatar.h"
00064 
00065 
00066 const F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f;
00067 const F32 SNAP_GUIDE_SCREEN_OFFSET = 0.05f;
00068 const F32 SNAP_GUIDE_SCREEN_LENGTH = 0.7f;
00069 const F32 SELECTED_MANIPULATOR_SCALE = 1.2f;
00070 const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
00071 const S32 NUM_MANIPULATORS = 14;
00072 
00073 const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = 
00074 {
00075         LLManip::LL_CORNER_NNN,
00076         LLManip::LL_CORNER_NNP,
00077         LLManip::LL_CORNER_NPN,
00078         LLManip::LL_CORNER_NPP,
00079         LLManip::LL_CORNER_PNN,
00080         LLManip::LL_CORNER_PNP,
00081         LLManip::LL_CORNER_PPN,
00082         LLManip::LL_CORNER_PPP,
00083         LLManip::LL_FACE_POSZ,
00084         LLManip::LL_FACE_POSX,
00085         LLManip::LL_FACE_POSY,
00086         LLManip::LL_FACE_NEGX,
00087         LLManip::LL_FACE_NEGY,
00088         LLManip::LL_FACE_NEGZ
00089 };
00090 
00091 
00092 
00093 // static
00094 void LLManipScale::setUniform(BOOL b)
00095 {
00096         gSavedSettings.setBOOL("ScaleUniform", b);
00097 }
00098 
00099 // static
00100 void LLManipScale::setShowAxes(BOOL b)
00101 {
00102         gSavedSettings.setBOOL("ScaleShowAxes", b);
00103 }
00104 
00105 // static
00106 void LLManipScale::setStretchTextures(BOOL b)
00107 {
00108         gSavedSettings.setBOOL("ScaleStretchTextures", b);
00109 }
00110 
00111 // static
00112 BOOL LLManipScale::getUniform()
00113 {
00114         return gSavedSettings.getBOOL("ScaleUniform");
00115 }
00116 
00117 // static
00118 BOOL LLManipScale::getShowAxes()
00119 {
00120         return gSavedSettings.getBOOL("ScaleShowAxes");
00121 }
00122 
00123 // static
00124 BOOL LLManipScale::getStretchTextures()
00125 {
00126         return gSavedSettings.getBOOL("ScaleStretchTextures");
00127 }
00128 
00129 inline void LLManipScale::conditionalHighlight( U32 part, const LLColor4* highlight, const LLColor4* normal )
00130 {
00131         LLColor4 default_highlight( 1.f, 1.f, 1.f, 1.f );
00132         LLColor4 default_normal( 0.7f, 0.7f, 0.7f, 0.6f );
00133         LLColor4 invisible(0.f, 0.f, 0.f, 0.f);
00134         F32 manipulator_scale = 1.f;
00135 
00136         for (S32 i = 0; i < NUM_MANIPULATORS; i++)
00137         {
00138                 if((U32)MANIPULATOR_IDS[i] == part)
00139                 {
00140                         manipulator_scale = mManipulatorScales[i];
00141                         break;
00142                 }
00143         }
00144 
00145         mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale;
00146         if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part)
00147         {
00148                 gGL.color4fv( invisible.mV );
00149         }
00150         else if( mHighlightedPart == (S32)part )
00151         {
00152                 gGL.color4fv( highlight ? highlight->mV : default_highlight.mV );
00153         }
00154         else
00155         {
00156                 gGL.color4fv( normal ? normal->mV : default_normal.mV  );
00157         }
00158 }
00159 
00160 void LLManipScale::handleSelect()
00161 {
00162         LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
00163         updateSnapGuides(bbox);
00164         LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
00165         gFloaterTools->setStatusText("scale");
00166         LLManip::handleSelect();
00167 }
00168 
00169 void LLManipScale::handleDeselect()
00170 {
00171         mHighlightedPart = LL_NO_PART;
00172         mManipPart = LL_NO_PART;
00173         LLManip::handleDeselect();
00174 }
00175 
00176 LLManipScale::LLManipScale( LLToolComposite* composite )
00177         : 
00178         LLManip( "Scale", composite ),
00179         mBoxHandleSize( 1.f ),
00180         mScaledBoxHandleSize( 1.f ),
00181         mManipPart( LL_NO_PART ),
00182         mLastMouseX( -1 ),
00183         mLastMouseY( -1 ),
00184         mSendUpdateOnMouseUp( FALSE ),
00185         mLastUpdateFlags( 0 ),
00186         mScaleSnapUnit1(1.f),
00187         mScaleSnapUnit2(1.f),
00188         mSnapRegimeOffset(0.f),
00189         mSnapGuideLength(0.f),
00190         mScaleSnapValue(0.f)
00191 { 
00192         mManipulatorScales = new F32[NUM_MANIPULATORS];
00193         for (S32 i = 0; i < NUM_MANIPULATORS; i++)
00194         {
00195                 mManipulatorScales[i] = 1.f;
00196         }
00197 }
00198 
00199 LLManipScale::~LLManipScale()
00200 {
00201         for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(), DeletePointer());
00202         delete[] mManipulatorScales;
00203 }
00204 
00205 void LLManipScale::render()
00206 {
00207         LLGLSUIDefault gls_ui;
00208         LLGLSNoTexture gls_no_texture;
00209         LLGLDepthTest gls_depth(GL_TRUE);
00210         LLGLEnable gl_blend(GL_BLEND);
00211         LLGLEnable gls_alpha_test(GL_ALPHA_TEST);
00212         
00213         if( canAffectSelection() )
00214         {
00215                 glMatrixMode(GL_MODELVIEW);
00216                 glPushMatrix();
00217                 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
00218                 {
00219                         F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
00220                         glScalef(zoom, zoom, zoom);
00221                 }
00222 
00224                 // Calculate size of drag handles       
00225 
00226                 const F32 BOX_HANDLE_BASE_SIZE          = 50.0f;   // box size in pixels = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR
00227                 const F32 BOX_HANDLE_BASE_FACTOR        = 0.2f;
00228                 
00229                 LLVector3 center_agent = gAgent.getPosAgentFromGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal());
00230 
00231                 F32 range;
00232                 F32 range_from_agent;
00233                 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
00234                 {
00235                         mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
00236                         mBoxHandleSize /= gAgent.getAvatarObject()->mHUDCurZoom;
00237                 }
00238                 else
00239                 {
00240                         range = dist_vec(gAgent.getCameraPositionAgent(), center_agent);
00241                         range_from_agent = dist_vec(gAgent.getPositionAgent(), center_agent);
00242 
00243                         // Don't draw manip if object too far away
00244                         if (gSavedSettings.getBOOL("LimitSelectDistance"))
00245                         {
00246                                 F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
00247                                 if (range_from_agent > max_select_distance)
00248                                 {
00249                                         return;
00250                                 }
00251                         }
00252 
00253                         if (range > 0.001f)
00254                         {
00255                                 // range != zero
00256                                 F32 fraction_of_fov = BOX_HANDLE_BASE_SIZE / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
00257                                 F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView();  // radians
00258                                 mBoxHandleSize = range * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR;
00259                         }
00260                         else
00261                         {
00262                                 // range == zero
00263                                 mBoxHandleSize = BOX_HANDLE_BASE_FACTOR;
00264                         }
00265                 }
00266 
00268                 // Draw bounding box
00269 
00270                 LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
00271                 LLVector3 pos_agent = bbox.getPositionAgent();
00272                 LLQuaternion rot = bbox.getRotation();
00273 
00274                 glMatrixMode(GL_MODELVIEW);
00275                 glPushMatrix();
00276                 {
00277                         glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ]);
00278 
00279                         F32 angle_radians, x, y, z;
00280                         rot.getAngleAxis(&angle_radians, &x, &y, &z);
00281                         glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
00282 
00283                         
00284                         {
00285                                 LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL);
00286                                 glPolygonOffset( -2.f, -2.f);
00287 
00288                                 // JC - Band-aid until edge stretch working similar to side stretch
00289                                 // in non-uniform.
00290                                 // renderEdges( bbox );
00291 
00292                                 renderCorners( bbox );
00293                                 renderFaces( bbox );
00294 
00295                                 if (mManipPart != LL_NO_PART)
00296                                 {
00297                                         renderGuidelinesPart( bbox );
00298                                 }
00299 
00300                                 glPolygonOffset( 0.f, 0.f);
00301                         }
00302                 }
00303                 glPopMatrix();
00304 
00305                 if (mManipPart != LL_NO_PART)
00306                 {
00307                         renderSnapGuides(bbox);
00308                 }
00309                 glPopMatrix();
00310 
00311                 renderXYZ(bbox.getExtentLocal());
00312         }
00313 }
00314 
00315 BOOL LLManipScale::handleMouseDown(S32 x, S32 y, MASK mask)
00316 {
00317         BOOL    handled = FALSE;
00318 
00319         LLViewerObject* hit_obj = gViewerWindow->lastObjectHit();
00320         if( hit_obj ||  
00321                 (mHighlightedPart != LL_NO_PART) )
00322         {
00323                 handled = handleMouseDownOnPart( x, y, mask );
00324         }
00325 
00326         return handled;
00327 }
00328 
00329 // Assumes that one of the arrows on an object was hit.
00330 BOOL LLManipScale::handleMouseDownOnPart( S32 x, S32 y, MASK mask )
00331 {
00332         BOOL can_scale = canAffectSelection();
00333         if (!can_scale)
00334         {
00335                 return FALSE;
00336         }
00337 
00338         highlightManipulators(x, y);
00339         S32 hit_part = mHighlightedPart;
00340 
00341         LLSelectMgr::getInstance()->enableSilhouette(FALSE);
00342         mManipPart = (EManipPart)hit_part;
00343 
00344         LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
00345         LLVector3 box_center_agent = bbox.getCenterAgent();
00346         LLVector3 box_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox ) );
00347         
00348         updateSnapGuides(bbox);
00349 
00350         mDragStartPointGlobal = gAgent.getPosGlobalFromAgent(box_corner_agent);
00351         mDragStartCenterGlobal = gAgent.getPosGlobalFromAgent(box_center_agent);
00352         LLVector3 far_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox ) );
00353         mDragFarHitGlobal = gAgent.getPosGlobalFromAgent(far_corner_agent);
00354         mDragPointGlobal = mDragStartPointGlobal;
00355 
00356         // we just started a drag, so save initial object positions, orientations, and scales
00357         LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
00358         // Route future Mouse messages here preemptively.  (Release on mouse up.)
00359         setMouseCapture( TRUE );
00360 
00361         mHelpTextTimer.reset();
00362         sNumTimesHelpTextShown++;
00363         return TRUE;
00364 }
00365 
00366 
00367 BOOL LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask)
00368 {
00369         // first, perform normal processing in case this was a quick-click
00370         handleHover(x, y, mask);
00371 
00372         if( hasMouseCapture() )
00373         {
00374                 if( (LL_FACE_MIN <= (S32)mManipPart) 
00375                         && ((S32)mManipPart <= LL_FACE_MAX) )
00376                 {
00377                         sendUpdates(TRUE,TRUE,FALSE);
00378                 }
00379                 else
00380                 if( (LL_CORNER_MIN <= (S32)mManipPart) 
00381                         && ((S32)mManipPart <= LL_CORNER_MAX) )
00382                 {
00383                         sendUpdates(TRUE,TRUE,TRUE);
00384                 }
00385                 
00386                 //send texture update
00387                 LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, getStretchTextures());
00388                 
00389                 LLSelectMgr::getInstance()->enableSilhouette(TRUE);
00390                 mManipPart = LL_NO_PART;
00391 
00392                 // Might have missed last update due to UPDATE_DELAY timing
00393                 LLSelectMgr::getInstance()->sendMultipleUpdate( mLastUpdateFlags );
00394                 
00395                 //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
00396                 LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
00397         }
00398         return LLManip::handleMouseUp(x, y, mask);
00399 }
00400 
00401 
00402 BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask)
00403 {
00404         if( hasMouseCapture() )
00405         {
00406                 if( mObjectSelection->isEmpty() )
00407                 {
00408                         // Somehow the object got deselected while we were dragging it.
00409                         setMouseCapture( FALSE );
00410                 }
00411                 else
00412                 {
00413                         drag( x, y );
00414                 }
00415                 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (active)" << llendl;              
00416         }
00417         else
00418         {
00419                 mInSnapRegime = FALSE;
00420                 // not dragging...
00421                 highlightManipulators(x, y);
00422         }
00423         
00424         // Patch up textures, if possible.
00425         LLSelectMgr::getInstance()->adjustTexturesByScale(FALSE, getStretchTextures());
00426 
00427         gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLSCALE);
00428         return TRUE;
00429 }
00430 
00431 void LLManipScale::highlightManipulators(S32 x, S32 y)
00432 {
00433         mHighlightedPart = LL_NO_PART;
00434 
00435         // If we have something selected, try to hit its manipulator handles.
00436         // Don't do this with nothing selected, as it kills the framerate.
00437         LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
00438 
00439         if( canAffectSelection() )
00440         {
00441                 LLMatrix4 transform;
00442                 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
00443                 {
00444                         LLVector4 translation(bbox.getPositionAgent());
00445                         transform.initRotTrans(bbox.getRotation(), translation);
00446                         LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
00447                         transform *= cfr;
00448                         LLMatrix4 window_scale;
00449                         F32 zoom_level = 2.f * gAgent.getAvatarObject()->mHUDCurZoom;
00450                         window_scale.initAll(LLVector3(zoom_level / LLViewerCamera::getInstance()->getAspect(), zoom_level, 0.f),
00451                                 LLQuaternion::DEFAULT,
00452                                 LLVector3::zero);
00453                         transform *= window_scale;
00454                 }
00455                 else
00456                 {
00457                         LLMatrix4 projMatrix = LLViewerCamera::getInstance()->getProjection();
00458                         LLMatrix4 modelView = LLViewerCamera::getInstance()->getModelview();
00459                         transform.initAll(LLVector3(1.f, 1.f, 1.f), bbox.getRotation(), bbox.getPositionAgent());
00460                         
00461                         transform *= modelView;
00462                         transform *= projMatrix;
00463                 }
00464 
00465                 LLVector3 min = bbox.getMinLocal();
00466                 LLVector3 max = bbox.getMaxLocal();
00467                 LLVector3 ctr = bbox.getCenterLocal();
00468 
00469                 S32 numManips = 0;
00470                 // corners
00471                 mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], min.mV[VY], min.mV[VZ], 1.f);
00472                 mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], min.mV[VY], max.mV[VZ], 1.f);
00473                 mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], max.mV[VY], min.mV[VZ], 1.f);
00474                 mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], max.mV[VY], max.mV[VZ], 1.f);
00475                 mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], min.mV[VY], min.mV[VZ], 1.f);
00476                 mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], min.mV[VY], max.mV[VZ], 1.f);
00477                 mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], max.mV[VY], min.mV[VZ], 1.f);
00478                 mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], max.mV[VY], max.mV[VZ], 1.f);
00479                 
00480                 // 1-D highlights are applicable iff one object is selected
00481                 if( mObjectSelection->getObjectCount() == 1 )
00482                 {
00483                         // face centers
00484                         mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], ctr.mV[VY], max.mV[VZ], 1.f);
00485                         mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], ctr.mV[VY], ctr.mV[VZ], 1.f);
00486                         mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], max.mV[VY], ctr.mV[VZ], 1.f);
00487                         mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], ctr.mV[VY], ctr.mV[VZ], 1.f);
00488                         mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], min.mV[VY], ctr.mV[VZ], 1.f);
00489                         mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], ctr.mV[VY], min.mV[VZ], 1.f);
00490                 }
00491 
00492                 for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(), DeletePointer());
00493                 mProjectedManipulators.clear();
00494                 
00495                 for (S32 i = 0; i < numManips; i++)
00496                 {
00497                         LLVector4 projectedVertex = mManipulatorVertices[i] * transform;
00498                         projectedVertex = projectedVertex * (1.f / projectedVertex.mV[VW]);
00499 
00500                         ManipulatorHandle* projManipulator = new ManipulatorHandle(LLVector3(projectedVertex.mV[VX], projectedVertex.mV[VY], 
00501                                 projectedVertex.mV[VZ]), MANIPULATOR_IDS[i], (i < 7) ? SCALE_MANIP_CORNER : SCALE_MANIP_FACE);
00502                         mProjectedManipulators.insert(projManipulator);
00503                 }
00504 
00505                 F32 half_width = (F32)gViewerWindow->getWindowWidth() / 2.f;
00506                 F32 half_height = (F32)gViewerWindow->getWindowHeight() / 2.f;
00507                 LLVector2 manip2d;
00508                 LLVector2 mousePos((F32)x - half_width, (F32)y - half_height);
00509                 LLVector2 delta;
00510 
00511                 mHighlightedPart = LL_NO_PART;
00512 
00513                 for (minpulator_list_t::iterator iter = mProjectedManipulators.begin();
00514                          iter != mProjectedManipulators.end(); ++iter)
00515                 {
00516                         ManipulatorHandle* manipulator = *iter;
00517                         {
00518                                 manip2d.setVec(manipulator->mPosition.mV[VX] * half_width, manipulator->mPosition.mV[VY] * half_height);
00519                                 
00520                                 delta = manip2d - mousePos;
00521                                 if (delta.magVecSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED)
00522                                 {
00523                                         mHighlightedPart = manipulator->mManipID;
00524 
00525                                         //llinfos << "Tried: " << mHighlightedPart << llendl;
00526                                         break;
00527                                 }
00528                         }
00529                 }
00530         }
00531 
00532         for (S32 i = 0; i < NUM_MANIPULATORS; i++)
00533         {
00534                 if (mHighlightedPart == MANIPULATOR_IDS[i])
00535                 {
00536                         mManipulatorScales[i] = lerp(mManipulatorScales[i], SELECTED_MANIPULATOR_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00537                 }
00538                 else
00539                 {
00540                         mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
00541                 }
00542         }
00543 
00544         lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (inactive)" << llendl;
00545 }
00546 
00547 
00548 void LLManipScale::renderFaces( const LLBBox& bbox )
00549 {
00550         // Don't bother to render the drag handles for 1-D scaling if 
00551         // more than one object is selected or if it is an attachment
00552         if ( mObjectSelection->getObjectCount() > 1 )
00553         {
00554                 return;
00555         }
00556 
00557     // This is a flattened representation of the box as render here
00558     //                                       .
00559     //              (+++)        (++-)      /|\t
00560     //                +------------+         | (texture coordinates)
00561     //                |            |         |
00562     //                |     1      |        (*) --->s
00563     //                |    +X      |   
00564         //                |            |
00565     // (+++)     (+-+)|            |(+--)     (++-)        (+++)
00566     //   +------------+------------+------------+------------+
00567     //   |0          3|3          7|7          4|4          0|
00568     //   |     0      |     4      |     5      |     2      |
00569     //   |    +Z      |    -Y      |    -Z      |    +Y      |
00570     //   |                |            |            |            |
00571     //   |1          2|2          6|6          5|5          1|
00572     //   +------------+------------+------------+------------+
00573     // (-++)     (--+)|            |(---)     (-+-)        (-++)
00574     //                |     3      |
00575     //                |    -X      |
00576     //                |            |
00577     //                |            |
00578     //                +------------+
00579     //              (-++)        (-+-)
00580 
00581         LLColor4 highlight_color( 1.f, 1.f, 1.f, 0.5f);
00582         LLColor4 normal_color(  1.f, 1.f, 1.f, 0.3f);
00583 
00584         LLColor4 x_highlight_color( 1.f, 0.2f, 0.2f, 1.0f);
00585         LLColor4 x_normal_color(        0.6f, 0.f, 0.f, 0.4f);
00586 
00587         LLColor4 y_highlight_color( 0.2f, 1.f, 0.2f, 1.0f);
00588         LLColor4 y_normal_color(        0.f, 0.6f, 0.f, 0.4f);
00589 
00590         LLColor4 z_highlight_color( 0.2f, 0.2f, 1.f, 1.0f);
00591         LLColor4 z_normal_color(        0.f, 0.f, 0.6f, 0.4f);
00592 
00593         LLColor4 default_normal_color( 0.7f, 0.7f, 0.7f, 0.15f );
00594 
00595         const LLVector3& min = bbox.getMinLocal();
00596         const LLVector3& max = bbox.getMaxLocal();
00597         LLVector3 ctr = bbox.getCenterLocal();
00598 
00599         if (mManipPart == LL_NO_PART)
00600         {
00601                 gGL.color4fv( default_normal_color.mV );
00602                 LLGLDepthTest gls_depth(GL_FALSE);
00603                 gGL.begin(LLVertexBuffer::QUADS); 
00604                 {
00605                         // Face 0
00606                         gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
00607                         gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
00608                         gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
00609                         gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
00610 
00611                         // Face 1
00612                         gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
00613                         gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
00614                         gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
00615                         gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
00616 
00617                         // Face 2
00618                         gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
00619                         gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
00620                         gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
00621                         gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
00622 
00623                         // Face 3
00624                         gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
00625                         gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
00626                         gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
00627                         gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
00628 
00629                         // Face 4
00630                         gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
00631                         gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
00632                         gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
00633                         gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
00634 
00635                         // Face 5
00636                         gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
00637                         gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
00638                         gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
00639                         gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
00640                 }
00641                 gGL.end();
00642         }
00643 
00644         // Find nearest vertex
00645         LLVector3 orientWRTHead = bbox.agentToLocalBasis( bbox.getCenterAgent() - gAgent.getCameraPositionAgent() );
00646         U32 nearest = 
00647                 (orientWRTHead.mV[0] < 0.0f ? 1 : 0) + 
00648                 (orientWRTHead.mV[1] < 0.0f ? 2 : 0) + 
00649                 (orientWRTHead.mV[2] < 0.0f ? 4 : 0);
00650 
00651         // opposite faces on Linden cubes:
00652         // 0 & 5
00653         // 1 & 3
00654         // 2 & 4
00655 
00656         // Table of order to draw faces, based on nearest vertex
00657         static U32 face_list[8][6] = { 
00658                 { 2,0,1, 4,5,3 }, // v6  F201 F453
00659                 { 2,0,3, 4,5,1 }, // v7  F203 F451
00660                 { 4,0,1, 2,5,3 }, // v5  F401 F253
00661                 { 4,0,3, 2,5,1 }, // v4  F403 F251
00662                 { 2,5,1, 4,0,3 }, // v2  F251 F403
00663                 { 2,5,3, 4,0,1 }, // v3  F253 F401
00664                 { 4,5,1, 2,0,3 }, // v1  F451 F203
00665                 { 4,5,3, 2,0,1 }  // v0  F453 F201
00666         };
00667 
00668         {
00669                 LLGLDepthTest gls_depth(GL_FALSE);
00670 
00671                 for (S32 i = 0; i < 6; i++)
00672                 {
00673                         U32 face = face_list[nearest][i];
00674                         switch( face )
00675                         {
00676                           case 0:
00677                                 conditionalHighlight( LL_FACE_POSZ, &z_highlight_color, &z_normal_color );
00678                                 renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) );
00679                                 break;
00680 
00681                           case 1:
00682                                 conditionalHighlight( LL_FACE_POSX, &x_highlight_color, &x_normal_color );
00683                                 renderAxisHandle( ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) );
00684                                 break;
00685 
00686                           case 2:
00687                                 conditionalHighlight( LL_FACE_POSY, &y_highlight_color, &y_normal_color );
00688                                 renderAxisHandle( ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) );
00689                                 break;
00690 
00691                           case 3:
00692                                 conditionalHighlight( LL_FACE_NEGX, &x_highlight_color, &x_normal_color );
00693                                 renderAxisHandle( ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) );
00694                                 break;
00695 
00696                           case 4:
00697                                 conditionalHighlight( LL_FACE_NEGY, &y_highlight_color, &y_normal_color );
00698                                 renderAxisHandle( ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) );
00699                                 break;
00700 
00701                           case 5:
00702                                 conditionalHighlight( LL_FACE_NEGZ, &z_highlight_color, &z_normal_color );
00703                                 renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) );
00704                                 break;
00705                         }
00706                 }
00707         }
00708 }
00709 
00710 void LLManipScale::renderEdges( const LLBBox& bbox )
00711 {
00712         LLVector3 extent = bbox.getExtentLocal();
00713         F32 edge_width = mBoxHandleSize * .6f;
00714 
00715         for( U32 part = LL_EDGE_MIN; part <= LL_EDGE_MAX; part++ )
00716         {
00717                 LLVector3 direction = edgeToUnitVector( part );
00718                 LLVector3 center_to_edge = unitVectorToLocalBBoxExtent( direction, bbox );
00719 
00720                 glPushMatrix();
00721                 {
00722                         glTranslatef( center_to_edge.mV[0], center_to_edge.mV[1], center_to_edge.mV[2] );
00723                         conditionalHighlight( part );
00724                         glScalef( 
00725                                 direction.mV[0] ? edge_width : extent.mV[VX],
00726                                 direction.mV[1] ? edge_width : extent.mV[VY],
00727                                 direction.mV[2] ? edge_width : extent.mV[VZ] );
00728                         gBox.render();
00729                 }
00730                 glPopMatrix();
00731         }
00732 }
00733 
00734 
00735 void LLManipScale::renderCorners( const LLBBox& bbox )
00736 {
00737         U32 part = LL_CORNER_NNN;
00738 
00739         F32 x_offset = bbox.getMinLocal().mV[VX];
00740         for( S32 i=0; i < 2; i++ )
00741         {
00742                 F32 y_offset = bbox.getMinLocal().mV[VY];
00743                 for( S32 j=0; j < 2; j++ )
00744                 {
00745                         F32 z_offset = bbox.getMinLocal().mV[VZ];
00746                         for( S32 k=0; k < 2; k++ )
00747                         {
00748                                 conditionalHighlight( part );
00749                                 renderBoxHandle( x_offset, y_offset, z_offset );
00750                                 part++;
00751 
00752                                 z_offset = bbox.getMaxLocal().mV[VZ];
00753 
00754                         }
00755                         y_offset = bbox.getMaxLocal().mV[VY];
00756                 }
00757                 x_offset = bbox.getMaxLocal().mV[VX];
00758   }
00759 }
00760 
00761 
00762 void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z )
00763 {
00764         LLImageGL::unbindTexture(0);
00765         LLGLDepthTest gls_depth(GL_FALSE);
00766 
00767         glPushMatrix();
00768         {
00769                 glTranslatef( x, y, z );
00770                 glScalef( mScaledBoxHandleSize, mScaledBoxHandleSize, mScaledBoxHandleSize );
00771                 gBox.render();
00772         }
00773         glPopMatrix();
00774 }
00775 
00776 
00777 void LLManipScale::renderAxisHandle( const LLVector3& start, const LLVector3& end )
00778 {
00779         if( getShowAxes() )
00780         {
00781                 // Draws a single "jacks" style handle: a long, retangular box from start to end.
00782                 LLVector3 offset_start = end - start;
00783                 offset_start.normVec();
00784                 offset_start = start + mBoxHandleSize * offset_start;
00785 
00786                 LLVector3 delta = end - offset_start;
00787                 LLVector3 pos = offset_start + 0.5f * delta;
00788 
00789                 glPushMatrix();
00790                 {
00791                         glTranslatef( pos.mV[VX], pos.mV[VY], pos.mV[VZ] );
00792                         glScalef( 
00793                                 mBoxHandleSize + llabs(delta.mV[VX]),
00794                                 mBoxHandleSize + llabs(delta.mV[VY]),
00795                                 mBoxHandleSize + llabs(delta.mV[VZ]));
00796                         gBox.render();
00797                 }
00798                 glPopMatrix();
00799         }
00800         else
00801         {
00802                 renderBoxHandle( end.mV[VX], end.mV[VY], end.mV[VZ] );
00803         }
00804 }
00805 
00806 
00807 void LLManipScale::drag( S32 x, S32 y )
00808 {
00809         if( (LL_FACE_MIN <= (S32)mManipPart) 
00810                 && ((S32)mManipPart <= LL_FACE_MAX) )
00811         {
00812                 dragFace( x, y );
00813         }
00814         else
00815         if( (LL_CORNER_MIN <= (S32)mManipPart) 
00816                 && ((S32)mManipPart <= LL_CORNER_MAX) )
00817         {
00818                 dragCorner( x, y );
00819         }
00820         
00821         // store changes to override updates
00822         for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
00823                  iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
00824         {
00825                 LLSelectNode* selectNode = *iter;
00826                 LLViewerObject*cur = selectNode->getObject();
00827                 if( cur->permModify() && cur->permMove() && !cur->isAvatar())
00828                 {
00829                         selectNode->mLastScale = cur->getScale();
00830                         selectNode->mLastPositionLocal = cur->getPosition();
00831                 }
00832         }       
00833 
00834         LLSelectMgr::getInstance()->updateSelectionCenter();
00835     gAgent.clearFocusObject();
00836 }
00837 
00838 // Scale around the 
00839 void LLManipScale::dragCorner( S32 x, S32 y )
00840 {
00841         LLBBox bbox     = LLSelectMgr::getInstance()->getBBoxOfSelection();
00842 
00843         // Suppress scale if mouse hasn't moved.
00844         if (x == mLastMouseX && y == mLastMouseY)
00845         {
00846         //      sendUpdates(TRUE,TRUE,TRUE);
00847                 return;
00848         }
00849 
00850         mLastMouseX = x;
00851         mLastMouseY = y;
00852 
00853         LLVector3d drag_start_point_global      = mDragStartPointGlobal;
00854         LLVector3d drag_start_center_global = mDragStartCenterGlobal;
00855         LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global);
00856         LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global);
00857 
00858         LLVector3d drag_start_dir_d;
00859         drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global);
00860         LLVector3 drag_start_dir_f;
00861         drag_start_dir_f.setVec(drag_start_dir_d);
00862 
00863         F32 s = 0;
00864         F32 t = 0;
00865 
00866         nearestPointOnLineFromMouse(x, y, 
00867                                                 drag_start_center_agent,
00868                                                 drag_start_point_agent,
00869                                                 s, t );
00870 
00871         F32 drag_start_dist = dist_vec(drag_start_point_agent, drag_start_center_agent);
00872 
00873         if( s <= 0 )  // we only care about intersections in front of the camera
00874         {
00875                 return;
00876         }
00877 
00878         LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d;
00879 
00880         F32 scale_factor = t;
00881 
00882         BOOL uniform = LLManipScale::getUniform();
00883 
00884         if( !uniform )
00885         {
00886                 scale_factor = 0.5f + (scale_factor * 0.5f);
00887         }
00888 
00889         // check for snapping
00890         LLVector3 drag_center_agent = gAgent.getPosAgentFromGlobal(drag_point_global);
00891         LLVector3 mouse_on_plane1;
00892         getMousePointOnPlaneAgent(mouse_on_plane1, x, y, drag_center_agent, mScalePlaneNormal1);
00893         LLVector3 mouse_on_plane2;
00894         getMousePointOnPlaneAgent(mouse_on_plane2, x, y, drag_center_agent, mScalePlaneNormal2);
00895         LLVector3 mouse_dir_1 = mouse_on_plane1 - mScaleCenter;
00896         LLVector3 mouse_dir_2 = mouse_on_plane2 - mScaleCenter;
00897         LLVector3 mouse_to_scale_line_1 = mouse_dir_1 - projected_vec(mouse_dir_1, mScaleDir);
00898         LLVector3 mouse_to_scale_line_2 = mouse_dir_2 - projected_vec(mouse_dir_2, mScaleDir);
00899         LLVector3 mouse_to_scale_line_dir_1 = mouse_to_scale_line_1;
00900         mouse_to_scale_line_dir_1.normVec();
00901         if (mouse_to_scale_line_dir_1 * mSnapGuideDir1 < 0.f)
00902         {
00903                 // need to keep sign of mouse offset wrt to snap guide direction
00904                 mouse_to_scale_line_dir_1 *= -1.f;
00905         }
00906         LLVector3 mouse_to_scale_line_dir_2 = mouse_to_scale_line_2;
00907         mouse_to_scale_line_dir_2.normVec();
00908         if (mouse_to_scale_line_dir_2 * mSnapGuideDir2 < 0.f)
00909         {
00910                 // need to keep sign of mouse offset wrt to snap guide direction
00911                 mouse_to_scale_line_dir_2 *= -1.f;
00912         }
00913 
00914         F32 snap_dir_dot_mouse_offset1 = mSnapGuideDir1 * mouse_to_scale_line_dir_1;
00915         F32 snap_dir_dot_mouse_offset2 = mSnapGuideDir2 * mouse_to_scale_line_dir_2;
00916 
00917         F32 dist_from_scale_line_1 = mouse_to_scale_line_1 * mouse_to_scale_line_dir_1; 
00918         F32 dist_from_scale_line_2 = mouse_to_scale_line_2 * mouse_to_scale_line_dir_2;
00919 
00920         F32 max_scale = partToMaxScale(mManipPart, bbox);
00921         F32 min_scale = partToMinScale(mManipPart, bbox);
00922 
00923         BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled");
00924         if (snap_enabled && dist_from_scale_line_1 > mSnapRegimeOffset * snap_dir_dot_mouse_offset1)
00925         {
00926                 mInSnapRegime = TRUE;
00927                 LLVector3 projected_drag_pos = mouse_on_plane1 - (dist_from_scale_line_1 / snap_dir_dot_mouse_offset1) * mSnapGuideDir1;
00928                 F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir;
00929 
00930                 F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
00931                 F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
00932                 F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions);
00933 
00934                 mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale);
00935 
00936                 scale_factor = mScaleSnapValue / drag_start_dist;
00937                 if( !uniform )
00938                 {
00939                         scale_factor *= 0.5f;
00940                 }
00941         }
00942         else if (snap_enabled && dist_from_scale_line_2 > mSnapRegimeOffset * snap_dir_dot_mouse_offset2)
00943         {
00944                 mInSnapRegime = TRUE;
00945                 LLVector3 projected_drag_pos = mouse_on_plane2 - (dist_from_scale_line_2 / snap_dir_dot_mouse_offset2) * mSnapGuideDir2;
00946                 F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir;
00947 
00948                 F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
00949                 F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions);
00950                 F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit2 / cur_subdivisions);
00951 
00952                 mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale);
00953 
00954                 scale_factor = mScaleSnapValue / drag_start_dist;
00955                 if( !uniform )
00956                 {
00957                         scale_factor *= 0.5f;
00958                 }
00959         }
00960         else 
00961         {
00962                 mInSnapRegime = FALSE;
00963         }
00964 
00965         F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE / MIN_PRIM_SCALE;
00966         F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE;
00967 
00968         // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale
00969         for (LLObjectSelection::iterator iter = mObjectSelection->begin();
00970                  iter != mObjectSelection->end(); iter++)
00971         {
00972                 LLSelectNode* selectNode = *iter;
00973                 LLViewerObject* cur = selectNode->getObject();
00974                 if(  cur->permModify() && cur->permMove() && !cur->isAvatar() )
00975                 {
00976                         const LLVector3& scale = selectNode->mSavedScale;
00977 
00978                         F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE / scale.mV[VZ] );
00979                         max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor );
00980 
00981                         F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] );
00982                         min_scale_factor = llmax( min_scale_factor, cur_min_scale_factor );
00983                 }
00984         }
00985 
00986         scale_factor = llclamp( scale_factor, min_scale_factor, max_scale_factor );
00987 
00988         LLVector3d drag_global = uniform ? mDragStartCenterGlobal : mDragFarHitGlobal;
00989 
00990         // do the root objects i.e. (TRUE == cur->isRootEdit())
00991         for (LLObjectSelection::iterator iter = mObjectSelection->begin();
00992                  iter != mObjectSelection->end(); iter++)
00993         {
00994                 LLSelectNode* selectNode = *iter;
00995                 LLViewerObject* cur = selectNode->getObject();
00996                 if( cur->permModify() && cur->permMove() && !cur->isAvatar() && cur->isRootEdit() )
00997                 {
00998                         const LLVector3& scale = selectNode->mSavedScale;
00999                         cur->setScale( scale_factor * scale );
01000                         
01001                         LLVector3 delta_pos;
01002                         LLVector3 original_pos = cur->getPositionEdit();
01003                         LLVector3d new_pos_global = drag_global + (selectNode->mSavedPositionGlobal - drag_global) * scale_factor;
01004                         if (!cur->isAttachment())
01005                         {
01006                                 new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
01007                         }
01008                         cur->setPositionAbsoluteGlobal( new_pos_global );
01009                         rebuild(cur);
01010                         
01011                         delta_pos = cur->getPositionEdit() - original_pos;
01012 
01013                         if (selectNode->mIndividualSelection)
01014                         {
01015                                 // counter-translate child objects if we are moving the root as an individual
01016                                 for (U32 child_num = 0; child_num < cur->mChildList.size(); child_num++)
01017                                 {
01018                                         LLViewerObject* childp = cur->mChildList[child_num];
01019 
01020                                         if (cur->isAttachment())
01021                                         {
01022                                                 LLVector3 child_pos = childp->getPosition() - (delta_pos * ~cur->getRotationEdit());
01023                                                 childp->setPosition(child_pos);
01024                                         }
01025                                         else
01026                                         {
01027                                                 LLVector3d child_pos_delta(delta_pos);
01028                                                 // RN: this updates drawable position instantly
01029                                                 childp->setPositionAbsoluteGlobal(childp->getPositionGlobal() - child_pos_delta);
01030                                         }
01031                                         rebuild(childp);
01032                                 }
01033                         }
01034                 }
01035         }
01036         // do the child objects i.e. (FALSE == cur->isRootEdit())
01037         for (LLObjectSelection::iterator iter = mObjectSelection->begin();
01038                  iter != mObjectSelection->end(); iter++)
01039         {
01040                 LLSelectNode* selectNode = *iter;
01041                 LLViewerObject*cur = selectNode->getObject();
01042                 if( cur->permModify() && cur->permMove() && !cur->isAvatar() && !cur->isRootEdit() )
01043                 {
01044                         const LLVector3& scale = selectNode->mSavedScale;
01045                         cur->setScale( scale_factor * scale, FALSE );
01046                                                         
01047                         if (!selectNode->mIndividualSelection)
01048                         {
01049                                 cur->setPosition(selectNode->mSavedPositionLocal * scale_factor);
01050                         }
01051 
01052                         rebuild(cur);
01053                 }
01054         }
01055 
01056         
01057 
01058         mDragPointGlobal = drag_point_global;
01059 }
01060 
01061         
01062 void LLManipScale::dragFace( S32 x, S32 y )
01063 {
01064         // Suppress scale if mouse hasn't moved.
01065         if (x == mLastMouseX && y == mLastMouseY)
01066         {
01067         //      sendUpdates(TRUE,TRUE,FALSE);
01068                 return;
01069         }
01070 
01071         mLastMouseX = x;
01072         mLastMouseY = y;
01073 
01074         LLVector3d drag_start_point_global      = mDragStartPointGlobal;
01075         LLVector3d drag_start_center_global = mDragStartCenterGlobal;
01076         LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global);
01077         LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global);
01078 
01079         LLVector3d drag_start_dir_d;
01080         drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global);
01081         LLVector3 drag_start_dir_f;
01082         drag_start_dir_f.setVec(drag_start_dir_d);
01083 
01084         LLBBox bbox     = LLSelectMgr::getInstance()->getBBoxOfSelection();
01085 
01086         F32 s = 0;
01087         F32 t = 0;
01088 
01089         nearestPointOnLineFromMouse(x,
01090                                                 y,
01091                                                 drag_start_center_agent,
01092                                                 drag_start_point_agent,
01093                                                 s, t );
01094 
01095         if( s <= 0 )  // we only care about intersections in front of the camera
01096         {
01097                 return;
01098         }
01099 
01100         LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d;
01101         LLVector3 part_dir_local        = partToUnitVector( mManipPart );
01102 
01103         // check for snapping
01104         LLVector3 mouse_on_plane;
01105         getMousePointOnPlaneAgent(mouse_on_plane, x, y, mScaleCenter, mScalePlaneNormal1 );
01106 
01107         LLVector3 mouse_on_scale_line = mScaleCenter + projected_vec(mouse_on_plane - mScaleCenter, mScaleDir);
01108         LLVector3 drag_delta(mouse_on_scale_line - drag_start_point_agent);
01109         F32 max_drag_dist = partToMaxScale(mManipPart, bbox);
01110         F32 min_drag_dist = partToMinScale(mManipPart, bbox);
01111 
01112         BOOL uniform = LLManipScale::getUniform();
01113         if( uniform )
01114         {
01115                 drag_delta *= 2.f;
01116         }
01117 
01118         LLVector3 scale_center_to_mouse = mouse_on_plane - mScaleCenter;
01119         F32 dist_from_scale_line = dist_vec(scale_center_to_mouse, (mouse_on_scale_line - mScaleCenter));
01120         F32 dist_along_scale_line = scale_center_to_mouse * mScaleDir;
01121 
01122         BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled");
01123 
01124         if (snap_enabled && dist_from_scale_line > mSnapRegimeOffset)
01125         {
01126                 mInSnapRegime = TRUE;
01127 
01128                 if (dist_along_scale_line > max_drag_dist)
01129                 {
01130                         mScaleSnapValue = max_drag_dist;
01131 
01132                         LLVector3 clamp_point = mScaleCenter + max_drag_dist * mScaleDir;
01133                         drag_delta.setVec(clamp_point - drag_start_point_agent);
01134                 }
01135                 else if (dist_along_scale_line < min_drag_dist)
01136                 {
01137                         mScaleSnapValue = min_drag_dist;
01138 
01139                         LLVector3 clamp_point = mScaleCenter + min_drag_dist * mScaleDir;
01140                         drag_delta.setVec(clamp_point - drag_start_point_agent);
01141                 }
01142                 else
01143                 {
01144                         F32 drag_dist = scale_center_to_mouse * mScaleDir;
01145                         F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + mScaleDir * drag_dist, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
01146                         F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
01147                         F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions);
01148                         relative_snap_dist -= snap_dist;
01149 
01150                         //make sure that values that the scale is "snapped to"
01151                         //do not exceed/go under the applicable max/mins
01152                         //this causes the box to shift displacements ever so slightly
01153                         //although the "snap value" should go down to 0
01154                         //see Jira 1027
01155                         relative_snap_dist = llclamp(relative_snap_dist,
01156                                                                                  drag_dist - max_drag_dist,
01157                                                                                  drag_dist - min_drag_dist);
01158 
01159                         mScaleSnapValue = drag_dist - relative_snap_dist;
01160 
01161                         if (llabs(relative_snap_dist) < snap_dist)
01162                         {
01163                                 LLVector3 drag_correction = relative_snap_dist * mScaleDir;
01164                                 if (uniform)
01165                                 {
01166                                         drag_correction *= 2.f;
01167                                 }
01168 
01169                                 drag_delta -= drag_correction;
01170                         }
01171                 }
01172         }
01173         else 
01174         {
01175                 mInSnapRegime = FALSE;
01176         }
01177 
01178         BOOL send_scale_update = FALSE;
01179         BOOL send_position_update = FALSE;
01180 
01181         LLVector3 dir_agent;
01182         if( part_dir_local.mV[VX] )
01183         {
01184                 dir_agent = bbox.localToAgentBasis( LLVector3::x_axis );
01185         }
01186         else if( part_dir_local.mV[VY] )
01187         {
01188                 dir_agent = bbox.localToAgentBasis( LLVector3::y_axis );
01189         }
01190         else if( part_dir_local.mV[VZ] )
01191         {
01192                 dir_agent = bbox.localToAgentBasis( LLVector3::z_axis );
01193         }
01194         stretchFace( 
01195                 projected_vec(drag_start_dir_f, dir_agent) + drag_start_center_agent,
01196                 projected_vec(drag_delta, dir_agent));
01197         send_position_update = TRUE;
01198         send_scale_update = TRUE;
01199 
01200         mDragPointGlobal = drag_point_global;
01201 }
01202 
01203 void LLManipScale::sendUpdates( BOOL send_position_update, BOOL send_scale_update, BOOL corner )
01204 {
01205         // Throttle updates to 10 per second.
01206         static LLTimer  update_timer;
01207         F32 elapsed_time = update_timer.getElapsedTimeF32();
01208         const F32 UPDATE_DELAY = 0.1f;                                          //  min time between transmitted updates
01209 
01210         if( send_scale_update || send_position_update )
01211         {
01212                 U32 update_flags = UPD_NONE;
01213                 if (send_position_update)       update_flags |= UPD_POSITION;
01214                 if (send_scale_update)          update_flags |= UPD_SCALE;
01215                 
01216 //              BOOL send_type = SEND_INDIVIDUALS;
01217                 if (corner)
01218                 {
01219                         update_flags |= UPD_UNIFORM;
01220                 }
01221                 // keep this up to date for sendonmouseup
01222                 mLastUpdateFlags = update_flags;
01223 
01224                 // enforce minimum update delay and don't stream updates on sub-object selections
01225                 if( elapsed_time > UPDATE_DELAY && !gSavedSettings.getBOOL("EditLinkedParts") )
01226                 {
01227                         LLSelectMgr::getInstance()->sendMultipleUpdate( update_flags );
01228                         update_timer.reset();
01229                         mSendUpdateOnMouseUp = FALSE;
01230                 }
01231                 else
01232                 {
01233                         mSendUpdateOnMouseUp = TRUE;
01234                 }
01235                 dialog_refresh_all();
01236         }
01237 }
01238 
01239 // Rescales in a single dimension.  Either uniform (standard) or one-sided (scale plus translation)
01240 // depending on mUniform.  Handles multiple selection and objects that are not aligned to the bounding box.
01241 void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVector3& drag_delta_agent )
01242 {
01243         LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal);
01244 
01245         for (LLObjectSelection::iterator iter = mObjectSelection->begin();
01246                  iter != mObjectSelection->end(); iter++)
01247         {
01248                 LLSelectNode* selectNode = *iter;
01249                 LLViewerObject*cur = selectNode->getObject();
01250                 if( cur->permModify() && cur->permMove() && !cur->isAvatar() )
01251                 {
01252                         LLBBox cur_bbox                 = cur->getBoundingBoxAgent();
01253                         LLVector3 start_local   = cur_bbox.agentToLocal( drag_start_agent );
01254                         LLVector3 end_local             = cur_bbox.agentToLocal( drag_start_agent + drag_delta_agent);
01255                         LLVector3 start_center_local = cur_bbox.agentToLocal( drag_start_center_agent );
01256                         LLVector3 axis                  = nearestAxis( start_local - start_center_local );
01257                         S32 axis_index                  = axis.mV[0] ? 0 : (axis.mV[1] ? 1 : 2 );
01258 
01259                         LLVector3 delta_local   = end_local - start_local;
01260                         F32 delta_local_mag             = delta_local.magVec();
01261                         LLVector3 dir_local;
01262                         if (delta_local_mag == 0.f)
01263                         {
01264                                 dir_local = axis;
01265                         }
01266                         else
01267                         {
01268                                 dir_local = delta_local / delta_local_mag; // normalized delta_local
01269                         }
01270 
01271                         F32 denom = axis * dir_local;
01272                         F32 desired_delta_size  = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom);  // in meters
01273                         F32 desired_scale               = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
01274                         // propagate scale constraint back to position offset
01275                         desired_delta_size              = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position
01276 
01277                         LLVector3 scale                 = cur->getScale();
01278                         scale.mV[axis_index]    = desired_scale;
01279                         cur->setScale(scale, FALSE);
01280                         rebuild(cur);                           
01281                         LLVector3 delta_pos;
01282                         if( !getUniform() )
01283                         {
01284                                 LLVector3 delta_pos_local = axis * (0.5f * desired_delta_size);
01285                                 LLVector3d delta_pos_global;
01286                                 delta_pos_global.setVec(cur_bbox.localToAgent( delta_pos_local ) - cur_bbox.getCenterAgent());
01287                                 LLVector3 cur_pos = cur->getPositionEdit();
01288 
01289                                 if (cur->isRootEdit() && !cur->isAttachment())
01290                                 {
01291                                         LLVector3d new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, selectNode->mSavedPositionGlobal + delta_pos_global);
01292                                         cur->setPositionGlobal( new_pos_global );
01293                                 }
01294                                 else
01295                                 {
01296                                         LLXform* parent_xform = cur->mDrawable->getXform()->getParent();
01297                                         LLVector3 new_pos_local;
01298                                         // this works in attachment point space using world space delta
01299                                         if (parent_xform)
01300                                         {
01301                                                 new_pos_local = selectNode->mSavedPositionLocal + (LLVector3(delta_pos_global) * ~parent_xform->getWorldRotation());
01302                                         }
01303                                         else
01304                                         {
01305                                                 new_pos_local = selectNode->mSavedPositionLocal + LLVector3(delta_pos_global);
01306                                         }
01307                                         cur->setPosition(new_pos_local);
01308                                 }
01309                                 delta_pos = cur->getPositionEdit() - cur_pos;
01310                         }
01311                         if (cur->isRootEdit() && selectNode->mIndividualSelection)
01312                         {
01313                                 // counter-translate child objects if we are moving the root as an individual
01314                                 for (U32 child_num = 0; child_num < cur->mChildList.size(); child_num++)
01315                                 {
01316                                         LLViewerObject* childp = cur->mChildList[child_num];
01317                                         if (!getUniform())
01318                                         {
01319                                                 LLVector3 child_pos = childp->getPosition() - (delta_pos * ~cur->getRotationEdit());
01320                                                 childp->setPosition(child_pos);
01321                                                 rebuild(childp);
01322                                         }
01323                                 }
01324                         }
01325                 }
01326         }
01327 }
01328 
01329 
01330 void LLManipScale::renderGuidelinesPart( const LLBBox& bbox )
01331 {
01332         LLVector3 guideline_start = bbox.getCenterLocal();
01333         
01334         LLVector3 guideline_end = unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox );
01335 
01336         if (!getUniform())
01337         {
01338                 guideline_start = unitVectorToLocalBBoxExtent( -partToUnitVector( mManipPart ), bbox );
01339         }
01340 
01341         guideline_end -= guideline_start;
01342         guideline_end.normVec();
01343         guideline_end *= LLWorld::getInstance()->getRegionWidthInMeters();
01344         guideline_end += guideline_start;
01345 
01346         {
01347                 LLGLDepthTest gls_depth(GL_TRUE);
01348                 gl_stippled_line_3d( guideline_start, guideline_end, LLColor4(1.f, 1.f, 1.f, 0.5f) );
01349         }
01350         {
01351                 LLGLDepthTest gls_depth(GL_FALSE);
01352                 gl_stippled_line_3d( guideline_start, guideline_end, LLColor4(1.f, 1.f, 1.f, 0.25f) );
01353         }
01354 }
01355 
01356 void LLManipScale::updateSnapGuides(const LLBBox& bbox)
01357 {
01358         LLVector3 grid_origin;
01359         LLVector3 grid_scale;
01360         LLQuaternion grid_rotation;
01361         LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
01362 
01363         LLVector3 box_corner_agent = bbox.localToAgent(unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox ));
01364         mScaleCenter = getUniform() ? bbox.getCenterAgent() : bbox.localToAgent(unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox ));
01365         mScaleDir = box_corner_agent - mScaleCenter;
01366         mScaleDir.normVec();
01367 
01368         if(mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01369         {
01370                 mSnapRegimeOffset = SNAP_GUIDE_SCREEN_OFFSET / gAgent.getAvatarObject()->mHUDCurZoom;
01371 
01372         }
01373         else
01374         {
01375                 F32 object_distance = dist_vec(mScaleCenter, LLViewerCamera::getInstance()->getOrigin());
01376                 mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET * gViewerWindow->getWindowWidth() * object_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio();
01377         }
01378         LLVector3 cam_at_axis;
01379         F32 snap_guide_length;
01380         if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01381         {
01382                 cam_at_axis.setVec(1.f, 0.f, 0.f);
01383                 snap_guide_length = SNAP_GUIDE_SCREEN_LENGTH / gAgent.getAvatarObject()->mHUDCurZoom;
01384         }
01385         else
01386         {
01387                 cam_at_axis = LLViewerCamera::getInstance()->getAtAxis();
01388                 F32 manipulator_distance = dist_vec(box_corner_agent, LLViewerCamera::getInstance()->getOrigin());
01389                 snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH * gViewerWindow->getWindowWidth() * manipulator_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio();
01390         }
01391         
01392         mSnapGuideLength = snap_guide_length / llmax(0.1f, (llmin(mSnapGuideDir1 * cam_at_axis, mSnapGuideDir2 * cam_at_axis)));
01393 
01394         LLVector3 off_axis_dir = mScaleDir % cam_at_axis;
01395         off_axis_dir.normVec();
01396 
01397         if( (LL_FACE_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_FACE_MAX) )
01398         {
01399                 LLVector3 object_scale = bbox.getMaxLocal();
01400                 object_scale.scaleVec(off_axis_dir * ~bbox.getRotation());
01401                 object_scale.abs();
01402                 if (object_scale.mV[VX] > object_scale.mV[VY] && object_scale.mV[VX] > object_scale.mV[VZ])
01403                 {
01404                         mSnapGuideDir1 = LLVector3::x_axis * bbox.getRotation();
01405                 }
01406                 else if (object_scale.mV[VY] > object_scale.mV[VZ])
01407                 {
01408                         mSnapGuideDir1 = LLVector3::y_axis * bbox.getRotation();
01409                 }
01410                 else
01411                 {
01412                         mSnapGuideDir1 = LLVector3::z_axis * bbox.getRotation();
01413                 }
01414 
01415                 LLVector3 scale_snap = grid_scale;
01416                 mScaleSnapUnit1 = scale_snap.scaleVec(partToUnitVector( mManipPart )).magVec();
01417                 mScaleSnapUnit2 = mScaleSnapUnit1;
01418                 mSnapGuideDir1 *= mSnapGuideDir1 * LLViewerCamera::getInstance()->getUpAxis() > 0.f ? 1.f : -1.f;
01419                 mSnapGuideDir2 = mSnapGuideDir1 * -1.f;
01420                 mSnapDir1 = mScaleDir;
01421                 mSnapDir2 = mScaleDir;
01422         }
01423         else if( (LL_CORNER_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_CORNER_MAX) )
01424         {
01425                 LLVector3 local_scale_dir = partToUnitVector( mManipPart );
01426                 LLVector3 local_camera_dir;
01427                 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
01428                 {
01429                         local_camera_dir = LLVector3(-1.f, 0.f, 0.f) * ~bbox.getRotation();
01430                 }
01431                 else
01432                 {
01433                         local_camera_dir = (LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent()) * ~bbox.getRotation();
01434                         local_camera_dir.normVec();
01435                 }
01436                 local_scale_dir -= projected_vec(local_scale_dir, local_camera_dir);
01437                 local_scale_dir.normVec();
01438                 LLVector3 x_axis_proj_camera = LLVector3::x_axis - projected_vec(LLVector3::x_axis, local_camera_dir);
01439                 x_axis_proj_camera.normVec();
01440                 LLVector3 y_axis_proj_camera = LLVector3::y_axis - projected_vec(LLVector3::y_axis, local_camera_dir);
01441                 y_axis_proj_camera.normVec();
01442                 LLVector3 z_axis_proj_camera = LLVector3::z_axis - projected_vec(LLVector3::z_axis, local_camera_dir);
01443                 z_axis_proj_camera.normVec();
01444                 F32 x_axis_proj = llabs(local_scale_dir * x_axis_proj_camera);
01445                 F32 y_axis_proj = llabs(local_scale_dir * y_axis_proj_camera);
01446                 F32 z_axis_proj = llabs(local_scale_dir * z_axis_proj_camera);
01447 
01448                 if (x_axis_proj > y_axis_proj && x_axis_proj > z_axis_proj)
01449                 {
01450                         mSnapGuideDir1 = LLVector3::y_axis;
01451                         mScaleSnapUnit2 = grid_scale.mV[VY];
01452                         mSnapGuideDir2 = LLVector3::z_axis;
01453                         mScaleSnapUnit1 = grid_scale.mV[VZ];
01454                 }
01455                 else if (y_axis_proj > z_axis_proj)
01456                 {
01457                         mSnapGuideDir1 = LLVector3::x_axis;
01458                         mScaleSnapUnit2 = grid_scale.mV[VX];
01459                         mSnapGuideDir2 = LLVector3::z_axis;
01460                         mScaleSnapUnit1 = grid_scale.mV[VZ];
01461                 }
01462                 else
01463                 {
01464                         mSnapGuideDir1 = LLVector3::x_axis;
01465                         mScaleSnapUnit2 = grid_scale.mV[VX];
01466                         mSnapGuideDir2 = LLVector3::y_axis;
01467                         mScaleSnapUnit1 = grid_scale.mV[VY];
01468                 }
01469 
01470                 LLVector3 snap_guide_flip(1.f, 1.f, 1.f);
01471                 switch (mManipPart)
01472                 {
01473                 case LL_CORNER_NNN:
01474                         break;
01475                 case LL_CORNER_NNP:
01476                         snap_guide_flip.setVec(1.f, 1.f, -1.f);
01477                         break;
01478                 case LL_CORNER_NPN:
01479                         snap_guide_flip.setVec(1.f, -1.f, 1.f);
01480                         break;
01481                 case LL_CORNER_NPP:
01482                         snap_guide_flip.setVec(1.f, -1.f, -1.f);
01483                         break;
01484                 case LL_CORNER_PNN:
01485                         snap_guide_flip.setVec(-1.f, 1.f, 1.f);
01486                         break;
01487                 case LL_CORNER_PNP:
01488                         snap_guide_flip.setVec(-1.f, 1.f, -1.f);
01489                         break;
01490                 case LL_CORNER_PPN:
01491                         snap_guide_flip.setVec(-1.f, -1.f, 1.f);
01492                         break;
01493                 case LL_CORNER_PPP:
01494                         snap_guide_flip.setVec(-1.f, -1.f, -1.f);
01495                         break;
01496                 default:
01497                         break;
01498                 }
01499                 mSnapGuideDir1.scaleVec(snap_guide_flip);
01500                 mSnapGuideDir2.scaleVec(snap_guide_flip);
01501                 mSnapGuideDir1.rotVec(bbox.getRotation());
01502                 mSnapGuideDir2.rotVec(bbox.getRotation());
01503                 mSnapDir1 = -1.f * mSnapGuideDir2;
01504                 mSnapDir2 = -1.f * mSnapGuideDir1;
01505         }
01506 
01507         mScalePlaneNormal1 = mSnapGuideDir1 % mScaleDir;
01508         mScalePlaneNormal1.normVec();
01509 
01510         mScalePlaneNormal2 = mSnapGuideDir2 % mScaleDir;
01511         mScalePlaneNormal2.normVec();   
01512 
01513         mScaleSnapUnit1 = mScaleSnapUnit1 / (mSnapDir1 * mScaleDir);
01514         mScaleSnapUnit2 = mScaleSnapUnit2 / (mSnapDir2 * mScaleDir);
01515 }
01516 
01517 void LLManipScale::renderSnapGuides(const LLBBox& bbox)
01518 {
01519         if (!gSavedSettings.getBOOL("SnapEnabled"))
01520         {
01521                 return;
01522         }
01523 
01524         F32 max_subdivisions = sGridMaxSubdivisionLevel;
01525         F32 grid_alpha = gSavedSettings.getF32("GridOpacity");
01526 
01527         F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox);
01528         LLVector3 drag_point = gAgent.getPosAgentFromGlobal(mDragPointGlobal);
01529 
01530         updateGridSettings();
01531 
01532         S32 pass;
01533         for (pass = 0; pass < 3; pass++)
01534         {
01535                 LLColor4 tick_color = setupSnapGuideRenderPass(pass);
01536 
01537                 gGL.begin(LLVertexBuffer::LINES);
01538                 LLVector3 line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir1 * mSnapRegimeOffset);
01539                 LLVector3 line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f)));
01540                 LLVector3 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f));
01541                 
01542                 gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
01543                 gGL.vertex3fv(line_start.mV);
01544                 gGL.color4fv(tick_color.mV);
01545                 gGL.vertex3fv(line_mid.mV);
01546                 gGL.vertex3fv(line_mid.mV);
01547                 gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
01548                 gGL.vertex3fv(line_end.mV);
01549 
01550                 line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir2 * mSnapRegimeOffset);
01551                 line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f)));
01552                 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f));
01553                 gGL.vertex3fv(line_start.mV);
01554                 gGL.color4fv(tick_color.mV);
01555                 gGL.vertex3fv(line_mid.mV);
01556                 gGL.vertex3fv(line_mid.mV);
01557                 gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
01558                 gGL.vertex3fv(line_end.mV);
01559                 gGL.end();
01560         }
01561 
01562         {
01563                 LLGLDepthTest gls_depth(GL_FALSE);
01564 
01565                 F32 dist_grid_axis = (drag_point - mScaleCenter) * mScaleDir;
01566                 // find distance to nearest smallest grid unit
01567                 F32 grid_offset1 = fmodf(dist_grid_axis, mScaleSnapUnit1 / max_subdivisions);
01568                 F32 grid_offset2 = fmodf(dist_grid_axis, mScaleSnapUnit2 / max_subdivisions);
01569 
01570                 // how many smallest grid units are we away from largest grid scale?
01571                 S32 sub_div_offset_1 = llround(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 / sGridMinSubdivisionLevel) / (mScaleSnapUnit1 / max_subdivisions));
01572                 S32 sub_div_offset_2 = llround(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 / sGridMinSubdivisionLevel) / (mScaleSnapUnit2 / max_subdivisions));
01573 
01574                 S32 num_ticks_per_side1 = llmax(1, lltrunc(0.5f * mSnapGuideLength / (mScaleSnapUnit1 / max_subdivisions)));
01575                 S32 num_ticks_per_side2 = llmax(1, lltrunc(0.5f * mSnapGuideLength / (mScaleSnapUnit2 / max_subdivisions)));
01576                 F32 dist_scale_units_1 = dist_grid_axis / (mScaleSnapUnit1 / max_subdivisions);
01577                 F32 dist_scale_units_2 = dist_grid_axis / (mScaleSnapUnit2 / max_subdivisions);
01578                 S32 ticks_from_scale_center_1 = lltrunc(dist_scale_units_1);
01579                 S32 ticks_from_scale_center_2 = lltrunc(dist_scale_units_2);
01580                 S32 max_ticks1 = llceil(max_point_on_scale_line / (mScaleSnapUnit1 / max_subdivisions) - dist_scale_units_1);
01581                 S32 max_ticks2 = llceil(max_point_on_scale_line / (mScaleSnapUnit2 / max_subdivisions) - dist_scale_units_2);
01582                 S32 start_tick = 0;
01583                 S32 stop_tick = 0;
01584 
01585                 if (mInSnapRegime)
01586                 {
01587                         // draw snap guide line
01588                         gGL.begin(LLVertexBuffer::LINES);
01589                         LLVector3 snap_line_center = mScaleCenter + (mScaleSnapValue * mScaleDir);
01590 
01591                         LLVector3 snap_line_start = snap_line_center + (mSnapGuideDir1 * mSnapRegimeOffset);
01592                         LLVector3 snap_line_end = snap_line_center + (mSnapGuideDir2 * mSnapRegimeOffset);
01593 
01594                         gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
01595                         gGL.vertex3fv(snap_line_start.mV);
01596                         gGL.vertex3fv(snap_line_center.mV);
01597                         gGL.vertex3fv(snap_line_center.mV);
01598                         gGL.vertex3fv(snap_line_end.mV);
01599                         gGL.end();
01600 
01601                         // draw snap guide arrow
01602                         gGL.begin(LLVertexBuffer::TRIANGLES);
01603                         {
01604                                 //gGLSNoCullFaces.set();
01605                                 gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
01606 
01607                                 LLVector3 arrow_dir;
01608                                 LLVector3 arrow_span = mScaleDir;
01609 
01610                                 arrow_dir = snap_line_start - snap_line_center;
01611                                 arrow_dir.normVec();
01612                                 gGL.vertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV);
01613                                 gGL.vertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV);
01614                                 gGL.vertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV);
01615 
01616                                 arrow_dir = snap_line_end - snap_line_center;
01617                                 arrow_dir.normVec();
01618                                 gGL.vertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV);
01619                                 gGL.vertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV);
01620                                 gGL.vertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV);
01621                         }
01622                         gGL.end();
01623                 }
01624         
01625                 LLVector2 screen_translate_axis(llabs(mScaleDir * LLViewerCamera::getInstance()->getLeftAxis()), llabs(mScaleDir * LLViewerCamera::getInstance()->getUpAxis()));
01626                 screen_translate_axis.normVec();
01627 
01628                 S32 tick_label_spacing = llround(screen_translate_axis * sTickLabelSpacing);
01629 
01630                 for (pass = 0; pass < 3; pass++)
01631                 {
01632                         LLColor4 tick_color = setupSnapGuideRenderPass(pass);
01633 
01634                         start_tick = -(llmin(ticks_from_scale_center_1, num_ticks_per_side1));
01635                         stop_tick = llmin(max_ticks1, num_ticks_per_side1);
01636 
01637                         gGL.begin(LLVertexBuffer::LINES);
01638                         // draw first row of ticks
01639                         for (S32 i = start_tick; i <= stop_tick; i++)
01640                         {
01641                                 F32 alpha = (1.f - (1.f *  ((F32)llabs(i) / (F32)num_ticks_per_side1)));
01642                                 LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit1 / max_subdivisions * (F32)i - grid_offset1));
01643 
01644                                 F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
01645 
01646                                 if (fmodf((F32)(i + sub_div_offset_1), (max_subdivisions / cur_subdivisions)) != 0.f)
01647                                 {
01648                                         continue;
01649                                 }
01650 
01651                                 F32 tick_scale = 1.f;
01652                                 for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
01653                                 {
01654                                         if (fmodf((F32)(i + sub_div_offset_1), division_level) == 0.f)
01655                                         {
01656                                                 break;
01657                                         }
01658                                         tick_scale *= 0.7f;
01659                                 }
01660 
01661                                 gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha);
01662                                 LLVector3 tick_start = tick_pos + (mSnapGuideDir1 * mSnapRegimeOffset);
01663                                 LLVector3 tick_end = tick_start + (mSnapGuideDir1 * mSnapRegimeOffset * tick_scale);
01664                                 gGL.vertex3fv(tick_start.mV);
01665                                 gGL.vertex3fv(tick_end.mV);
01666                         }
01667 
01668                         // draw opposite row of ticks
01669                         start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2));
01670                         stop_tick = llmin(max_ticks2, num_ticks_per_side2);
01671 
01672                         for (S32 i = start_tick; i <= stop_tick; i++)
01673                         {
01674                                 F32 alpha = (1.f - (1.f *  ((F32)llabs(i) / (F32)num_ticks_per_side2)));
01675                                 LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit2 / max_subdivisions * (F32)i - grid_offset2));
01676 
01677                                 F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
01678 
01679                                 if (fmodf((F32)(i + sub_div_offset_2), (max_subdivisions / cur_subdivisions)) != 0.f)
01680                                 {
01681                                         continue;
01682                                 }
01683 
01684                                 F32 tick_scale = 1.f;
01685                                 for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
01686                                 {
01687                                         if (fmodf((F32)(i + sub_div_offset_2), division_level) == 0.f)
01688                                         {
01689                                                 break;
01690                                         }
01691                                         tick_scale *= 0.7f;
01692                                 }
01693 
01694                                 gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha);
01695                                 LLVector3 tick_start = tick_pos + (mSnapGuideDir2 * mSnapRegimeOffset);
01696                                 LLVector3 tick_end = tick_start + (mSnapGuideDir2 * mSnapRegimeOffset * tick_scale);
01697                                 gGL.vertex3fv(tick_start.mV);
01698                                 gGL.vertex3fv(tick_end.mV);
01699                         }
01700                         gGL.end();
01701                 }
01702 
01703                 // render tick labels
01704                 start_tick = -(llmin(ticks_from_scale_center_1, num_ticks_per_side1));
01705                 stop_tick = llmin(max_ticks1, num_ticks_per_side1);
01706 
01707                 F32 grid_resolution = mObjectSelection->getSelectType() == SELECT_TYPE_HUD ? 0.25f : llmax(gSavedSettings.getF32("GridResolution"), 0.001f);
01708                 S32 label_sub_div_offset_1 = llround(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1  * 32.f) / (mScaleSnapUnit1 / max_subdivisions));
01709                 S32 label_sub_div_offset_2 = llround(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2  * 32.f) / (mScaleSnapUnit2 / max_subdivisions));
01710 
01711                 for (S32 i = start_tick; i <= stop_tick; i++)
01712                 {
01713                         F32 tick_scale = 1.f;
01714                         F32 alpha = grid_alpha * (1.f - (0.5f *  ((F32)llabs(i) / (F32)num_ticks_per_side1)));
01715                         LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit1 / max_subdivisions * (F32)i - grid_offset1));
01716 
01717                         for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
01718                         {
01719                                 if (fmodf((F32)(i + label_sub_div_offset_1), division_level) == 0.f)
01720                                 {
01721                                         break;
01722                                 }
01723                                 tick_scale *= 0.7f;
01724                         }
01725 
01726                         if (fmodf((F32)(i + label_sub_div_offset_1), (max_subdivisions / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, tick_label_spacing)))) == 0.f)
01727                         {
01728                                 LLVector3 text_origin = tick_pos + 
01729                                         (mSnapGuideDir1 * mSnapRegimeOffset * (1.f + tick_scale));
01730 
01731                                 EGridMode grid_mode = LLSelectMgr::getInstance()->getGridMode();
01732                                 F32 tick_val;
01733                                 if (grid_mode == GRID_MODE_WORLD)
01734                                 {
01735                                         tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit1 / grid_resolution);
01736                                 }
01737                                 else
01738                                 {
01739                                         tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit1 * 2.f);
01740                                 }
01741 
01742                                 if (getUniform())
01743                                 {
01744                                         tick_val *= 2.f;
01745                                 }
01746 
01747                                 F32 text_highlight = 0.8f;
01748 
01749                                 if (is_approx_equal(tick_val, mScaleSnapValue) && mInSnapRegime)
01750                                 {
01751                                         text_highlight = 1.f;
01752                                 }
01753 
01754                                 renderTickValue(text_origin, tick_val, grid_mode == GRID_MODE_WORLD ? "m" : "x", LLColor4(text_highlight, text_highlight, text_highlight, alpha));
01755                         }
01756                 }
01757 
01758                 // label ticks on opposite side
01759                 if (mScaleSnapUnit2 != mScaleSnapUnit1)
01760                 {
01761                         start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2));
01762                         stop_tick = llmin(max_ticks2, num_ticks_per_side2);
01763                         for (S32 i = start_tick; i <= stop_tick; i++)
01764                         {
01765                                 F32 tick_scale = 1.f;
01766                                 F32 alpha = grid_alpha * (1.f - (0.5f *  ((F32)llabs(i) / (F32)num_ticks_per_side2)));
01767                                 LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit2 / max_subdivisions * (F32)i - grid_offset2));
01768 
01769                                 for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
01770                                 {
01771                                         if (fmodf((F32)(i + label_sub_div_offset_2), division_level) == 0.f)
01772                                         {
01773                                                 break;
01774                                         }
01775                                         tick_scale *= 0.7f;
01776                                 }
01777 
01778                                 if (fmodf((F32)(i + label_sub_div_offset_2), (max_subdivisions / llmin(max_subdivisions, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, tick_label_spacing)))) == 0.f)
01779                                 {
01780                                         LLVector3 text_origin = tick_pos + 
01781                                                 (mSnapGuideDir2 * mSnapRegimeOffset * (1.f + tick_scale));
01782 
01783                                         EGridMode grid_mode = LLSelectMgr::getInstance()->getGridMode();
01784                                         F32 tick_val;
01785                                         if (grid_mode == GRID_MODE_WORLD)
01786                                         {
01787                                                 tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit2 / grid_resolution);
01788                                         }
01789                                         else
01790                                         {
01791                                                 tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit2 * 2.f);
01792                                         }
01793 
01794                                         if (getUniform())
01795                                         {
01796                                                 tick_val *= 2.f;
01797                                         }
01798 
01799                                         F32 text_highlight = 0.8f;
01800 
01801                                         if (is_approx_equal(tick_val, mScaleSnapValue) && mInSnapRegime)
01802                                         {
01803                                                 text_highlight = 1.f;
01804                                         }
01805 
01806                                         renderTickValue(text_origin, tick_val, grid_mode == GRID_MODE_WORLD ? "m" : "x", LLColor4(text_highlight, text_highlight, text_highlight, alpha));
01807                                 }
01808                         }
01809                 }
01810 
01811 
01812                 // render help text
01813                 if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
01814                 {
01815                         if (mHelpTextTimer.getElapsedTimeF32() < sHelpTextVisibleTime + sHelpTextFadeTime && sNumTimesHelpTextShown < sMaxTimesShowHelpText)
01816                         {
01817                                 LLVector3 selection_center_start = LLSelectMgr::getInstance()->getSavedBBoxOfSelection().getCenterAgent();
01818 
01819                                 LLVector3 offset_dir;
01820                                 if (mSnapGuideDir1 * LLViewerCamera::getInstance()->getAtAxis() > mSnapGuideDir2 * LLViewerCamera::getInstance()->getAtAxis())
01821                                 {
01822                                         offset_dir = mSnapGuideDir2;
01823                                 }
01824                                 else
01825                                 {
01826                                         offset_dir = mSnapGuideDir1;
01827                                 }
01828 
01829                                 LLVector3 help_text_pos = selection_center_start + (mSnapRegimeOffset * 5.f * offset_dir);
01830                                 const LLFontGL* big_fontp = LLFontGL::sSansSerif;
01831 
01832                                 std::string help_text = "Move mouse cursor over ruler";
01833                                 LLColor4 help_text_color = LLColor4::white;
01834                                 help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, grid_alpha, 0.f);
01835                                 hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
01836                                 help_text = "to snap to grid";
01837                                 help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapRegimeOffset * 0.4f;
01838                                 hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
01839                         }
01840                 }
01841         }
01842 }
01843 
01844 // Returns unit vector in direction of part of an origin-centered cube
01845 LLVector3 LLManipScale::partToUnitVector( S32 part ) const
01846 {
01847         if( (LL_FACE_MIN <= part) && (part <= LL_FACE_MAX) )
01848         {
01849                 return faceToUnitVector( part );
01850         }
01851         else
01852         if( (LL_CORNER_MIN <= part) && (part <= LL_CORNER_MAX) )
01853         {
01854                 return cornerToUnitVector( part );
01855         }
01856         else
01857         if( (LL_EDGE_MIN <= part) && (part <= LL_EDGE_MAX ) )
01858         {
01859                 return edgeToUnitVector( part );
01860         }
01861         return LLVector3();
01862 }
01863 
01864 
01865 // Returns unit vector in direction of face of an origin-centered cube
01866 LLVector3 LLManipScale::faceToUnitVector( S32 part ) const
01867 {
01868         llassert( (LL_FACE_MIN <= part) && (part <= LL_FACE_MAX) );
01869         switch( part )
01870         {
01871                 case LL_FACE_POSX:
01872                         return LLVector3(  1.f,  0.f,  0.f );
01873 
01874                 case LL_FACE_NEGX:
01875                         return LLVector3( -1.f,  0.f,  0.f );
01876 
01877                 case LL_FACE_POSY:
01878                         return LLVector3(  0.f,  1.f,  0.f );
01879 
01880                 case LL_FACE_NEGY:
01881                         return LLVector3(  0.f, -1.f,  0.f );
01882 
01883                 case LL_FACE_POSZ:
01884                         return LLVector3(  0.f,  0.f,  1.f );
01885 
01886                 case LL_FACE_NEGZ:
01887                         return LLVector3(  0.f,  0.f, -1.f );
01888         }
01889         return LLVector3();
01890 }
01891 
01892 
01893 // Returns unit vector in direction of corner of an origin-centered cube
01894 LLVector3 LLManipScale::cornerToUnitVector( S32 part ) const
01895 {
01896         llassert( (LL_CORNER_MIN <= part) && (part <= LL_CORNER_MAX) );
01897         LLVector3 vec;
01898         switch(part)
01899         {
01900                 case LL_CORNER_NNN:
01901                         vec.setVec(-F_SQRT3, -F_SQRT3, -F_SQRT3);
01902                         break;
01903                 case LL_CORNER_NNP:             
01904                         vec.setVec(-F_SQRT3, -F_SQRT3, F_SQRT3);
01905                         break;
01906                 case LL_CORNER_NPN:
01907                         vec.setVec(-F_SQRT3, F_SQRT3, -F_SQRT3);
01908                         break;
01909                 case LL_CORNER_NPP:
01910                         vec.setVec(-F_SQRT3, F_SQRT3, F_SQRT3);
01911                         break;
01912                 case LL_CORNER_PNN:
01913                         vec.setVec(F_SQRT3, -F_SQRT3, -F_SQRT3);
01914                         break;
01915                 case LL_CORNER_PNP:
01916                         vec.setVec(F_SQRT3, -F_SQRT3, F_SQRT3);
01917                         break;
01918                 case LL_CORNER_PPN:
01919                         vec.setVec(F_SQRT3, F_SQRT3, -F_SQRT3);
01920                         break;
01921                 case LL_CORNER_PPP:
01922                         vec.setVec(F_SQRT3, F_SQRT3, F_SQRT3);
01923                         break;
01924                 default:
01925                         vec.clearVec();
01926         }
01927 
01928         return vec;
01929 }
01930 
01931 // Returns unit vector in direction of edge of an origin-centered cube
01932 LLVector3 LLManipScale::edgeToUnitVector( S32 part ) const
01933 {
01934         llassert( (LL_EDGE_MIN <= part) && (part <= LL_EDGE_MAX) );
01935         part -= LL_EDGE_MIN;
01936         S32 rotation = part >> 2;                               // Edge between which faces: 0 => XY, 1 => YZ, 2 => ZX
01937         LLVector3 v;
01938         v.mV[rotation]                  = (part & 1) ? F_SQRT2 : -F_SQRT2;
01939         v.mV[(rotation+1) % 3]  = (part & 2) ? F_SQRT2 : -F_SQRT2;
01940         // v.mV[(rotation+2) % 3] defaults to 0.
01941         return v;
01942 }
01943 
01944 // Non-linear scale of origin-centered unit cube to non-origin-centered, non-symetrical bounding box
01945 LLVector3 LLManipScale::unitVectorToLocalBBoxExtent( const LLVector3& v, const LLBBox& bbox ) const
01946 {
01947         const LLVector3& min = bbox.getMinLocal();
01948         const LLVector3& max = bbox.getMaxLocal();
01949         LLVector3 ctr = bbox.getCenterLocal();
01950 
01951         return LLVector3(
01952                 v.mV[0] ? (v.mV[0]>0 ? max.mV[0] : min.mV[0] ) : ctr.mV[0], 
01953                 v.mV[1] ? (v.mV[1]>0 ? max.mV[1] : min.mV[1] ) : ctr.mV[1], 
01954                 v.mV[2] ? (v.mV[2]>0 ? max.mV[2] : min.mV[2] ) : ctr.mV[2] );
01955 }
01956 
01957 // returns max allowable scale along a given stretch axis
01958 F32             LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const
01959 {
01960         F32 max_scale_factor = 0.f;
01961         LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox );
01962         bbox_extents.abs();
01963         F32 max_extent = 0.f;
01964         for (U32 i = VX; i <= VZ; i++)
01965         {
01966                 if (bbox_extents.mV[i] > max_extent)
01967                 {
01968                         max_extent = bbox_extents.mV[i];
01969                 }
01970         }
01971         max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE / max_extent;
01972 
01973         if (getUniform())
01974         {
01975                 max_scale_factor *= 0.5f;
01976         }
01977 
01978         return max_scale_factor;
01979 }
01980 
01981 // returns min allowable scale along a given stretch axis
01982 F32             LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const
01983 {
01984         LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox );
01985         bbox_extents.abs();
01986         F32 min_extent = DEFAULT_MAX_PRIM_SCALE;
01987         for (U32 i = VX; i <= VZ; i++)
01988         {
01989                 if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent)
01990                 {
01991                         min_extent = bbox_extents.mV[i];
01992                 }
01993         }
01994         F32 min_scale_factor = bbox_extents.magVec() * MIN_PRIM_SCALE / min_extent;
01995 
01996         if (getUniform())
01997         {
01998                 min_scale_factor *= 0.5f;
01999         }
02000 
02001         return min_scale_factor;
02002 }
02003 
02004 // Returns the axis aligned unit vector closest to v.
02005 LLVector3 LLManipScale::nearestAxis( const LLVector3& v ) const
02006 {
02007         // Note: yes, this is a slow but easy implementation
02008         // assumes v is normalized
02009 
02010         F32 coords[][3] =
02011                 {
02012                         { 1.f, 0.f, 0.f },
02013                         { 0.f, 1.f, 0.f },
02014                         { 0.f, 0.f, 1.f },
02015                         {-1.f, 0.f, 0.f },
02016                         { 0.f,-1.f, 0.f },
02017                         { 0.f, 0.f,-1.f }
02018                 };
02019 
02020         F32 cosine[6];
02021         cosine[0] = v * LLVector3( coords[0] );
02022         cosine[1] = v * LLVector3( coords[1] );
02023         cosine[2] = v * LLVector3( coords[2] );
02024         cosine[3] = -cosine[0];
02025         cosine[4] = -cosine[1];
02026         cosine[5] = -cosine[2];
02027 
02028         F32 greatest_cos = cosine[0];
02029         S32 greatest_index = 0;
02030         for( S32 i=1; i<6; i++ )
02031         {
02032                 if( greatest_cos < cosine[i] )
02033                 {
02034                         greatest_cos = cosine[i];
02035                         greatest_index = i;
02036                 }
02037         }
02038 
02039         return LLVector3( coords[greatest_index] );
02040 }
02041 
02042 // virtual
02043 BOOL LLManipScale::canAffectSelection()
02044 {
02045         // An selection is scalable if you are allowed to both edit and move 
02046         // everything in it, and it does not have any sitting agents
02047         BOOL can_scale = mObjectSelection->getObjectCount() != 0;
02048         if (can_scale)
02049         {
02050                 struct f : public LLSelectedObjectFunctor
02051                 {
02052                         virtual bool apply(LLViewerObject* objectp)
02053                         {
02054                                 return objectp->permModify() && objectp->permMove() && !objectp->isSeat();
02055                         }
02056                 } func;
02057                 can_scale = mObjectSelection->applyToObjects(&func);
02058         }
02059         return can_scale;
02060 }

Generated on Fri May 16 08:33:47 2008 for SecondLife by  doxygen 1.5.5