llmaniprotate.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220
  1. /**
  2. * @file llmaniprotate.cpp
  3. * @brief LLManipRotate class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-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 "llmaniprotate.h"
  34. #include "llbutton.h"
  35. #include "llgl.h"
  36. #include "llprimitive.h"
  37. #include "llrender.h"
  38. #include "llagent.h"
  39. #include "lldrawable.h"
  40. #include "llhoverview.h"
  41. #include "llfloatertools.h"
  42. #include "llpipeline.h"
  43. #include "llselectmgr.h"
  44. #include "llstatusbar.h"
  45. #include "llviewercamera.h"
  46. #include "llviewercontrol.h"
  47. #include "llviewerdisplay.h" // For hud_render_text()
  48. #include "llviewerobject.h"
  49. #include "llviewershadermgr.h"
  50. #include "llviewerwindow.h"
  51. #include "llvoavatarself.h"
  52. #include "llworld.h"
  53. constexpr F32 RADIUS_PIXELS = 100.f; // Size in screen space
  54. constexpr F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS;
  55. constexpr F32 WIDTH_PIXELS = 8;
  56. constexpr S32 CIRCLE_STEPS = 100;
  57. constexpr F32 MAX_MANIP_SELECT_DISTANCE = 100.f;
  58. constexpr F32 SNAP_ANGLE_INCREMENT = 5.625f;
  59. constexpr F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT;
  60. constexpr F32 SNAP_GUIDE_RADIUS_1 = 2.8f;
  61. constexpr F32 SNAP_GUIDE_RADIUS_2 = 2.4f;
  62. constexpr F32 SNAP_GUIDE_RADIUS_3 = 2.2f;
  63. constexpr F32 SNAP_GUIDE_RADIUS_4 = 2.1f;
  64. constexpr F32 SNAP_GUIDE_RADIUS_5 = 2.05f;
  65. constexpr F32 SNAP_GUIDE_INNER_RADIUS = 2.f;
  66. constexpr F32 SELECTED_MANIPULATOR_SCALE = 1.05f;
  67. constexpr F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
  68. // gcc accepts constexpr here, but not clang...
  69. static const F32 AXIS_ONTO_CAM_TOLERANCE = cosf(80.f * DEG_TO_RAD);
  70. LLManipRotate::LLManipRotate(LLToolComposite* composite)
  71. : LLManip(std::string("Rotate"), composite),
  72. mRotationCenter(),
  73. mCenterScreen(),
  74. mRotation(),
  75. mMouseDown(),
  76. mMouseCur(),
  77. mRadiusMeters(0.f),
  78. mCenterToCam(),
  79. mCenterToCamNorm(),
  80. mCenterToCamMag(0.f),
  81. mCenterToProfilePlane(),
  82. mCenterToProfilePlaneMag(0.f),
  83. mSmoothRotate(false),
  84. mCamEdgeOn(false),
  85. mManipulatorScales(1.f, 1.f, 1.f, 1.f)
  86. {
  87. }
  88. // static
  89. bool LLManipRotate::getSnapEnabled()
  90. {
  91. static LLCachedControl<bool> snap_enabled(gSavedSettings, "SnapEnabled");
  92. return snap_enabled;
  93. }
  94. void LLManipRotate::handleSelect()
  95. {
  96. // *FIX: put this in mouseDown ?
  97. gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
  98. if (gFloaterToolsp)
  99. {
  100. gFloaterToolsp->setStatusText("rotate");
  101. }
  102. LLManip::handleSelect();
  103. }
  104. void LLManipRotate::render()
  105. {
  106. LLGLSUIDefault gls_ui;
  107. gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
  108. LLGLDepthTest gls_depth(GL_TRUE);
  109. LLGLEnable gl_blend(GL_BLEND);
  110. // You can rotate if you can move
  111. LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(true);
  112. if (!first_object)
  113. {
  114. return;
  115. }
  116. if (!updateVisiblity())
  117. {
  118. return;
  119. }
  120. gGL.matrixMode(LLRender::MM_MODELVIEW);
  121. gGL.pushMatrix();
  122. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  123. {
  124. F32 zoom = gAgent.mHUDCurZoom;
  125. gGL.scalef(zoom, zoom, zoom);
  126. }
  127. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  128. LLColor4 highlight_outside(1.f, 1.f, 0.f, 1.f);
  129. LLColor4 highlight_inside(0.7f, 0.7f, 0.f, 0.5f);
  130. F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
  131. gGL.pushMatrix();
  132. {
  133. // are we in the middle of a constrained drag?
  134. if (mManipPart >= LL_ROT_X && mManipPart <= LL_ROT_Z)
  135. {
  136. renderSnapGuides();
  137. }
  138. else
  139. {
  140. gDebugProgram.bind();
  141. LLGLEnable cull_face(GL_CULL_FACE);
  142. LLGLDepthTest gls_depth(GL_FALSE);
  143. gGL.pushMatrix();
  144. {
  145. // Draw "sphere" (intersection of sphere with tangent cone that
  146. // has apex at camera)
  147. gGL.translatef(mCenterToProfilePlane.mV[VX],
  148. mCenterToProfilePlane.mV[VY],
  149. mCenterToProfilePlane.mV[VZ]);
  150. gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
  151. // Inverse change of basis vectors
  152. LLVector3 forward = mCenterToCamNorm;
  153. LLVector3 left = gAgent.getUpAxis() % forward;
  154. left.normalize();
  155. LLVector3 up = forward % left;
  156. LLVector4 a(-forward);
  157. a.mV[3] = 0;
  158. LLVector4 b(up);
  159. b.mV[3] = 0;
  160. LLVector4 c(left);
  161. c.mV[3] = 0;
  162. LLMatrix4 mat;
  163. mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f));
  164. LLMatrix4a mata;
  165. mata.loadu(mat.getF32ptr());
  166. gGL.multMatrix(mata);
  167. static const LLMatrix4a rot = gl_gen_rot(-90, 0.f, 1.f, 0.f);
  168. gGL.rotatef(rot);
  169. LLColor4 color;
  170. if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
  171. {
  172. color.set(0.8f, 0.8f, 0.8f, 0.8f);
  173. gGL.scalef(mManipulatorScales.mV[VW],
  174. mManipulatorScales.mV[VW],
  175. mManipulatorScales.mV[VW]);
  176. }
  177. else
  178. {
  179. color.set(0.7f, 0.7f, 0.7f, 0.6f);
  180. }
  181. gGL.diffuseColor4fv(color.mV);
  182. gl_washer_2d(mRadiusMeters + width_meters, mRadiusMeters,
  183. CIRCLE_STEPS, color, color);
  184. if (mManipPart == LL_NO_PART)
  185. {
  186. gGL.color4f(0.7f, 0.7f, 0.7f, 0.3f);
  187. gGL.diffuseColor4f(0.7f, 0.7f, 0.7f, 0.3f);
  188. gl_circle_2d(0, 0, mRadiusMeters, CIRCLE_STEPS, true);
  189. }
  190. gGL.flush();
  191. }
  192. gGL.popMatrix();
  193. gUIProgram.bind();
  194. }
  195. gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
  196. LLQuaternion rot;
  197. F32 angle_radians, x, y, z;
  198. LLVector3 grid_origin;
  199. LLVector3 grid_scale;
  200. LLQuaternion grid_rotation;
  201. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  202. grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
  203. gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
  204. gDebugProgram.bind();
  205. F32 critical_damp =
  206. LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE);
  207. if (mManipPart == LL_ROT_Z)
  208. {
  209. static const LLVector4 rot_z_axis(1.f, 1.f,
  210. SELECTED_MANIPULATOR_SCALE, 1.f);
  211. mManipulatorScales = lerp(mManipulatorScales, rot_z_axis,
  212. critical_damp);
  213. gGL.pushMatrix();
  214. {
  215. // Selected part
  216. gGL.scalef(mManipulatorScales.mV[VZ],
  217. mManipulatorScales.mV[VZ],
  218. mManipulatorScales.mV[VZ]);
  219. renderActiveRing(mRadiusMeters, width_meters,
  220. LLColor4(0.f, 0.f, 1.f, 1.f),
  221. LLColor4(0.f, 0.f, 1.f, 0.3f));
  222. }
  223. gGL.popMatrix();
  224. }
  225. else if (mManipPart == LL_ROT_Y)
  226. {
  227. mManipulatorScales =
  228. lerp(mManipulatorScales,
  229. LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f),
  230. critical_damp);
  231. gGL.pushMatrix();
  232. {
  233. static const LLMatrix4a rot = gl_gen_rot(90.f, 1.f, 0.f, 0.f);
  234. gGL.rotatef(rot);
  235. gGL.scalef(mManipulatorScales.mV[VY],
  236. mManipulatorScales.mV[VY],
  237. mManipulatorScales.mV[VY]);
  238. renderActiveRing(mRadiusMeters, width_meters,
  239. LLColor4(0.f, 1.f, 0.f, 1.f),
  240. LLColor4(0.f, 1.f, 0.f, 0.3f));
  241. }
  242. gGL.popMatrix();
  243. }
  244. else if (mManipPart == LL_ROT_X)
  245. {
  246. mManipulatorScales = lerp(mManipulatorScales,
  247. LLVector4(SELECTED_MANIPULATOR_SCALE,
  248. 1.f, 1.f, 1.f),
  249. critical_damp);
  250. gGL.pushMatrix();
  251. {
  252. static const LLMatrix4a rot = gl_gen_rot(90.f, 0.f, 1.f, 0.f);
  253. gGL.rotatef(rot);
  254. gGL.scalef(mManipulatorScales.mV[VX],
  255. mManipulatorScales.mV[VX],
  256. mManipulatorScales.mV[VX]);
  257. renderActiveRing(mRadiusMeters, width_meters,
  258. LLColor4(1.f, 0.f, 0.f, 1.f),
  259. LLColor4(1.f, 0.f, 0.f, 0.3f));
  260. }
  261. gGL.popMatrix();
  262. }
  263. else if (mManipPart == LL_ROT_ROLL)
  264. {
  265. mManipulatorScales =
  266. lerp(mManipulatorScales,
  267. LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE),
  268. critical_damp);
  269. }
  270. else if (mManipPart == LL_NO_PART)
  271. {
  272. if (mHighlightedPart == LL_NO_PART)
  273. {
  274. mManipulatorScales =
  275. lerp(mManipulatorScales,
  276. LLVector4(1.f, 1.f, 1.f, 1.f),
  277. critical_damp);
  278. }
  279. LLGLEnable cull_face(GL_CULL_FACE);
  280. LLGLEnable clip_plane0(GL_CLIP_PLANE0);
  281. LLGLDepthTest gls_depth(GL_FALSE);
  282. // First pass: centers. Second pass: sides.
  283. for (S32 i = 0; i < 2; i++)
  284. {
  285. gGL.pushMatrix();
  286. {
  287. if (mHighlightedPart == LL_ROT_Z)
  288. {
  289. mManipulatorScales =
  290. lerp(mManipulatorScales,
  291. LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f),
  292. critical_damp);
  293. gGL.scalef(mManipulatorScales.mV[VZ],
  294. mManipulatorScales.mV[VZ],
  295. mManipulatorScales.mV[VZ]);
  296. // Hovering over part
  297. gl_ring(mRadiusMeters, width_meters,
  298. LLColor4(0.f, 0.f, 1.f, 1.f),
  299. LLColor4(0.f, 0.f, 1.f, 0.5f),
  300. CIRCLE_STEPS, i);
  301. }
  302. else
  303. {
  304. // Default
  305. gl_ring(mRadiusMeters, width_meters,
  306. LLColor4(0.f, 0.f, 0.8f, 0.8f),
  307. LLColor4(0.f, 0.f, 0.8f, 0.4f),
  308. CIRCLE_STEPS, i);
  309. }
  310. }
  311. gGL.popMatrix();
  312. gGL.pushMatrix();
  313. {
  314. static const LLMatrix4a rot =
  315. gl_gen_rot(90.f, 1.f, 0.f, 0.f);
  316. gGL.rotatef(rot);
  317. if (mHighlightedPart == LL_ROT_Y)
  318. {
  319. mManipulatorScales =
  320. lerp(mManipulatorScales,
  321. LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f),
  322. critical_damp);
  323. gGL.scalef(mManipulatorScales.mV[VY],
  324. mManipulatorScales.mV[VY],
  325. mManipulatorScales.mV[VY]);
  326. // Hovering over part
  327. gl_ring(mRadiusMeters, width_meters,
  328. LLColor4(0.f, 1.f, 0.f, 1.f),
  329. LLColor4(0.f, 1.f, 0.f, 0.5f),
  330. CIRCLE_STEPS, i);
  331. }
  332. else
  333. {
  334. // Default
  335. gl_ring(mRadiusMeters, width_meters,
  336. LLColor4(0.f, 0.8f, 0.f, 0.8f),
  337. LLColor4(0.f, 0.8f, 0.f, 0.4f),
  338. CIRCLE_STEPS, i);
  339. }
  340. }
  341. gGL.popMatrix();
  342. gGL.pushMatrix();
  343. {
  344. static const LLMatrix4a rot =
  345. gl_gen_rot(90.f, 0.f, 1.f, 0.f);
  346. gGL.rotatef(rot);
  347. if (mHighlightedPart == LL_ROT_X)
  348. {
  349. mManipulatorScales =
  350. lerp(mManipulatorScales,
  351. LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f),
  352. critical_damp);
  353. gGL.scalef(mManipulatorScales.mV[VX],
  354. mManipulatorScales.mV[VX],
  355. mManipulatorScales.mV[VX]);
  356. // Hovering over part
  357. gl_ring(mRadiusMeters, width_meters,
  358. LLColor4(1.f, 0.f, 0.f, 1.f),
  359. LLColor4(1.f, 0.f, 0.f, 0.5f),
  360. CIRCLE_STEPS, i);
  361. }
  362. else
  363. {
  364. // Default
  365. gl_ring(mRadiusMeters, width_meters,
  366. LLColor4(0.8f, 0.f, 0.f, 0.8f),
  367. LLColor4(0.8f, 0.f, 0.f, 0.4f),
  368. CIRCLE_STEPS, i);
  369. }
  370. }
  371. gGL.popMatrix();
  372. if (mHighlightedPart == LL_ROT_ROLL)
  373. {
  374. mManipulatorScales =
  375. lerp(mManipulatorScales,
  376. LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE),
  377. critical_damp);
  378. }
  379. }
  380. }
  381. gUIProgram.bind();
  382. }
  383. gGL.popMatrix();
  384. gGL.popMatrix();
  385. LLVector3 euler_angles;
  386. LLQuaternion object_rot = first_object->getRotationEdit();
  387. object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]),
  388. &(euler_angles.mV[VZ]));
  389. euler_angles *= RAD_TO_DEG;
  390. euler_angles.mV[VX] = ll_round(fmodf(euler_angles.mV[VX] + 360.f, 360.f),
  391. 0.05f);
  392. euler_angles.mV[VY] = ll_round(fmodf(euler_angles.mV[VY] + 360.f, 360.f),
  393. 0.05f);
  394. euler_angles.mV[VZ] = ll_round(fmodf(euler_angles.mV[VZ] + 360.f, 360.f),
  395. 0.05f);
  396. renderXYZ(euler_angles);
  397. }
  398. bool LLManipRotate::handleMouseDown(S32 x, S32 y, MASK mask)
  399. {
  400. bool handled = false;
  401. LLViewerObject* first_object =
  402. mObjectSelection->getFirstMoveableObject(true);
  403. if (first_object)
  404. {
  405. if (mHighlightedPart != LL_NO_PART)
  406. {
  407. handled = handleMouseDownOnPart(x, y, mask);
  408. }
  409. }
  410. return handled;
  411. }
  412. // Assumes that one of the parts of the manipulator was hit.
  413. bool LLManipRotate::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
  414. {
  415. if (!canAffectSelection())
  416. {
  417. return false;
  418. }
  419. highlightManipulators(x, y);
  420. S32 hit_part = mHighlightedPart;
  421. // We just started a drag, so save initial object positions
  422. gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_ROTATE);
  423. // Save selection center
  424. mRotationCenter = gAgent.getPosGlobalFromAgent(getPivotPoint());
  425. mManipPart = (EManipPart)hit_part;
  426. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  427. if (mManipPart == LL_ROT_GENERAL)
  428. {
  429. mMouseDown = intersectMouseWithSphere(x, y, center, mRadiusMeters);
  430. }
  431. else
  432. {
  433. // Project onto the plane of the ring
  434. LLVector3 axis = getConstraintAxis();
  435. F32 axis_onto_cam = fabsf(axis * mCenterToCamNorm);
  436. if (axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE)
  437. {
  438. LLVector3 up_from_axis = mCenterToCamNorm % axis;
  439. up_from_axis.normalize();
  440. LLVector3 cur_intersection;
  441. getMousePointOnPlaneAgent(cur_intersection, x, y, center,
  442. mCenterToCam);
  443. cur_intersection -= center;
  444. mMouseDown = projected_vec(cur_intersection, up_from_axis);
  445. F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
  446. F32 mouse_dist_sqrd = mMouseDown.lengthSquared();
  447. if (mouse_dist_sqrd > 0.0001f)
  448. {
  449. mouse_depth = sqrtf(mouse_depth * mouse_depth -
  450. mouse_dist_sqrd);
  451. }
  452. LLVector3 projected_center_to_cam = mCenterToCamNorm -
  453. projected_vec(mCenterToCamNorm,
  454. axis);
  455. mMouseDown += mouse_depth * projected_center_to_cam;
  456. }
  457. else
  458. {
  459. mMouseDown = findNearestPointOnRing(x, y, center, axis) - center;
  460. mMouseDown.normalize();
  461. }
  462. }
  463. mMouseCur = mMouseDown;
  464. // Route future Mouse messages here preemptively (release on mouse up).
  465. setMouseCapture(true);
  466. gSelectMgr.enableSilhouette(false);
  467. mHelpTextTimer.reset();
  468. ++sNumTimesHelpTextShown;
  469. return true;
  470. }
  471. LLVector3 LLManipRotate::findNearestPointOnRing(S32 x, S32 y,
  472. const LLVector3& center,
  473. const LLVector3& axis)
  474. {
  475. // Project the delta onto the ring and rescale it by the radius so that it
  476. // is _on_ the ring.
  477. LLVector3 proj_onto_ring;
  478. getMousePointOnPlaneAgent(proj_onto_ring, x, y, center, axis);
  479. proj_onto_ring -= center;
  480. proj_onto_ring.normalize();
  481. return center + proj_onto_ring * mRadiusMeters;
  482. }
  483. bool LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask)
  484. {
  485. // first, perform normal processing in case this was a quick-click
  486. handleHover(x, y, mask);
  487. if (hasMouseCapture())
  488. {
  489. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  490. end = mObjectSelection->end();
  491. iter != end; ++iter)
  492. {
  493. LLSelectNode* nodep = *iter;
  494. LLViewerObject* object = nodep->getObject();
  495. if (!object)
  496. {
  497. llwarns << "NULL selected object !" << llendl;
  498. continue;
  499. }
  500. LLViewerObject* root_object = object->getRootEdit();
  501. // have permission to move and object is root of selection or
  502. // individually selected
  503. if (object->permMove() && !object->isPermanentEnforced() &&
  504. (!root_object || !root_object->isPermanentEnforced()) &&
  505. (object->isRootEdit() || nodep->mIndividualSelection))
  506. {
  507. object->mUnselectedChildrenPositions.clear() ;
  508. }
  509. }
  510. mManipPart = LL_NO_PART;
  511. // Might have missed last update due to timing.
  512. gSelectMgr.sendMultipleUpdate(UPD_ROTATION | UPD_POSITION);
  513. gSelectMgr.enableSilhouette(true);
  514. #if 0
  515. gAgent.setObjectTracking(gSavedSettings.getBool("TrackFocusObject"));
  516. #endif
  517. gSelectMgr.updateSelectionCenter();
  518. gSelectMgr.saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
  519. }
  520. return LLManip::handleMouseUp(x, y, mask);
  521. }
  522. bool LLManipRotate::handleHover(S32 x, S32 y, MASK mask)
  523. {
  524. if (hasMouseCapture())
  525. {
  526. if (mObjectSelection->isEmpty())
  527. {
  528. // Somehow the object got deselected while we were dragging it.
  529. setMouseCapture(false);
  530. }
  531. else
  532. {
  533. drag(x, y);
  534. }
  535. LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (active)"
  536. << LL_ENDL;
  537. }
  538. else
  539. {
  540. highlightManipulators(x, y);
  541. LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (inactive)"
  542. << LL_ENDL;
  543. }
  544. gViewerWindowp->setCursor(UI_CURSOR_TOOLROTATE);
  545. return true;
  546. }
  547. LLVector3 LLManipRotate::projectToSphere(F32 x, F32 y, bool* on_sphere)
  548. {
  549. F32 z = 0.f;
  550. F32 dist_squared = x*x + y*y;
  551. *on_sphere = dist_squared <= SQ_RADIUS;
  552. if (*on_sphere)
  553. {
  554. z = sqrtf(SQ_RADIUS - dist_squared);
  555. }
  556. return LLVector3(x, y, z);
  557. }
  558. // Freeform rotation
  559. void LLManipRotate::drag(S32 x, S32 y)
  560. {
  561. if (!updateVisiblity())
  562. {
  563. return;
  564. }
  565. if (mManipPart == LL_ROT_GENERAL)
  566. {
  567. mRotation = dragUnconstrained(x, y);
  568. }
  569. else
  570. {
  571. mRotation = dragConstrained(x, y);
  572. }
  573. bool gltf_mode = false;
  574. bool damped = mSmoothRotate;
  575. mSmoothRotate = false;
  576. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  577. end = mObjectSelection->end();
  578. iter != end; ++iter)
  579. {
  580. LLSelectNode* nodep = *iter;
  581. LLViewerObject* object = nodep->getObject();
  582. if (!object)
  583. {
  584. llwarns << "NULL selected object !" << llendl;
  585. continue;
  586. }
  587. LLViewerObject* root_object = object->getRootEdit();
  588. // Have permission to move and object is root of selection or
  589. // individually selected
  590. if (object->permMove() && !object->isPermanentEnforced() &&
  591. (!root_object || !root_object->isPermanentEnforced()) &&
  592. (object->isRootEdit() || nodep->mIndividualSelection))
  593. {
  594. if (nodep->mSelectedGLTFNode != -1)
  595. {
  596. // Manipulating a GLTF node
  597. gltf_mode = true;
  598. LLQuaternion new_rot = nodep->mSavedRotation * mRotation;
  599. object->setGLTFNodeRotationAgent(nodep->mSelectedGLTFNode,
  600. new_rot);
  601. }
  602. if (gltf_mode)
  603. {
  604. continue;
  605. }
  606. if (!object->isRootEdit())
  607. {
  608. // Child objects should not update if parent is selected
  609. LLViewerObject* editable_root =
  610. (LLViewerObject*)object->getParent();
  611. if (editable_root->isSelected())
  612. {
  613. // we will be moved properly by our parent, so skip
  614. continue;
  615. }
  616. }
  617. LLQuaternion new_rot = nodep->mSavedRotation * mRotation;
  618. std::vector<LLVector3>& child_positions =
  619. object->mUnselectedChildrenPositions ;
  620. std::vector<LLQuaternion> child_rotations;
  621. if (object->isRootEdit() && nodep->mIndividualSelection)
  622. {
  623. object->saveUnselectedChildrenRotation(child_rotations) ;
  624. object->saveUnselectedChildrenPosition(child_positions) ;
  625. }
  626. if (object->getParent() && object->mDrawable.notNull())
  627. {
  628. LLQuaternion invParentRotation =
  629. object->mDrawable->mXform.getParent()->getWorldRotation();
  630. invParentRotation.transpose();
  631. object->setRotation(new_rot * invParentRotation, damped);
  632. rebuild(object);
  633. }
  634. else
  635. {
  636. object->setRotation(new_rot, damped);
  637. rebuild(object);
  638. }
  639. // For individually selected roots, we need to counter-rotate all
  640. // the children
  641. if (object->isRootEdit() && nodep->mIndividualSelection)
  642. {
  643. // RN: must do non-damped updates on these objects so relative
  644. // rotation appears constant instead of having two competing
  645. // slerps making the child objects appear to "wobble"
  646. object->resetChildrenRotationAndPosition(child_rotations,
  647. child_positions);
  648. }
  649. }
  650. }
  651. if (!gltf_mode)
  652. {
  653. // Update positions
  654. for (LLObjectSelection::iterator iter = mObjectSelection->begin(),
  655. end = mObjectSelection->end();
  656. iter != end; ++iter)
  657. {
  658. LLSelectNode* nodep = *iter;
  659. if (nodep->mSelectedGLTFNode != -1)
  660. {
  661. continue;
  662. }
  663. LLViewerObject* object = nodep->getObject();
  664. if (!object)
  665. {
  666. llwarns << "NULL selected object !" << llendl;
  667. continue;
  668. }
  669. LLViewerObject* root_object = object->getRootEdit();
  670. // To avoid cumulative position changes we calculate the objects
  671. // new position using its saved position
  672. if (object->permMove() && !object->isPermanentEnforced() &&
  673. (!root_object || !root_object->isPermanentEnforced()))
  674. {
  675. LLVector3 center =
  676. gAgent.getPosAgentFromGlobal(mRotationCenter);
  677. LLVector3 old_position;
  678. LLVector3 new_position;
  679. if (object->isAttachment() && object->mDrawable.notNull())
  680. {
  681. // Need to work in drawable space to handle selected items
  682. // from multiple attachments (which have no shared frame of
  683. // reference other than their render positions).
  684. LLXform* parent_xform = object->mDrawable->getXform()->getParent();
  685. new_position = nodep->mSavedPositionLocal *
  686. parent_xform->getWorldRotation() +
  687. parent_xform->getWorldPosition();
  688. old_position = object->getPosition() *
  689. parent_xform->getWorldRotation() +
  690. //object->getRenderPosition();
  691. parent_xform->getWorldPosition();
  692. }
  693. else
  694. {
  695. new_position =
  696. gAgent.getPosAgentFromGlobal(nodep->mSavedPositionGlobal);
  697. old_position = object->getPositionAgent();
  698. }
  699. // New relative rotated position
  700. new_position = (new_position - center) * mRotation;
  701. new_position += center;
  702. if (object->isRootEdit() && !object->isAttachment())
  703. {
  704. LLVector3d new_pos_global =
  705. gAgent.getPosGlobalFromAgent(new_position);
  706. new_pos_global =
  707. gWorld.clipToVisibleRegions(nodep->mSavedPositionGlobal,
  708. new_pos_global);
  709. new_position =
  710. gAgent.getPosAgentFromGlobal(new_pos_global);
  711. }
  712. // For individually selected child objects
  713. if (!object->isRootEdit() && nodep->mIndividualSelection)
  714. {
  715. LLViewerObject* parentp =
  716. (LLViewerObject*)object->getParent();
  717. if (!parentp->isSelected())
  718. {
  719. if (object->isAttachment() &&
  720. object->mDrawable.notNull())
  721. {
  722. // Find position relative to render position of
  723. // parent
  724. object->setPositionLocal((new_position -
  725. parentp->getRenderPosition()) *
  726. ~parentp->getRenderRotation());
  727. rebuild(object);
  728. }
  729. else
  730. {
  731. object->setPositionParent((new_position -
  732. parentp->getPositionAgent()) *
  733. ~parentp->getRotationRegion());
  734. rebuild(object);
  735. }
  736. }
  737. }
  738. else if (object->isRootEdit())
  739. {
  740. if (object->isAttachment() && object->mDrawable.notNull())
  741. {
  742. LLXform* parent_xform =
  743. object->mDrawable->getXform()->getParent();
  744. object->setPositionLocal((new_position -
  745. parent_xform->getWorldPosition()) *
  746. ~parent_xform->getWorldRotation());
  747. rebuild(object);
  748. }
  749. else
  750. {
  751. object->setPositionAgent(new_position);
  752. rebuild(object);
  753. }
  754. }
  755. // For individually selected roots, we need to counter-
  756. //translate all unselected children
  757. if (object->isRootEdit() && nodep->mIndividualSelection)
  758. {
  759. // Only offset by parent's translation as we have already
  760. // countered parent's rotation
  761. rebuild(object);
  762. object->resetChildrenPosition(old_position - new_position);
  763. }
  764. }
  765. }
  766. }
  767. // Store changes to override updates
  768. for (LLObjectSelection::iterator
  769. iter = gSelectMgr.getSelection()->begin(),
  770. end = gSelectMgr.getSelection()->end();
  771. iter != end; ++iter)
  772. {
  773. LLSelectNode* nodep = *iter;
  774. LLViewerObject* object = nodep->getObject();
  775. if (!object)
  776. {
  777. llwarns << "NULL selected object !" << llendl;
  778. continue;
  779. }
  780. LLViewerObject* root_object = object->getRootEdit();
  781. if (!object->isAvatar() && object->permModify() &&
  782. object->permMove() && !object->isPermanentEnforced() &&
  783. (!root_object || !root_object->isPermanentEnforced()))
  784. {
  785. nodep->mLastRotation = object->getRotation();
  786. nodep->mLastPositionLocal = object->getPosition();
  787. }
  788. }
  789. gSelectMgr.updateSelectionCenter();
  790. // RN: just clear focus so camera doesn't follow spurious object updates
  791. gAgent.clearFocusObject();
  792. dialog_refresh_all();
  793. }
  794. void LLManipRotate::renderActiveRing(F32 radius, F32 width,
  795. const LLColor4& front_color,
  796. const LLColor4& back_color)
  797. {
  798. LLGLEnable cull_face(GL_CULL_FACE);
  799. gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, false);
  800. gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, true);
  801. {
  802. LLGLDepthTest gls_depth(GL_FALSE);
  803. gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS,
  804. false);
  805. gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS,
  806. true);
  807. }
  808. }
  809. void LLManipRotate::renderSnapGuides()
  810. {
  811. if (!getSnapEnabled())
  812. {
  813. return;
  814. }
  815. LLVector3 grid_origin;
  816. LLVector3 grid_scale;
  817. LLQuaternion grid_rotation;
  818. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale, true);
  819. LLVector3 constraint_axis = getConstraintAxis();
  820. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  821. LLVector3 cam_at_axis;
  822. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  823. {
  824. cam_at_axis.set(1.f, 0.f, 0.f);
  825. }
  826. else
  827. {
  828. cam_at_axis = center - gAgent.getCameraPositionAgent();
  829. cam_at_axis.normalize();
  830. }
  831. LLVector3 world_snap_axis;
  832. LLVector3 test_axis = constraint_axis;
  833. bool constrain_to_ref_object = false;
  834. if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT &&
  835. isAgentAvatarValid())
  836. {
  837. test_axis = test_axis * ~grid_rotation;
  838. }
  839. else if (gSelectMgr.getGridMode() == GRID_MODE_REF_OBJECT)
  840. {
  841. test_axis = test_axis * ~grid_rotation;
  842. constrain_to_ref_object = true;
  843. }
  844. test_axis.abs();
  845. // Find closest global/reference axis to local constraint axis;
  846. if (test_axis.mV[VX] > test_axis.mV[VY] &&
  847. test_axis.mV[VX] > test_axis.mV[VZ])
  848. {
  849. world_snap_axis = LLVector3::y_axis;
  850. }
  851. else if (test_axis.mV[VY] > test_axis.mV[VZ])
  852. {
  853. world_snap_axis = LLVector3::z_axis;
  854. }
  855. else
  856. {
  857. world_snap_axis = LLVector3::x_axis;
  858. }
  859. LLVector3 projected_snap_axis = world_snap_axis;
  860. if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT &&
  861. isAgentAvatarValid())
  862. {
  863. projected_snap_axis = projected_snap_axis * grid_rotation;
  864. }
  865. else if (constrain_to_ref_object)
  866. {
  867. projected_snap_axis = projected_snap_axis * grid_rotation;
  868. }
  869. // Project world snap axis onto constraint plane
  870. projected_snap_axis -= projected_vec(projected_snap_axis, constraint_axis);
  871. projected_snap_axis.normalize();
  872. S32 num_rings = mCamEdgeOn ? 2 : 1;
  873. for (S32 ring_num = 0; ring_num < num_rings; ring_num++)
  874. {
  875. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  876. if (mCamEdgeOn)
  877. {
  878. // Draw two opposing rings
  879. if (ring_num == 0)
  880. {
  881. center += constraint_axis * mRadiusMeters * 0.5f;
  882. }
  883. else
  884. {
  885. center -= constraint_axis * mRadiusMeters * 0.5f;
  886. }
  887. }
  888. LLGLDepthTest gls_depth(GL_FALSE);
  889. for (S32 pass = 0; pass < 3; ++pass)
  890. {
  891. // Render snap guide ring
  892. gGL.pushMatrix();
  893. LLQuaternion snap_guide_rot;
  894. F32 angle_radians, x, y, z;
  895. snap_guide_rot.shortestArc(LLVector3::z_axis, getConstraintAxis());
  896. snap_guide_rot.getAngleAxis(&angle_radians, &x, &y, &z);
  897. gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
  898. gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
  899. LLColor4 line_color = setupSnapGuideRenderPass(pass);
  900. gGL.color4fv(line_color.mV);
  901. if (mCamEdgeOn)
  902. {
  903. // render an arc
  904. LLVector3 edge_normal = cam_at_axis % constraint_axis;
  905. edge_normal.normalize();
  906. LLVector3 x_axis_snap = LLVector3::x_axis * snap_guide_rot;
  907. LLVector3 y_axis_snap = LLVector3::y_axis * snap_guide_rot;
  908. F32 end_angle = atan2f(y_axis_snap * edge_normal, x_axis_snap *
  909. edge_normal);
  910. F32 start_angle = end_angle - F_PI;
  911. gl_arc_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS,
  912. CIRCLE_STEPS, false, start_angle, end_angle);
  913. }
  914. else
  915. {
  916. gl_circle_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS,
  917. CIRCLE_STEPS, false);
  918. }
  919. gGL.popMatrix();
  920. // *TODO: translate
  921. static const std::string up_str("Up");
  922. static const std::string dwn_str("Down");
  923. static const std::string bck_str("Back");
  924. static const std::string fwd_str("Forward");
  925. static const std::string lft_str("Left");
  926. static const std::string rgt_str("Right");
  927. static const std::string nth_str("North");
  928. static const std::string sth_str("South");
  929. static const std::string wst_str("West");
  930. static const std::string est_str("East");
  931. bool is_attachment = mObjectSelection->isAttachment();
  932. const std::string& dir1_str = is_attachment ? fwd_str : est_str;
  933. const std::string& dir2_str = is_attachment ? lft_str : nth_str;
  934. const std::string& dir3_str = is_attachment ? rgt_str : sth_str;
  935. const std::string& dir4_str = is_attachment ? bck_str : wst_str;
  936. for (S32 i = 0; i < 64; i++)
  937. {
  938. bool render_text = true;
  939. F32 deg = 5.625f * (F32)i;
  940. LLVector3 inner_point;
  941. LLVector3 outer_point;
  942. LLVector3 text_point;
  943. LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis);
  944. gGL.begin(LLRender::LINES);
  945. {
  946. inner_point = (projected_snap_axis * mRadiusMeters *
  947. SNAP_GUIDE_INNER_RADIUS * rot) + center;
  948. F32 tick_length = 0.f;
  949. if (i % 16 == 0)
  950. {
  951. tick_length = mRadiusMeters *
  952. (SNAP_GUIDE_RADIUS_1 - SNAP_GUIDE_INNER_RADIUS);
  953. }
  954. else if (i % 8 == 0)
  955. {
  956. tick_length = mRadiusMeters *
  957. (SNAP_GUIDE_RADIUS_2 - SNAP_GUIDE_INNER_RADIUS);
  958. }
  959. else if (i % 4 == 0)
  960. {
  961. tick_length = mRadiusMeters *
  962. (SNAP_GUIDE_RADIUS_3 - SNAP_GUIDE_INNER_RADIUS);
  963. }
  964. else if (i % 2 == 0)
  965. {
  966. tick_length = mRadiusMeters *
  967. (SNAP_GUIDE_RADIUS_4 - SNAP_GUIDE_INNER_RADIUS);
  968. }
  969. else
  970. {
  971. tick_length = mRadiusMeters *
  972. (SNAP_GUIDE_RADIUS_5 - SNAP_GUIDE_INNER_RADIUS);
  973. }
  974. if (mCamEdgeOn)
  975. {
  976. // don't draw ticks that are on back side of circle
  977. F32 dot = cam_at_axis * (projected_snap_axis * rot);
  978. if (dot > 0.f)
  979. {
  980. outer_point = inner_point;
  981. render_text = false;
  982. }
  983. else
  984. {
  985. if (ring_num == 0)
  986. {
  987. outer_point = inner_point +
  988. (constraint_axis * tick_length) *
  989. rot;
  990. }
  991. else
  992. {
  993. outer_point = inner_point -
  994. (constraint_axis * tick_length) *
  995. rot;
  996. }
  997. }
  998. }
  999. else
  1000. {
  1001. outer_point = inner_point +
  1002. (projected_snap_axis * tick_length) *
  1003. rot;
  1004. }
  1005. text_point = outer_point +
  1006. (projected_snap_axis * mRadiusMeters * 0.1f) *
  1007. rot;
  1008. gGL.vertex3fv(inner_point.mV);
  1009. gGL.vertex3fv(outer_point.mV);
  1010. }
  1011. gGL.end();
  1012. // RN: text rendering does own shadow pass, so only render once
  1013. if (pass == 1 && render_text && i % 16 == 0)
  1014. {
  1015. if (world_snap_axis.mV[VX])
  1016. {
  1017. if (i == 0)
  1018. {
  1019. renderTickText(text_point, dir1_str);
  1020. }
  1021. else if (i == 16)
  1022. {
  1023. if (constraint_axis.mV[VZ] > 0.f)
  1024. {
  1025. renderTickText(text_point, dir2_str);
  1026. }
  1027. else
  1028. {
  1029. renderTickText(text_point, dir3_str);
  1030. }
  1031. }
  1032. else if (i == 32)
  1033. {
  1034. renderTickText(text_point, dir4_str);
  1035. }
  1036. else if (constraint_axis.mV[VZ] > 0.f)
  1037. {
  1038. renderTickText(text_point, dir3_str);
  1039. }
  1040. else
  1041. {
  1042. renderTickText(text_point, dir2_str);
  1043. }
  1044. }
  1045. else if (world_snap_axis.mV[VY])
  1046. {
  1047. if (i == 0)
  1048. {
  1049. renderTickText(text_point, dir2_str);
  1050. }
  1051. else if (i == 16)
  1052. {
  1053. if (constraint_axis.mV[VX] > 0.f)
  1054. {
  1055. renderTickText(text_point, up_str);
  1056. }
  1057. else
  1058. {
  1059. renderTickText(text_point, dwn_str);
  1060. }
  1061. }
  1062. else if (i == 32)
  1063. {
  1064. renderTickText(text_point, dir3_str);
  1065. }
  1066. else if (constraint_axis.mV[VX] > 0.f)
  1067. {
  1068. renderTickText(text_point, dwn_str);
  1069. }
  1070. else
  1071. {
  1072. renderTickText(text_point, up_str);
  1073. }
  1074. }
  1075. else if (world_snap_axis.mV[VZ])
  1076. {
  1077. if (i == 0)
  1078. {
  1079. renderTickText(text_point, up_str);
  1080. }
  1081. else if (i == 16)
  1082. {
  1083. if (constraint_axis.mV[VY] > 0.f)
  1084. {
  1085. renderTickText(text_point, dir1_str);
  1086. }
  1087. else
  1088. {
  1089. renderTickText(text_point, dir4_str);
  1090. }
  1091. }
  1092. else if (i == 32)
  1093. {
  1094. renderTickText(text_point, dwn_str);
  1095. }
  1096. else if (constraint_axis.mV[VY] > 0.f)
  1097. {
  1098. renderTickText(text_point, dir4_str);
  1099. }
  1100. else
  1101. {
  1102. renderTickText(text_point, dir1_str);
  1103. }
  1104. }
  1105. }
  1106. gGL.color4fv(line_color.mV);
  1107. }
  1108. // Now render projected object axis
  1109. if (mInSnapRegime)
  1110. {
  1111. LLVector3 object_axis;
  1112. getObjectAxisClosestToMouse(object_axis);
  1113. // Project onto constraint plane
  1114. LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(true);
  1115. object_axis = object_axis * first_node->getObject()->getRenderRotation();
  1116. object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
  1117. object_axis.normalize();
  1118. object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center;
  1119. LLVector3 line_start = center;
  1120. gGL.begin(LLRender::LINES);
  1121. {
  1122. gGL.vertex3fv(line_start.mV);
  1123. gGL.vertex3fv(object_axis.mV);
  1124. }
  1125. gGL.end();
  1126. // Draw snap guide arrow
  1127. gGL.begin(LLRender::TRIANGLES);
  1128. {
  1129. LLVector3 arrow_dir;
  1130. LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
  1131. arrow_span.normalize();
  1132. arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
  1133. arrow_dir.normalize();
  1134. if (ring_num == 1)
  1135. {
  1136. arrow_dir *= -1.f;
  1137. }
  1138. gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
  1139. gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
  1140. gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
  1141. }
  1142. gGL.end();
  1143. {
  1144. LLGLDepthTest gls_depth(GL_TRUE);
  1145. gGL.begin(LLRender::LINES);
  1146. {
  1147. gGL.vertex3fv(line_start.mV);
  1148. gGL.vertex3fv(object_axis.mV);
  1149. }
  1150. gGL.end();
  1151. // Draw snap guide arrow
  1152. gGL.begin(LLRender::TRIANGLES);
  1153. {
  1154. LLVector3 arrow_dir;
  1155. LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
  1156. arrow_span.normalize();
  1157. arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
  1158. arrow_dir.normalize();
  1159. if (ring_num == 1)
  1160. {
  1161. arrow_dir *= -1.f;
  1162. }
  1163. gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
  1164. gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
  1165. gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
  1166. }
  1167. gGL.end();
  1168. }
  1169. }
  1170. }
  1171. }
  1172. // Render help text
  1173. if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
  1174. {
  1175. if (mHelpTextTimer.getElapsedTimeF32() <
  1176. sHelpTextVisibleTime + sHelpTextFadeTime &&
  1177. sNumTimesHelpTextShown < sMaxTimesShowHelpText)
  1178. {
  1179. LLVector3 sel_center = gSelectMgr.getSavedBBoxOfSelection().getCenterAgent();
  1180. LLVector3 offset_dir = gViewerCamera.getUpAxis();
  1181. static LLCachedControl<F32> grid_alpha(gSavedSettings,
  1182. "GridOpacity");
  1183. LLVector3 help_text_pos = sel_center + mRadiusMeters * 3.f * offset_dir;
  1184. LLColor4 help_text_color = LLColor4::white;
  1185. help_text_color.mV[VALPHA] =
  1186. clamp_rescale(mHelpTextTimer.getElapsedTimeF32(),
  1187. sHelpTextVisibleTime,
  1188. sHelpTextVisibleTime + sHelpTextFadeTime,
  1189. grid_alpha, 0.f);
  1190. const LLFontGL* big_fontp = LLFontGL::getFontSansSerif();
  1191. static LLWString text1 =
  1192. utf8str_to_wstring("Move mouse cursor over ruler");
  1193. static F32 text1_width = -0.5f *
  1194. big_fontp->getWidthF32(text1.c_str());
  1195. hud_render_text(text1, help_text_pos, *big_fontp, LLFontGL::NORMAL,
  1196. text1_width, 3.f, help_text_color, false);
  1197. static LLWString text2 = utf8str_to_wstring("to snap to grid");
  1198. static F32 text2_width = -0.5f *
  1199. big_fontp->getWidthF32(text2.c_str());
  1200. help_text_pos -= offset_dir * mRadiusMeters * 0.4f;
  1201. hud_render_text(text2, help_text_pos, *big_fontp, LLFontGL::NORMAL,
  1202. text2_width, 3.f, help_text_color, false);
  1203. }
  1204. }
  1205. }
  1206. // Returns true if center of sphere is visible. Also sets a bunch of member
  1207. // variables that are used later (e.g. mCenterToCam)
  1208. bool LLManipRotate::updateVisiblity()
  1209. {
  1210. // We do not want to recalculate the center of the selection during a drag.
  1211. // Due to packet delays, sometimes half the objects in the selection have
  1212. // their new position and half have their old one. This creates subtle
  1213. // errors in the computed center position for that frame. Unfortunately,
  1214. // these errors accumulate. The result is objects seem to "fly apart"
  1215. // during rotations. JC - 03.26.2002
  1216. if (!hasMouseCapture())
  1217. {
  1218. mRotationCenter = gAgent.getPosGlobalFromAgent(getPivotPoint());
  1219. }
  1220. bool visible = false;
  1221. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  1222. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1223. {
  1224. F32 zoom = gAgent.mHUDCurZoom;
  1225. mCenterToCam = LLVector3(-1.f / zoom, 0.f, 0.f);
  1226. mCenterToCamNorm = mCenterToCam;
  1227. mCenterToCamMag = mCenterToCamNorm.normalize();
  1228. mRadiusMeters = RADIUS_PIXELS / (F32)gViewerCamera.getViewHeightInPixels();
  1229. mRadiusMeters /= zoom;
  1230. mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
  1231. mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
  1232. mCenterScreen.set((S32)((0.5f - mRotationCenter.mdV[VY]) /
  1233. zoom * gViewerWindowp->getWindowWidth()),
  1234. (S32)((mRotationCenter.mdV[VZ] + 0.5f) /
  1235. zoom * gViewerWindowp->getWindowHeight()));
  1236. visible = true;
  1237. }
  1238. else
  1239. {
  1240. visible = gViewerCamera.projectPosAgentToScreen(center, mCenterScreen);
  1241. if (visible)
  1242. {
  1243. mCenterToCam = gAgent.getCameraPositionAgent() - center;
  1244. mCenterToCamNorm = mCenterToCam;
  1245. mCenterToCamMag = mCenterToCamNorm.normalize();
  1246. LLVector3 cameraAtAxis = gViewerCamera.getAtAxis();
  1247. cameraAtAxis.normalize();
  1248. F32 z_dist = -1.f * (mCenterToCam * cameraAtAxis);
  1249. // Do not drag manip if object too far away
  1250. static LLCachedControl<bool> limit_select_distance(gSavedSettings,
  1251. "LimitSelectDistance");
  1252. static LLCachedControl<F32> max_select_distance(gSavedSettings,
  1253. "MaxSelectDistance");
  1254. if (limit_select_distance &&
  1255. dist_vec(gAgent.getPositionAgent(),
  1256. center) > max_select_distance)
  1257. {
  1258. visible = false;
  1259. }
  1260. if (mCenterToCamMag > 0.001f)
  1261. {
  1262. F32 fraction_of_fov = RADIUS_PIXELS /
  1263. (F32)gViewerCamera.getViewHeightInPixels();
  1264. F32 apparent_angle = fraction_of_fov * gViewerCamera.getView();
  1265. mRadiusMeters = z_dist * tanf(apparent_angle);
  1266. mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters /
  1267. mCenterToCamMag;
  1268. mCenterToProfilePlane = -mCenterToProfilePlaneMag *
  1269. mCenterToCamNorm;
  1270. }
  1271. else
  1272. {
  1273. visible = false;
  1274. }
  1275. }
  1276. }
  1277. mCamEdgeOn = false;
  1278. F32 axis_onto_cam =
  1279. mManipPart >= LL_ROT_X ? fabsf(getConstraintAxis() * mCenterToCamNorm)
  1280. : 0.f;
  1281. if (axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE)
  1282. {
  1283. mCamEdgeOn = true;
  1284. }
  1285. return visible;
  1286. }
  1287. LLQuaternion LLManipRotate::dragUnconstrained(S32 x, S32 y)
  1288. {
  1289. LLVector3 cam = gAgent.getCameraPositionAgent();
  1290. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  1291. mMouseCur = intersectMouseWithSphere(x, y, center, mRadiusMeters);
  1292. F32 delta_x = (F32)(mCenterScreen.mX - x);
  1293. F32 delta_y = (F32)(mCenterScreen.mY - y);
  1294. F32 dist_from_sphere_center = sqrtf(delta_x * delta_x + delta_y * delta_y);
  1295. LLVector3 axis = mMouseDown % mMouseCur;
  1296. F32 angle = atan2f(sqrtf(axis * axis), mMouseDown * mMouseCur);
  1297. axis.normalize();
  1298. LLQuaternion sphere_rot(angle, axis);
  1299. if (is_approx_zero(1.f - mMouseDown * mMouseCur))
  1300. {
  1301. return LLQuaternion::DEFAULT;
  1302. }
  1303. else if (dist_from_sphere_center < RADIUS_PIXELS)
  1304. {
  1305. return sphere_rot;
  1306. }
  1307. else
  1308. {
  1309. LLVector3 intersection;
  1310. getMousePointOnPlaneAgent(intersection, x, y,
  1311. center + mCenterToProfilePlane,
  1312. mCenterToCamNorm);
  1313. // Amount dragging in sphere from center to periphery would rotate
  1314. // object
  1315. F32 in_sphere_angle = F_PI_BY_TWO;
  1316. F32 dist_to_tangent_point = mRadiusMeters;
  1317. if (!is_approx_zero(mCenterToProfilePlaneMag))
  1318. {
  1319. dist_to_tangent_point = sqrtf(mRadiusMeters * mRadiusMeters -
  1320. mCenterToProfilePlaneMag *
  1321. mCenterToProfilePlaneMag);
  1322. in_sphere_angle = atan2f(dist_to_tangent_point,
  1323. mCenterToProfilePlaneMag);
  1324. }
  1325. LLVector3 profile_center_to_intersection =
  1326. intersection - (center + mCenterToProfilePlane);
  1327. F32 dist_to_intersection = profile_center_to_intersection.normalize();
  1328. F32 angle = (-1.f + dist_to_intersection / dist_to_tangent_point) *
  1329. in_sphere_angle;
  1330. LLVector3 axis;
  1331. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1332. {
  1333. axis = LLVector3(-1.f, 0.f, 0.f) % profile_center_to_intersection;
  1334. }
  1335. else
  1336. {
  1337. axis = (cam - center) % profile_center_to_intersection;
  1338. axis.normalize();
  1339. }
  1340. return sphere_rot * LLQuaternion(angle, axis);
  1341. }
  1342. }
  1343. LLVector3 LLManipRotate::getConstraintAxis()
  1344. {
  1345. LLVector3 axis;
  1346. if (LL_ROT_ROLL == mManipPart)
  1347. {
  1348. axis = mCenterToCamNorm;
  1349. }
  1350. else
  1351. {
  1352. S32 axis_dir = mManipPart - LL_ROT_X;
  1353. if (axis_dir >= 0 && axis_dir < 3)
  1354. {
  1355. axis.mV[axis_dir] = 1.f;
  1356. }
  1357. else
  1358. {
  1359. llwarns << "Got bogus hit part " << mManipPart << llendl;
  1360. llassert(false);
  1361. axis.mV[0] = 1.f;
  1362. }
  1363. LLVector3 grid_origin;
  1364. LLVector3 grid_scale;
  1365. LLQuaternion grid_rotation;
  1366. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  1367. LLSelectNode* first_node =
  1368. mObjectSelection->getFirstMoveableNode(true);
  1369. if (first_node)
  1370. {
  1371. // *FIX: get agent local attachment grid working
  1372. // Put rotation into frame of first selected root object
  1373. axis = axis * grid_rotation;
  1374. }
  1375. }
  1376. return axis;
  1377. }
  1378. LLQuaternion LLManipRotate::dragConstrained(S32 x, S32 y)
  1379. {
  1380. LLSelectNode* first_object_node =
  1381. mObjectSelection->getFirstMoveableNode(true);
  1382. LLVector3 constraint_axis = getConstraintAxis();
  1383. LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  1384. F32 angle = 0.f;
  1385. // build snap axes
  1386. LLVector3 grid_origin;
  1387. LLVector3 grid_scale;
  1388. LLQuaternion grid_rotation;
  1389. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  1390. LLVector3 axis1;
  1391. LLVector3 axis2;
  1392. LLVector3 test_axis = constraint_axis;
  1393. if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT &&
  1394. isAgentAvatarValid())
  1395. {
  1396. test_axis = test_axis * ~grid_rotation;
  1397. }
  1398. else if (gSelectMgr.getGridMode() == GRID_MODE_REF_OBJECT)
  1399. {
  1400. test_axis = test_axis * ~grid_rotation;
  1401. }
  1402. test_axis.abs();
  1403. // Find closest global axis to constraint axis;
  1404. if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
  1405. {
  1406. axis1 = LLVector3::y_axis;
  1407. }
  1408. else if (test_axis.mV[VY] > test_axis.mV[VZ])
  1409. {
  1410. axis1 = LLVector3::z_axis;
  1411. }
  1412. else
  1413. {
  1414. axis1 = LLVector3::x_axis;
  1415. }
  1416. if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT &&
  1417. isAgentAvatarValid())
  1418. {
  1419. axis1 = axis1 * grid_rotation;
  1420. }
  1421. else if (gSelectMgr.getGridMode() == GRID_MODE_REF_OBJECT)
  1422. {
  1423. axis1 = axis1 * grid_rotation;
  1424. }
  1425. // Project axis onto constraint plane
  1426. axis1 -= (axis1 * constraint_axis) * constraint_axis;
  1427. axis1.normalize();
  1428. // Calculate third and final axis
  1429. axis2 = constraint_axis % axis1;
  1430. const F32 snap_radius = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
  1431. if (mCamEdgeOn)
  1432. {
  1433. // We are looking at the ring edge-on.
  1434. LLVector3 snap_plane_center = center +
  1435. (constraint_axis * mRadiusMeters * 0.5f);
  1436. LLVector3 cam_to_snap_plane;
  1437. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1438. {
  1439. cam_to_snap_plane.set(1.f, 0.f, 0.f);
  1440. }
  1441. else
  1442. {
  1443. cam_to_snap_plane = snap_plane_center -
  1444. gAgent.getCameraPositionAgent();
  1445. cam_to_snap_plane.normalize();
  1446. }
  1447. LLVector3 projected_mouse;
  1448. bool hit = getMousePointOnPlaneAgent(projected_mouse, x, y,
  1449. snap_plane_center,
  1450. constraint_axis);
  1451. projected_mouse -= snap_plane_center;
  1452. if (getSnapEnabled())
  1453. {
  1454. S32 snap_plane = 0;
  1455. F32 dot = cam_to_snap_plane * constraint_axis;
  1456. if (fabsf(dot) < 0.01f)
  1457. {
  1458. // Looking at ring edge on, project onto view plane and check
  1459. // if mouse is past ring
  1460. getMousePointOnPlaneAgent(projected_mouse, x, y,
  1461. snap_plane_center,
  1462. cam_to_snap_plane);
  1463. projected_mouse -= snap_plane_center;
  1464. dot = projected_mouse * constraint_axis;
  1465. if (projected_mouse * constraint_axis > 0)
  1466. {
  1467. snap_plane = 1;
  1468. }
  1469. projected_mouse -= dot * constraint_axis;
  1470. }
  1471. else if (dot > 0.f)
  1472. {
  1473. // Look for mouse position outside and in front of snap circle
  1474. if (hit && projected_mouse * cam_to_snap_plane < 0.f &&
  1475. projected_mouse.length() > snap_radius)
  1476. {
  1477. snap_plane = 1;
  1478. }
  1479. }
  1480. // Look for mouse position inside or in back of snap circle
  1481. else if (!hit || projected_mouse * cam_to_snap_plane > 0.f ||
  1482. projected_mouse.length() < snap_radius)
  1483. {
  1484. snap_plane = 1;
  1485. }
  1486. if (snap_plane == 0)
  1487. {
  1488. // Try other plane
  1489. snap_plane_center = center -
  1490. constraint_axis * mRadiusMeters * 0.5f;
  1491. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1492. {
  1493. cam_to_snap_plane.set(1.f, 0.f, 0.f);
  1494. }
  1495. else
  1496. {
  1497. cam_to_snap_plane = snap_plane_center -
  1498. gAgent.getCameraPositionAgent();
  1499. cam_to_snap_plane.normalize();
  1500. }
  1501. hit = getMousePointOnPlaneAgent(projected_mouse, x, y,
  1502. snap_plane_center,
  1503. constraint_axis);
  1504. projected_mouse -= snap_plane_center;
  1505. dot = cam_to_snap_plane * constraint_axis;
  1506. if (fabsf(dot) < 0.01f)
  1507. {
  1508. // Looking at ring edge on, project onto view plane and
  1509. // check if mouse is past ring
  1510. getMousePointOnPlaneAgent(projected_mouse, x, y,
  1511. snap_plane_center,
  1512. cam_to_snap_plane);
  1513. projected_mouse -= snap_plane_center;
  1514. dot = projected_mouse * constraint_axis;
  1515. if (projected_mouse * constraint_axis < 0)
  1516. {
  1517. snap_plane = 2;
  1518. }
  1519. projected_mouse -= dot * constraint_axis;
  1520. }
  1521. else if (dot < 0.f)
  1522. {
  1523. // Look for mouse position outside and in front of snap
  1524. // circle
  1525. if (hit && projected_mouse * cam_to_snap_plane < 0.f &&
  1526. projected_mouse.length() > snap_radius)
  1527. {
  1528. snap_plane = 2;
  1529. }
  1530. }
  1531. // Look for mouse position inside or in back of snap circle
  1532. else if (!hit || projected_mouse * cam_to_snap_plane > 0.f ||
  1533. projected_mouse.length() < snap_radius)
  1534. {
  1535. snap_plane = 2;
  1536. }
  1537. }
  1538. if (snap_plane > 0)
  1539. {
  1540. LLVector3 cam_at_axis;
  1541. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  1542. {
  1543. cam_at_axis.set(1.f, 0.f, 0.f);
  1544. }
  1545. else
  1546. {
  1547. cam_at_axis = snap_plane_center -
  1548. gAgent.getCameraPositionAgent();
  1549. cam_at_axis.normalize();
  1550. }
  1551. // First, project mouse onto screen plane at point tangent to
  1552. // rotation radius.
  1553. getMousePointOnPlaneAgent(projected_mouse, x, y,
  1554. snap_plane_center, cam_at_axis);
  1555. // Project that point onto rotation plane
  1556. projected_mouse -= snap_plane_center;
  1557. projected_mouse -= projected_vec(projected_mouse,
  1558. constraint_axis);
  1559. F32 mouse_lateral_dist = llmin(snap_radius,
  1560. projected_mouse.length());
  1561. F32 mouse_depth = snap_radius;
  1562. if (fabsf(mouse_lateral_dist) > 0.01f)
  1563. {
  1564. mouse_depth = sqrtf(snap_radius * snap_radius -
  1565. mouse_lateral_dist * mouse_lateral_dist);
  1566. }
  1567. LLVector3 projected_camera_at = cam_at_axis -
  1568. projected_vec(cam_at_axis,
  1569. constraint_axis);
  1570. projected_mouse -= mouse_depth * projected_camera_at;
  1571. if (!mInSnapRegime)
  1572. {
  1573. mSmoothRotate = true;
  1574. }
  1575. mInSnapRegime = true;
  1576. // 0 to 360 deg
  1577. F32 mouse_angle = fmodf(atan2f(projected_mouse * axis1,
  1578. projected_mouse * axis2) *
  1579. RAD_TO_DEG + 360.f, 360.f);
  1580. F32 relative_mouse_angle = fmodf(mouse_angle + SNAP_ANGLE_DETENTE / 2,
  1581. SNAP_ANGLE_INCREMENT);
  1582. LLVector3 object_axis;
  1583. getObjectAxisClosestToMouse(object_axis);
  1584. object_axis = object_axis * first_object_node->mSavedRotation;
  1585. // Project onto constraint plane
  1586. object_axis = object_axis -
  1587. object_axis * getConstraintAxis() * getConstraintAxis();
  1588. object_axis.normalize();
  1589. if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
  1590. {
  1591. F32 quantized_mouse_angle = mouse_angle - relative_mouse_angle +
  1592. SNAP_ANGLE_DETENTE * 0.5f;
  1593. angle = quantized_mouse_angle * DEG_TO_RAD -
  1594. atan2f(object_axis * axis1, object_axis * axis2);
  1595. }
  1596. else
  1597. {
  1598. angle = mouse_angle * DEG_TO_RAD -
  1599. atan2f(object_axis * axis1, object_axis * axis2);
  1600. }
  1601. return LLQuaternion(-angle, constraint_axis);
  1602. }
  1603. else
  1604. {
  1605. if (mInSnapRegime)
  1606. {
  1607. mSmoothRotate = true;
  1608. }
  1609. mInSnapRegime = false;
  1610. }
  1611. }
  1612. else
  1613. {
  1614. if (mInSnapRegime)
  1615. {
  1616. mSmoothRotate = true;
  1617. }
  1618. mInSnapRegime = false;
  1619. }
  1620. if (!mInSnapRegime)
  1621. {
  1622. LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis;
  1623. up_from_axis.normalize();
  1624. LLVector3 cur_intersection;
  1625. getMousePointOnPlaneAgent(cur_intersection, x, y, center,
  1626. mCenterToCam);
  1627. cur_intersection -= center;
  1628. mMouseCur = projected_vec(cur_intersection, up_from_axis);
  1629. F32 mouse_depth = snap_radius;
  1630. F32 mouse_dist_sqrd = mMouseCur.lengthSquared();
  1631. if (mouse_dist_sqrd > 0.0001f)
  1632. {
  1633. mouse_depth = sqrtf(snap_radius * snap_radius -
  1634. mouse_dist_sqrd);
  1635. }
  1636. LLVector3 projected_center_to_cam = mCenterToCamNorm -
  1637. projected_vec(mCenterToCamNorm,
  1638. constraint_axis);
  1639. mMouseCur += mouse_depth * projected_center_to_cam;
  1640. F32 dist = cur_intersection * up_from_axis - mMouseDown * up_from_axis;
  1641. angle = dist / snap_radius * -F_PI_BY_TWO;
  1642. }
  1643. }
  1644. else
  1645. {
  1646. LLVector3 projected_mouse;
  1647. getMousePointOnPlaneAgent(projected_mouse, x, y, center, constraint_axis);
  1648. projected_mouse -= center;
  1649. mMouseCur = projected_mouse;
  1650. mMouseCur.normalize();
  1651. if (!first_object_node)
  1652. {
  1653. return LLQuaternion::DEFAULT;
  1654. }
  1655. if (getSnapEnabled() && projected_mouse.length() > snap_radius)
  1656. {
  1657. if (!mInSnapRegime)
  1658. {
  1659. mSmoothRotate = true;
  1660. }
  1661. mInSnapRegime = true;
  1662. // 0 to 360 deg
  1663. F32 mouse_angle = fmodf(atan2f(projected_mouse * axis1,
  1664. projected_mouse * axis2) *
  1665. RAD_TO_DEG + 360.f, 360.f);
  1666. F32 relative_mouse_angle = fmodf(mouse_angle + SNAP_ANGLE_DETENTE / 2,
  1667. SNAP_ANGLE_INCREMENT);
  1668. //fmodf(ll_round(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
  1669. LLVector3 object_axis;
  1670. getObjectAxisClosestToMouse(object_axis);
  1671. object_axis = object_axis * first_object_node->mSavedRotation;
  1672. // project onto constraint plane
  1673. object_axis = object_axis - object_axis * getConstraintAxis() *
  1674. getConstraintAxis();
  1675. object_axis.normalize();
  1676. if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
  1677. {
  1678. F32 quantized_mouse_angle = mouse_angle - relative_mouse_angle +
  1679. SNAP_ANGLE_DETENTE * 0.5f;
  1680. angle = quantized_mouse_angle * DEG_TO_RAD -
  1681. atan2f(object_axis * axis1, object_axis * axis2);
  1682. }
  1683. else
  1684. {
  1685. angle = mouse_angle * DEG_TO_RAD -
  1686. atan2f(object_axis * axis1, object_axis * axis2);
  1687. }
  1688. return LLQuaternion(-angle, constraint_axis);
  1689. }
  1690. else
  1691. {
  1692. if (mInSnapRegime)
  1693. {
  1694. mSmoothRotate = true;
  1695. }
  1696. mInSnapRegime = false;
  1697. }
  1698. LLVector3 axis = mMouseDown % mMouseCur;
  1699. angle = atan2f(sqrtf(axis * axis), mMouseCur * mMouseDown);
  1700. F32 dir = axis * constraint_axis; // cross product
  1701. if (dir < 0.f)
  1702. {
  1703. angle *= -1.f;
  1704. }
  1705. }
  1706. static LLCachedControl<F32> rotation_step(gSavedSettings, "RotationStep");
  1707. F32 step_size = DEG_TO_RAD * rotation_step;
  1708. angle -= fmod(angle, step_size);
  1709. return LLQuaternion(angle, constraint_axis);
  1710. }
  1711. LLVector3 LLManipRotate::intersectMouseWithSphere(S32 x, S32 y,
  1712. const LLVector3& sphere_center,
  1713. F32 sphere_radius)
  1714. {
  1715. LLVector3 ray_pt;
  1716. LLVector3 ray_dir;
  1717. mouseToRay(x, y, &ray_pt, &ray_dir);
  1718. return intersectRayWithSphere(ray_pt, ray_dir, sphere_center, sphere_radius);
  1719. }
  1720. LLVector3 LLManipRotate::intersectRayWithSphere(const LLVector3& ray_pt,
  1721. const LLVector3& ray_dir,
  1722. const LLVector3& sphere_center,
  1723. F32 sphere_radius)
  1724. {
  1725. LLVector3 ray_pt_to_center = sphere_center - ray_pt;
  1726. F32 center_distance = ray_pt_to_center.normalize();
  1727. F32 dot = ray_dir * ray_pt_to_center;
  1728. if (dot == 0.f)
  1729. {
  1730. return LLVector3::zero;
  1731. }
  1732. // Point which ray hits plane centered on sphere origin, facing ray origin
  1733. LLVector3 intersection_sphere_plane =
  1734. ray_pt + ray_dir * center_distance / dot;
  1735. // Vector from sphere origin to the point, normalized to sphere radius
  1736. LLVector3 sphere_center_to_intersection =
  1737. (intersection_sphere_plane - sphere_center) / sphere_radius;
  1738. LLVector3 result;
  1739. F32 dist_squared = sphere_center_to_intersection.lengthSquared();
  1740. if (dist_squared > 1.f)
  1741. {
  1742. result = sphere_center_to_intersection;
  1743. result.normalize();
  1744. }
  1745. else
  1746. {
  1747. result = sphere_center_to_intersection -
  1748. ray_dir * sqrtf(1.f - dist_squared);
  1749. }
  1750. return result;
  1751. }
  1752. // Utility function. Should probably be moved to another class.
  1753. //static
  1754. void LLManipRotate::mouseToRay(S32 x, S32 y, LLVector3* ray_pt,
  1755. LLVector3* ray_dir)
  1756. {
  1757. if (gSelectMgr.getSelection()->getSelectType() == SELECT_TYPE_HUD)
  1758. {
  1759. F32 zoom = gAgent.mHUDCurZoom;
  1760. F32 mouse_x = ((F32)x / gViewerWindowp->getWindowWidth() - 0.5f) / zoom;
  1761. F32 mouse_y = ((F32)y / gViewerWindowp->getWindowHeight() - 0.5f) / zoom;
  1762. *ray_pt = LLVector3(-1.f, -mouse_x, mouse_y);
  1763. *ray_dir = LLVector3(1.f, 0.f, 0.f);
  1764. }
  1765. else
  1766. {
  1767. *ray_pt = gAgent.getCameraPositionAgent();
  1768. gViewerCamera.projectScreenToPosAgent(x, y, ray_dir);
  1769. *ray_dir -= *ray_pt;
  1770. ray_dir->normalize();
  1771. }
  1772. }
  1773. void LLManipRotate::highlightManipulators(S32 x, S32 y)
  1774. {
  1775. mHighlightedPart = LL_NO_PART;
  1776. //LLBBox bbox = gSelectMgr.getBBoxOfSelection();
  1777. LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(true);
  1778. if (!first_object)
  1779. {
  1780. return;
  1781. }
  1782. LLVector3 rotation_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
  1783. LLVector3 mouse_dir_x;
  1784. LLVector3 mouse_dir_y;
  1785. LLVector3 mouse_dir_z;
  1786. LLVector3 intersection_roll;
  1787. LLVector3 grid_origin;
  1788. LLVector3 grid_scale;
  1789. LLQuaternion grid_rotation;
  1790. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  1791. LLVector3 rot_x_axis = LLVector3::x_axis * grid_rotation;
  1792. LLVector3 rot_y_axis = LLVector3::y_axis * grid_rotation;
  1793. LLVector3 rot_z_axis = LLVector3::z_axis * grid_rotation;
  1794. F32 proj_rot_x_axis = fabsf(rot_x_axis * mCenterToCamNorm);
  1795. F32 proj_rot_y_axis = fabsf(rot_y_axis * mCenterToCamNorm);
  1796. F32 proj_rot_z_axis = fabsf(rot_z_axis * mCenterToCamNorm);
  1797. F32 min_select_distance = 0.f;
  1798. F32 cur_select_distance = 0.f;
  1799. // test x
  1800. getMousePointOnPlaneAgent(mouse_dir_x, x, y, rotation_center, rot_x_axis);
  1801. mouse_dir_x -= rotation_center;
  1802. // push intersection point out when working at obtuse angle to make ring
  1803. // easier to hit
  1804. mouse_dir_x *= 1.f + (1.f - fabsf(rot_x_axis * mCenterToCamNorm)) * 0.1f;
  1805. // test y
  1806. getMousePointOnPlaneAgent(mouse_dir_y, x, y, rotation_center, rot_y_axis);
  1807. mouse_dir_y -= rotation_center;
  1808. mouse_dir_y *= 1.f + (1.f - fabsf(rot_y_axis * mCenterToCamNorm)) * 0.1f;
  1809. // test z
  1810. getMousePointOnPlaneAgent(mouse_dir_z, x, y, rotation_center, rot_z_axis);
  1811. mouse_dir_z -= rotation_center;
  1812. mouse_dir_z *= 1.f + (1.f - fabsf(rot_z_axis * mCenterToCamNorm)) * 0.1f;
  1813. // test roll
  1814. getMousePointOnPlaneAgent(intersection_roll, x, y, rotation_center,
  1815. mCenterToCamNorm);
  1816. intersection_roll -= rotation_center;
  1817. F32 dist_x = mouse_dir_x.normalize();
  1818. F32 dist_y = mouse_dir_y.normalize();
  1819. F32 dist_z = mouse_dir_z.normalize();
  1820. F32 distance_threshold = MAX_MANIP_SELECT_DISTANCE * mRadiusMeters /
  1821. gViewerWindowp->getWindowHeight();
  1822. if (fabsf(dist_x - mRadiusMeters) * llmax(0.05f, proj_rot_x_axis) <
  1823. distance_threshold)
  1824. {
  1825. // selected x
  1826. cur_select_distance = dist_x * mouse_dir_x * mCenterToCamNorm;
  1827. if (cur_select_distance >= -0.05f &&
  1828. (min_select_distance == 0.f ||
  1829. cur_select_distance > min_select_distance))
  1830. {
  1831. min_select_distance = cur_select_distance;
  1832. mHighlightedPart = LL_ROT_X;
  1833. }
  1834. }
  1835. if (fabsf(dist_y - mRadiusMeters) * llmax(0.05f, proj_rot_y_axis) <
  1836. distance_threshold)
  1837. {
  1838. // selected y
  1839. cur_select_distance = dist_y * mouse_dir_y * mCenterToCamNorm;
  1840. if (cur_select_distance >= -0.05f &&
  1841. (min_select_distance == 0.f ||
  1842. cur_select_distance > min_select_distance))
  1843. {
  1844. min_select_distance = cur_select_distance;
  1845. mHighlightedPart = LL_ROT_Y;
  1846. }
  1847. }
  1848. if (fabsf(dist_z - mRadiusMeters) * llmax(0.05f, proj_rot_z_axis) <
  1849. distance_threshold)
  1850. {
  1851. // selected z
  1852. cur_select_distance = dist_z * mouse_dir_z * mCenterToCamNorm;
  1853. if (cur_select_distance >= -0.05f &&
  1854. (min_select_distance == 0.f ||
  1855. cur_select_distance > min_select_distance))
  1856. {
  1857. min_select_distance = cur_select_distance;
  1858. mHighlightedPart = LL_ROT_Z;
  1859. }
  1860. }
  1861. // Test for edge-on intersections
  1862. if (proj_rot_x_axis < 0.05f)
  1863. {
  1864. if ((proj_rot_y_axis > 0.05f && dist_y < mRadiusMeters &&
  1865. dist_y * fabsf(mouse_dir_y * rot_x_axis) < distance_threshold) ||
  1866. (proj_rot_z_axis > 0.05f && dist_z < mRadiusMeters &&
  1867. dist_z * fabsf(mouse_dir_z * rot_x_axis) < distance_threshold))
  1868. {
  1869. mHighlightedPart = LL_ROT_X;
  1870. }
  1871. }
  1872. if (proj_rot_y_axis < 0.05f)
  1873. {
  1874. if ((proj_rot_x_axis > 0.05f && dist_x < mRadiusMeters &&
  1875. dist_x * fabsf(mouse_dir_x * rot_y_axis) < distance_threshold) ||
  1876. (proj_rot_z_axis > 0.05f && dist_z < mRadiusMeters &&
  1877. dist_z * fabsf(mouse_dir_z * rot_y_axis) < distance_threshold))
  1878. {
  1879. mHighlightedPart = LL_ROT_Y;
  1880. }
  1881. }
  1882. if (proj_rot_z_axis < 0.05f)
  1883. {
  1884. if ((proj_rot_x_axis > 0.05f && dist_x < mRadiusMeters &&
  1885. dist_x * fabsf(mouse_dir_x * rot_z_axis) < distance_threshold) ||
  1886. (proj_rot_y_axis > 0.05f && dist_y < mRadiusMeters &&
  1887. dist_y * fabsf(mouse_dir_y * rot_z_axis) < distance_threshold))
  1888. {
  1889. mHighlightedPart = LL_ROT_Z;
  1890. }
  1891. }
  1892. // Test for roll
  1893. if (mHighlightedPart == LL_NO_PART)
  1894. {
  1895. F32 roll_distance = intersection_roll.length();
  1896. F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
  1897. // use larger distance threshold for roll as it is checked only if
  1898. // something else wasn't highlighted
  1899. if (fabsf(roll_distance - mRadiusMeters - width_meters * 2.f) <
  1900. distance_threshold * 2.f)
  1901. {
  1902. mHighlightedPart = LL_ROT_ROLL;
  1903. }
  1904. else if (roll_distance < mRadiusMeters)
  1905. {
  1906. mHighlightedPart = LL_ROT_GENERAL;
  1907. }
  1908. }
  1909. }
  1910. S32 LLManipRotate::getObjectAxisClosestToMouse(LLVector3& object_axis)
  1911. {
  1912. LLSelectNode* first_object_node =
  1913. mObjectSelection->getFirstMoveableNode(true);
  1914. if (!first_object_node)
  1915. {
  1916. object_axis.clear();
  1917. return -1;
  1918. }
  1919. LLQuaternion obj_rotation = first_object_node->mSavedRotation;
  1920. LLVector3 mouse_down_object = mMouseDown * ~obj_rotation;
  1921. LLVector3 mouse_down_abs = mouse_down_object;
  1922. mouse_down_abs.abs();
  1923. S32 axis_index = 0;
  1924. if (mouse_down_abs.mV[VX] > mouse_down_abs.mV[VY] &&
  1925. mouse_down_abs.mV[VX] > mouse_down_abs.mV[VZ])
  1926. {
  1927. if (mouse_down_object.mV[VX] > 0.f)
  1928. {
  1929. object_axis = LLVector3::x_axis;
  1930. }
  1931. else
  1932. {
  1933. object_axis = LLVector3::x_axis_neg;
  1934. }
  1935. axis_index = VX;
  1936. }
  1937. else if (mouse_down_abs.mV[VY] > mouse_down_abs.mV[VZ])
  1938. {
  1939. if (mouse_down_object.mV[VY] > 0.f)
  1940. {
  1941. object_axis = LLVector3::y_axis;
  1942. }
  1943. else
  1944. {
  1945. object_axis = LLVector3::y_axis_neg;
  1946. }
  1947. axis_index = VY;
  1948. }
  1949. else
  1950. {
  1951. if (mouse_down_object.mV[VZ] > 0.f)
  1952. {
  1953. object_axis = LLVector3::z_axis;
  1954. }
  1955. else
  1956. {
  1957. object_axis = LLVector3::z_axis_neg;
  1958. }
  1959. axis_index = VZ;
  1960. }
  1961. return axis_index;
  1962. }
  1963. //virtual
  1964. bool LLManipRotate::canAffectSelection()
  1965. {
  1966. bool can_rotate = mObjectSelection->getObjectCount() != 0;
  1967. if (can_rotate)
  1968. {
  1969. struct f final : public LLSelectedObjectFunctor
  1970. {
  1971. bool apply(LLViewerObject* objectp) override
  1972. {
  1973. static LLCachedControl<bool> edit_linked_parts(gSavedSettings,
  1974. "EditLinkedParts");
  1975. if (!objectp)
  1976. {
  1977. llwarns << "NULL object passed to functor !" << llendl;
  1978. return false;
  1979. }
  1980. LLViewerObject* root_object = objectp->getRootEdit();
  1981. return objectp->permMove() &&
  1982. !objectp->isPermanentEnforced() &&
  1983. (!root_object || !root_object->isPermanentEnforced()) &&
  1984. (objectp->permModify() || !edit_linked_parts);
  1985. }
  1986. } func;
  1987. can_rotate = mObjectSelection->applyToObjects(&func);
  1988. }
  1989. return can_rotate;
  1990. }