llmanipscale.cpp 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469
  1. /**
  2. * @file llmanipscale.cpp
  3. * @brief LLManipScale class implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llmanipscale.h"
  34. #include "llbbox.h"
  35. #include "llgl.h"
  36. #include "llrender.h"
  37. #include "llrenderutils.h"
  38. #include "llprimitive.h"
  39. #include "llagent.h"
  40. #include "lldrawable.h"
  41. #include "llfloatertools.h"
  42. #include "llgridmanager.h" // For gIsInSecondLife
  43. #include "llmeshrepository.h"
  44. #include "llselectmgr.h"
  45. #include "llstatusbar.h"
  46. #include "llviewercamera.h"
  47. #include "llviewercontrol.h"
  48. #include "llviewerdisplay.h" // For hud_render_text()
  49. #include "llviewerobject.h"
  50. #include "llviewerregion.h"
  51. #include "llviewerwindow.h"
  52. #include "llvoavatar.h"
  53. #include "llworld.h"
  54. constexpr F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f;
  55. constexpr F32 SNAP_GUIDE_SCREEN_OFFSET = 0.05f;
  56. constexpr F32 SNAP_GUIDE_SCREEN_LENGTH = 0.7f;
  57. constexpr F32 SELECTED_MANIPULATOR_SCALE = 1.2f;
  58. constexpr F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
  59. constexpr S32 NUM_MANIPULATORS = 14;
  60. const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] =
  61. {
  62. LLManip::LL_CORNER_NNN,
  63. LLManip::LL_CORNER_NNP,
  64. LLManip::LL_CORNER_NPN,
  65. LLManip::LL_CORNER_NPP,
  66. LLManip::LL_CORNER_PNN,
  67. LLManip::LL_CORNER_PNP,
  68. LLManip::LL_CORNER_PPN,
  69. LLManip::LL_CORNER_PPP,
  70. LLManip::LL_FACE_POSZ,
  71. LLManip::LL_FACE_POSX,
  72. LLManip::LL_FACE_POSY,
  73. LLManip::LL_FACE_NEGX,
  74. LLManip::LL_FACE_NEGY,
  75. LLManip::LL_FACE_NEGZ
  76. };
  77. //static
  78. F32 LLManipScale::maxPrimScale(bool is_flora)
  79. {
  80. static LLCachedControl<F32> os_max_prim_scale(gSavedSettings,
  81. "OSMaxPrimScale");
  82. // A bit of a hack, but if it is foilage, we do not want to use the largest
  83. // scale which would result in giant trees and grass.
  84. if (!is_flora && !gIsInSecondLife)
  85. {
  86. return llclamp((F32)os_max_prim_scale, DEFAULT_MAX_PRIM_SCALE,
  87. 65536.0f);
  88. }
  89. if (!is_flora && gMeshRepo.meshRezEnabled())
  90. {
  91. return DEFAULT_MAX_PRIM_SCALE;
  92. }
  93. return DEFAULT_MAX_PRIM_SCALE_NO_MESH;
  94. }
  95. //static
  96. F32 LLManipScale::minPrimScale(bool is_flora)
  97. {
  98. static LLCachedControl<F32> os_min_prim_scale(gSavedSettings,
  99. "OSMinPrimScale");
  100. // A bit of a hack, but if it is foilage, we do not want to use the
  101. // smallest scale which would result in micro trees and grass.
  102. if (!is_flora && !gIsInSecondLife)
  103. {
  104. return llclamp((F32)os_min_prim_scale, 0.0001f,
  105. DEFAULT_MIN_PRIM_SCALE);
  106. }
  107. return DEFAULT_MIN_PRIM_SCALE;
  108. }
  109. //static
  110. void LLManipScale::setUniform(bool b)
  111. {
  112. gSavedSettings.setBool("ScaleUniform", b);
  113. }
  114. //static
  115. void LLManipScale::setShowAxes(bool b)
  116. {
  117. gSavedSettings.setBool("ScaleShowAxes", b);
  118. }
  119. //static
  120. void LLManipScale::setStretchTextures(bool b)
  121. {
  122. gSavedSettings.setBool("ScaleStretchTextures", b);
  123. }
  124. //static
  125. bool LLManipScale::getUniform()
  126. {
  127. static LLCachedControl<bool> scale_uniform(gSavedSettings, "ScaleUniform");
  128. return (bool)scale_uniform;
  129. }
  130. //static
  131. bool LLManipScale::getShowAxes()
  132. {
  133. static LLCachedControl<bool> scale_show_axes(gSavedSettings,
  134. "ScaleShowAxes");
  135. return (bool)scale_show_axes;
  136. }
  137. //static
  138. bool LLManipScale::getStretchTextures()
  139. {
  140. static LLCachedControl<bool> scale_stretch_textures(gSavedSettings,
  141. "ScaleStretchTextures");
  142. return (bool)scale_stretch_textures;
  143. }
  144. //static
  145. bool LLManipScale::getSnapEnabled()
  146. {
  147. static LLCachedControl<bool> snap_enabled(gSavedSettings, "SnapEnabled");
  148. return snap_enabled;
  149. }
  150. LL_INLINE void LLManipScale::conditionalHighlight(U32 part,
  151. const LLColor4* highlight,
  152. const LLColor4* normal)
  153. {
  154. LLColor4 default_highlight(1.f, 1.f, 1.f, 1.f);
  155. LLColor4 default_normal(0.7f, 0.7f, 0.7f, 0.6f);
  156. LLColor4 invisible(0.f, 0.f, 0.f, 0.f);
  157. F32 manipulator_scale = 1.f;
  158. for (S32 i = 0; i < NUM_MANIPULATORS; ++i)
  159. {
  160. if ((U32)MANIPULATOR_IDS[i] == part)
  161. {
  162. manipulator_scale = mManipulatorScales[i];
  163. break;
  164. }
  165. }
  166. mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale;
  167. if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part)
  168. {
  169. gGL.color4fv(invisible.mV);
  170. }
  171. else if (mHighlightedPart == (S32)part)
  172. {
  173. gGL.color4fv(highlight ? highlight->mV : default_highlight.mV);
  174. }
  175. else
  176. {
  177. gGL.color4fv(normal ? normal->mV : default_normal.mV);
  178. }
  179. }
  180. void LLManipScale::handleSelect()
  181. {
  182. LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  183. updateSnapGuides(bbox);
  184. gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
  185. if (gFloaterToolsp)
  186. {
  187. gFloaterToolsp->setStatusText("scale");
  188. }
  189. LLManip::handleSelect();
  190. }
  191. LLManipScale::LLManipScale(LLToolComposite* composite)
  192. : LLManip(std::string("Scale"), composite),
  193. mBoxHandleSize(1.f),
  194. mScaledBoxHandleSize(1.f),
  195. mLastMouseX(-1),
  196. mLastMouseY(-1),
  197. mLastUpdateFlags(0),
  198. mScaleSnapUnit1(1.f),
  199. mScaleSnapUnit2(1.f),
  200. mSnapRegimeOffset(0.f),
  201. mTickPixelSpacing1(0.f),
  202. mTickPixelSpacing2(0.f),
  203. mSnapGuideLength(0.f),
  204. mSnapRegime(SNAP_REGIME_NONE),
  205. mScaleSnappedValue(0.f)
  206. {
  207. mManipulatorScales = new F32[NUM_MANIPULATORS];
  208. for (S32 i = 0; i < NUM_MANIPULATORS; ++i)
  209. {
  210. mManipulatorScales[i] = 1.f;
  211. }
  212. }
  213. LLManipScale::~LLManipScale()
  214. {
  215. for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(),
  216. DeletePointer());
  217. mProjectedManipulators.clear();
  218. delete[] mManipulatorScales;
  219. }
  220. void LLManipScale::render()
  221. {
  222. LLGLSUIDefault gls_ui;
  223. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  224. LLGLDepthTest gls_depth(GL_TRUE);
  225. LLGLEnable gl_blend(GL_BLEND);
  226. if (canAffectSelection())
  227. {
  228. gGL.matrixMode(LLRender::MM_MODELVIEW);
  229. gGL.pushMatrix();
  230. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  231. {
  232. F32 zoom = gAgent.mHUDCurZoom;
  233. gGL.scalef(zoom, zoom, zoom);
  234. }
  235. // Calculate size of drag handles
  236. // Box size in pixels = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR
  237. constexpr F32 BOX_HANDLE_BASE_SIZE = 50.f;
  238. constexpr F32 BOX_HANDLE_BASE_FACTOR = 0.2f;
  239. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  240. {
  241. mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR /
  242. (F32)gViewerCamera.getViewHeightInPixels();
  243. mBoxHandleSize /= gAgent.mHUDCurZoom;
  244. }
  245. else
  246. {
  247. LLVector3 center_agent =
  248. gAgent.getPosAgentFromGlobal(gSelectMgr.getSelectionCenterGlobal());
  249. F32 range = dist_vec(gAgent.getCameraPositionAgent(),
  250. center_agent);
  251. F32 range_from_agent = dist_vec(gAgent.getPositionAgent(),
  252. center_agent);
  253. // Don't draw manip if object too far away
  254. static LLCachedControl<bool> limit_select_distance(gSavedSettings,
  255. "LimitSelectDistance");
  256. static LLCachedControl<F32> max_select_distance(gSavedSettings,
  257. "MaxSelectDistance");
  258. if (limit_select_distance)
  259. {
  260. if (range_from_agent > max_select_distance)
  261. {
  262. return;
  263. }
  264. }
  265. static LLCachedControl<bool> zoom_dependent_handles(gSavedSettings,
  266. "ZoomDependentResizeHandles");
  267. if (zoom_dependent_handles)
  268. {
  269. mBoxHandleSize = BOX_HANDLE_BASE_FACTOR * BOX_HANDLE_BASE_SIZE *
  270. (1.005f - gAgent.getCameraZoomFraction()) / 20.f;
  271. }
  272. else if (range > 0.001f)
  273. {
  274. // range != zero
  275. F32 fraction_of_fov =
  276. BOX_HANDLE_BASE_SIZE /
  277. (F32)gViewerCamera.getViewHeightInPixels();
  278. F32 apparent_angle = fraction_of_fov *
  279. gViewerCamera.getView(); // radians
  280. mBoxHandleSize = range * tanf(apparent_angle) *
  281. BOX_HANDLE_BASE_FACTOR;
  282. }
  283. else
  284. {
  285. // range == zero
  286. mBoxHandleSize = BOX_HANDLE_BASE_FACTOR;
  287. }
  288. }
  289. ////////////////////////////////////////////////////////////////////////
  290. // Draw bounding box
  291. LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  292. LLVector3 pos_agent = bbox.getPositionAgent();
  293. LLQuaternion rot = bbox.getRotation();
  294. gGL.matrixMode(LLRender::MM_MODELVIEW);
  295. gGL.pushMatrix();
  296. {
  297. gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ]);
  298. F32 angle_radians, x, y, z;
  299. rot.getAngleAxis(&angle_radians, &x, &y, &z);
  300. gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
  301. {
  302. LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL);
  303. glPolygonOffset(-2.f, -2.f);
  304. renderCorners(bbox);
  305. renderFaces(bbox);
  306. if (mManipPart != LL_NO_PART)
  307. {
  308. renderGuidelinesPart(bbox);
  309. }
  310. glPolygonOffset(0.f, 0.f);
  311. }
  312. }
  313. gGL.popMatrix();
  314. if (mManipPart != LL_NO_PART)
  315. {
  316. renderSnapGuides(bbox);
  317. }
  318. gGL.popMatrix();
  319. renderXYZ(bbox.getExtentLocal());
  320. }
  321. }
  322. bool LLManipScale::handleMouseDown(S32 x, S32 y, MASK mask)
  323. {
  324. if (mHighlightedPart != LL_NO_PART)
  325. {
  326. return handleMouseDownOnPart(x, y, mask);
  327. }
  328. return false;
  329. }
  330. // Assumes that one of the arrows on an object was hit.
  331. bool LLManipScale::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
  332. {
  333. if (!canAffectSelection())
  334. {
  335. return false;
  336. }
  337. highlightManipulators(x, y);
  338. S32 hit_part = mHighlightedPart;
  339. gSelectMgr.enableSilhouette(false);
  340. mManipPart = (EManipPart)hit_part;
  341. LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  342. LLVector3 box_center_agent = bbox.getCenterAgent();
  343. LLVector3 box_corner_agent =
  344. bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
  345. bbox));
  346. updateSnapGuides(bbox);
  347. mDragStartPointGlobal = gAgent.getPosGlobalFromAgent(box_corner_agent);
  348. mDragStartCenterGlobal = gAgent.getPosGlobalFromAgent(box_center_agent);
  349. LLVector3 far_corner_agent =
  350. bbox.localToAgent(unitVectorToLocalBBoxExtent(-1.f * partToUnitVector(mManipPart),
  351. bbox));
  352. mDragFarHitGlobal = gAgent.getPosGlobalFromAgent(far_corner_agent);
  353. mDragPointGlobal = mDragStartPointGlobal;
  354. // We just started a drag, so save initial object positions, orientations,
  355. // and scales
  356. gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
  357. // Route future Mouse messages here preemptively. (Release on mouse up.)
  358. setMouseCapture(true);
  359. mHelpTextTimer.reset();
  360. ++sNumTimesHelpTextShown;
  361. return true;
  362. }
  363. bool LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask)
  364. {
  365. // First, perform normal processing in case this was a quick-click
  366. handleHover(x, y, mask);
  367. if (hasMouseCapture())
  368. {
  369. if (LL_FACE_MIN <= (S32)mManipPart && (S32)mManipPart <= LL_FACE_MAX)
  370. {
  371. sendUpdates(true, true, false);
  372. }
  373. else if (LL_CORNER_MIN <= (S32)mManipPart &&
  374. (S32)mManipPart <= LL_CORNER_MAX)
  375. {
  376. sendUpdates(true, true, true);
  377. }
  378. //send texture update
  379. gSelectMgr.adjustTexturesByScale(true, getStretchTextures());
  380. gSelectMgr.enableSilhouette(true);
  381. mManipPart = LL_NO_PART;
  382. // Might have missed last update due to UPDATE_DELAY timing
  383. gSelectMgr.sendMultipleUpdate(mLastUpdateFlags);
  384. #if 0
  385. gAgent.setObjectTracking(gSavedSettings.getBool("TrackFocusObject"));
  386. #endif
  387. gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
  388. }
  389. return LLManip::handleMouseUp(x, y, mask);
  390. }
  391. bool LLManipScale::handleHover(S32 x, S32 y, MASK mask)
  392. {
  393. if (hasMouseCapture())
  394. {
  395. if (mObjectSelection->isEmpty())
  396. {
  397. // Somehow the object got deselected while we were dragging it.
  398. setMouseCapture(false);
  399. }
  400. else
  401. {
  402. drag(x, y);
  403. }
  404. LL_DEBUGS("UserInput") << "hover handled by LLManipScale (active)"
  405. << LL_ENDL;
  406. }
  407. else
  408. {
  409. mSnapRegime = SNAP_REGIME_NONE;
  410. // not dragging...
  411. highlightManipulators(x, y);
  412. }
  413. // Patch up textures, if possible.
  414. gSelectMgr.adjustTexturesByScale(false, getStretchTextures());
  415. gWindowp->setCursor(UI_CURSOR_TOOLSCALE);
  416. return true;
  417. }
  418. void LLManipScale::highlightManipulators(S32 x, S32 y)
  419. {
  420. mHighlightedPart = LL_NO_PART;
  421. // If we have something selected, try to hit its manipulator handles.
  422. // Do not do this with nothing selected, as it kills the framerate.
  423. LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  424. if (canAffectSelection())
  425. {
  426. LLMatrix4 transform;
  427. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  428. {
  429. LLVector4 translation(bbox.getPositionAgent());
  430. transform.initRotTrans(bbox.getRotation(), translation);
  431. LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
  432. transform *= cfr;
  433. LLMatrix4 window_scale;
  434. F32 zoom_level = 2.f * gAgent.mHUDCurZoom;
  435. window_scale.initAll(LLVector3(zoom_level / gViewerCamera.getAspect(),
  436. zoom_level, 0.f),
  437. LLQuaternion::DEFAULT,
  438. LLVector3::zero);
  439. transform *= window_scale;
  440. }
  441. else
  442. {
  443. LLMatrix4 proj_mat = gViewerCamera.getProjection();
  444. LLMatrix4 model_view = gViewerCamera.getModelview();
  445. transform.initAll(LLVector3(1.f, 1.f, 1.f), bbox.getRotation(),
  446. bbox.getPositionAgent());
  447. transform *= model_view;
  448. transform *= proj_mat;
  449. }
  450. LLVector3 min = bbox.getMinLocal();
  451. LLVector3 max = bbox.getMaxLocal();
  452. LLVector3 ctr = bbox.getCenterLocal();
  453. S32 manips = 0;
  454. // corners
  455. mManipulatorVertices[manips++] = LLVector4(min.mV[VX], min.mV[VY],
  456. min.mV[VZ], 1.f);
  457. mManipulatorVertices[manips++] = LLVector4(min.mV[VX], min.mV[VY],
  458. max.mV[VZ], 1.f);
  459. mManipulatorVertices[manips++] = LLVector4(min.mV[VX], max.mV[VY],
  460. min.mV[VZ], 1.f);
  461. mManipulatorVertices[manips++] = LLVector4(min.mV[VX], max.mV[VY],
  462. max.mV[VZ], 1.f);
  463. mManipulatorVertices[manips++] = LLVector4(max.mV[VX], min.mV[VY],
  464. min.mV[VZ], 1.f);
  465. mManipulatorVertices[manips++] = LLVector4(max.mV[VX], min.mV[VY],
  466. max.mV[VZ], 1.f);
  467. mManipulatorVertices[manips++] = LLVector4(max.mV[VX], max.mV[VY],
  468. min.mV[VZ], 1.f);
  469. mManipulatorVertices[manips++] = LLVector4(max.mV[VX], max.mV[VY],
  470. max.mV[VZ], 1.f);
  471. // 1-D highlights are applicable iff one object is selected
  472. if (mObjectSelection->getObjectCount() == 1)
  473. {
  474. // Face centers
  475. mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], ctr.mV[VY],
  476. max.mV[VZ], 1.f);
  477. mManipulatorVertices[manips++] = LLVector4(max.mV[VX], ctr.mV[VY],
  478. ctr.mV[VZ], 1.f);
  479. mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], max.mV[VY],
  480. ctr.mV[VZ], 1.f);
  481. mManipulatorVertices[manips++] = LLVector4(min.mV[VX], ctr.mV[VY],
  482. ctr.mV[VZ], 1.f);
  483. mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], min.mV[VY],
  484. ctr.mV[VZ], 1.f);
  485. mManipulatorVertices[manips++] = LLVector4(ctr.mV[VX], ctr.mV[VY],
  486. min.mV[VZ], 1.f);
  487. }
  488. for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(),
  489. DeletePointer());
  490. mProjectedManipulators.clear();
  491. for (S32 i = 0; i < manips; ++i)
  492. {
  493. LLVector4 projectedVertex = mManipulatorVertices[i] * transform;
  494. projectedVertex = projectedVertex * (1.f / projectedVertex.mV[VW]);
  495. ManipulatorHandle* proj_manip =
  496. new ManipulatorHandle(LLVector3(projectedVertex.mV[VX],
  497. projectedVertex.mV[VY],
  498. projectedVertex.mV[VZ]),
  499. MANIPULATOR_IDS[i],
  500. i < 7 ? SCALE_MANIP_CORNER
  501. : SCALE_MANIP_FACE);
  502. mProjectedManipulators.insert(proj_manip);
  503. }
  504. F32 half_width = (F32)gViewerWindowp->getWindowWidth() * 0.5f;
  505. F32 half_height = (F32)gViewerWindowp->getWindowHeight() * 0.5f;
  506. LLVector2 manip2d;
  507. LLVector2 mousePos((F32)x - half_width, (F32)y - half_height);
  508. LLVector2 delta;
  509. mHighlightedPart = LL_NO_PART;
  510. for (manipulator_list_t::iterator iter = mProjectedManipulators.begin();
  511. iter != mProjectedManipulators.end(); ++iter)
  512. {
  513. ManipulatorHandle* manipulator = *iter;
  514. {
  515. manip2d.set(manipulator->mPosition.mV[VX] * half_width,
  516. manipulator->mPosition.mV[VY] * half_height);
  517. delta = manip2d - mousePos;
  518. if (delta.lengthSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED)
  519. {
  520. mHighlightedPart = manipulator->mManipID;
  521. break;
  522. }
  523. }
  524. }
  525. }
  526. F32 critical_damp =
  527. LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE);
  528. for (S32 i = 0; i < NUM_MANIPULATORS; ++i)
  529. {
  530. if (mHighlightedPart == MANIPULATOR_IDS[i])
  531. {
  532. mManipulatorScales[i] = lerp(mManipulatorScales[i],
  533. SELECTED_MANIPULATOR_SCALE,
  534. critical_damp);
  535. }
  536. else
  537. {
  538. mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f,
  539. critical_damp);
  540. }
  541. }
  542. LL_DEBUGS("UserInput") << "hover handled by LLManipScale (inactive)"
  543. << LL_ENDL;
  544. }
  545. void LLManipScale::renderFaces(const LLBBox& bbox)
  546. {
  547. // Do not bother to render the drag handles for 1-D scaling if more than
  548. // one object is selected or if it is an attachment
  549. if (mObjectSelection->getObjectCount() > 1)
  550. {
  551. return;
  552. }
  553. // This is a flattened representation of the box as render here
  554. // .
  555. // (+++) (++-) /|\t
  556. // +------------+ | (texture coordinates)
  557. // | | |
  558. // | 1 | (*) --->s
  559. // | +X |
  560. // | |
  561. // (+++) (+-+)| |(+--) (++-) (+++)
  562. // +------------+------------+------------+------------+
  563. // |0 3|3 7|7 4|4 0|
  564. // | 0 | 4 | 5 | 2 |
  565. // | +Z | -Y | -Z | +Y |
  566. // | | | | |
  567. // |1 2|2 6|6 5|5 1|
  568. // +------------+------------+------------+------------+
  569. // (-++) (--+)| |(---) (-+-) (-++)
  570. // | 3 |
  571. // | -X |
  572. // | |
  573. // | |
  574. // +------------+
  575. // (-++) (-+-)
  576. LLColor4 highlight_color(1.f, 1.f, 1.f, 0.5f);
  577. LLColor4 normal_color(1.f, 1.f, 1.f, 0.3f);
  578. LLColor4 x_highlight_color(1.f, 0.2f, 0.2f, 1.0f);
  579. LLColor4 x_normal_color(0.6f, 0.f, 0.f, 0.4f);
  580. LLColor4 y_highlight_color(0.2f, 1.f, 0.2f, 1.0f);
  581. LLColor4 y_normal_color(0.f, 0.6f, 0.f, 0.4f);
  582. LLColor4 z_highlight_color(0.2f, 0.2f, 1.f, 1.0f);
  583. LLColor4 z_normal_color(0.f, 0.f, 0.6f, 0.4f);
  584. LLColor4 default_normal_color(0.7f, 0.7f, 0.7f, 0.15f);
  585. const LLVector3& min = bbox.getMinLocal();
  586. const LLVector3& max = bbox.getMaxLocal();
  587. LLVector3 ctr = bbox.getCenterLocal();
  588. if (mManipPart == LL_NO_PART)
  589. {
  590. gGL.color4fv(default_normal_color.mV);
  591. LLGLDepthTest gls_depth(GL_FALSE);
  592. gGL.begin(LLRender::TRIANGLES);
  593. {
  594. // Face 0
  595. gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
  596. gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
  597. gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
  598. gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
  599. gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
  600. gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
  601. // Face 1
  602. gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
  603. gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
  604. gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
  605. gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
  606. gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
  607. gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
  608. // Face 2
  609. gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
  610. gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
  611. gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
  612. gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
  613. gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
  614. gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
  615. // Face 3
  616. gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
  617. gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
  618. gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
  619. gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
  620. gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
  621. gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
  622. // Face 4
  623. gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
  624. gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
  625. gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
  626. gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
  627. gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
  628. gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
  629. // Face 5
  630. gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
  631. gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
  632. gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
  633. gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
  634. gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
  635. gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
  636. }
  637. gGL.end();
  638. }
  639. // Find nearest vertex
  640. LLVector3 orientWRTHead =
  641. bbox.agentToLocalBasis(bbox.getCenterAgent() -
  642. gAgent.getCameraPositionAgent());
  643. U32 nearest = (orientWRTHead.mV[0] < 0.f ? 1 : 0) +
  644. (orientWRTHead.mV[1] < 0.f ? 2 : 0) +
  645. (orientWRTHead.mV[2] < 0.f ? 4 : 0);
  646. // Opposite faces on Linden cubes:
  647. // 0 & 5
  648. // 1 & 3
  649. // 2 & 4
  650. // Table of order to draw faces, based on nearest vertex
  651. static U32 face_list[8][6] = {
  652. { 2,0,1, 4,5,3 }, // v6 F201 F453
  653. { 2,0,3, 4,5,1 }, // v7 F203 F451
  654. { 4,0,1, 2,5,3 }, // v5 F401 F253
  655. { 4,0,3, 2,5,1 }, // v4 F403 F251
  656. { 2,5,1, 4,0,3 }, // v2 F251 F403
  657. { 2,5,3, 4,0,1 }, // v3 F253 F401
  658. { 4,5,1, 2,0,3 }, // v1 F451 F203
  659. { 4,5,3, 2,0,1 } // v0 F453 F201
  660. };
  661. {
  662. LLGLDepthTest gls_depth(GL_FALSE);
  663. for (S32 i = 0; i < 6; ++i)
  664. {
  665. U32 face = face_list[nearest][i];
  666. switch (face)
  667. {
  668. case 0:
  669. conditionalHighlight(LL_FACE_POSZ, &z_highlight_color,
  670. &z_normal_color);
  671. renderAxisHandle(ctr,
  672. LLVector3(ctr.mV[VX], ctr.mV[VY],
  673. max.mV[VZ]));
  674. break;
  675. case 1:
  676. conditionalHighlight(LL_FACE_POSX, &x_highlight_color,
  677. &x_normal_color);
  678. renderAxisHandle(ctr,
  679. LLVector3(max.mV[VX], ctr.mV[VY],
  680. ctr.mV[VZ]));
  681. break;
  682. case 2:
  683. conditionalHighlight(LL_FACE_POSY, &y_highlight_color,
  684. &y_normal_color);
  685. renderAxisHandle(ctr,
  686. LLVector3(ctr.mV[VX], max.mV[VY],
  687. ctr.mV[VZ]));
  688. break;
  689. case 3:
  690. conditionalHighlight(LL_FACE_NEGX, &x_highlight_color,
  691. &x_normal_color);
  692. renderAxisHandle(ctr,
  693. LLVector3(min.mV[VX], ctr.mV[VY],
  694. ctr.mV[VZ]));
  695. break;
  696. case 4:
  697. conditionalHighlight(LL_FACE_NEGY, &y_highlight_color,
  698. &y_normal_color);
  699. renderAxisHandle(ctr,
  700. LLVector3(ctr.mV[VX], min.mV[VY],
  701. ctr.mV[VZ]));
  702. break;
  703. case 5:
  704. conditionalHighlight(LL_FACE_NEGZ, &z_highlight_color,
  705. &z_normal_color);
  706. renderAxisHandle(ctr,
  707. LLVector3(ctr.mV[VX], ctr.mV[VY],
  708. min.mV[VZ]));
  709. }
  710. }
  711. }
  712. }
  713. void LLManipScale::renderCorners(const LLBBox& bbox)
  714. {
  715. U32 part = LL_CORNER_NNN;
  716. F32 x_offset = bbox.getMinLocal().mV[VX];
  717. for (S32 i = 0; i < 2; ++i)
  718. {
  719. F32 y_offset = bbox.getMinLocal().mV[VY];
  720. for (S32 j = 0; j < 2; ++j)
  721. {
  722. F32 z_offset = bbox.getMinLocal().mV[VZ];
  723. for (S32 k = 0; k < 2; ++k)
  724. {
  725. conditionalHighlight(part++);
  726. renderBoxHandle(x_offset, y_offset, z_offset);
  727. z_offset = bbox.getMaxLocal().mV[VZ];
  728. }
  729. y_offset = bbox.getMaxLocal().mV[VY];
  730. }
  731. x_offset = bbox.getMaxLocal().mV[VX];
  732. }
  733. }
  734. void LLManipScale::renderBoxHandle(F32 x, F32 y, F32 z)
  735. {
  736. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  737. LLGLDepthTest gls_depth(GL_FALSE);
  738. gGL.pushMatrix();
  739. {
  740. gGL.translatef(x, y, z);
  741. gGL.scalef(mScaledBoxHandleSize, mScaledBoxHandleSize,
  742. mScaledBoxHandleSize);
  743. gBox.render();
  744. }
  745. gGL.popMatrix();
  746. }
  747. void LLManipScale::renderAxisHandle(const LLVector3& start,
  748. const LLVector3& end)
  749. {
  750. if (getShowAxes())
  751. {
  752. // Draws a single "jacks" style handle: a long, retangular box from
  753. // start to end.
  754. LLVector3 offset_start = end - start;
  755. offset_start.normalize();
  756. offset_start = start + mBoxHandleSize * offset_start;
  757. LLVector3 delta = end - offset_start;
  758. LLVector3 pos = offset_start + 0.5f * delta;
  759. gGL.pushMatrix();
  760. {
  761. gGL.translatef(pos.mV[VX], pos.mV[VY], pos.mV[VZ]);
  762. gGL.scalef(mBoxHandleSize + fabsf(delta.mV[VX]),
  763. mBoxHandleSize + fabsf(delta.mV[VY]),
  764. mBoxHandleSize + fabsf(delta.mV[VZ]));
  765. gBox.render();
  766. }
  767. gGL.popMatrix();
  768. }
  769. else
  770. {
  771. renderBoxHandle(end.mV[VX], end.mV[VY], end.mV[VZ]);
  772. }
  773. }
  774. // General scale call
  775. void LLManipScale::drag(S32 x, S32 y)
  776. {
  777. if (LL_FACE_MIN <= (S32)mManipPart && (S32)mManipPart <= LL_FACE_MAX)
  778. {
  779. dragFace(x, y);
  780. }
  781. else if (LL_CORNER_MIN <= (S32)mManipPart &&
  782. (S32)mManipPart <= LL_CORNER_MAX)
  783. {
  784. dragCorner(x, y);
  785. }
  786. // store changes to override updates
  787. for (LLObjectSelection::iterator
  788. iter = gSelectMgr.getSelection()->begin(),
  789. end = gSelectMgr.getSelection()->end();
  790. iter != end; ++iter)
  791. {
  792. LLSelectNode* selectNode = *iter;
  793. LLViewerObject* object = selectNode->getObject();
  794. if (!object)
  795. {
  796. llwarns << "NULL selected object !" << llendl;
  797. continue;
  798. }
  799. LLViewerObject* root_object = object->getRootEdit();
  800. if (!object->isAvatar() && object->permModify() &&
  801. object->permMove() && !object->isPermanentEnforced() &&
  802. (!root_object || !root_object->isPermanentEnforced()))
  803. {
  804. selectNode->mLastScale = object->getScale();
  805. selectNode->mLastPositionLocal = object->getPosition();
  806. }
  807. }
  808. gSelectMgr.updateSelectionCenter();
  809. gAgent.clearFocusObject();
  810. }
  811. // Scale on three axis simultaneously
  812. void LLManipScale::dragCorner(S32 x, S32 y)
  813. {
  814. // Suppress scale if mouse hasn't moved.
  815. if (x == mLastMouseX && y == mLastMouseY)
  816. {
  817. return;
  818. }
  819. mLastMouseX = x;
  820. mLastMouseY = y;
  821. LLVector3 drag_start_point_agent =
  822. gAgent.getPosAgentFromGlobal(mDragStartPointGlobal);
  823. LLVector3 drag_start_center_agent =
  824. gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal);
  825. LLVector3d drag_start_dir_d;
  826. drag_start_dir_d.set(mDragStartPointGlobal - mDragStartCenterGlobal);
  827. F32 s = 0;
  828. F32 t = 0;
  829. nearestPointOnLineFromMouse(x, y, drag_start_center_agent,
  830. drag_start_point_agent, s, t);
  831. if (s <= 0) // we only care about intersections in front of the camera
  832. {
  833. return;
  834. }
  835. mDragPointGlobal = lerp(mDragStartCenterGlobal, mDragStartPointGlobal, t);
  836. LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  837. F32 max_scale = partToMaxScale(mManipPart, bbox);
  838. F32 min_scale = partToMinScale(mManipPart, bbox);
  839. F32 scale_factor = 1.f;
  840. bool uniform = getUniform();
  841. // check for snapping
  842. LLVector3 mouse_on_plane1;
  843. getMousePointOnPlaneAgent(mouse_on_plane1, x, y, mScaleCenter,
  844. mScalePlaneNormal1);
  845. mouse_on_plane1 -= mScaleCenter;
  846. LLVector3 mouse_on_plane2;
  847. getMousePointOnPlaneAgent(mouse_on_plane2, x, y, mScaleCenter,
  848. mScalePlaneNormal2);
  849. mouse_on_plane2 -= mScaleCenter;
  850. LLVector3 projected_drag_pos1, projected_drag_pos2;
  851. projected_drag_pos1 =
  852. inverse_projected_vec(mScaleDir,
  853. orthogonal_component(mouse_on_plane1,
  854. mSnapGuideDir1));
  855. projected_drag_pos2 =
  856. inverse_projected_vec(mScaleDir,
  857. orthogonal_component(mouse_on_plane2,
  858. mSnapGuideDir2));
  859. bool snap_enabled = getSnapEnabled();
  860. if (snap_enabled &&
  861. (mouse_on_plane1 - projected_drag_pos1) * mSnapGuideDir1 >
  862. mSnapRegimeOffset)
  863. {
  864. mInSnapRegime = true;
  865. // Projecting the drag position allows for negative results, versus
  866. // using the length which will result in a "reverse scaling" bug.
  867. F32 drag_dist = mScaleDir * projected_drag_pos1;
  868. F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter +
  869. projected_drag_pos1,
  870. mScaleDir,
  871. mScaleSnapUnit1,
  872. mTickPixelSpacing1),
  873. sGridMinSubdivisionLevel,
  874. sGridMaxSubdivisionLevel);
  875. F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
  876. F32 relative_snap_dist = fmodf(drag_dist + snap_dist,
  877. mScaleSnapUnit1 / cur_subdivisions);
  878. mScaleSnappedValue =
  879. llclamp(drag_dist - (relative_snap_dist - snap_dist),
  880. min_scale, max_scale);
  881. scale_factor = mScaleSnappedValue /
  882. dist_vec(drag_start_point_agent,
  883. drag_start_center_agent);
  884. mScaleSnappedValue /= mScaleSnapUnit1 * 2.f;
  885. mSnapRegime = SNAP_REGIME_UPPER;
  886. if (!uniform)
  887. {
  888. scale_factor *= 0.5f;
  889. }
  890. }
  891. else if (snap_enabled &&
  892. (mouse_on_plane2 - projected_drag_pos2) * mSnapGuideDir2 > mSnapRegimeOffset)
  893. {
  894. // Projecting the drag position allows for negative results, versus
  895. // using the length which will result in a "reverse scaling" bug.
  896. F32 drag_dist = mScaleDir * projected_drag_pos2;
  897. F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter +
  898. projected_drag_pos2,
  899. mScaleDir,
  900. mScaleSnapUnit2,
  901. mTickPixelSpacing2),
  902. sGridMinSubdivisionLevel,
  903. sGridMaxSubdivisionLevel);
  904. F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions);
  905. F32 relative_snap_dist = fmodf(drag_dist + snap_dist,
  906. mScaleSnapUnit2 / cur_subdivisions);
  907. mScaleSnappedValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)),
  908. min_scale, max_scale);
  909. scale_factor = mScaleSnappedValue /
  910. dist_vec(drag_start_point_agent,
  911. drag_start_center_agent);
  912. mScaleSnappedValue /= mScaleSnapUnit2 * 2.f;
  913. mSnapRegime = SNAP_REGIME_LOWER;
  914. if (!uniform)
  915. {
  916. scale_factor *= 0.5f;
  917. }
  918. }
  919. else
  920. {
  921. mSnapRegime = SNAP_REGIME_NONE;
  922. scale_factor = t;
  923. if (!uniform)
  924. {
  925. scale_factor = 0.5f + scale_factor * 0.5f;
  926. }
  927. }
  928. F32 max_prim_scale = maxPrimScale();
  929. F32 min_prim_scale = minPrimScale();
  930. F32 max_scale_factor = max_prim_scale / min_prim_scale;
  931. F32 min_scale_factor = min_prim_scale / max_prim_scale;
  932. // find max and min scale factors that will make biggest object hit max
  933. // absolute scale and smallest object hit min absolute scale
  934. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  935. end = mObjectSelection->end();
  936. iter != end; ++iter)
  937. {
  938. LLSelectNode* selectNode = *iter;
  939. LLViewerObject* object = selectNode->getObject();
  940. if (!object)
  941. {
  942. llwarns << "NULL selected object !" << llendl;
  943. continue;
  944. }
  945. LLViewerObject* root_object = object->getRootEdit();
  946. if (!object->isAvatar() && object->permModify() &&
  947. object->permMove() && !object->isPermanentEnforced() &&
  948. (!root_object || !root_object->isPermanentEnforced()))
  949. {
  950. const LLVector3& scale = selectNode->mSavedScale;
  951. F32 cur_max_scale_factor = llmin(max_prim_scale / scale.mV[VX],
  952. max_prim_scale / scale.mV[VY],
  953. max_prim_scale / scale.mV[VZ]);
  954. max_scale_factor = llmin(max_scale_factor, cur_max_scale_factor);
  955. F32 cur_min_scale_factor = llmax(min_prim_scale / scale.mV[VX],
  956. min_prim_scale / scale.mV[VY],
  957. min_prim_scale / scale.mV[VZ]);
  958. min_scale_factor = llmax(min_scale_factor, cur_min_scale_factor);
  959. }
  960. }
  961. scale_factor = llclamp(scale_factor, min_scale_factor, max_scale_factor);
  962. LLVector3d drag_global = uniform ? mDragStartCenterGlobal : mDragFarHitGlobal;
  963. // do the root objects i.e. (true == cur->isRootEdit())
  964. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  965. end = mObjectSelection->end();
  966. iter != end; ++iter)
  967. {
  968. LLSelectNode* selectNode = *iter;
  969. LLViewerObject* cur = selectNode->getObject();
  970. if (!cur)
  971. {
  972. llwarns << "NULL selected object !" << llendl;
  973. continue;
  974. }
  975. LLViewerObject* root_object = cur->getRootEdit();
  976. if (!cur->isAvatar() && cur->permModify() && cur->permMove() &&
  977. !cur->isPermanentEnforced() && cur->isRootEdit() &&
  978. (!root_object || !root_object->isPermanentEnforced()))
  979. {
  980. const LLVector3& scale = selectNode->mSavedScale;
  981. cur->setScale(scale_factor * scale);
  982. LLVector3 original_pos = cur->getPositionEdit();
  983. LLVector3d new_pos_global = drag_global +
  984. (selectNode->mSavedPositionGlobal -
  985. drag_global) * scale_factor;
  986. if (!cur->isAttachment())
  987. {
  988. new_pos_global =
  989. gWorld.clipToVisibleRegions(selectNode->mSavedPositionGlobal,
  990. new_pos_global);
  991. }
  992. cur->setPositionAbsoluteGlobal(new_pos_global);
  993. rebuild(cur);
  994. if (selectNode->mIndividualSelection)
  995. {
  996. LLVector3 delta_pos = cur->getPositionEdit() - original_pos;
  997. // Counter-translate child objects if we are moving the root as
  998. // an individual
  999. LLViewerObject::const_child_list_t& child_list = cur->getChildren();
  1000. for (LLViewerObject::child_list_t::const_iterator
  1001. iter2 = child_list.begin(),
  1002. end2 = child_list.end();
  1003. iter2 != end2; ++iter2)
  1004. {
  1005. LLViewerObject* childp = *iter2;
  1006. if (cur->isAttachment())
  1007. {
  1008. LLVector3 child_pos =
  1009. childp->getPosition() -
  1010. delta_pos * ~cur->getRotationEdit();
  1011. childp->setPositionLocal(child_pos);
  1012. }
  1013. else
  1014. {
  1015. LLVector3d child_pos_delta(delta_pos);
  1016. // RN: this updates drawable position instantly
  1017. childp->setPositionAbsoluteGlobal(childp->getPositionGlobal() -
  1018. child_pos_delta);
  1019. }
  1020. rebuild(childp);
  1021. }
  1022. }
  1023. }
  1024. }
  1025. // Do the child objects i.e. (false == cur->isRootEdit())
  1026. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  1027. end = mObjectSelection->end();
  1028. iter != end; ++iter)
  1029. {
  1030. LLSelectNode* selectNode = *iter;
  1031. LLViewerObject* cur = selectNode->getObject();
  1032. if (!cur)
  1033. {
  1034. llwarns << "NULL selected object !" << llendl;
  1035. continue;
  1036. }
  1037. LLViewerObject* root_object = cur->getRootEdit();
  1038. if (!cur->isAvatar() && cur->permModify() && cur->permMove() &&
  1039. !cur->isPermanentEnforced() && !cur->isRootEdit() &&
  1040. (!root_object || !root_object->isPermanentEnforced()))
  1041. {
  1042. const LLVector3& scale = selectNode->mSavedScale;
  1043. cur->setScale(scale_factor * scale, false);
  1044. if (!selectNode->mIndividualSelection)
  1045. {
  1046. cur->setPositionLocal(selectNode->mSavedPositionLocal *
  1047. scale_factor);
  1048. }
  1049. rebuild(cur);
  1050. }
  1051. }
  1052. }
  1053. // Scale on a single axis
  1054. void LLManipScale::dragFace(S32 x, S32 y)
  1055. {
  1056. // Suppress scale if mouse hasn't moved.
  1057. if (x == mLastMouseX && y == mLastMouseY)
  1058. {
  1059. return;
  1060. }
  1061. mLastMouseX = x;
  1062. mLastMouseY = y;
  1063. LLVector3d drag_start_point_global = mDragStartPointGlobal;
  1064. LLVector3d drag_start_center_global = mDragStartCenterGlobal;
  1065. LLVector3 drag_start_point_agent =
  1066. gAgent.getPosAgentFromGlobal(drag_start_point_global);
  1067. LLVector3 drag_start_center_agent =
  1068. gAgent.getPosAgentFromGlobal(drag_start_center_global);
  1069. LLVector3d drag_start_dir_d;
  1070. drag_start_dir_d.set(drag_start_point_global - drag_start_center_global);
  1071. LLVector3 drag_start_dir_f;
  1072. drag_start_dir_f.set(drag_start_dir_d);
  1073. LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  1074. F32 s = 0;
  1075. F32 t = 0;
  1076. nearestPointOnLineFromMouse(x, y, drag_start_center_agent,
  1077. drag_start_point_agent, s, t);
  1078. if (s <= 0)
  1079. {
  1080. // we only care about intersections in front of the camera
  1081. return;
  1082. }
  1083. LLVector3d drag_point_global = drag_start_center_global +
  1084. t * drag_start_dir_d;
  1085. LLVector3 part_dir_local = partToUnitVector(mManipPart);
  1086. // check for snapping
  1087. LLVector3 mouse_on_plane;
  1088. getMousePointOnPlaneAgent(mouse_on_plane, x, y, mScaleCenter,
  1089. mScalePlaneNormal1);
  1090. LLVector3 mouse_on_scale_line =
  1091. mScaleCenter + projected_vec(mouse_on_plane - mScaleCenter,
  1092. mScaleDir);
  1093. LLVector3 drag_delta(mouse_on_scale_line - drag_start_point_agent);
  1094. F32 max_drag_dist = partToMaxScale(mManipPart, bbox);
  1095. F32 min_drag_dist = partToMinScale(mManipPart, bbox);
  1096. bool uniform = getUniform();
  1097. if (uniform)
  1098. {
  1099. drag_delta *= 2.f;
  1100. }
  1101. LLVector3 scale_center_to_mouse = mouse_on_plane - mScaleCenter;
  1102. F32 dist_from_scale_line = dist_vec(scale_center_to_mouse,
  1103. mouse_on_scale_line - mScaleCenter);
  1104. F32 dist_along_scale_line = scale_center_to_mouse * mScaleDir;
  1105. bool snap_enabled = getSnapEnabled();
  1106. if (snap_enabled && dist_from_scale_line > mSnapRegimeOffset)
  1107. {
  1108. // A face drag doesn't have split regimes.
  1109. mSnapRegime = (ESnapRegimes)(SNAP_REGIME_UPPER | SNAP_REGIME_LOWER);
  1110. if (dist_along_scale_line > max_drag_dist)
  1111. {
  1112. mScaleSnappedValue = max_drag_dist;
  1113. LLVector3 clamp_point = mScaleCenter + max_drag_dist * mScaleDir;
  1114. drag_delta.set(clamp_point - drag_start_point_agent);
  1115. }
  1116. else if (dist_along_scale_line < min_drag_dist)
  1117. {
  1118. mScaleSnappedValue = min_drag_dist;
  1119. LLVector3 clamp_point = mScaleCenter + min_drag_dist * mScaleDir;
  1120. drag_delta.set(clamp_point - drag_start_point_agent);
  1121. }
  1122. else
  1123. {
  1124. F32 drag_dist = scale_center_to_mouse * mScaleDir;
  1125. F32 cur_subdivisions =
  1126. llclamp(getSubdivisionLevel(mScaleCenter +
  1127. mScaleDir * drag_dist,
  1128. mScaleDir, mScaleSnapUnit1,
  1129. mTickPixelSpacing1),
  1130. sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
  1131. F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
  1132. F32 relative_snap_dist = fmodf(drag_dist + snap_dist,
  1133. mScaleSnapUnit1 / cur_subdivisions);
  1134. relative_snap_dist -= snap_dist;
  1135. // Make sure that values that the scale is "snapped to" do not
  1136. // exceed/go under the applicable max/mins; this causes the box to
  1137. // shift displacements ever so slightly although the "snap value"
  1138. // should go down to 0. See Jira 1027
  1139. relative_snap_dist = llclamp(relative_snap_dist,
  1140. drag_dist - max_drag_dist,
  1141. drag_dist - min_drag_dist);
  1142. mScaleSnappedValue =
  1143. (drag_dist - relative_snap_dist) / (mScaleSnapUnit1 * 2.f);
  1144. if (fabsf(relative_snap_dist) < snap_dist)
  1145. {
  1146. LLVector3 drag_correction = relative_snap_dist * mScaleDir;
  1147. if (uniform)
  1148. {
  1149. drag_correction *= 2.f;
  1150. }
  1151. drag_delta -= drag_correction;
  1152. }
  1153. }
  1154. }
  1155. else
  1156. {
  1157. mSnapRegime = SNAP_REGIME_NONE;
  1158. }
  1159. LLVector3 dir_agent;
  1160. if (part_dir_local.mV[VX])
  1161. {
  1162. dir_agent = bbox.localToAgentBasis(LLVector3::x_axis);
  1163. }
  1164. else if (part_dir_local.mV[VY])
  1165. {
  1166. dir_agent = bbox.localToAgentBasis(LLVector3::y_axis);
  1167. }
  1168. else if (part_dir_local.mV[VZ])
  1169. {
  1170. dir_agent = bbox.localToAgentBasis(LLVector3::z_axis);
  1171. }
  1172. stretchFace(projected_vec(drag_start_dir_f, dir_agent) +
  1173. drag_start_center_agent,
  1174. projected_vec(drag_delta, dir_agent));
  1175. mDragPointGlobal = drag_point_global;
  1176. }
  1177. void LLManipScale::sendUpdates(bool send_position_update,
  1178. bool send_scale_update, bool corner)
  1179. {
  1180. // Throttle updates to 10 per second.
  1181. static LLTimer update_timer;
  1182. F32 elapsed_time = update_timer.getElapsedTimeF32();
  1183. constexpr F32 UPDATE_DELAY = 0.1f; // Min time between transmitted updates
  1184. if (send_scale_update || send_position_update)
  1185. {
  1186. U32 update_flags = UPD_NONE;
  1187. if (send_position_update) update_flags |= UPD_POSITION;
  1188. if (send_scale_update) update_flags |= UPD_SCALE;
  1189. if (corner)
  1190. {
  1191. update_flags |= UPD_UNIFORM;
  1192. }
  1193. // keep this up to date for sendonmouseup
  1194. mLastUpdateFlags = update_flags;
  1195. // enforce minimum update delay and don't stream updates on sub-object
  1196. // selections
  1197. static LLCachedControl<bool> edit_linked_parts(gSavedSettings,
  1198. "EditLinkedParts");
  1199. if (elapsed_time > UPDATE_DELAY && !edit_linked_parts)
  1200. {
  1201. gSelectMgr.sendMultipleUpdate(update_flags);
  1202. update_timer.reset();
  1203. }
  1204. dialog_refresh_all();
  1205. }
  1206. }
  1207. // Rescales in a single dimension. Either uniform (standard) or one-sided
  1208. // (scale plus translation) depending on mUniform. Handles multiple selection
  1209. // and objects that are not aligned to the bounding box.
  1210. void LLManipScale::stretchFace(const LLVector3& drag_start_agent,
  1211. const LLVector3& drag_delta_agent)
  1212. {
  1213. LLVector3 drag_start_center_agent =
  1214. gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal);
  1215. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  1216. end = mObjectSelection->end();
  1217. iter != end; ++iter)
  1218. {
  1219. LLSelectNode* selectNode = *iter;
  1220. LLViewerObject* cur = selectNode->getObject();
  1221. if (!cur)
  1222. {
  1223. llwarns << "NULL selected object !" << llendl;
  1224. continue;
  1225. }
  1226. LLViewerObject* root_object = cur->getRootEdit();
  1227. if (cur->permModify() && cur->permMove() &&
  1228. !cur->isPermanentEnforced() && !cur->isAvatar() &&
  1229. (!root_object || !root_object->isPermanentEnforced()))
  1230. {
  1231. LLBBox cur_bbox = cur->getBoundingBoxAgent();
  1232. LLVector3 start_local = cur_bbox.agentToLocal(drag_start_agent);
  1233. LLVector3 end_local = cur_bbox.agentToLocal(drag_start_agent +
  1234. drag_delta_agent);
  1235. LLVector3 start_center_local = cur_bbox.agentToLocal(drag_start_center_agent);
  1236. LLVector3 axis = nearestAxis(start_local - start_center_local);
  1237. S32 axis_index = axis.mV[0] ? 0 : (axis.mV[1] ? 1 : 2);
  1238. LLVector3 delta_local = end_local - start_local;
  1239. F32 delta_local_mag = delta_local.length();
  1240. LLVector3 dir_local;
  1241. if (delta_local_mag == 0.f)
  1242. {
  1243. dir_local = axis;
  1244. }
  1245. else
  1246. {
  1247. // Normalized delta_local
  1248. dir_local = delta_local / delta_local_mag;
  1249. }
  1250. F32 denom = axis * dir_local;
  1251. F32 desired_delta_size =
  1252. is_approx_zero(denom) ? 0.f : delta_local_mag / denom;
  1253. F32 desired_scale =
  1254. llclamp(selectNode->mSavedScale.mV[axis_index] +
  1255. desired_delta_size,
  1256. minPrimScale(), maxPrimScale());
  1257. // Propagate scale constraint back to position offset
  1258. desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index];
  1259. LLVector3 scale = cur->getScale();
  1260. scale.mV[axis_index] = desired_scale;
  1261. cur->setScale(scale, false);
  1262. rebuild(cur);
  1263. LLVector3 delta_pos;
  1264. if (!getUniform())
  1265. {
  1266. LLVector3 delta_pos_local = axis * (0.5f * desired_delta_size);
  1267. LLVector3d delta_pos_global;
  1268. delta_pos_global.set(cur_bbox.localToAgent(delta_pos_local) -
  1269. cur_bbox.getCenterAgent());
  1270. LLVector3 cur_pos = cur->getPositionEdit();
  1271. if (cur->isRootEdit() && !cur->isAttachment())
  1272. {
  1273. LLVector3d new_pos_global =
  1274. gWorld.clipToVisibleRegions(selectNode->mSavedPositionGlobal,
  1275. selectNode->mSavedPositionGlobal +
  1276. delta_pos_global);
  1277. cur->setPositionGlobal(new_pos_global);
  1278. }
  1279. else
  1280. {
  1281. LLXform* parent_xform =
  1282. cur->mDrawable->getXform()->getParent();
  1283. LLVector3 new_pos_local;
  1284. // This works in attachment point space using world space
  1285. // delta
  1286. if (parent_xform)
  1287. {
  1288. new_pos_local = selectNode->mSavedPositionLocal +
  1289. LLVector3(delta_pos_global) *
  1290. ~parent_xform->getWorldRotation();
  1291. }
  1292. else
  1293. {
  1294. new_pos_local = selectNode->mSavedPositionLocal +
  1295. LLVector3(delta_pos_global);
  1296. }
  1297. cur->setPositionLocal(new_pos_local);
  1298. }
  1299. delta_pos = cur->getPositionEdit() - cur_pos;
  1300. }
  1301. if (cur->isRootEdit() && selectNode->mIndividualSelection)
  1302. {
  1303. // Counter-translate child objects if we are moving the root as
  1304. // an individual
  1305. LLViewerObject::const_child_list_t& child_list =
  1306. cur->getChildren();
  1307. for (LLViewerObject::child_list_t::const_iterator
  1308. iter2 = child_list.begin(), end2 = child_list.end();
  1309. iter2 != end2; ++iter2)
  1310. {
  1311. LLViewerObject* childp = *iter2;
  1312. if (!getUniform())
  1313. {
  1314. LLVector3 child_pos = childp->getPosition() -
  1315. delta_pos *
  1316. ~cur->getRotationEdit();
  1317. childp->setPositionLocal(child_pos);
  1318. rebuild(childp);
  1319. }
  1320. }
  1321. }
  1322. }
  1323. }
  1324. }
  1325. void LLManipScale::renderGuidelinesPart(const LLBBox& bbox)
  1326. {
  1327. LLVector3 guideline_start = bbox.getCenterLocal();
  1328. LLVector3 guideline_end;
  1329. guideline_end = unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
  1330. bbox);
  1331. if (!getUniform())
  1332. {
  1333. guideline_start =
  1334. unitVectorToLocalBBoxExtent(-partToUnitVector(mManipPart), bbox);
  1335. }
  1336. guideline_end -= guideline_start;
  1337. guideline_end.normalize();
  1338. LLViewerRegion* region = gAgent.getRegion();
  1339. guideline_end *= region ? region->getWidth() : REGION_WIDTH_METERS;
  1340. guideline_end += guideline_start;
  1341. {
  1342. LLGLDepthTest gls_depth(GL_TRUE);
  1343. static const LLColor4 semi_transparent_white(1.f, 1.f, 1.f, 0.5f);
  1344. gl_line_3d(guideline_start, guideline_end, semi_transparent_white);
  1345. }
  1346. {
  1347. LLGLDepthTest gls_depth(GL_FALSE);
  1348. static const LLColor4 almost_transparent_white(1.f, 1.f, 1.f, 0.5f);
  1349. gl_line_3d(guideline_start, guideline_end, almost_transparent_white);
  1350. }
  1351. }
  1352. void LLManipScale::updateSnapGuides(const LLBBox& bbox)
  1353. {
  1354. LLVector3 grid_origin;
  1355. LLVector3 grid_scale;
  1356. LLQuaternion grid_rotation;
  1357. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  1358. LLVector3 box_corner_agent =
  1359. bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
  1360. bbox));
  1361. bool uniform = getUniform();
  1362. mScaleCenter =
  1363. uniform ? bbox.getCenterAgent()
  1364. : bbox.localToAgent(unitVectorToLocalBBoxExtent(-1.f *
  1365. partToUnitVector(mManipPart),
  1366. bbox));
  1367. mScaleDir = box_corner_agent - mScaleCenter;
  1368. mScaleDir.normalize();
  1369. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1370. {
  1371. mSnapRegimeOffset = SNAP_GUIDE_SCREEN_OFFSET / gAgent.mHUDCurZoom;
  1372. }
  1373. else
  1374. {
  1375. F32 object_distance = dist_vec(box_corner_agent,
  1376. gViewerCamera.getOrigin());
  1377. mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET *
  1378. gViewerWindowp->getWindowWidth() *
  1379. object_distance) /
  1380. gViewerCamera.getPixelMeterRatio();
  1381. }
  1382. LLVector3 cam_at_axis;
  1383. F32 snap_guide_length;
  1384. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1385. {
  1386. cam_at_axis.set(1.f, 0.f, 0.f);
  1387. snap_guide_length = SNAP_GUIDE_SCREEN_LENGTH / gAgent.mHUDCurZoom;
  1388. }
  1389. else
  1390. {
  1391. cam_at_axis = gViewerCamera.getAtAxis();
  1392. F32 manipulator_distance = dist_vec(box_corner_agent,
  1393. gViewerCamera.getOrigin());
  1394. snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH *
  1395. gViewerWindowp->getWindowWidth() *
  1396. manipulator_distance) /
  1397. gViewerCamera.getPixelMeterRatio();
  1398. }
  1399. mSnapGuideLength = snap_guide_length /
  1400. llmax(0.1f, llmin(mSnapGuideDir1 * cam_at_axis,
  1401. mSnapGuideDir2 * cam_at_axis));
  1402. LLVector3 off_axis_dir = mScaleDir % cam_at_axis;
  1403. off_axis_dir.normalize();
  1404. if (LL_FACE_MIN <= (S32)mManipPart && (S32)mManipPart <= LL_FACE_MAX)
  1405. {
  1406. LLVector3 bbox_relative_cam_dir = off_axis_dir * ~bbox.getRotation();
  1407. bbox_relative_cam_dir.abs();
  1408. if (bbox_relative_cam_dir.mV[VX] > bbox_relative_cam_dir.mV[VY] &&
  1409. bbox_relative_cam_dir.mV[VX] > bbox_relative_cam_dir.mV[VZ])
  1410. {
  1411. mSnapGuideDir1 = LLVector3::x_axis * bbox.getRotation();
  1412. }
  1413. else if (bbox_relative_cam_dir.mV[VY] > bbox_relative_cam_dir.mV[VZ])
  1414. {
  1415. mSnapGuideDir1 = LLVector3::y_axis * bbox.getRotation();
  1416. }
  1417. else
  1418. {
  1419. mSnapGuideDir1 = LLVector3::z_axis * bbox.getRotation();
  1420. }
  1421. LLVector3 scale_snap = grid_scale;
  1422. mScaleSnapUnit1 =
  1423. scale_snap.scaleVec(partToUnitVector(mManipPart)).length();
  1424. mScaleSnapUnit2 = mScaleSnapUnit1;
  1425. mSnapGuideDir1 *=
  1426. mSnapGuideDir1 * gViewerCamera.getUpAxis() > 0.f ? 1.f : -1.f;
  1427. mSnapGuideDir2 = mSnapGuideDir1 * -1.f;
  1428. mSnapDir1 = mScaleDir;
  1429. mSnapDir2 = mScaleDir;
  1430. }
  1431. else if (LL_CORNER_MIN <= (S32)mManipPart &&
  1432. (S32)mManipPart <= LL_CORNER_MAX)
  1433. {
  1434. LLVector3 local_camera_dir;
  1435. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1436. {
  1437. local_camera_dir = LLVector3(-1.f, 0.f, 0.f) * ~bbox.getRotation();
  1438. }
  1439. else
  1440. {
  1441. local_camera_dir = (gViewerCamera.getOrigin() - box_corner_agent) *
  1442. ~bbox.getRotation();
  1443. local_camera_dir.normalize();
  1444. }
  1445. LLVector3 axis_flip;
  1446. switch (mManipPart)
  1447. {
  1448. case LL_CORNER_NNN:
  1449. axis_flip.set(1.f, 1.f, 1.f);
  1450. break;
  1451. case LL_CORNER_NNP:
  1452. axis_flip.set(1.f, 1.f, -1.f);
  1453. break;
  1454. case LL_CORNER_NPN:
  1455. axis_flip.set(1.f, -1.f, 1.f);
  1456. break;
  1457. case LL_CORNER_NPP:
  1458. axis_flip.set(1.f, -1.f, -1.f);
  1459. break;
  1460. case LL_CORNER_PNN:
  1461. axis_flip.set(-1.f, 1.f, 1.f);
  1462. break;
  1463. case LL_CORNER_PNP:
  1464. axis_flip.set(-1.f, 1.f, -1.f);
  1465. break;
  1466. case LL_CORNER_PPN:
  1467. axis_flip.set(-1.f, -1.f, 1.f);
  1468. break;
  1469. case LL_CORNER_PPP:
  1470. axis_flip.set(-1.f, -1.f, -1.f);
  1471. break;
  1472. default:
  1473. break;
  1474. }
  1475. // Account for which side of the object the camera is located and
  1476. // negate appropriate axes
  1477. local_camera_dir.scaleVec(axis_flip);
  1478. // normalize to object scale
  1479. LLVector3 bbox_extent = bbox.getExtentLocal();
  1480. local_camera_dir.scaleVec(LLVector3(1.f / bbox_extent.mV[VX],
  1481. 1.f / bbox_extent.mV[VY],
  1482. 1.f / bbox_extent.mV[VZ]));
  1483. S32 scale_face = -1;
  1484. if ((local_camera_dir.mV[VX] > 0.f) == (local_camera_dir.mV[VY] > 0.f))
  1485. {
  1486. if ((local_camera_dir.mV[VZ] > 0.f) == (local_camera_dir.mV[VY] > 0.f))
  1487. {
  1488. LLVector3 local_camera_dir_abs = local_camera_dir;
  1489. local_camera_dir_abs.abs();
  1490. // All neighboring faces of bbox are pointing towards camera or
  1491. // away from camera; use largest magnitude face for snap guides
  1492. if (local_camera_dir_abs.mV[VX] > local_camera_dir_abs.mV[VY])
  1493. {
  1494. if (local_camera_dir_abs.mV[VX] > local_camera_dir_abs.mV[VZ])
  1495. {
  1496. scale_face = VX;
  1497. }
  1498. else
  1499. {
  1500. scale_face = VZ;
  1501. }
  1502. }
  1503. else // y > x
  1504. {
  1505. if (local_camera_dir_abs.mV[VY] > local_camera_dir_abs.mV[VZ])
  1506. {
  1507. scale_face = VY;
  1508. }
  1509. else
  1510. {
  1511. scale_face = VZ;
  1512. }
  1513. }
  1514. }
  1515. else
  1516. {
  1517. // z axis facing opposite direction from x and y relative to
  1518. // camera, use x and y for snap guides
  1519. scale_face = VZ;
  1520. }
  1521. }
  1522. else
  1523. {
  1524. // x and y axes are facing in opposite directions relative to
  1525. // camera
  1526. if ((local_camera_dir.mV[VZ] > 0.f) == (local_camera_dir.mV[VY] > 0.f))
  1527. {
  1528. // x axis facing opposite direction from y and z relative to
  1529. // camera, use y and z for snap guides
  1530. scale_face = VX;
  1531. }
  1532. else
  1533. {
  1534. // y axis facing opposite direction from x and z relative to
  1535. // camera, use x and z for snap guides
  1536. scale_face = VY;
  1537. }
  1538. }
  1539. switch (scale_face)
  1540. {
  1541. case VX:
  1542. // x axis face being scaled, use y and z for snap guides
  1543. mSnapGuideDir1 = LLVector3::y_axis.scaledVec(axis_flip);
  1544. mScaleSnapUnit1 = grid_scale.mV[VZ];
  1545. mSnapGuideDir2 = LLVector3::z_axis.scaledVec(axis_flip);
  1546. mScaleSnapUnit2 = grid_scale.mV[VY];
  1547. break;
  1548. case VY:
  1549. // y axis facing being scaled, use x and z for snap guides
  1550. mSnapGuideDir1 = LLVector3::x_axis.scaledVec(axis_flip);
  1551. mScaleSnapUnit1 = grid_scale.mV[VZ];
  1552. mSnapGuideDir2 = LLVector3::z_axis.scaledVec(axis_flip);
  1553. mScaleSnapUnit2 = grid_scale.mV[VX];
  1554. break;
  1555. case VZ:
  1556. // z axis facing being scaled, use x and y for snap guides
  1557. mSnapGuideDir1 = LLVector3::x_axis.scaledVec(axis_flip);
  1558. mScaleSnapUnit1 = grid_scale.mV[VY];
  1559. mSnapGuideDir2 = LLVector3::y_axis.scaledVec(axis_flip);
  1560. mScaleSnapUnit2 = grid_scale.mV[VX];
  1561. break;
  1562. default:
  1563. mSnapGuideDir1.setZero();
  1564. mScaleSnapUnit1 = 0.f;
  1565. mSnapGuideDir2.setZero();
  1566. mScaleSnapUnit2 = 0.f;
  1567. break;
  1568. }
  1569. mSnapGuideDir1.rotVec(bbox.getRotation());
  1570. mSnapGuideDir2.rotVec(bbox.getRotation());
  1571. mSnapDir1 = -1.f * mSnapGuideDir2;
  1572. mSnapDir2 = -1.f * mSnapGuideDir1;
  1573. }
  1574. mScalePlaneNormal1 = mSnapGuideDir1 % mScaleDir;
  1575. mScalePlaneNormal1.normalize();
  1576. mScalePlaneNormal2 = mSnapGuideDir2 % mScaleDir;
  1577. mScalePlaneNormal2.normalize();
  1578. mScaleSnapUnit1 = mScaleSnapUnit1 / (mSnapDir1 * mScaleDir);
  1579. mScaleSnapUnit2 = mScaleSnapUnit2 / (mSnapDir2 * mScaleDir);
  1580. mTickPixelSpacing1 = ll_roundp((F32)MIN_DIVISION_PIXEL_WIDTH /
  1581. (mScaleDir % mSnapGuideDir1).length());
  1582. mTickPixelSpacing2 = ll_roundp((F32)MIN_DIVISION_PIXEL_WIDTH /
  1583. (mScaleDir % mSnapGuideDir2).length());
  1584. if (uniform)
  1585. {
  1586. mScaleSnapUnit1 *= 0.5f;
  1587. mScaleSnapUnit2 *= 0.5f;
  1588. }
  1589. }
  1590. void LLManipScale::renderSnapGuides(const LLBBox& bbox)
  1591. {
  1592. if (!getSnapEnabled())
  1593. {
  1594. return;
  1595. }
  1596. static LLCachedControl<F32> grid_alpha(gSavedSettings, "GridOpacity");
  1597. F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox);
  1598. LLVector3 drag_point = gAgent.getPosAgentFromGlobal(mDragPointGlobal);
  1599. updateGridSettings();
  1600. S32 pass;
  1601. for (pass = 0; pass < 3; ++pass)
  1602. {
  1603. LLColor4 tick_color = setupSnapGuideRenderPass(pass);
  1604. gGL.begin(LLRender::LINES);
  1605. LLVector3 line_mid = mScaleCenter + mScaleSnappedValue * mScaleDir +
  1606. mSnapGuideDir1 * mSnapRegimeOffset;
  1607. LLVector3 line_start = line_mid -
  1608. mScaleDir * llmin(mScaleSnappedValue,
  1609. mSnapGuideLength * 0.5f);
  1610. LLVector3 line_end = line_mid +
  1611. mScaleDir * llmin(max_point_on_scale_line -
  1612. mScaleSnappedValue,
  1613. mSnapGuideLength * 0.5f);
  1614. gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
  1615. tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
  1616. gGL.vertex3fv(line_start.mV);
  1617. gGL.color4fv(tick_color.mV);
  1618. gGL.vertex3fv(line_mid.mV);
  1619. gGL.vertex3fv(line_mid.mV);
  1620. gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
  1621. tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
  1622. gGL.vertex3fv(line_end.mV);
  1623. line_mid = mScaleCenter + mScaleSnappedValue * mScaleDir +
  1624. mSnapGuideDir2 * mSnapRegimeOffset;
  1625. line_start = line_mid -
  1626. mScaleDir * llmin(mScaleSnappedValue,
  1627. mSnapGuideLength * 0.5f);
  1628. line_end = line_mid +
  1629. mScaleDir * llmin(max_point_on_scale_line -
  1630. mScaleSnappedValue,
  1631. mSnapGuideLength * 0.5f);
  1632. gGL.vertex3fv(line_start.mV);
  1633. gGL.color4fv(tick_color.mV);
  1634. gGL.vertex3fv(line_mid.mV);
  1635. gGL.vertex3fv(line_mid.mV);
  1636. gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
  1637. tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
  1638. gGL.vertex3fv(line_end.mV);
  1639. gGL.end();
  1640. }
  1641. {
  1642. LLGLDepthTest gls_depth(GL_FALSE);
  1643. F32 dist_grid_axis = llmax(0.f,
  1644. (drag_point - mScaleCenter) * mScaleDir);
  1645. F32 smallest_subdivision1 = mScaleSnapUnit1 / sGridMaxSubdivisionLevel;
  1646. F32 smallest_subdivision2 = mScaleSnapUnit2 / sGridMaxSubdivisionLevel;
  1647. F32 dist_scale_units_1 = dist_grid_axis / smallest_subdivision1;
  1648. F32 dist_scale_units_2 = dist_grid_axis / smallest_subdivision2;
  1649. // find distance to nearest smallest grid unit
  1650. F32 grid_multiple1 = llfloor(dist_scale_units_1);
  1651. F32 grid_multiple2 = llfloor(dist_scale_units_2);
  1652. F32 grid_offset1 = fmodf(dist_grid_axis, smallest_subdivision1);
  1653. F32 grid_offset2 = fmodf(dist_grid_axis, smallest_subdivision2);
  1654. // how many smallest grid units are we away from largest grid scale?
  1655. S32 sub_div_offset_1 = ll_round(fmod(dist_grid_axis - grid_offset1,
  1656. mScaleSnapUnit1 /
  1657. sGridMinSubdivisionLevel) /
  1658. smallest_subdivision1);
  1659. S32 sub_div_offset_2 = ll_round(fmod(dist_grid_axis - grid_offset2,
  1660. mScaleSnapUnit2 /
  1661. sGridMinSubdivisionLevel) /
  1662. smallest_subdivision2);
  1663. S32 num_ticks_per_side1 = llmax(1, lltrunc(0.5f * mSnapGuideLength /
  1664. smallest_subdivision1));
  1665. S32 num_ticks_per_side2 = llmax(1, lltrunc(0.5f * mSnapGuideLength /
  1666. smallest_subdivision2));
  1667. S32 ticks_from_scale_center_1 = lltrunc(dist_scale_units_1);
  1668. S32 ticks_from_scale_center_2 = lltrunc(dist_scale_units_2);
  1669. S32 max_ticks1 = llceil(max_point_on_scale_line /
  1670. smallest_subdivision1 - dist_scale_units_1);
  1671. S32 max_ticks2 = llceil(max_point_on_scale_line /
  1672. smallest_subdivision2 - dist_scale_units_2);
  1673. S32 start_tick = 0;
  1674. S32 stop_tick = 0;
  1675. if (mSnapRegime != SNAP_REGIME_NONE)
  1676. {
  1677. // draw snap guide line
  1678. gGL.begin(LLRender::LINES);
  1679. LLVector3 snap_line_center =
  1680. bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(mManipPart),
  1681. bbox));
  1682. LLVector3 snap_line_start = snap_line_center +
  1683. mSnapGuideDir1 * mSnapRegimeOffset;
  1684. LLVector3 snap_line_end = snap_line_center +
  1685. mSnapGuideDir2 * mSnapRegimeOffset;
  1686. gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
  1687. gGL.vertex3fv(snap_line_start.mV);
  1688. gGL.vertex3fv(snap_line_center.mV);
  1689. gGL.vertex3fv(snap_line_center.mV);
  1690. gGL.vertex3fv(snap_line_end.mV);
  1691. gGL.end();
  1692. // Draw snap guide arrow
  1693. gGL.begin(LLRender::TRIANGLES);
  1694. {
  1695. //gGLSNoCullFaces.set();
  1696. gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
  1697. LLVector3 arrow_dir;
  1698. LLVector3 arrow_span = mScaleDir;
  1699. arrow_dir = snap_line_start - snap_line_center;
  1700. arrow_dir.normalize();
  1701. gGL.vertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV);
  1702. gGL.vertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV);
  1703. gGL.vertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV);
  1704. arrow_dir = snap_line_end - snap_line_center;
  1705. arrow_dir.normalize();
  1706. gGL.vertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV);
  1707. gGL.vertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV);
  1708. gGL.vertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV);
  1709. }
  1710. gGL.end();
  1711. }
  1712. LLVector2 screen_translate_axis(fabsf(mScaleDir *
  1713. gViewerCamera.getLeftAxis()),
  1714. fabsf(mScaleDir *
  1715. gViewerCamera.getUpAxis()));
  1716. screen_translate_axis.normalize();
  1717. S32 tick_label_spacing = ll_roundp(screen_translate_axis *
  1718. sTickLabelSpacing);
  1719. for (pass = 0; pass < 3; ++pass)
  1720. {
  1721. LLColor4 tick_color = setupSnapGuideRenderPass(pass);
  1722. start_tick = -llmin(ticks_from_scale_center_1, num_ticks_per_side1);
  1723. stop_tick = llmin(max_ticks1, num_ticks_per_side1);
  1724. gGL.begin(LLRender::LINES);
  1725. // draw first row of ticks
  1726. for (S32 i = start_tick; i <= stop_tick; ++i)
  1727. {
  1728. F32 alpha = 1.f - (F32)abs(i) / (F32)num_ticks_per_side1;
  1729. LLVector3 tick_pos = mScaleCenter +
  1730. mScaleDir * (grid_multiple1 + i) *
  1731. smallest_subdivision1;
  1732. F32 tick_scale = 1.f;
  1733. for (F32 division_level = sGridMaxSubdivisionLevel;
  1734. division_level >= sGridMinSubdivisionLevel;
  1735. division_level *= 0.5f)
  1736. {
  1737. if (fmodf((F32)(i + sub_div_offset_1),
  1738. division_level) == 0.f)
  1739. {
  1740. break;
  1741. }
  1742. tick_scale *= 0.7f;
  1743. }
  1744. gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
  1745. tick_color.mV[VBLUE],
  1746. tick_color.mV[VALPHA] * alpha);
  1747. LLVector3 tick_start = tick_pos +
  1748. mSnapGuideDir1 * mSnapRegimeOffset;
  1749. LLVector3 tick_end = tick_start +
  1750. mSnapGuideDir1 * mSnapRegimeOffset *
  1751. tick_scale;
  1752. gGL.vertex3fv(tick_start.mV);
  1753. gGL.vertex3fv(tick_end.mV);
  1754. }
  1755. // Draw opposite row of ticks
  1756. start_tick = -llmin(ticks_from_scale_center_2,
  1757. num_ticks_per_side2);
  1758. stop_tick = llmin(max_ticks2, num_ticks_per_side2);
  1759. for (S32 i = start_tick; i <= stop_tick; ++i)
  1760. {
  1761. F32 alpha = 1.f - (F32)abs(i) / (F32)num_ticks_per_side2;
  1762. LLVector3 tick_pos = mScaleCenter +
  1763. mScaleDir * (grid_multiple2 + i) *
  1764. smallest_subdivision2;
  1765. F32 tick_scale = 1.f;
  1766. for (F32 division_level = sGridMaxSubdivisionLevel;
  1767. division_level >= sGridMinSubdivisionLevel;
  1768. division_level *= 0.5f)
  1769. {
  1770. if (fmodf((F32)(i + sub_div_offset_2),
  1771. division_level) == 0.f)
  1772. {
  1773. break;
  1774. }
  1775. tick_scale *= 0.7f;
  1776. }
  1777. gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN],
  1778. tick_color.mV[VBLUE],
  1779. tick_color.mV[VALPHA] * alpha);
  1780. LLVector3 tick_start = tick_pos +
  1781. mSnapGuideDir2 * mSnapRegimeOffset;
  1782. LLVector3 tick_end = tick_start +
  1783. mSnapGuideDir2 * mSnapRegimeOffset *
  1784. tick_scale;
  1785. gGL.vertex3fv(tick_start.mV);
  1786. gGL.vertex3fv(tick_end.mV);
  1787. }
  1788. gGL.end();
  1789. }
  1790. // Render upper tick labels
  1791. start_tick = -llmin(ticks_from_scale_center_1, num_ticks_per_side1);
  1792. stop_tick = llmin(max_ticks1, num_ticks_per_side1);
  1793. F32 grid_resolution = 0.25f;
  1794. if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
  1795. {
  1796. static LLCachedControl<F32> grid_res(gSavedSettings,
  1797. "GridResolution");
  1798. grid_resolution = llmax((F32)grid_res, 0.001f);
  1799. }
  1800. S32 label_sub_div_offset_1 = ll_round(fmod(dist_grid_axis -
  1801. grid_offset1,
  1802. mScaleSnapUnit1 * 32.f) /
  1803. smallest_subdivision1);
  1804. S32 label_sub_div_offset_2 = ll_round(fmod(dist_grid_axis -
  1805. grid_offset2,
  1806. mScaleSnapUnit2 * 32.f) /
  1807. smallest_subdivision2);
  1808. for (S32 i = start_tick; i <= stop_tick; ++i)
  1809. {
  1810. F32 tick_scale = 1.f;
  1811. F32 alpha = grid_alpha *
  1812. (1.f -
  1813. 0.5f * (F32)abs(i) / (F32)num_ticks_per_side1);
  1814. LLVector3 tick_pos = mScaleCenter +
  1815. mScaleDir * (grid_multiple1 + i) *
  1816. smallest_subdivision1;
  1817. for (F32 division_level = sGridMaxSubdivisionLevel;
  1818. division_level >= sGridMinSubdivisionLevel;
  1819. division_level *= 0.5f)
  1820. {
  1821. if (fmodf((F32)(i + label_sub_div_offset_1),
  1822. division_level) == 0.f)
  1823. {
  1824. break;
  1825. }
  1826. tick_scale *= 0.7f;
  1827. }
  1828. if (fmodf((F32)(i + label_sub_div_offset_1),
  1829. sGridMaxSubdivisionLevel /
  1830. llmin(sGridMaxSubdivisionLevel,
  1831. getSubdivisionLevel(tick_pos, mScaleDir,
  1832. mScaleSnapUnit1,
  1833. tick_label_spacing))) == 0.f)
  1834. {
  1835. LLVector3 text_origin = tick_pos +
  1836. (mSnapGuideDir1 * mSnapRegimeOffset * (1.f + tick_scale));
  1837. EGridMode grid_mode = gSelectMgr.getGridMode();
  1838. F32 tick_val;
  1839. if (grid_mode == GRID_MODE_WORLD)
  1840. {
  1841. tick_val = (grid_multiple1 + i) *
  1842. grid_resolution / sGridMaxSubdivisionLevel;
  1843. }
  1844. else
  1845. {
  1846. tick_val = 0.5f * (grid_multiple1 + i) /
  1847. sGridMaxSubdivisionLevel;
  1848. }
  1849. // Highlight this text if the tick value matches the snapped to
  1850. // value, and if either the second set of ticks isn't going to
  1851. // be shown or cursor is in the first snap regime.
  1852. F32 text_highlight = 0.8f;
  1853. if (is_approx_equal(tick_val, mScaleSnappedValue) &&
  1854. (mScaleSnapUnit2 == mScaleSnapUnit1 ||
  1855. (mSnapRegime & SNAP_REGIME_UPPER)))
  1856. {
  1857. text_highlight = 1.f;
  1858. }
  1859. renderTickValue(text_origin, tick_val,
  1860. grid_mode == GRID_MODE_WORLD ? std::string("m")
  1861. : std::string("x"),
  1862. LLColor4(text_highlight, text_highlight,
  1863. text_highlight, alpha));
  1864. }
  1865. }
  1866. // Label ticks on opposite side, only can happen in scaling modes that
  1867. // effect more than one axis and when the object's axis don't have the
  1868. // same scale. A differing scale indicates both conditions.
  1869. if (mScaleSnapUnit2 != mScaleSnapUnit1)
  1870. {
  1871. start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2));
  1872. stop_tick = llmin(max_ticks2, num_ticks_per_side2);
  1873. for (S32 i = start_tick; i <= stop_tick; ++i)
  1874. {
  1875. F32 tick_scale = 1.f;
  1876. F32 alpha = grid_alpha *
  1877. (1.f - 0.5f * ((F32)abs(i) /
  1878. (F32)num_ticks_per_side2));
  1879. LLVector3 tick_pos = mScaleCenter +
  1880. mScaleDir * (grid_multiple2 + i) *
  1881. smallest_subdivision2;
  1882. for (F32 division_level = sGridMaxSubdivisionLevel;
  1883. division_level >= sGridMinSubdivisionLevel;
  1884. division_level *= 0.5f)
  1885. {
  1886. if (fmodf((F32)(i + label_sub_div_offset_2),
  1887. division_level) == 0.f)
  1888. {
  1889. break;
  1890. }
  1891. tick_scale *= 0.7f;
  1892. }
  1893. if (fmodf((F32)(i + label_sub_div_offset_2),
  1894. sGridMaxSubdivisionLevel /
  1895. llmin(sGridMaxSubdivisionLevel,
  1896. getSubdivisionLevel(tick_pos, mScaleDir,
  1897. mScaleSnapUnit2,
  1898. tick_label_spacing))) == 0.f)
  1899. {
  1900. LLVector3 text_origin = tick_pos +
  1901. mSnapGuideDir2 *
  1902. mSnapRegimeOffset *
  1903. (1.f + tick_scale);
  1904. EGridMode grid_mode = gSelectMgr.getGridMode();
  1905. F32 tick_val;
  1906. if (grid_mode == GRID_MODE_WORLD)
  1907. {
  1908. tick_val = (grid_multiple2 + i) * grid_resolution /
  1909. sGridMaxSubdivisionLevel;
  1910. }
  1911. else
  1912. {
  1913. tick_val = 0.5f * (grid_multiple2 + i) /
  1914. sGridMaxSubdivisionLevel;
  1915. }
  1916. F32 text_highlight = 0.8f;
  1917. if (is_approx_equal(tick_val, mScaleSnappedValue) &&
  1918. (mSnapRegime & SNAP_REGIME_LOWER))
  1919. {
  1920. text_highlight = 1.f;
  1921. }
  1922. renderTickValue(text_origin, tick_val,
  1923. grid_mode == GRID_MODE_WORLD ? std::string("m")
  1924. : std::string("x"),
  1925. LLColor4(text_highlight, text_highlight,
  1926. text_highlight, alpha));
  1927. }
  1928. }
  1929. }
  1930. // Render help text
  1931. if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
  1932. {
  1933. if (mHelpTextTimer.getElapsedTimeF32() <
  1934. sHelpTextVisibleTime + sHelpTextFadeTime &&
  1935. sNumTimesHelpTextShown < sMaxTimesShowHelpText)
  1936. {
  1937. LLVector3 sel_center =
  1938. gSelectMgr.getSavedBBoxOfSelection().getCenterAgent();
  1939. LLVector3 offset_dir;
  1940. if (mSnapGuideDir1 * gViewerCamera.getAtAxis() >
  1941. mSnapGuideDir2 * gViewerCamera.getAtAxis())
  1942. {
  1943. offset_dir = mSnapGuideDir2;
  1944. }
  1945. else
  1946. {
  1947. offset_dir = mSnapGuideDir1;
  1948. }
  1949. LLVector3 help_text_pos = sel_center +
  1950. mSnapRegimeOffset * 5.f * offset_dir;
  1951. LLColor4 help_text_color = LLColor4::white;
  1952. help_text_color.mV[VALPHA] =
  1953. clamp_rescale(mHelpTextTimer.getElapsedTimeF32(),
  1954. sHelpTextVisibleTime,
  1955. sHelpTextVisibleTime + sHelpTextFadeTime,
  1956. grid_alpha, 0.f);
  1957. const LLFontGL* big_fontp = LLFontGL::getFontSansSerif();
  1958. static LLWString text1 =
  1959. utf8str_to_wstring("Move mouse cursor over ruler");
  1960. static F32 text1_width = -0.5f *
  1961. big_fontp->getWidthF32(text1.c_str());
  1962. hud_render_text(text1, help_text_pos, *big_fontp,
  1963. LLFontGL::NORMAL, text1_width, 3.f,
  1964. help_text_color, false);
  1965. static LLWString text2 = utf8str_to_wstring("to snap to grid");
  1966. static F32 text2_width = -0.5f *
  1967. big_fontp->getWidthF32(text2.c_str());
  1968. help_text_pos -= gViewerCamera.getUpAxis() *
  1969. mSnapRegimeOffset * 0.4f;
  1970. hud_render_text(text2, help_text_pos, *big_fontp,
  1971. LLFontGL::NORMAL, text2_width, 3.f,
  1972. help_text_color, false);
  1973. }
  1974. }
  1975. }
  1976. }
  1977. // Returns unit vector in direction of part of an origin-centered cube
  1978. LLVector3 LLManipScale::partToUnitVector(S32 part) const
  1979. {
  1980. if (LL_FACE_MIN <= part && part <= LL_FACE_MAX)
  1981. {
  1982. return faceToUnitVector(part);
  1983. }
  1984. if (LL_CORNER_MIN <= part && part <= LL_CORNER_MAX)
  1985. {
  1986. return cornerToUnitVector(part);
  1987. }
  1988. if (LL_EDGE_MIN <= part && part <= LL_EDGE_MAX)
  1989. {
  1990. return edgeToUnitVector(part);
  1991. }
  1992. return LLVector3();
  1993. }
  1994. // Returns unit vector in direction of face of an origin-centered cube
  1995. LLVector3 LLManipScale::faceToUnitVector(S32 part) const
  1996. {
  1997. llassert(LL_FACE_MIN <= part && part <= LL_FACE_MAX);
  1998. switch (part)
  1999. {
  2000. case LL_FACE_POSX:
  2001. return LLVector3(1.f, 0.f, 0.f);
  2002. case LL_FACE_NEGX:
  2003. return LLVector3(-1.f, 0.f, 0.f);
  2004. case LL_FACE_POSY:
  2005. return LLVector3(0.f, 1.f, 0.f);
  2006. case LL_FACE_NEGY:
  2007. return LLVector3(0.f, -1.f, 0.f);
  2008. case LL_FACE_POSZ:
  2009. return LLVector3(0.f, 0.f, 1.f);
  2010. case LL_FACE_NEGZ:
  2011. return LLVector3(0.f, 0.f, -1.f);
  2012. }
  2013. return LLVector3();
  2014. }
  2015. // Returns unit vector in direction of corner of an origin-centered cube
  2016. LLVector3 LLManipScale::cornerToUnitVector(S32 part) const
  2017. {
  2018. llassert(LL_CORNER_MIN <= part && part <= LL_CORNER_MAX);
  2019. switch (part)
  2020. {
  2021. case LL_CORNER_NNN:
  2022. return LLVector3(-F_SQRT3, -F_SQRT3, -F_SQRT3);
  2023. case LL_CORNER_NNP:
  2024. return LLVector3(-F_SQRT3, -F_SQRT3, F_SQRT3);
  2025. case LL_CORNER_NPN:
  2026. return LLVector3(-F_SQRT3, F_SQRT3, -F_SQRT3);
  2027. case LL_CORNER_NPP:
  2028. return LLVector3(-F_SQRT3, F_SQRT3, F_SQRT3);
  2029. case LL_CORNER_PNN:
  2030. return LLVector3(F_SQRT3, -F_SQRT3, -F_SQRT3);
  2031. case LL_CORNER_PNP:
  2032. return LLVector3(F_SQRT3, -F_SQRT3, F_SQRT3);
  2033. case LL_CORNER_PPN:
  2034. return LLVector3(F_SQRT3, F_SQRT3, -F_SQRT3);
  2035. case LL_CORNER_PPP:
  2036. return LLVector3(F_SQRT3, F_SQRT3, F_SQRT3);
  2037. }
  2038. return LLVector3();
  2039. }
  2040. // Returns unit vector in direction of edge of an origin-centered cube
  2041. LLVector3 LLManipScale::edgeToUnitVector(S32 part) const
  2042. {
  2043. llassert(LL_EDGE_MIN <= part && part <= LL_EDGE_MAX);
  2044. part -= LL_EDGE_MIN;
  2045. // Edge between which faces: 0 => XY, 1 => YZ, 2 => ZX
  2046. S32 rotation = part >> 2;
  2047. LLVector3 v;
  2048. v.mV[rotation] = (part & 1) ? F_SQRT2 : -F_SQRT2;
  2049. v.mV[(rotation + 1) % 3] = (part & 2) ? F_SQRT2 : -F_SQRT2;
  2050. // v.mV[(rotation+2) % 3] defaults to 0.
  2051. return v;
  2052. }
  2053. // Non-linear scale of origin-centered unit cube to non-origin-centered,
  2054. // non-symetrical bounding box
  2055. LLVector3 LLManipScale::unitVectorToLocalBBoxExtent(const LLVector3& v,
  2056. const LLBBox& bbox) const
  2057. {
  2058. const LLVector3& min = bbox.getMinLocal();
  2059. const LLVector3& max = bbox.getMaxLocal();
  2060. LLVector3 ctr = bbox.getCenterLocal();
  2061. return LLVector3(v.mV[0] ? (v.mV[0]>0 ? max.mV[0] : min.mV[0]) : ctr.mV[0],
  2062. v.mV[1] ? (v.mV[1]>0 ? max.mV[1] : min.mV[1]) : ctr.mV[1],
  2063. v.mV[2] ? (v.mV[2]>0 ? max.mV[2] : min.mV[2]) : ctr.mV[2]);
  2064. }
  2065. // Teturns max allowable scale along a given stretch axis
  2066. F32 LLManipScale::partToMaxScale(S32 part, const LLBBox& bbox) const
  2067. {
  2068. F32 max_scale_factor = 0.f;
  2069. LLVector3 bbox_extents = unitVectorToLocalBBoxExtent(partToUnitVector(part),
  2070. bbox);
  2071. bbox_extents.abs();
  2072. F32 max_extent = 0.f;
  2073. for (U32 i = VX; i <= VZ; ++i)
  2074. {
  2075. if (bbox_extents.mV[i] > max_extent)
  2076. {
  2077. max_extent = bbox_extents.mV[i];
  2078. }
  2079. }
  2080. max_scale_factor = bbox_extents.length() * maxPrimScale() / max_extent;
  2081. if (getUniform())
  2082. {
  2083. max_scale_factor *= 0.5f;
  2084. }
  2085. return max_scale_factor;
  2086. }
  2087. // Returns min allowable scale along a given stretch axis
  2088. F32 LLManipScale::partToMinScale(S32 part, const LLBBox& bbox) const
  2089. {
  2090. LLVector3 bbox_extents;
  2091. bbox_extents = unitVectorToLocalBBoxExtent(partToUnitVector(part), bbox);
  2092. bbox_extents.abs();
  2093. F32 min_extent = maxPrimScale();
  2094. for (U32 i = VX; i <= VZ; ++i)
  2095. {
  2096. if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent)
  2097. {
  2098. min_extent = bbox_extents.mV[i];
  2099. }
  2100. }
  2101. F32 min_scale_factor = bbox_extents.length() * minPrimScale() / min_extent;
  2102. if (getUniform())
  2103. {
  2104. min_scale_factor *= 0.5f;
  2105. }
  2106. return min_scale_factor;
  2107. }
  2108. // Returns the axis aligned unit vector closest to v.
  2109. LLVector3 LLManipScale::nearestAxis(const LLVector3& v) const
  2110. {
  2111. // Note: yes, this is a slow but easy implementation. Assumes that v is
  2112. // normalized
  2113. static LLVector3 coords[] = {
  2114. LLVector3(1.f, 0.f, 0.f),
  2115. LLVector3(0.f, 1.f, 0.f),
  2116. LLVector3(0.f, 0.f, 1.f),
  2117. LLVector3(-1.f, 0.f, 0.f),
  2118. LLVector3(0.f, -1.f, 0.f),
  2119. LLVector3(0.f, 0.f, -1.f)
  2120. };
  2121. F32 cosine[6];
  2122. F32 cos = v * coords[0];
  2123. cosine[0] = cos;
  2124. cosine[3] = -cos;
  2125. cos = v * coords[1];
  2126. cosine[1] = cos;
  2127. cosine[4] = -cos;
  2128. cos = v * coords[2];
  2129. cosine[2] = cos;
  2130. cosine[5] = -cos;
  2131. F32 greatest_cos = cosine[0];
  2132. S32 greatest_index = 0;
  2133. for (S32 i = 1; i < 6; ++i)
  2134. {
  2135. cos = cosine[i];
  2136. if (greatest_cos < cos)
  2137. {
  2138. greatest_cos = cos;
  2139. greatest_index = i;
  2140. }
  2141. }
  2142. return coords[greatest_index];
  2143. }
  2144. //virtual
  2145. bool LLManipScale::canAffectSelection()
  2146. {
  2147. // A selection is scalable if you are allowed to both edit and move
  2148. // everything in it, and it does not have any sitting agents
  2149. bool can_scale = mObjectSelection->getObjectCount() != 0;
  2150. if (can_scale)
  2151. {
  2152. struct f final : public LLSelectedObjectFunctor
  2153. {
  2154. bool apply(LLViewerObject* objectp) override
  2155. {
  2156. if (!objectp)
  2157. {
  2158. llwarns << "NULL object passed to functor !" << llendl;
  2159. return false;
  2160. }
  2161. LLViewerObject* root_object = objectp->getRootEdit();
  2162. return objectp->permModify() && objectp->permMove() &&
  2163. !objectp->isPermanentEnforced() && !objectp->isSeat() &&
  2164. (!root_object ||
  2165. (!root_object->isPermanentEnforced() &&
  2166. !root_object->isSeat()));
  2167. }
  2168. } func;
  2169. can_scale = mObjectSelection->applyToObjects(&func);
  2170. }
  2171. return can_scale;
  2172. }