123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469 |
- /**
- * @file llmanipscale.cpp
- * @brief LLManipScale class implementation
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llmanipscale.h"
- #include "llbbox.h"
- #include "llgl.h"
- #include "llrender.h"
- #include "llrenderutils.h"
- #include "llprimitive.h"
- #include "llagent.h"
- #include "lldrawable.h"
- #include "llfloatertools.h"
- #include "llgridmanager.h" // For gIsInSecondLife
- #include "llmeshrepository.h"
- #include "llselectmgr.h"
- #include "llstatusbar.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewerdisplay.h" // For hud_render_text()
- #include "llviewerobject.h"
- #include "llviewerregion.h"
- #include "llviewerwindow.h"
- #include "llvoavatar.h"
- #include "llworld.h"
- constexpr F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f;
- constexpr F32 SNAP_GUIDE_SCREEN_OFFSET = 0.05f;
- constexpr F32 SNAP_GUIDE_SCREEN_LENGTH = 0.7f;
- constexpr F32 SELECTED_MANIPULATOR_SCALE = 1.2f;
- constexpr F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
- constexpr S32 NUM_MANIPULATORS = 14;
- const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] =
- {
- LLManip::LL_CORNER_NNN,
- LLManip::LL_CORNER_NNP,
- LLManip::LL_CORNER_NPN,
- LLManip::LL_CORNER_NPP,
- LLManip::LL_CORNER_PNN,
- LLManip::LL_CORNER_PNP,
- LLManip::LL_CORNER_PPN,
- LLManip::LL_CORNER_PPP,
- LLManip::LL_FACE_POSZ,
- LLManip::LL_FACE_POSX,
- LLManip::LL_FACE_POSY,
- LLManip::LL_FACE_NEGX,
- LLManip::LL_FACE_NEGY,
- LLManip::LL_FACE_NEGZ
- };
- //static
- F32 LLManipScale::maxPrimScale(bool is_flora)
- {
- static LLCachedControl<F32> os_max_prim_scale(gSavedSettings,
- "OSMaxPrimScale");
- // A bit of a hack, but if it is foilage, we do not want to use the largest
- // scale which would result in giant trees and grass.
- if (!is_flora && !gIsInSecondLife)
- {
- return llclamp((F32)os_max_prim_scale, DEFAULT_MAX_PRIM_SCALE,
- 65536.0f);
- }
- if (!is_flora && gMeshRepo.meshRezEnabled())
- {
- return DEFAULT_MAX_PRIM_SCALE;
- }
- return DEFAULT_MAX_PRIM_SCALE_NO_MESH;
- }
- //static
- F32 LLManipScale::minPrimScale(bool is_flora)
- {
- static LLCachedControl<F32> os_min_prim_scale(gSavedSettings,
- "OSMinPrimScale");
- // A bit of a hack, but if it is foilage, we do not want to use the
- // smallest scale which would result in micro trees and grass.
- if (!is_flora && !gIsInSecondLife)
- {
- return llclamp((F32)os_min_prim_scale, 0.0001f,
- DEFAULT_MIN_PRIM_SCALE);
- }
- return DEFAULT_MIN_PRIM_SCALE;
- }
- //static
- void LLManipScale::setUniform(bool b)
- {
- gSavedSettings.setBool("ScaleUniform", b);
- }
- //static
- void LLManipScale::setShowAxes(bool b)
- {
- gSavedSettings.setBool("ScaleShowAxes", b);
- }
- //static
- void LLManipScale::setStretchTextures(bool b)
- {
- gSavedSettings.setBool("ScaleStretchTextures", b);
- }
- //static
- bool LLManipScale::getUniform()
- {
- static LLCachedControl<bool> scale_uniform(gSavedSettings, "ScaleUniform");
- return (bool)scale_uniform;
- }
- //static
- bool LLManipScale::getShowAxes()
- {
- static LLCachedControl<bool> scale_show_axes(gSavedSettings,
- "ScaleShowAxes");
- return (bool)scale_show_axes;
- }
- //static
- bool LLManipScale::getStretchTextures()
- {
- static LLCachedControl<bool> scale_stretch_textures(gSavedSettings,
- "ScaleStretchTextures");
- return (bool)scale_stretch_textures;
- }
- //static
- bool LLManipScale::getSnapEnabled()
- {
- static LLCachedControl<bool> snap_enabled(gSavedSettings, "SnapEnabled");
- return snap_enabled;
- }
- LL_INLINE void LLManipScale::conditionalHighlight(U32 part,
- const LLColor4* highlight,
- const LLColor4* normal)
- {
- LLColor4 default_highlight(1.f, 1.f, 1.f, 1.f);
- LLColor4 default_normal(0.7f, 0.7f, 0.7f, 0.6f);
- LLColor4 invisible(0.f, 0.f, 0.f, 0.f);
- F32 manipulator_scale = 1.f;
- for (S32 i = 0; i < NUM_MANIPULATORS; ++i)
- {
- if ((U32)MANIPULATOR_IDS[i] == part)
- {
- manipulator_scale = mManipulatorScales[i];
- break;
- }
- }
- mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale;
- if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part)
- {
- gGL.color4fv(invisible.mV);
- }
- else if (mHighlightedPart == (S32)part)
- {
- gGL.color4fv(highlight ? highlight->mV : default_highlight.mV);
- }
- else
- {
- gGL.color4fv(normal ? normal->mV : default_normal.mV);
- }
- }
- void LLManipScale::handleSelect()
- {
- LLBBox bbox = gSelectMgr.getBBoxOfSelection();
- updateSnapGuides(bbox);
- gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
- if (gFloaterToolsp)
- {
- gFloaterToolsp->setStatusText("scale");
- }
- LLManip::handleSelect();
- }
- LLManipScale::LLManipScale(LLToolComposite* composite)
- : LLManip(std::string("Scale"), composite),
- mBoxHandleSize(1.f),
- mScaledBoxHandleSize(1.f),
- mLastMouseX(-1),
- mLastMouseY(-1),
- mLastUpdateFlags(0),
- mScaleSnapUnit1(1.f),
- mScaleSnapUnit2(1.f),
- mSnapRegimeOffset(0.f),
- mTickPixelSpacing1(0.f),
- mTickPixelSpacing2(0.f),
- mSnapGuideLength(0.f),
- mSnapRegime(SNAP_REGIME_NONE),
- mScaleSnappedValue(0.f)
- {
- mManipulatorScales = new F32[NUM_MANIPULATORS];
- for (S32 i = 0; i < NUM_MANIPULATORS; ++i)
- {
- mManipulatorScales[i] = 1.f;
- }
- }
- LLManipScale::~LLManipScale()
- {
- for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(),
- DeletePointer());
- mProjectedManipulators.clear();
- delete[] mManipulatorScales;
- }
- void LLManipScale::render()
- {
- LLGLSUIDefault gls_ui;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest gls_depth(GL_TRUE);
- LLGLEnable gl_blend(GL_BLEND);
- if (canAffectSelection())
- {
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
- {
- F32 zoom = gAgent.mHUDCurZoom;
- gGL.scalef(zoom, zoom, zoom);
- }
- // Calculate size of drag handles
- // Box size in pixels = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR
- constexpr F32 BOX_HANDLE_BASE_SIZE = 50.f;
- constexpr F32 BOX_HANDLE_BASE_FACTOR = 0.2f;
- if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
- {
- mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR /
- (F32)gViewerCamera.getViewHeightInPixels();
- mBoxHandleSize /= gAgent.mHUDCurZoom;
- }
- else
- {
- LLVector3 center_agent =
- gAgent.getPosAgentFromGlobal(gSelectMgr.getSelectionCenterGlobal());
- F32 range = dist_vec(gAgent.getCameraPositionAgent(),
- center_agent);
- F32 range_from_agent = dist_vec(gAgent.getPositionAgent(),
- center_agent);
- // Don't draw manip if object too far away
- static LLCachedControl<bool> limit_select_distance(gSavedSettings,
- "LimitSelectDistance");
- static LLCachedControl<F32> max_select_distance(gSavedSettings,
- "MaxSelectDistance");
- if (limit_select_distance)
- {
- if (range_from_agent > max_select_distance)
- {
- return;
- }
- }
- static LLCachedControl<bool> zoom_dependent_handles(gSavedSettings,
- "ZoomDependentResizeHandles");
- if (zoom_dependent_handles)
- {
- mBoxHandleSize = BOX_HANDLE_BASE_FACTOR * BOX_HANDLE_BASE_SIZE *
- (1.005f - gAgent.getCameraZoomFraction()) / 20.f;
- }
- else if (range > 0.001f)
- {
- // range != zero
- F32 fraction_of_fov =
- BOX_HANDLE_BASE_SIZE /
- (F32)gViewerCamera.getViewHeightInPixels();
- F32 apparent_angle = fraction_of_fov *
- gViewerCamera.getView(); // radians
- mBoxHandleSize = range * tanf(apparent_angle) *
- BOX_HANDLE_BASE_FACTOR;
- }
- else
- {
- // range == zero
- mBoxHandleSize = BOX_HANDLE_BASE_FACTOR;
- }
- }
- ////////////////////////////////////////////////////////////////////////
- // Draw bounding box
- LLBBox bbox = gSelectMgr.getBBoxOfSelection();
- LLVector3 pos_agent = bbox.getPositionAgent();
- LLQuaternion rot = bbox.getRotation();
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- {
- gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ]);
- F32 angle_radians, x, y, z;
- rot.getAngleAxis(&angle_radians, &x, &y, &z);
- gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
- {
- LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL);
- glPolygonOffset(-2.f, -2.f);
- renderCorners(bbox);
- renderFaces(bbox);
- if (mManipPart != LL_NO_PART)
- {
- renderGuidelinesPart(bbox);
- }
- glPolygonOffset(0.f, 0.f);
- }
- }
- gGL.popMatrix();
- if (mManipPart != LL_NO_PART)
- {
- renderSnapGuides(bbox);
- }
- gGL.popMatrix();
- renderXYZ(bbox.getExtentLocal());
- }
- }
- bool LLManipScale::handleMouseDown(S32 x, S32 y, MASK mask)
- {
- if (mHighlightedPart != LL_NO_PART)
- {
- return handleMouseDownOnPart(x, y, mask);
- }
- return false;
- }
- // Assumes that one of the arrows on an object was hit.
- bool LLManipScale::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
- {
- if (!canAffectSelection())
- {
- return false;
- }
- highlightManipulators(x, y);
- S32 hit_part = mHighlightedPart;
- gSelectMgr.enableSilhouette(false);
- mManipPart = (EManipPart)hit_part;
- LLBBox bbox = gSelectMgr.getBBoxOfSelection();
- LLVector3 box_center_agent = bbox.getCenterAgent();
- LLVector3 box_corner_agent =
- bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
- bbox));
- updateSnapGuides(bbox);
- mDragStartPointGlobal = gAgent.getPosGlobalFromAgent(box_corner_agent);
- mDragStartCenterGlobal = gAgent.getPosGlobalFromAgent(box_center_agent);
- LLVector3 far_corner_agent =
- bbox.localToAgent(unitVectorToLocalBBoxExtent(-1.f * partToUnitVector(mManipPart),
- bbox));
- mDragFarHitGlobal = gAgent.getPosGlobalFromAgent(far_corner_agent);
- mDragPointGlobal = mDragStartPointGlobal;
- // We just started a drag, so save initial object positions, orientations,
- // and scales
- gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
- // Route future Mouse messages here preemptively. (Release on mouse up.)
- setMouseCapture(true);
- mHelpTextTimer.reset();
- ++sNumTimesHelpTextShown;
- return true;
- }
- bool LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask)
- {
- // First, perform normal processing in case this was a quick-click
- handleHover(x, y, mask);
- if (hasMouseCapture())
- {
- if (LL_FACE_MIN <= (S32)mManipPart && (S32)mManipPart <= LL_FACE_MAX)
- {
- sendUpdates(true, true, false);
- }
- else if (LL_CORNER_MIN <= (S32)mManipPart &&
- (S32)mManipPart <= LL_CORNER_MAX)
- {
- sendUpdates(true, true, true);
- }
- //send texture update
- gSelectMgr.adjustTexturesByScale(true, getStretchTextures());
- gSelectMgr.enableSilhouette(true);
- mManipPart = LL_NO_PART;
- // Might have missed last update due to UPDATE_DELAY timing
- gSelectMgr.sendMultipleUpdate(mLastUpdateFlags);
- #if 0
- gAgent.setObjectTracking(gSavedSettings.getBool("TrackFocusObject"));
- #endif
- gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
- }
- return LLManip::handleMouseUp(x, y, mask);
- }
- bool LLManipScale::handleHover(S32 x, S32 y, MASK mask)
- {
- if (hasMouseCapture())
- {
- if (mObjectSelection->isEmpty())
- {
- // Somehow the object got deselected while we were dragging it.
- setMouseCapture(false);
- }
- else
- {
- drag(x, y);
- }
- LL_DEBUGS("UserInput") << "hover handled by LLManipScale (active)"
- << LL_ENDL;
- }
- else
- {
- mSnapRegime = SNAP_REGIME_NONE;
- // not dragging...
- highlightManipulators(x, y);
- }
- // Patch up textures, if possible.
- gSelectMgr.adjustTexturesByScale(false, getStretchTextures());
- gWindowp->setCursor(UI_CURSOR_TOOLSCALE);
- return true;
- }
- void LLManipScale::highlightManipulators(S32 x, S32 y)
- {
- mHighlightedPart = LL_NO_PART;
- // If we have something selected, try to hit its manipulator handles.
- // Do not do this with nothing selected, as it kills the framerate.
- LLBBox bbox = gSelectMgr.getBBoxOfSelection();
- if (canAffectSelection())
- {
- LLMatrix4 transform;
- if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
- {
- LLVector4 translation(bbox.getPositionAgent());
- transform.initRotTrans(bbox.getRotation(), translation);
- LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
- transform *= cfr;
- LLMatrix4 window_scale;
- F32 zoom_level = 2.f * gAgent.mHUDCurZoom;
- window_scale.initAll(LLVector3(zoom_level / gViewerCamera.getAspect(),
- zoom_level, 0.f),
- LLQuaternion::DEFAULT,
- LLVector3::zero);
- transform *= window_scale;
- }
- else
- {
- LLMatrix4 proj_mat = gViewerCamera.getProjection();
- LLMatrix4 model_view = gViewerCamera.getModelview();
- transform.initAll(LLVector3(1.f, 1.f, 1.f), bbox.getRotation(),
- bbox.getPositionAgent());
- transform *= model_view;
- transform *= proj_mat;
- }
- LLVector3 min = bbox.getMinLocal();
- LLVector3 max = bbox.getMaxLocal();
- LLVector3 ctr = bbox.getCenterLocal();
- S32 manips = 0;
- // corners
- mManipulatorVertices[manips++] = LLVector4(min.mV[VX], min.mV[VY],
- min.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(min.mV[VX], min.mV[VY],
- max.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(min.mV[VX], max.mV[VY],
- min.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(min.mV[VX], max.mV[VY],
- max.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(max.mV[VX], min.mV[VY],
- min.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(max.mV[VX], min.mV[VY],
- max.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(max.mV[VX], max.mV[VY],
- min.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(max.mV[VX], max.mV[VY],
- max.mV[VZ], 1.f);
- // 1-D highlights are applicable iff one object is selected
- if (mObjectSelection->getObjectCount() == 1)
- {
- // Face centers
- mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], ctr.mV[VY],
- max.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(max.mV[VX], ctr.mV[VY],
- ctr.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], max.mV[VY],
- ctr.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(min.mV[VX], ctr.mV[VY],
- ctr.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], min.mV[VY],
- ctr.mV[VZ], 1.f);
- mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], ctr.mV[VY],
- min.mV[VZ], 1.f);
- }
- for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(),
- DeletePointer());
- mProjectedManipulators.clear();
- for (S32 i = 0; i < manips; ++i)
- {
- LLVector4 projectedVertex = mManipulatorVertices[i] * transform;
- projectedVertex = projectedVertex * (1.f / projectedVertex.mV[VW]);
- ManipulatorHandle* proj_manip =
- new ManipulatorHandle(LLVector3(projectedVertex.mV[VX],
- projectedVertex.mV[VY],
- projectedVertex.mV[VZ]),
- MANIPULATOR_IDS[i],
- i < 7 ? SCALE_MANIP_CORNER
- : SCALE_MANIP_FACE);
- mProjectedManipulators.insert(proj_manip);
- }
- F32 half_width = (F32)gViewerWindowp->getWindowWidth() * 0.5f;
- F32 half_height = (F32)gViewerWindowp->getWindowHeight() * 0.5f;
- LLVector2 manip2d;
- LLVector2 mousePos((F32)x - half_width, (F32)y - half_height);
- LLVector2 delta;
- mHighlightedPart = LL_NO_PART;
- for (manipulator_list_t::iterator iter = mProjectedManipulators.begin();
- iter != mProjectedManipulators.end(); ++iter)
- {
- ManipulatorHandle* manipulator = *iter;
- {
- manip2d.set(manipulator->mPosition.mV[VX] * half_width,
- manipulator->mPosition.mV[VY] * half_height);
- delta = manip2d - mousePos;
- if (delta.lengthSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED)
- {
- mHighlightedPart = manipulator->mManipID;
- break;
- }
- }
- }
- }
- F32 critical_damp =
- LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE);
- for (S32 i = 0; i < NUM_MANIPULATORS; ++i)
- {
- if (mHighlightedPart == MANIPULATOR_IDS[i])
- {
- mManipulatorScales[i] = lerp(mManipulatorScales[i],
- SELECTED_MANIPULATOR_SCALE,
- critical_damp);
- }
- else
- {
- mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f,
- critical_damp);
- }
- }
- LL_DEBUGS("UserInput") << "hover handled by LLManipScale (inactive)"
- << LL_ENDL;
- }
- void LLManipScale::renderFaces(const LLBBox& bbox)
- {
- // Do not bother to render the drag handles for 1-D scaling if more than
- // one object is selected or if it is an attachment
- if (mObjectSelection->getObjectCount() > 1)
- {
- return;
- }
- // This is a flattened representation of the box as render here
- // .
- // (+++) (++-) /|\t
- // +------------+ | (texture coordinates)
- // | | |
- // | 1 | (*) --->s
- // | +X |
- // | |
- // (+++) (+-+)| |(+--) (++-) (+++)
- // +------------+------------+------------+------------+
- // |0 3|3 7|7 4|4 0|
- // | 0 | 4 | 5 | 2 |
- // | +Z | -Y | -Z | +Y |
- // | | | | |
- // |1 2|2 6|6 5|5 1|
- // +------------+------------+------------+------------+
- // (-++) (--+)| |(---) (-+-) (-++)
- // | 3 |
- // | -X |
- // | |
- // | |
- // +------------+
- // (-++) (-+-)
- LLColor4 highlight_color(1.f, 1.f, 1.f, 0.5f);
- LLColor4 normal_color(1.f, 1.f, 1.f, 0.3f);
- LLColor4 x_highlight_color(1.f, 0.2f, 0.2f, 1.0f);
- LLColor4 x_normal_color(0.6f, 0.f, 0.f, 0.4f);
- LLColor4 y_highlight_color(0.2f, 1.f, 0.2f, 1.0f);
- LLColor4 y_normal_color(0.f, 0.6f, 0.f, 0.4f);
- LLColor4 z_highlight_color(0.2f, 0.2f, 1.f, 1.0f);
- LLColor4 z_normal_color(0.f, 0.f, 0.6f, 0.4f);
- LLColor4 default_normal_color(0.7f, 0.7f, 0.7f, 0.15f);
- const LLVector3& min = bbox.getMinLocal();
- const LLVector3& max = bbox.getMaxLocal();
- LLVector3 ctr = bbox.getCenterLocal();
- if (mManipPart == LL_NO_PART)
- {
- gGL.color4fv(default_normal_color.mV);
- LLGLDepthTest gls_depth(GL_FALSE);
- gGL.begin(LLRender::TRIANGLES);
- {
- // Face 0
- gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
- // Face 1
- gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
- // Face 2
- gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
- // Face 3
- gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
- // Face 4
- gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
- gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
- // Face 5
- gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
- gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
- gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
- }
- gGL.end();
- }
- // Find nearest vertex
- LLVector3 orientWRTHead =
- bbox.agentToLocalBasis(bbox.getCenterAgent() -
- gAgent.getCameraPositionAgent());
- U32 nearest = (orientWRTHead.mV[0] < 0.f ? 1 : 0) +
- (orientWRTHead.mV[1] < 0.f ? 2 : 0) +
- (orientWRTHead.mV[2] < 0.f ? 4 : 0);
- // Opposite faces on Linden cubes:
- // 0 & 5
- // 1 & 3
- // 2 & 4
- // Table of order to draw faces, based on nearest vertex
- static U32 face_list[8][6] = {
- { 2,0,1, 4,5,3 }, // v6 F201 F453
- { 2,0,3, 4,5,1 }, // v7 F203 F451
- { 4,0,1, 2,5,3 }, // v5 F401 F253
- { 4,0,3, 2,5,1 }, // v4 F403 F251
- { 2,5,1, 4,0,3 }, // v2 F251 F403
- { 2,5,3, 4,0,1 }, // v3 F253 F401
- { 4,5,1, 2,0,3 }, // v1 F451 F203
- { 4,5,3, 2,0,1 } // v0 F453 F201
- };
- {
- LLGLDepthTest gls_depth(GL_FALSE);
- for (S32 i = 0; i < 6; ++i)
- {
- U32 face = face_list[nearest][i];
- switch (face)
- {
- case 0:
- conditionalHighlight(LL_FACE_POSZ, &z_highlight_color,
- &z_normal_color);
- renderAxisHandle(ctr,
- LLVector3(ctr.mV[VX], ctr.mV[VY],
- max.mV[VZ]));
- break;
- case 1:
- conditionalHighlight(LL_FACE_POSX, &x_highlight_color,
- &x_normal_color);
- renderAxisHandle(ctr,
- LLVector3(max.mV[VX], ctr.mV[VY],
- ctr.mV[VZ]));
- break;
- case 2:
- conditionalHighlight(LL_FACE_POSY, &y_highlight_color,
- &y_normal_color);
- renderAxisHandle(ctr,
- LLVector3(ctr.mV[VX], max.mV[VY],
- ctr.mV[VZ]));
- break;
- case 3:
- conditionalHighlight(LL_FACE_NEGX, &x_highlight_color,
- &x_normal_color);
- renderAxisHandle(ctr,
- LLVector3(min.mV[VX], ctr.mV[VY],
- ctr.mV[VZ]));
- break;
- case 4:
- conditionalHighlight(LL_FACE_NEGY, &y_highlight_color,
- &y_normal_color);
- renderAxisHandle(ctr,
- LLVector3(ctr.mV[VX], min.mV[VY],
- ctr.mV[VZ]));
- break;
- case 5:
- conditionalHighlight(LL_FACE_NEGZ, &z_highlight_color,
- &z_normal_color);
- renderAxisHandle(ctr,
- LLVector3(ctr.mV[VX], ctr.mV[VY],
- min.mV[VZ]));
- }
- }
- }
- }
- void LLManipScale::renderCorners(const LLBBox& bbox)
- {
- U32 part = LL_CORNER_NNN;
- F32 x_offset = bbox.getMinLocal().mV[VX];
- for (S32 i = 0; i < 2; ++i)
- {
- F32 y_offset = bbox.getMinLocal().mV[VY];
- for (S32 j = 0; j < 2; ++j)
- {
- F32 z_offset = bbox.getMinLocal().mV[VZ];
- for (S32 k = 0; k < 2; ++k)
- {
- conditionalHighlight(part++);
- renderBoxHandle(x_offset, y_offset, z_offset);
- z_offset = bbox.getMaxLocal().mV[VZ];
- }
- y_offset = bbox.getMaxLocal().mV[VY];
- }
- x_offset = bbox.getMaxLocal().mV[VX];
- }
- }
- void LLManipScale::renderBoxHandle(F32 x, F32 y, F32 z)
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest gls_depth(GL_FALSE);
- gGL.pushMatrix();
- {
- gGL.translatef(x, y, z);
- gGL.scalef(mScaledBoxHandleSize, mScaledBoxHandleSize,
- mScaledBoxHandleSize);
- gBox.render();
- }
- gGL.popMatrix();
- }
- void LLManipScale::renderAxisHandle(const LLVector3& start,
- const LLVector3& end)
- {
- if (getShowAxes())
- {
- // Draws a single "jacks" style handle: a long, retangular box from
- // start to end.
- LLVector3 offset_start = end - start;
- offset_start.normalize();
- offset_start = start + mBoxHandleSize * offset_start;
- LLVector3 delta = end - offset_start;
- LLVector3 pos = offset_start + 0.5f * delta;
- gGL.pushMatrix();
- {
- gGL.translatef(pos.mV[VX], pos.mV[VY], pos.mV[VZ]);
- gGL.scalef(mBoxHandleSize + fabsf(delta.mV[VX]),
- mBoxHandleSize + fabsf(delta.mV[VY]),
- mBoxHandleSize + fabsf(delta.mV[VZ]));
- gBox.render();
- }
- gGL.popMatrix();
- }
- else
- {
- renderBoxHandle(end.mV[VX], end.mV[VY], end.mV[VZ]);
- }
- }
- // General scale call
- void LLManipScale::drag(S32 x, S32 y)
- {
- if (LL_FACE_MIN <= (S32)mManipPart && (S32)mManipPart <= LL_FACE_MAX)
- {
- dragFace(x, y);
- }
- else if (LL_CORNER_MIN <= (S32)mManipPart &&
- (S32)mManipPart <= LL_CORNER_MAX)
- {
- dragCorner(x, y);
- }
- // store changes to override updates
- for (LLObjectSelection::iterator
- iter = gSelectMgr.getSelection()->begin(),
- end = gSelectMgr.getSelection()->end();
- iter != end; ++iter)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* object = selectNode->getObject();
- if (!object)
- {
- llwarns << "NULL selected object !" << llendl;
- continue;
- }
- LLViewerObject* root_object = object->getRootEdit();
- if (!object->isAvatar() && object->permModify() &&
- object->permMove() && !object->isPermanentEnforced() &&
- (!root_object || !root_object->isPermanentEnforced()))
- {
- selectNode->mLastScale = object->getScale();
- selectNode->mLastPositionLocal = object->getPosition();
- }
- }
- gSelectMgr.updateSelectionCenter();
- gAgent.clearFocusObject();
- }
- // Scale on three axis simultaneously
- void LLManipScale::dragCorner(S32 x, S32 y)
- {
- // Suppress scale if mouse hasn't moved.
- if (x == mLastMouseX && y == mLastMouseY)
- {
- return;
- }
- mLastMouseX = x;
- mLastMouseY = y;
- LLVector3 drag_start_point_agent =
- gAgent.getPosAgentFromGlobal(mDragStartPointGlobal);
- LLVector3 drag_start_center_agent =
- gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal);
- LLVector3d drag_start_dir_d;
- drag_start_dir_d.set(mDragStartPointGlobal - mDragStartCenterGlobal);
- F32 s = 0;
- F32 t = 0;
- nearestPointOnLineFromMouse(x, y, drag_start_center_agent,
- drag_start_point_agent, s, t);
- if (s <= 0) // we only care about intersections in front of the camera
- {
- return;
- }
- mDragPointGlobal = lerp(mDragStartCenterGlobal, mDragStartPointGlobal, t);
- LLBBox bbox = gSelectMgr.getBBoxOfSelection();
- F32 max_scale = partToMaxScale(mManipPart, bbox);
- F32 min_scale = partToMinScale(mManipPart, bbox);
- F32 scale_factor = 1.f;
- bool uniform = getUniform();
- // check for snapping
- LLVector3 mouse_on_plane1;
- getMousePointOnPlaneAgent(mouse_on_plane1, x, y, mScaleCenter,
- mScalePlaneNormal1);
- mouse_on_plane1 -= mScaleCenter;
- LLVector3 mouse_on_plane2;
- getMousePointOnPlaneAgent(mouse_on_plane2, x, y, mScaleCenter,
- mScalePlaneNormal2);
- mouse_on_plane2 -= mScaleCenter;
- LLVector3 projected_drag_pos1, projected_drag_pos2;
- projected_drag_pos1 =
- inverse_projected_vec(mScaleDir,
- orthogonal_component(mouse_on_plane1,
- mSnapGuideDir1));
- projected_drag_pos2 =
- inverse_projected_vec(mScaleDir,
- orthogonal_component(mouse_on_plane2,
- mSnapGuideDir2));
- bool snap_enabled = getSnapEnabled();
- if (snap_enabled &&
- (mouse_on_plane1 - projected_drag_pos1) * mSnapGuideDir1 >
- mSnapRegimeOffset)
- {
- mInSnapRegime = true;
- // Projecting the drag position allows for negative results, versus
- // using the length which will result in a "reverse scaling" bug.
- F32 drag_dist = mScaleDir * projected_drag_pos1;
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter +
- projected_drag_pos1,
- mScaleDir,
- mScaleSnapUnit1,
- mTickPixelSpacing1),
- sGridMinSubdivisionLevel,
- sGridMaxSubdivisionLevel);
- F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
- F32 relative_snap_dist = fmodf(drag_dist + snap_dist,
- mScaleSnapUnit1 / cur_subdivisions);
- mScaleSnappedValue =
- llclamp(drag_dist - (relative_snap_dist - snap_dist),
- min_scale, max_scale);
- scale_factor = mScaleSnappedValue /
- dist_vec(drag_start_point_agent,
- drag_start_center_agent);
- mScaleSnappedValue /= mScaleSnapUnit1 * 2.f;
- mSnapRegime = SNAP_REGIME_UPPER;
- if (!uniform)
- {
- scale_factor *= 0.5f;
- }
- }
- else if (snap_enabled &&
- (mouse_on_plane2 - projected_drag_pos2) * mSnapGuideDir2 > mSnapRegimeOffset)
- {
- // Projecting the drag position allows for negative results, versus
- // using the length which will result in a "reverse scaling" bug.
- F32 drag_dist = mScaleDir * projected_drag_pos2;
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter +
- projected_drag_pos2,
- mScaleDir,
- mScaleSnapUnit2,
- mTickPixelSpacing2),
- sGridMinSubdivisionLevel,
- sGridMaxSubdivisionLevel);
- F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions);
- F32 relative_snap_dist = fmodf(drag_dist + snap_dist,
- mScaleSnapUnit2 / cur_subdivisions);
- mScaleSnappedValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)),
- min_scale, max_scale);
- scale_factor = mScaleSnappedValue /
- dist_vec(drag_start_point_agent,
- drag_start_center_agent);
- mScaleSnappedValue /= mScaleSnapUnit2 * 2.f;
- mSnapRegime = SNAP_REGIME_LOWER;
- if (!uniform)
- {
- scale_factor *= 0.5f;
- }
- }
- else
- {
- mSnapRegime = SNAP_REGIME_NONE;
- scale_factor = t;
- if (!uniform)
- {
- scale_factor = 0.5f + scale_factor * 0.5f;
- }
- }
- F32 max_prim_scale = maxPrimScale();
- F32 min_prim_scale = minPrimScale();
- F32 max_scale_factor = max_prim_scale / min_prim_scale;
- F32 min_scale_factor = min_prim_scale / max_prim_scale;
- // find max and min scale factors that will make biggest object hit max
- // absolute scale and smallest object hit min absolute scale
- for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
- end = mObjectSelection->end();
- iter != end; ++iter)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* object = selectNode->getObject();
- if (!object)
- {
- llwarns << "NULL selected object !" << llendl;
- continue;
- }
- LLViewerObject* root_object = object->getRootEdit();
- if (!object->isAvatar() && object->permModify() &&
- object->permMove() && !object->isPermanentEnforced() &&
- (!root_object || !root_object->isPermanentEnforced()))
- {
- const LLVector3& scale = selectNode->mSavedScale;
- F32 cur_max_scale_factor = llmin(max_prim_scale / scale.mV[VX],
- max_prim_scale / scale.mV[VY],
- max_prim_scale / scale.mV[VZ]);
- max_scale_factor = llmin(max_scale_factor, cur_max_scale_factor);
- F32 cur_min_scale_factor = llmax(min_prim_scale / scale.mV[VX],
- min_prim_scale / scale.mV[VY],
- min_prim_scale / scale.mV[VZ]);
- min_scale_factor = llmax(min_scale_factor, cur_min_scale_factor);
- }
- }
- scale_factor = llclamp(scale_factor, min_scale_factor, max_scale_factor);
- LLVector3d drag_global = uniform ? mDragStartCenterGlobal : mDragFarHitGlobal;
- // do the root objects i.e. (true == cur->isRootEdit())
- for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
- end = mObjectSelection->end();
- iter != end; ++iter)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* cur = selectNode->getObject();
- if (!cur)
- {
- llwarns << "NULL selected object !" << llendl;
- continue;
- }
- LLViewerObject* root_object = cur->getRootEdit();
- if (!cur->isAvatar() && cur->permModify() && cur->permMove() &&
- !cur->isPermanentEnforced() && cur->isRootEdit() &&
- (!root_object || !root_object->isPermanentEnforced()))
- {
- const LLVector3& scale = selectNode->mSavedScale;
- cur->setScale(scale_factor * scale);
- LLVector3 original_pos = cur->getPositionEdit();
- LLVector3d new_pos_global = drag_global +
- (selectNode->mSavedPositionGlobal -
- drag_global) * scale_factor;
- if (!cur->isAttachment())
- {
- new_pos_global =
- gWorld.clipToVisibleRegions(selectNode->mSavedPositionGlobal,
- new_pos_global);
- }
- cur->setPositionAbsoluteGlobal(new_pos_global);
- rebuild(cur);
- if (selectNode->mIndividualSelection)
- {
- LLVector3 delta_pos = cur->getPositionEdit() - original_pos;
- // Counter-translate child objects if we are moving the root as
- // an individual
- LLViewerObject::const_child_list_t& child_list = cur->getChildren();
- for (LLViewerObject::child_list_t::const_iterator
- iter2 = child_list.begin(),
- end2 = child_list.end();
- iter2 != end2; ++iter2)
- {
- LLViewerObject* childp = *iter2;
- if (cur->isAttachment())
- {
- LLVector3 child_pos =
- childp->getPosition() -
- delta_pos * ~cur->getRotationEdit();
- childp->setPositionLocal(child_pos);
- }
- else
- {
- LLVector3d child_pos_delta(delta_pos);
- // RN: this updates drawable position instantly
- childp->setPositionAbsoluteGlobal(childp->getPositionGlobal() -
- child_pos_delta);
- }
- rebuild(childp);
- }
- }
- }
- }
- // Do the child objects i.e. (false == cur->isRootEdit())
- for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
- end = mObjectSelection->end();
- iter != end; ++iter)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* cur = selectNode->getObject();
- if (!cur)
- {
- llwarns << "NULL selected object !" << llendl;
- continue;
- }
- LLViewerObject* root_object = cur->getRootEdit();
- if (!cur->isAvatar() && cur->permModify() && cur->permMove() &&
- !cur->isPermanentEnforced() && !cur->isRootEdit() &&
- (!root_object || !root_object->isPermanentEnforced()))
- {
- const LLVector3& scale = selectNode->mSavedScale;
- cur->setScale(scale_factor * scale, false);
- if (!selectNode->mIndividualSelection)
- {
- cur->setPositionLocal(selectNode->mSavedPositionLocal *
- scale_factor);
- }
- rebuild(cur);
- }
- }
- }
- // Scale on a single axis
- void LLManipScale::dragFace(S32 x, S32 y)
- {
- // Suppress scale if mouse hasn't moved.
- if (x == mLastMouseX && y == mLastMouseY)
- {
- return;
- }
- mLastMouseX = x;
- mLastMouseY = y;
- LLVector3d drag_start_point_global = mDragStartPointGlobal;
- LLVector3d drag_start_center_global = mDragStartCenterGlobal;
- LLVector3 drag_start_point_agent =
- gAgent.getPosAgentFromGlobal(drag_start_point_global);
- LLVector3 drag_start_center_agent =
- gAgent.getPosAgentFromGlobal(drag_start_center_global);
- LLVector3d drag_start_dir_d;
- drag_start_dir_d.set(drag_start_point_global - drag_start_center_global);
- LLVector3 drag_start_dir_f;
- drag_start_dir_f.set(drag_start_dir_d);
- LLBBox bbox = gSelectMgr.getBBoxOfSelection();
- F32 s = 0;
- F32 t = 0;
- nearestPointOnLineFromMouse(x, y, drag_start_center_agent,
- drag_start_point_agent, s, t);
- if (s <= 0)
- {
- // we only care about intersections in front of the camera
- return;
- }
- LLVector3d drag_point_global = drag_start_center_global +
- t * drag_start_dir_d;
- LLVector3 part_dir_local = partToUnitVector(mManipPart);
- // check for snapping
- LLVector3 mouse_on_plane;
- getMousePointOnPlaneAgent(mouse_on_plane, x, y, mScaleCenter,
- mScalePlaneNormal1);
- LLVector3 mouse_on_scale_line =
- mScaleCenter + projected_vec(mouse_on_plane - mScaleCenter,
- mScaleDir);
- LLVector3 drag_delta(mouse_on_scale_line - drag_start_point_agent);
- F32 max_drag_dist = partToMaxScale(mManipPart, bbox);
- F32 min_drag_dist = partToMinScale(mManipPart, bbox);
- bool uniform = getUniform();
- if (uniform)
- {
- drag_delta *= 2.f;
- }
- LLVector3 scale_center_to_mouse = mouse_on_plane - mScaleCenter;
- F32 dist_from_scale_line = dist_vec(scale_center_to_mouse,
- mouse_on_scale_line - mScaleCenter);
- F32 dist_along_scale_line = scale_center_to_mouse * mScaleDir;
- bool snap_enabled = getSnapEnabled();
- if (snap_enabled && dist_from_scale_line > mSnapRegimeOffset)
- {
- // A face drag doesn't have split regimes.
- mSnapRegime = (ESnapRegimes)(SNAP_REGIME_UPPER | SNAP_REGIME_LOWER);
- if (dist_along_scale_line > max_drag_dist)
- {
- mScaleSnappedValue = max_drag_dist;
- LLVector3 clamp_point = mScaleCenter + max_drag_dist * mScaleDir;
- drag_delta.set(clamp_point - drag_start_point_agent);
- }
- else if (dist_along_scale_line < min_drag_dist)
- {
- mScaleSnappedValue = min_drag_dist;
- LLVector3 clamp_point = mScaleCenter + min_drag_dist * mScaleDir;
- drag_delta.set(clamp_point - drag_start_point_agent);
- }
- else
- {
- F32 drag_dist = scale_center_to_mouse * mScaleDir;
- F32 cur_subdivisions =
- llclamp(getSubdivisionLevel(mScaleCenter +
- mScaleDir * drag_dist,
- mScaleDir, mScaleSnapUnit1,
- mTickPixelSpacing1),
- sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
- F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
- F32 relative_snap_dist = fmodf(drag_dist + snap_dist,
- mScaleSnapUnit1 / cur_subdivisions);
- relative_snap_dist -= snap_dist;
- // Make sure that values that the scale is "snapped to" do not
- // exceed/go under the applicable max/mins; this causes the box to
- // shift displacements ever so slightly although the "snap value"
- // should go down to 0. See Jira 1027
- relative_snap_dist = llclamp(relative_snap_dist,
- drag_dist - max_drag_dist,
- drag_dist - min_drag_dist);
- mScaleSnappedValue =
- (drag_dist - relative_snap_dist) / (mScaleSnapUnit1 * 2.f);
- if (fabsf(relative_snap_dist) < snap_dist)
- {
- LLVector3 drag_correction = relative_snap_dist * mScaleDir;
- if (uniform)
- {
- drag_correction *= 2.f;
- }
- drag_delta -= drag_correction;
- }
- }
- }
- else
- {
- mSnapRegime = SNAP_REGIME_NONE;
- }
- LLVector3 dir_agent;
- if (part_dir_local.mV[VX])
- {
- dir_agent = bbox.localToAgentBasis(LLVector3::x_axis);
- }
- else if (part_dir_local.mV[VY])
- {
- dir_agent = bbox.localToAgentBasis(LLVector3::y_axis);
- }
- else if (part_dir_local.mV[VZ])
- {
- dir_agent = bbox.localToAgentBasis(LLVector3::z_axis);
- }
- stretchFace(projected_vec(drag_start_dir_f, dir_agent) +
- drag_start_center_agent,
- projected_vec(drag_delta, dir_agent));
- mDragPointGlobal = drag_point_global;
- }
- void LLManipScale::sendUpdates(bool send_position_update,
- bool send_scale_update, bool corner)
- {
- // Throttle updates to 10 per second.
- static LLTimer update_timer;
- F32 elapsed_time = update_timer.getElapsedTimeF32();
- constexpr F32 UPDATE_DELAY = 0.1f; // Min time between transmitted updates
- if (send_scale_update || send_position_update)
- {
- U32 update_flags = UPD_NONE;
- if (send_position_update) update_flags |= UPD_POSITION;
- if (send_scale_update) update_flags |= UPD_SCALE;
- if (corner)
- {
- update_flags |= UPD_UNIFORM;
- }
- // keep this up to date for sendonmouseup
- mLastUpdateFlags = update_flags;
- // enforce minimum update delay and don't stream updates on sub-object
- // selections
- static LLCachedControl<bool> edit_linked_parts(gSavedSettings,
- "EditLinkedParts");
- if (elapsed_time > UPDATE_DELAY && !edit_linked_parts)
- {
- gSelectMgr.sendMultipleUpdate(update_flags);
- update_timer.reset();
- }
- dialog_refresh_all();
- }
- }
- // Rescales in a single dimension. Either uniform (standard) or one-sided
- // (scale plus translation) depending on mUniform. Handles multiple selection
- // and objects that are not aligned to the bounding box.
- void LLManipScale::stretchFace(const LLVector3& drag_start_agent,
- const LLVector3& drag_delta_agent)
- {
- LLVector3 drag_start_center_agent =
- gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal);
- for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
- end = mObjectSelection->end();
- iter != end; ++iter)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* cur = selectNode->getObject();
- if (!cur)
- {
- llwarns << "NULL selected object !" << llendl;
- continue;
- }
- LLViewerObject* root_object = cur->getRootEdit();
- if (cur->permModify() && cur->permMove() &&
- !cur->isPermanentEnforced() && !cur->isAvatar() &&
- (!root_object || !root_object->isPermanentEnforced()))
- {
- LLBBox cur_bbox = cur->getBoundingBoxAgent();
- LLVector3 start_local = cur_bbox.agentToLocal(drag_start_agent);
- LLVector3 end_local = cur_bbox.agentToLocal(drag_start_agent +
- drag_delta_agent);
- LLVector3 start_center_local = cur_bbox.agentToLocal(drag_start_center_agent);
- LLVector3 axis = nearestAxis(start_local - start_center_local);
- S32 axis_index = axis.mV[0] ? 0 : (axis.mV[1] ? 1 : 2);
- LLVector3 delta_local = end_local - start_local;
- F32 delta_local_mag = delta_local.length();
- LLVector3 dir_local;
- if (delta_local_mag == 0.f)
- {
- dir_local = axis;
- }
- else
- {
- // Normalized delta_local
- dir_local = delta_local / delta_local_mag;
- }
- F32 denom = axis * dir_local;
- F32 desired_delta_size =
- is_approx_zero(denom) ? 0.f : delta_local_mag / denom;
- F32 desired_scale =
- llclamp(selectNode->mSavedScale.mV[axis_index] +
- desired_delta_size,
- minPrimScale(), maxPrimScale());
- // Propagate scale constraint back to position offset
- desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index];
- LLVector3 scale = cur->getScale();
- scale.mV[axis_index] = desired_scale;
- cur->setScale(scale, false);
- rebuild(cur);
- LLVector3 delta_pos;
- if (!getUniform())
- {
- LLVector3 delta_pos_local = axis * (0.5f * desired_delta_size);
- LLVector3d delta_pos_global;
- delta_pos_global.set(cur_bbox.localToAgent(delta_pos_local) -
- cur_bbox.getCenterAgent());
- LLVector3 cur_pos = cur->getPositionEdit();
- if (cur->isRootEdit() && !cur->isAttachment())
- {
- LLVector3d new_pos_global =
- gWorld.clipToVisibleRegions(selectNode->mSavedPositionGlobal,
- selectNode->mSavedPositionGlobal +
- delta_pos_global);
- cur->setPositionGlobal(new_pos_global);
- }
- else
- {
- LLXform* parent_xform =
- cur->mDrawable->getXform()->getParent();
- LLVector3 new_pos_local;
- // This works in attachment point space using world space
- // delta
- if (parent_xform)
- {
- new_pos_local = selectNode->mSavedPositionLocal +
- LLVector3(delta_pos_global) *
- ~parent_xform->getWorldRotation();
- }
- else
- {
- new_pos_local = selectNode->mSavedPositionLocal +
- LLVector3(delta_pos_global);
- }
- cur->setPositionLocal(new_pos_local);
- }
- delta_pos = cur->getPositionEdit() - cur_pos;
- }
- if (cur->isRootEdit() && selectNode->mIndividualSelection)
- {
- // Counter-translate child objects if we are moving the root as
- // an individual
- LLViewerObject::const_child_list_t& child_list =
- cur->getChildren();
- for (LLViewerObject::child_list_t::const_iterator
- iter2 = child_list.begin(), end2 = child_list.end();
- iter2 != end2; ++iter2)
- {
- LLViewerObject* childp = *iter2;
- if (!getUniform())
- {
- LLVector3 child_pos = childp->getPosition() -
- delta_pos *
- ~cur->getRotationEdit();
- childp->setPositionLocal(child_pos);
- rebuild(childp);
- }
- }
- }
- }
- }
- }
- void LLManipScale::renderGuidelinesPart(const LLBBox& bbox)
- {
- LLVector3 guideline_start = bbox.getCenterLocal();
- LLVector3 guideline_end;
- guideline_end = unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
- bbox);
- if (!getUniform())
- {
- guideline_start =
- unitVectorToLocalBBoxExtent(-partToUnitVector(mManipPart), bbox);
- }
- guideline_end -= guideline_start;
- guideline_end.normalize();
- LLViewerRegion* region = gAgent.getRegion();
- guideline_end *= region ? region->getWidth() : REGION_WIDTH_METERS;
- guideline_end += guideline_start;
- {
- LLGLDepthTest gls_depth(GL_TRUE);
- static const LLColor4 semi_transparent_white(1.f, 1.f, 1.f, 0.5f);
- gl_line_3d(guideline_start, guideline_end, semi_transparent_white);
- }
- {
- LLGLDepthTest gls_depth(GL_FALSE);
- static const LLColor4 almost_transparent_white(1.f, 1.f, 1.f, 0.5f);
- gl_line_3d(guideline_start, guideline_end, almost_transparent_white);
- }
- }
- void LLManipScale::updateSnapGuides(const LLBBox& bbox)
- {
- LLVector3 grid_origin;
- LLVector3 grid_scale;
- LLQuaternion grid_rotation;
- gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
- LLVector3 box_corner_agent =
- bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
- bbox));
- bool uniform = getUniform();
- mScaleCenter =
- uniform ? bbox.getCenterAgent()
- : bbox.localToAgent(unitVectorToLocalBBoxExtent(-1.f *
- partToUnitVector(mManipPart),
- bbox));
- mScaleDir = box_corner_agent - mScaleCenter;
- mScaleDir.normalize();
- if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
- {
- mSnapRegimeOffset = SNAP_GUIDE_SCREEN_OFFSET / gAgent.mHUDCurZoom;
- }
- else
- {
- F32 object_distance = dist_vec(box_corner_agent,
- gViewerCamera.getOrigin());
- mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET *
- gViewerWindowp->getWindowWidth() *
- object_distance) /
- gViewerCamera.getPixelMeterRatio();
- }
- LLVector3 cam_at_axis;
- F32 snap_guide_length;
- if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
- {
- cam_at_axis.set(1.f, 0.f, 0.f);
- snap_guide_length = SNAP_GUIDE_SCREEN_LENGTH / gAgent.mHUDCurZoom;
- }
- else
- {
- cam_at_axis = gViewerCamera.getAtAxis();
- F32 manipulator_distance = dist_vec(box_corner_agent,
- gViewerCamera.getOrigin());
- snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH *
- gViewerWindowp->getWindowWidth() *
- manipulator_distance) /
- gViewerCamera.getPixelMeterRatio();
- }
- mSnapGuideLength = snap_guide_length /
- llmax(0.1f, llmin(mSnapGuideDir1 * cam_at_axis,
- mSnapGuideDir2 * cam_at_axis));
- LLVector3 off_axis_dir = mScaleDir % cam_at_axis;
- off_axis_dir.normalize();
- if (LL_FACE_MIN <= (S32)mManipPart && (S32)mManipPart <= LL_FACE_MAX)
- {
- LLVector3 bbox_relative_cam_dir = off_axis_dir * ~bbox.getRotation();
- bbox_relative_cam_dir.abs();
- if (bbox_relative_cam_dir.mV[VX] > bbox_relative_cam_dir.mV[VY] &&
- bbox_relative_cam_dir.mV[VX] > bbox_relative_cam_dir.mV[VZ])
- {
- mSnapGuideDir1 = LLVector3::x_axis * bbox.getRotation();
- }
- else if (bbox_relative_cam_dir.mV[VY] > bbox_relative_cam_dir.mV[VZ])
- {
- mSnapGuideDir1 = LLVector3::y_axis * bbox.getRotation();
- }
- else
- {
- mSnapGuideDir1 = LLVector3::z_axis * bbox.getRotation();
- }
- LLVector3 scale_snap = grid_scale;
- mScaleSnapUnit1 =
- scale_snap.scaleVec(partToUnitVector(mManipPart)).length();
- mScaleSnapUnit2 = mScaleSnapUnit1;
- mSnapGuideDir1 *=
- mSnapGuideDir1 * gViewerCamera.getUpAxis() > 0.f ? 1.f : -1.f;
- mSnapGuideDir2 = mSnapGuideDir1 * -1.f;
- mSnapDir1 = mScaleDir;
- mSnapDir2 = mScaleDir;
- }
- else if (LL_CORNER_MIN <= (S32)mManipPart &&
- (S32)mManipPart <= LL_CORNER_MAX)
- {
- LLVector3 local_camera_dir;
- if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
- {
- local_camera_dir = LLVector3(-1.f, 0.f, 0.f) * ~bbox.getRotation();
- }
- else
- {
- local_camera_dir = (gViewerCamera.getOrigin() - box_corner_agent) *
- ~bbox.getRotation();
- local_camera_dir.normalize();
- }
- LLVector3 axis_flip;
- switch (mManipPart)
- {
- case LL_CORNER_NNN:
- axis_flip.set(1.f, 1.f, 1.f);
- break;
- case LL_CORNER_NNP:
- axis_flip.set(1.f, 1.f, -1.f);
- break;
- case LL_CORNER_NPN:
- axis_flip.set(1.f, -1.f, 1.f);
- break;
- case LL_CORNER_NPP:
- axis_flip.set(1.f, -1.f, -1.f);
- break;
- case LL_CORNER_PNN:
- axis_flip.set(-1.f, 1.f, 1.f);
- break;
- case LL_CORNER_PNP:
- axis_flip.set(-1.f, 1.f, -1.f);
- break;
- case LL_CORNER_PPN:
- axis_flip.set(-1.f, -1.f, 1.f);
- break;
- case LL_CORNER_PPP:
- axis_flip.set(-1.f, -1.f, -1.f);
- break;
- default:
- break;
- }
- // Account for which side of the object the camera is located and
- // negate appropriate axes
- local_camera_dir.scaleVec(axis_flip);
- // normalize to object scale
- LLVector3 bbox_extent = bbox.getExtentLocal();
- local_camera_dir.scaleVec(LLVector3(1.f / bbox_extent.mV[VX],
- 1.f / bbox_extent.mV[VY],
- 1.f / bbox_extent.mV[VZ]));
- S32 scale_face = -1;
- if ((local_camera_dir.mV[VX] > 0.f) == (local_camera_dir.mV[VY] > 0.f))
- {
- if ((local_camera_dir.mV[VZ] > 0.f) == (local_camera_dir.mV[VY] > 0.f))
- {
- LLVector3 local_camera_dir_abs = local_camera_dir;
- local_camera_dir_abs.abs();
- // All neighboring faces of bbox are pointing towards camera or
- // away from camera; use largest magnitude face for snap guides
- if (local_camera_dir_abs.mV[VX] > local_camera_dir_abs.mV[VY])
- {
- if (local_camera_dir_abs.mV[VX] > local_camera_dir_abs.mV[VZ])
- {
- scale_face = VX;
- }
- else
- {
- scale_face = VZ;
- }
- }
- else // y > x
- {
- if (local_camera_dir_abs.mV[VY] > local_camera_dir_abs.mV[VZ])
- {
- scale_face = VY;
- }
- else
- {
- scale_face = VZ;
- }
- }
- }
- else
- {
- // z axis facing opposite direction from x and y relative to
- // camera, use x and y for snap guides
- scale_face = VZ;
- }
- }
- else
- {
- // x and y axes are facing in opposite directions relative to
- // camera
- if ((local_camera_dir.mV[VZ] > 0.f) == (local_camera_dir.mV[VY] > 0.f))
- {
- // x axis facing opposite direction from y and z relative to
- // camera, use y and z for snap guides
- scale_face = VX;
- }
- else
- {
- // y axis facing opposite direction from x and z relative to
- // camera, use x and z for snap guides
- scale_face = VY;
- }
- }
- switch (scale_face)
- {
- case VX:
- // x axis face being scaled, use y and z for snap guides
- mSnapGuideDir1 = LLVector3::y_axis.scaledVec(axis_flip);
- mScaleSnapUnit1 = grid_scale.mV[VZ];
- mSnapGuideDir2 = LLVector3::z_axis.scaledVec(axis_flip);
- mScaleSnapUnit2 = grid_scale.mV[VY];
- break;
- case VY:
- // y axis facing being scaled, use x and z for snap guides
- mSnapGuideDir1 = LLVector3::x_axis.scaledVec(axis_flip);
- mScaleSnapUnit1 = grid_scale.mV[VZ];
- mSnapGuideDir2 = LLVector3::z_axis.scaledVec(axis_flip);
- mScaleSnapUnit2 = grid_scale.mV[VX];
- break;
- case VZ:
- // z axis facing being scaled, use x and y for snap guides
- mSnapGuideDir1 = LLVector3::x_axis.scaledVec(axis_flip);
- mScaleSnapUnit1 = grid_scale.mV[VY];
- mSnapGuideDir2 = LLVector3::y_axis.scaledVec(axis_flip);
- mScaleSnapUnit2 = grid_scale.mV[VX];
- break;
- default:
- mSnapGuideDir1.setZero();
- mScaleSnapUnit1 = 0.f;
- mSnapGuideDir2.setZero();
- mScaleSnapUnit2 = 0.f;
- break;
- }
- mSnapGuideDir1.rotVec(bbox.getRotation());
- mSnapGuideDir2.rotVec(bbox.getRotation());
- mSnapDir1 = -1.f * mSnapGuideDir2;
- mSnapDir2 = -1.f * mSnapGuideDir1;
- }
- mScalePlaneNormal1 = mSnapGuideDir1 % mScaleDir;
- mScalePlaneNormal1.normalize();
- mScalePlaneNormal2 = mSnapGuideDir2 % mScaleDir;
- mScalePlaneNormal2.normalize();
- mScaleSnapUnit1 = mScaleSnapUnit1 / (mSnapDir1 * mScaleDir);
- mScaleSnapUnit2 = mScaleSnapUnit2 / (mSnapDir2 * mScaleDir);
- mTickPixelSpacing1 = ll_roundp((F32)MIN_DIVISION_PIXEL_WIDTH /
- (mScaleDir % mSnapGuideDir1).length());
- mTickPixelSpacing2 = ll_roundp((F32)MIN_DIVISION_PIXEL_WIDTH /
- (mScaleDir % mSnapGuideDir2).length());
- if (uniform)
- {
- mScaleSnapUnit1 *= 0.5f;
- mScaleSnapUnit2 *= 0.5f;
- }
- }
- void LLManipScale::renderSnapGuides(const LLBBox& bbox)
- {
- if (!getSnapEnabled())
- {
- return;
- }
- static LLCachedControl<F32> grid_alpha(gSavedSettings, "GridOpacity");
- F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox);
- LLVector3 drag_point = gAgent.getPosAgentFromGlobal(mDragPointGlobal);
- updateGridSettings();
- S32 pass;
- for (pass = 0; pass < 3; ++pass)
- {
- LLColor4 tick_color = setupSnapGuideRenderPass(pass);
- gGL.begin(LLRender::LINES);
- LLVector3 line_mid = mScaleCenter + mScaleSnappedValue * mScaleDir +
- mSnapGuideDir1 * mSnapRegimeOffset;
- LLVector3 line_start = line_mid -
- mScaleDir * llmin(mScaleSnappedValue,
- mSnapGuideLength * 0.5f);
- LLVector3 line_end = line_mid +
- mScaleDir * llmin(max_point_on_scale_line -
- mScaleSnappedValue,
- mSnapGuideLength * 0.5f);
- gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
- tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
- gGL.vertex3fv(line_start.mV);
- gGL.color4fv(tick_color.mV);
- gGL.vertex3fv(line_mid.mV);
- gGL.vertex3fv(line_mid.mV);
- gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
- tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
- gGL.vertex3fv(line_end.mV);
- line_mid = mScaleCenter + mScaleSnappedValue * mScaleDir +
- mSnapGuideDir2 * mSnapRegimeOffset;
- line_start = line_mid -
- mScaleDir * llmin(mScaleSnappedValue,
- mSnapGuideLength * 0.5f);
- line_end = line_mid +
- mScaleDir * llmin(max_point_on_scale_line -
- mScaleSnappedValue,
- mSnapGuideLength * 0.5f);
- gGL.vertex3fv(line_start.mV);
- gGL.color4fv(tick_color.mV);
- gGL.vertex3fv(line_mid.mV);
- gGL.vertex3fv(line_mid.mV);
- gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
- tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
- gGL.vertex3fv(line_end.mV);
- gGL.end();
- }
- {
- LLGLDepthTest gls_depth(GL_FALSE);
- F32 dist_grid_axis = llmax(0.f,
- (drag_point - mScaleCenter) * mScaleDir);
- F32 smallest_subdivision1 = mScaleSnapUnit1 / sGridMaxSubdivisionLevel;
- F32 smallest_subdivision2 = mScaleSnapUnit2 / sGridMaxSubdivisionLevel;
- F32 dist_scale_units_1 = dist_grid_axis / smallest_subdivision1;
- F32 dist_scale_units_2 = dist_grid_axis / smallest_subdivision2;
- // find distance to nearest smallest grid unit
- F32 grid_multiple1 = llfloor(dist_scale_units_1);
- F32 grid_multiple2 = llfloor(dist_scale_units_2);
- F32 grid_offset1 = fmodf(dist_grid_axis, smallest_subdivision1);
- F32 grid_offset2 = fmodf(dist_grid_axis, smallest_subdivision2);
- // how many smallest grid units are we away from largest grid scale?
- S32 sub_div_offset_1 = ll_round(fmod(dist_grid_axis - grid_offset1,
- mScaleSnapUnit1 /
- sGridMinSubdivisionLevel) /
- smallest_subdivision1);
- S32 sub_div_offset_2 = ll_round(fmod(dist_grid_axis - grid_offset2,
- mScaleSnapUnit2 /
- sGridMinSubdivisionLevel) /
- smallest_subdivision2);
- S32 num_ticks_per_side1 = llmax(1, lltrunc(0.5f * mSnapGuideLength /
- smallest_subdivision1));
- S32 num_ticks_per_side2 = llmax(1, lltrunc(0.5f * mSnapGuideLength /
- smallest_subdivision2));
- S32 ticks_from_scale_center_1 = lltrunc(dist_scale_units_1);
- S32 ticks_from_scale_center_2 = lltrunc(dist_scale_units_2);
- S32 max_ticks1 = llceil(max_point_on_scale_line /
- smallest_subdivision1 - dist_scale_units_1);
- S32 max_ticks2 = llceil(max_point_on_scale_line /
- smallest_subdivision2 - dist_scale_units_2);
- S32 start_tick = 0;
- S32 stop_tick = 0;
- if (mSnapRegime != SNAP_REGIME_NONE)
- {
- // draw snap guide line
- gGL.begin(LLRender::LINES);
- LLVector3 snap_line_center =
- bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
- bbox));
- LLVector3 snap_line_start = snap_line_center +
- mSnapGuideDir1 * mSnapRegimeOffset;
- LLVector3 snap_line_end = snap_line_center +
- mSnapGuideDir2 * mSnapRegimeOffset;
- gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
- gGL.vertex3fv(snap_line_start.mV);
- gGL.vertex3fv(snap_line_center.mV);
- gGL.vertex3fv(snap_line_center.mV);
- gGL.vertex3fv(snap_line_end.mV);
- gGL.end();
- // Draw snap guide arrow
- gGL.begin(LLRender::TRIANGLES);
- {
- //gGLSNoCullFaces.set();
- gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
- LLVector3 arrow_dir;
- LLVector3 arrow_span = mScaleDir;
- arrow_dir = snap_line_start - snap_line_center;
- arrow_dir.normalize();
- gGL.vertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV);
- gGL.vertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV);
- gGL.vertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV);
- arrow_dir = snap_line_end - snap_line_center;
- arrow_dir.normalize();
- gGL.vertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV);
- gGL.vertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV);
- gGL.vertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV);
- }
- gGL.end();
- }
- LLVector2 screen_translate_axis(fabsf(mScaleDir *
- gViewerCamera.getLeftAxis()),
- fabsf(mScaleDir *
- gViewerCamera.getUpAxis()));
- screen_translate_axis.normalize();
- S32 tick_label_spacing = ll_roundp(screen_translate_axis *
- sTickLabelSpacing);
- for (pass = 0; pass < 3; ++pass)
- {
- LLColor4 tick_color = setupSnapGuideRenderPass(pass);
- start_tick = -llmin(ticks_from_scale_center_1, num_ticks_per_side1);
- stop_tick = llmin(max_ticks1, num_ticks_per_side1);
- gGL.begin(LLRender::LINES);
- // draw first row of ticks
- for (S32 i = start_tick; i <= stop_tick; ++i)
- {
- F32 alpha = 1.f - (F32)abs(i) / (F32)num_ticks_per_side1;
- LLVector3 tick_pos = mScaleCenter +
- mScaleDir * (grid_multiple1 + i) *
- smallest_subdivision1;
- F32 tick_scale = 1.f;
- for (F32 division_level = sGridMaxSubdivisionLevel;
- division_level >= sGridMinSubdivisionLevel;
- division_level *= 0.5f)
- {
- if (fmodf((F32)(i + sub_div_offset_1),
- division_level) == 0.f)
- {
- break;
- }
- tick_scale *= 0.7f;
- }
- gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
- tick_color.mV[VBLUE],
- tick_color.mV[VALPHA] * alpha);
- LLVector3 tick_start = tick_pos +
- mSnapGuideDir1 * mSnapRegimeOffset;
- LLVector3 tick_end = tick_start +
- mSnapGuideDir1 * mSnapRegimeOffset *
- tick_scale;
- gGL.vertex3fv(tick_start.mV);
- gGL.vertex3fv(tick_end.mV);
- }
- // Draw opposite row of ticks
- start_tick = -llmin(ticks_from_scale_center_2,
- num_ticks_per_side2);
- stop_tick = llmin(max_ticks2, num_ticks_per_side2);
- for (S32 i = start_tick; i <= stop_tick; ++i)
- {
- F32 alpha = 1.f - (F32)abs(i) / (F32)num_ticks_per_side2;
- LLVector3 tick_pos = mScaleCenter +
- mScaleDir * (grid_multiple2 + i) *
- smallest_subdivision2;
- F32 tick_scale = 1.f;
- for (F32 division_level = sGridMaxSubdivisionLevel;
- division_level >= sGridMinSubdivisionLevel;
- division_level *= 0.5f)
- {
- if (fmodf((F32)(i + sub_div_offset_2),
- division_level) == 0.f)
- {
- break;
- }
- tick_scale *= 0.7f;
- }
- gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
- tick_color.mV[VBLUE],
- tick_color.mV[VALPHA] * alpha);
- LLVector3 tick_start = tick_pos +
- mSnapGuideDir2 * mSnapRegimeOffset;
- LLVector3 tick_end = tick_start +
- mSnapGuideDir2 * mSnapRegimeOffset *
- tick_scale;
- gGL.vertex3fv(tick_start.mV);
- gGL.vertex3fv(tick_end.mV);
- }
- gGL.end();
- }
- // Render upper tick labels
- start_tick = -llmin(ticks_from_scale_center_1, num_ticks_per_side1);
- stop_tick = llmin(max_ticks1, num_ticks_per_side1);
- F32 grid_resolution = 0.25f;
- if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
- {
- static LLCachedControl<F32> grid_res(gSavedSettings,
- "GridResolution");
- grid_resolution = llmax((F32)grid_res, 0.001f);
- }
- S32 label_sub_div_offset_1 = ll_round(fmod(dist_grid_axis -
- grid_offset1,
- mScaleSnapUnit1 * 32.f) /
- smallest_subdivision1);
- S32 label_sub_div_offset_2 = ll_round(fmod(dist_grid_axis -
- grid_offset2,
- mScaleSnapUnit2 * 32.f) /
- smallest_subdivision2);
- for (S32 i = start_tick; i <= stop_tick; ++i)
- {
- F32 tick_scale = 1.f;
- F32 alpha = grid_alpha *
- (1.f -
- 0.5f * (F32)abs(i) / (F32)num_ticks_per_side1);
- LLVector3 tick_pos = mScaleCenter +
- mScaleDir * (grid_multiple1 + i) *
- smallest_subdivision1;
- for (F32 division_level = sGridMaxSubdivisionLevel;
- division_level >= sGridMinSubdivisionLevel;
- division_level *= 0.5f)
- {
- if (fmodf((F32)(i + label_sub_div_offset_1),
- division_level) == 0.f)
- {
- break;
- }
- tick_scale *= 0.7f;
- }
- if (fmodf((F32)(i + label_sub_div_offset_1),
- sGridMaxSubdivisionLevel /
- llmin(sGridMaxSubdivisionLevel,
- getSubdivisionLevel(tick_pos, mScaleDir,
- mScaleSnapUnit1,
- tick_label_spacing))) == 0.f)
- {
- LLVector3 text_origin = tick_pos +
- (mSnapGuideDir1 * mSnapRegimeOffset * (1.f + tick_scale));
- EGridMode grid_mode = gSelectMgr.getGridMode();
- F32 tick_val;
- if (grid_mode == GRID_MODE_WORLD)
- {
- tick_val = (grid_multiple1 + i) *
- grid_resolution / sGridMaxSubdivisionLevel;
- }
- else
- {
- tick_val = 0.5f * (grid_multiple1 + i) /
- sGridMaxSubdivisionLevel;
- }
- // Highlight this text if the tick value matches the snapped to
- // value, and if either the second set of ticks isn't going to
- // be shown or cursor is in the first snap regime.
- F32 text_highlight = 0.8f;
- if (is_approx_equal(tick_val, mScaleSnappedValue) &&
- (mScaleSnapUnit2 == mScaleSnapUnit1 ||
- (mSnapRegime & SNAP_REGIME_UPPER)))
- {
- text_highlight = 1.f;
- }
- renderTickValue(text_origin, tick_val,
- grid_mode == GRID_MODE_WORLD ? std::string("m")
- : std::string("x"),
- LLColor4(text_highlight, text_highlight,
- text_highlight, alpha));
- }
- }
- // Label ticks on opposite side, only can happen in scaling modes that
- // effect more than one axis and when the object's axis don't have the
- // same scale. A differing scale indicates both conditions.
- if (mScaleSnapUnit2 != mScaleSnapUnit1)
- {
- start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2));
- stop_tick = llmin(max_ticks2, num_ticks_per_side2);
- for (S32 i = start_tick; i <= stop_tick; ++i)
- {
- F32 tick_scale = 1.f;
- F32 alpha = grid_alpha *
- (1.f - 0.5f * ((F32)abs(i) /
- (F32)num_ticks_per_side2));
- LLVector3 tick_pos = mScaleCenter +
- mScaleDir * (grid_multiple2 + i) *
- smallest_subdivision2;
- for (F32 division_level = sGridMaxSubdivisionLevel;
- division_level >= sGridMinSubdivisionLevel;
- division_level *= 0.5f)
- {
- if (fmodf((F32)(i + label_sub_div_offset_2),
- division_level) == 0.f)
- {
- break;
- }
- tick_scale *= 0.7f;
- }
- if (fmodf((F32)(i + label_sub_div_offset_2),
- sGridMaxSubdivisionLevel /
- llmin(sGridMaxSubdivisionLevel,
- getSubdivisionLevel(tick_pos, mScaleDir,
- mScaleSnapUnit2,
- tick_label_spacing))) == 0.f)
- {
- LLVector3 text_origin = tick_pos +
- mSnapGuideDir2 *
- mSnapRegimeOffset *
- (1.f + tick_scale);
- EGridMode grid_mode = gSelectMgr.getGridMode();
- F32 tick_val;
- if (grid_mode == GRID_MODE_WORLD)
- {
- tick_val = (grid_multiple2 + i) * grid_resolution /
- sGridMaxSubdivisionLevel;
- }
- else
- {
- tick_val = 0.5f * (grid_multiple2 + i) /
- sGridMaxSubdivisionLevel;
- }
- F32 text_highlight = 0.8f;
- if (is_approx_equal(tick_val, mScaleSnappedValue) &&
- (mSnapRegime & SNAP_REGIME_LOWER))
- {
- text_highlight = 1.f;
- }
- renderTickValue(text_origin, tick_val,
- grid_mode == GRID_MODE_WORLD ? std::string("m")
- : std::string("x"),
- LLColor4(text_highlight, text_highlight,
- text_highlight, alpha));
- }
- }
- }
- // Render help text
- if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
- {
- if (mHelpTextTimer.getElapsedTimeF32() <
- sHelpTextVisibleTime + sHelpTextFadeTime &&
- sNumTimesHelpTextShown < sMaxTimesShowHelpText)
- {
- LLVector3 sel_center =
- gSelectMgr.getSavedBBoxOfSelection().getCenterAgent();
- LLVector3 offset_dir;
- if (mSnapGuideDir1 * gViewerCamera.getAtAxis() >
- mSnapGuideDir2 * gViewerCamera.getAtAxis())
- {
- offset_dir = mSnapGuideDir2;
- }
- else
- {
- offset_dir = mSnapGuideDir1;
- }
- LLVector3 help_text_pos = sel_center +
- mSnapRegimeOffset * 5.f * offset_dir;
- LLColor4 help_text_color = LLColor4::white;
- help_text_color.mV[VALPHA] =
- clamp_rescale(mHelpTextTimer.getElapsedTimeF32(),
- sHelpTextVisibleTime,
- sHelpTextVisibleTime + sHelpTextFadeTime,
- grid_alpha, 0.f);
- const LLFontGL* big_fontp = LLFontGL::getFontSansSerif();
- static LLWString text1 =
- utf8str_to_wstring("Move mouse cursor over ruler");
- static F32 text1_width = -0.5f *
- big_fontp->getWidthF32(text1.c_str());
- hud_render_text(text1, help_text_pos, *big_fontp,
- LLFontGL::NORMAL, text1_width, 3.f,
- help_text_color, false);
- static LLWString text2 = utf8str_to_wstring("to snap to grid");
- static F32 text2_width = -0.5f *
- big_fontp->getWidthF32(text2.c_str());
- help_text_pos -= gViewerCamera.getUpAxis() *
- mSnapRegimeOffset * 0.4f;
- hud_render_text(text2, help_text_pos, *big_fontp,
- LLFontGL::NORMAL, text2_width, 3.f,
- help_text_color, false);
- }
- }
- }
- }
- // Returns unit vector in direction of part of an origin-centered cube
- LLVector3 LLManipScale::partToUnitVector(S32 part) const
- {
- if (LL_FACE_MIN <= part && part <= LL_FACE_MAX)
- {
- return faceToUnitVector(part);
- }
- if (LL_CORNER_MIN <= part && part <= LL_CORNER_MAX)
- {
- return cornerToUnitVector(part);
- }
- if (LL_EDGE_MIN <= part && part <= LL_EDGE_MAX)
- {
- return edgeToUnitVector(part);
- }
- return LLVector3();
- }
- // Returns unit vector in direction of face of an origin-centered cube
- LLVector3 LLManipScale::faceToUnitVector(S32 part) const
- {
- llassert(LL_FACE_MIN <= part && part <= LL_FACE_MAX);
- switch (part)
- {
- case LL_FACE_POSX:
- return LLVector3(1.f, 0.f, 0.f);
- case LL_FACE_NEGX:
- return LLVector3(-1.f, 0.f, 0.f);
- case LL_FACE_POSY:
- return LLVector3(0.f, 1.f, 0.f);
- case LL_FACE_NEGY:
- return LLVector3(0.f, -1.f, 0.f);
- case LL_FACE_POSZ:
- return LLVector3(0.f, 0.f, 1.f);
- case LL_FACE_NEGZ:
- return LLVector3(0.f, 0.f, -1.f);
- }
- return LLVector3();
- }
- // Returns unit vector in direction of corner of an origin-centered cube
- LLVector3 LLManipScale::cornerToUnitVector(S32 part) const
- {
- llassert(LL_CORNER_MIN <= part && part <= LL_CORNER_MAX);
- switch (part)
- {
- case LL_CORNER_NNN:
- return LLVector3(-F_SQRT3, -F_SQRT3, -F_SQRT3);
- case LL_CORNER_NNP:
- return LLVector3(-F_SQRT3, -F_SQRT3, F_SQRT3);
- case LL_CORNER_NPN:
- return LLVector3(-F_SQRT3, F_SQRT3, -F_SQRT3);
- case LL_CORNER_NPP:
- return LLVector3(-F_SQRT3, F_SQRT3, F_SQRT3);
- case LL_CORNER_PNN:
- return LLVector3(F_SQRT3, -F_SQRT3, -F_SQRT3);
- case LL_CORNER_PNP:
- return LLVector3(F_SQRT3, -F_SQRT3, F_SQRT3);
- case LL_CORNER_PPN:
- return LLVector3(F_SQRT3, F_SQRT3, -F_SQRT3);
- case LL_CORNER_PPP:
- return LLVector3(F_SQRT3, F_SQRT3, F_SQRT3);
- }
- return LLVector3();
- }
- // Returns unit vector in direction of edge of an origin-centered cube
- LLVector3 LLManipScale::edgeToUnitVector(S32 part) const
- {
- llassert(LL_EDGE_MIN <= part && part <= LL_EDGE_MAX);
- part -= LL_EDGE_MIN;
- // Edge between which faces: 0 => XY, 1 => YZ, 2 => ZX
- S32 rotation = part >> 2;
- LLVector3 v;
- v.mV[rotation] = (part & 1) ? F_SQRT2 : -F_SQRT2;
- v.mV[(rotation + 1) % 3] = (part & 2) ? F_SQRT2 : -F_SQRT2;
- // v.mV[(rotation+2) % 3] defaults to 0.
- return v;
- }
- // Non-linear scale of origin-centered unit cube to non-origin-centered,
- // non-symetrical bounding box
- LLVector3 LLManipScale::unitVectorToLocalBBoxExtent(const LLVector3& v,
- const LLBBox& bbox) const
- {
- const LLVector3& min = bbox.getMinLocal();
- const LLVector3& max = bbox.getMaxLocal();
- LLVector3 ctr = bbox.getCenterLocal();
- return LLVector3(v.mV[0] ? (v.mV[0]>0 ? max.mV[0] : min.mV[0]) : ctr.mV[0],
- v.mV[1] ? (v.mV[1]>0 ? max.mV[1] : min.mV[1]) : ctr.mV[1],
- v.mV[2] ? (v.mV[2]>0 ? max.mV[2] : min.mV[2]) : ctr.mV[2]);
- }
- // Teturns max allowable scale along a given stretch axis
- F32 LLManipScale::partToMaxScale(S32 part, const LLBBox& bbox) const
- {
- F32 max_scale_factor = 0.f;
- LLVector3 bbox_extents = unitVectorToLocalBBoxExtent(partToUnitVector(part),
- bbox);
- bbox_extents.abs();
- F32 max_extent = 0.f;
- for (U32 i = VX; i <= VZ; ++i)
- {
- if (bbox_extents.mV[i] > max_extent)
- {
- max_extent = bbox_extents.mV[i];
- }
- }
- max_scale_factor = bbox_extents.length() * maxPrimScale() / max_extent;
- if (getUniform())
- {
- max_scale_factor *= 0.5f;
- }
- return max_scale_factor;
- }
- // Returns min allowable scale along a given stretch axis
- F32 LLManipScale::partToMinScale(S32 part, const LLBBox& bbox) const
- {
- LLVector3 bbox_extents;
- bbox_extents = unitVectorToLocalBBoxExtent(partToUnitVector(part), bbox);
- bbox_extents.abs();
- F32 min_extent = maxPrimScale();
- for (U32 i = VX; i <= VZ; ++i)
- {
- if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent)
- {
- min_extent = bbox_extents.mV[i];
- }
- }
- F32 min_scale_factor = bbox_extents.length() * minPrimScale() / min_extent;
- if (getUniform())
- {
- min_scale_factor *= 0.5f;
- }
- return min_scale_factor;
- }
- // Returns the axis aligned unit vector closest to v.
- LLVector3 LLManipScale::nearestAxis(const LLVector3& v) const
- {
- // Note: yes, this is a slow but easy implementation. Assumes that v is
- // normalized
- static LLVector3 coords[] = {
- LLVector3(1.f, 0.f, 0.f),
- LLVector3(0.f, 1.f, 0.f),
- LLVector3(0.f, 0.f, 1.f),
- LLVector3(-1.f, 0.f, 0.f),
- LLVector3(0.f, -1.f, 0.f),
- LLVector3(0.f, 0.f, -1.f)
- };
- F32 cosine[6];
- F32 cos = v * coords[0];
- cosine[0] = cos;
- cosine[3] = -cos;
- cos = v * coords[1];
- cosine[1] = cos;
- cosine[4] = -cos;
- cos = v * coords[2];
- cosine[2] = cos;
- cosine[5] = -cos;
- F32 greatest_cos = cosine[0];
- S32 greatest_index = 0;
- for (S32 i = 1; i < 6; ++i)
- {
- cos = cosine[i];
- if (greatest_cos < cos)
- {
- greatest_cos = cos;
- greatest_index = i;
- }
- }
- return coords[greatest_index];
- }
- //virtual
- bool LLManipScale::canAffectSelection()
- {
- // A selection is scalable if you are allowed to both edit and move
- // everything in it, and it does not have any sitting agents
- bool can_scale = mObjectSelection->getObjectCount() != 0;
- if (can_scale)
- {
- struct f final : public LLSelectedObjectFunctor
- {
- bool apply(LLViewerObject* objectp) override
- {
- if (!objectp)
- {
- llwarns << "NULL object passed to functor !" << llendl;
- return false;
- }
- LLViewerObject* root_object = objectp->getRootEdit();
- return objectp->permModify() && objectp->permMove() &&
- !objectp->isPermanentEnforced() && !objectp->isSeat() &&
- (!root_object ||
- (!root_object->isPermanentEnforced() &&
- !root_object->isSeat()));
- }
- } func;
- can_scale = mObjectSelection->applyToObjects(&func);
- }
- return can_scale;
- }
|