llmanip.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /**
  2. * @file llmanip.cpp
  3. * @brief LLManip 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 "llmanip.h"
  34. #include "llgl.h"
  35. #include "lllocale.h"
  36. #include "llprimitive.h"
  37. #include "llrender.h"
  38. #include "llview.h"
  39. #include "llagent.h"
  40. #include "lldrawable.h"
  41. #include "llfontgl.h"
  42. #include "llpipeline.h"
  43. #include "llselectmgr.h"
  44. #include "llviewercamera.h"
  45. #include "llviewercontrol.h"
  46. #include "llviewerdisplay.h" // For hud_render_text()
  47. #include "llviewerjoint.h"
  48. #include "llviewerobject.h"
  49. #include "llviewerregion.h"
  50. #include "llviewertexturelist.h"
  51. #include "llviewerwindow.h"
  52. #include "llvoavatar.h"
  53. #include "llworld.h"
  54. // Local constants...
  55. constexpr F32 VERTICAL_OFFSET = 50.f;
  56. F32 LLManip::sHelpTextVisibleTime = 2.f;
  57. F32 LLManip::sHelpTextFadeTime = 2.f;
  58. S32 LLManip::sNumTimesHelpTextShown = 0;
  59. S32 LLManip::sMaxTimesShowHelpText = 5;
  60. F32 LLManip::sGridMaxSubdivisionLevel = 32.f;
  61. F32 LLManip::sGridMinSubdivisionLevel = 1.f;
  62. LLVector2 LLManip::sTickLabelSpacing(60.f, 25.f);
  63. //static
  64. void LLManip::rebuild(LLViewerObject* vobj)
  65. {
  66. LLDrawable* drawablep = vobj->mDrawable;
  67. if (drawablep && drawablep->getVOVolume())
  68. {
  69. gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME);
  70. drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
  71. drawablep->updateMove();
  72. LLSpatialGroup* group = drawablep->getSpatialGroup();
  73. if (group)
  74. {
  75. group->dirtyGeom();
  76. gPipeline.markRebuild(group);
  77. }
  78. LLViewerObject::const_child_list_t& child_list = vobj->getChildren();
  79. for (LLViewerObject::child_list_t::const_iterator
  80. iter = child_list.begin(), endIter = child_list.end();
  81. iter != endIter; ++iter)
  82. {
  83. LLViewerObject* child = *iter;
  84. if (child) // Paranoia
  85. {
  86. rebuild(child);
  87. }
  88. }
  89. }
  90. }
  91. LLManip::LLManip(const std::string& name, LLToolComposite* composite)
  92. : LLTool(name, composite),
  93. mInSnapRegime(false),
  94. mHighlightedPart(LL_NO_PART),
  95. mManipPart(LL_NO_PART)
  96. {
  97. }
  98. void LLManip::getManipNormal(LLViewerObject* object, EManipPart manip,
  99. LLVector3& normal)
  100. {
  101. LLVector3 grid_origin;
  102. LLVector3 grid_scale;
  103. LLQuaternion grid_rotation;
  104. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  105. if (manip >= LL_X_ARROW && manip <= LL_Z_ARROW)
  106. {
  107. LLVector3 arrow_axis;
  108. getManipAxis(object, manip, arrow_axis);
  109. LLVector3 cross = arrow_axis % gViewerCamera.getAtAxis();
  110. normal = cross % arrow_axis;
  111. normal.normalize();
  112. }
  113. else if (manip >= LL_YZ_PLANE && manip <= LL_XY_PLANE)
  114. {
  115. switch (manip)
  116. {
  117. case LL_YZ_PLANE:
  118. normal = LLVector3::x_axis;
  119. break;
  120. case LL_XZ_PLANE:
  121. normal = LLVector3::y_axis;
  122. break;
  123. case LL_XY_PLANE:
  124. normal = LLVector3::z_axis;
  125. break;
  126. default:
  127. break;
  128. }
  129. normal.rotVec(grid_rotation);
  130. }
  131. else
  132. {
  133. normal.clear();
  134. }
  135. }
  136. bool LLManip::getManipAxis(LLViewerObject* object, EManipPart manip,
  137. LLVector3& axis)
  138. {
  139. LLVector3 grid_origin;
  140. LLVector3 grid_scale;
  141. LLQuaternion grid_rotation;
  142. gSelectMgr.getGrid(grid_origin, grid_rotation, grid_scale);
  143. if (manip == LL_X_ARROW)
  144. {
  145. axis = LLVector3::x_axis;
  146. }
  147. else if (manip == LL_Y_ARROW)
  148. {
  149. axis = LLVector3::y_axis;
  150. }
  151. else if (manip == LL_Z_ARROW)
  152. {
  153. axis = LLVector3::z_axis;
  154. }
  155. else
  156. {
  157. return false;
  158. }
  159. axis.rotVec(grid_rotation);
  160. return true;
  161. }
  162. F32 LLManip::getSubdivisionLevel(const LLVector3& reference_point,
  163. const LLVector3& translate_axis,
  164. F32 grid_scale, S32 min_pixel_spacing)
  165. {
  166. // Update current snap subdivision level
  167. LLVector3 cam_to_reference;
  168. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  169. {
  170. cam_to_reference = LLVector3(1.f / gAgent.mHUDCurZoom, 0.f, 0.f);
  171. }
  172. else
  173. {
  174. cam_to_reference = reference_point - gViewerCamera.getOrigin();
  175. }
  176. F32 current_range = cam_to_reference.normalize();
  177. F32 projected_translation_axis_length = (translate_axis % cam_to_reference).length();
  178. F32 subdivisions = llmax(projected_translation_axis_length * grid_scale /
  179. (current_range / gViewerCamera.getPixelMeterRatio() *
  180. min_pixel_spacing), 0.f);
  181. subdivisions = llclamp(powf(2.f, llfloor(logf(subdivisions) / F_LN2)),
  182. 1.f / 32.f, 32.f);
  183. return subdivisions;
  184. }
  185. void LLManip::handleSelect()
  186. {
  187. mObjectSelection = gSelectMgr.getEditSelection();
  188. }
  189. void LLManip::handleDeselect()
  190. {
  191. mHighlightedPart = LL_NO_PART;
  192. mManipPart = LL_NO_PART;
  193. mObjectSelection = NULL;
  194. }
  195. LLObjectSelectionHandle LLManip::getSelection()
  196. {
  197. return mObjectSelection;
  198. }
  199. bool LLManip::handleHover(S32 x, S32 y, MASK mask)
  200. {
  201. // We only handle the event if mousedown started with us
  202. if (hasMouseCapture())
  203. {
  204. if (mObjectSelection->isEmpty())
  205. {
  206. // Somehow the object got deselected while we were dragging it.
  207. // Release the mouse
  208. setMouseCapture(false);
  209. }
  210. LL_DEBUGS("UserInput") << "hover handled by LLManip (active)"
  211. << LL_ENDL;
  212. }
  213. else
  214. {
  215. LL_DEBUGS("UserInput") << "hover handled by LLManip (inactive)"
  216. << LL_ENDL;
  217. }
  218. gViewerWindowp->setCursor(UI_CURSOR_ARROW);
  219. return true;
  220. }
  221. bool LLManip::handleMouseUp(S32 x, S32 y, MASK mask)
  222. {
  223. bool handled = false;
  224. if (hasMouseCapture())
  225. {
  226. handled = true;
  227. setMouseCapture(false);
  228. }
  229. return handled;
  230. }
  231. void LLManip::updateGridSettings()
  232. {
  233. sGridMaxSubdivisionLevel = gSavedSettings.getBool("GridSubUnit") ? (F32)gSavedSettings.getS32("GridSubdivision")
  234. : 1.f;
  235. }
  236. bool LLManip::getMousePointOnPlaneAgent(LLVector3& point, S32 x, S32 y,
  237. LLVector3 origin, LLVector3 normal)
  238. {
  239. LLVector3d origin_double = gAgent.getPosGlobalFromAgent(origin);
  240. LLVector3d global_point;
  241. bool result = getMousePointOnPlaneGlobal(global_point, x, y, origin_double,
  242. normal);
  243. point = gAgent.getPosAgentFromGlobal(global_point);
  244. return result;
  245. }
  246. bool LLManip::getMousePointOnPlaneGlobal(LLVector3d& point,
  247. S32 x, S32 y,
  248. LLVector3d origin,
  249. LLVector3 normal) const
  250. {
  251. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  252. {
  253. bool result = false;
  254. F32 mouse_x = ((F32)x / gViewerWindowp->getWindowWidth() - 0.5f) *
  255. gViewerCamera.getAspect() /
  256. gAgent.mHUDCurZoom;
  257. F32 mouse_y = ((F32)y / gViewerWindowp->getWindowHeight() - 0.5f) /
  258. gAgent.mHUDCurZoom;
  259. LLVector3 origin_agent = gAgent.getPosAgentFromGlobal(origin);
  260. LLVector3 mouse_pos = LLVector3(0.f, -mouse_x, mouse_y);
  261. if (fabsf(normal.mV[VX]) < 0.001f)
  262. {
  263. // use largish value that should be outside HUD manipulation range
  264. mouse_pos.mV[VX] = 10.f;
  265. }
  266. else
  267. {
  268. mouse_pos.mV[VX] = (normal * (origin_agent - mouse_pos))
  269. / (normal.mV[VX]);
  270. result = true;
  271. }
  272. point = gAgent.getPosGlobalFromAgent(mouse_pos);
  273. return result;
  274. }
  275. else
  276. {
  277. return gViewerWindowp->mousePointOnPlaneGlobal(point, x, y, origin,
  278. normal);
  279. }
  280. }
  281. // Given the line defined by mouse cursor (a1 + a_param*(a2-a1)) and the line
  282. // defined by b1 + b_param * (b2 - b1), returns a_param and b_param for the
  283. // points where lines are closest to each other.
  284. // Returns false if the two lines are parallel.
  285. bool LLManip::nearestPointOnLineFromMouse(S32 x, S32 y, const LLVector3& b1,
  286. const LLVector3& b2, F32& a_param,
  287. F32& b_param)
  288. {
  289. LLVector3 a1;
  290. LLVector3 a2;
  291. if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
  292. {
  293. F32 mouse_x = (((F32)x / gViewerWindowp->getWindowWidth()) - 0.5f) *
  294. gViewerCamera.getAspect() /
  295. gAgent.mHUDCurZoom;
  296. F32 mouse_y = (((F32)y / gViewerWindowp->getWindowHeight()) - 0.5f) /
  297. gAgent.mHUDCurZoom;
  298. a1 = LLVector3(llmin(b1.mV[VX] - 0.1f, b2.mV[VX] - 0.1f, 0.f),
  299. -mouse_x, mouse_y);
  300. a2 = a1 + LLVector3(1.f, 0.f, 0.f);
  301. }
  302. else
  303. {
  304. a1 = gAgent.getCameraPositionAgent();
  305. a2 = gAgent.getCameraPositionAgent() + LLVector3(gViewerWindowp->mouseDirectionGlobal(x, y));
  306. }
  307. bool parallel = true;
  308. LLVector3 a = a2 - a1;
  309. LLVector3 b = b2 - b1;
  310. LLVector3 normal;
  311. F32 dist, denom;
  312. normal = (b % a) % b; // normal to plane (P) through b and (shortest line between a and b)
  313. normal.normalize();
  314. dist = b1 * normal; // distance from origin to P
  315. denom = normal * a;
  316. if (denom < -F_APPROXIMATELY_ZERO || F_APPROXIMATELY_ZERO < denom)
  317. {
  318. a_param = (dist - normal * a1) / denom;
  319. parallel = false;
  320. }
  321. normal = (a % b) % a; // normal to plane (P) through a and (shortest line between a and b)
  322. normal.normalize();
  323. dist = a1 * normal; // distance from origin to P
  324. denom = normal * b;
  325. if (denom < -F_APPROXIMATELY_ZERO || F_APPROXIMATELY_ZERO < denom)
  326. {
  327. b_param = (dist - normal * b1) / denom;
  328. parallel = false;
  329. }
  330. return parallel;
  331. }
  332. LLVector3 LLManip::getSavedPivotPoint() const
  333. {
  334. return gSelectMgr.getSavedBBoxOfSelection().getCenterAgent();
  335. }
  336. LLVector3 LLManip::getPivotPoint()
  337. {
  338. static LLCachedControl<bool> at_root(gSavedSettings,
  339. "BuildUseRootForPivot");
  340. LLViewerObject* objectp = mObjectSelection->getFirstRootObject(true);
  341. if (objectp && (at_root || mObjectSelection->getObjectCount() == 1) &&
  342. mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
  343. {
  344. LLSelectNode* nodep = mObjectSelection->getFirstNode();
  345. if (nodep->mSelectedGLTFNode != -1)
  346. {
  347. return objectp->getGLTFNodePositionAgent(nodep->mSelectedGLTFNode);
  348. }
  349. return objectp->getPivotPositionAgent();
  350. }
  351. return gSelectMgr.getBBoxOfSelection().getCenterAgent();
  352. }
  353. void LLManip::renderGuidelines(bool draw_x, bool draw_y, bool draw_z)
  354. {
  355. LLVector3 grid_origin;
  356. LLQuaternion grid_rot;
  357. LLVector3 grid_scale;
  358. gSelectMgr.getGrid(grid_origin, grid_rot, grid_scale);
  359. constexpr bool children_ok = true;
  360. LLViewerObject* object = mObjectSelection->getFirstRootObject(children_ok);
  361. if (!object)
  362. {
  363. return;
  364. }
  365. //LLVector3 center_agent = gSelectMgr.getBBoxOfSelection().getCenterAgent();
  366. LLVector3 center_agent = getPivotPoint();
  367. gGL.pushMatrix();
  368. {
  369. gGL.translatef(center_agent.mV[VX], center_agent.mV[VY],
  370. center_agent.mV[VZ]);
  371. F32 angle_radians, x, y, z;
  372. grid_rot.getAngleAxis(&angle_radians, &x, &y, &z);
  373. gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
  374. LLViewerRegion* region = gAgent.getRegion();
  375. F32 region_size = region ? region->getWidth() : REGION_WIDTH_METERS;
  376. constexpr F32 LINE_ALPHA = 0.33f;
  377. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  378. LLUI::setLineWidth(1.5f);
  379. if (draw_x)
  380. {
  381. gGL.color4f(1.f, 0.f, 0.f, LINE_ALPHA);
  382. gGL.begin(LLRender::LINES);
  383. gGL.vertex3f(-region_size, 0.f, 0.f);
  384. gGL.vertex3f( region_size, 0.f, 0.f);
  385. gGL.end();
  386. }
  387. if (draw_y)
  388. {
  389. gGL.color4f(0.f, 1.f, 0.f, LINE_ALPHA);
  390. gGL.begin(LLRender::LINES);
  391. gGL.vertex3f(0.f, -region_size, 0.f);
  392. gGL.vertex3f(0.f, region_size, 0.f);
  393. gGL.end();
  394. }
  395. if (draw_z)
  396. {
  397. gGL.color4f(0.f, 0.f, 1.f, LINE_ALPHA);
  398. gGL.begin(LLRender::LINES);
  399. gGL.vertex3f(0.f, 0.f, -region_size);
  400. gGL.vertex3f(0.f, 0.f, region_size);
  401. gGL.end();
  402. }
  403. LLUI::setLineWidth(1.0f);
  404. }
  405. gGL.popMatrix();
  406. }
  407. void LLManip::renderXYZ(const LLVector3& vec)
  408. {
  409. static const LLFontGL* font = LLFontGL::getFontSansSerif();
  410. static const LLColor4 color_x(1.f, 0.5f, 0.5f, 1.f);
  411. static const LLColor4 color_y(0.5f, 1.f, 0.5f, 1.f);
  412. static const LLColor4 color_z(0.5f, 0.5f, 1.f, 1.f);
  413. static const LLColor4 color_bg(0.f, 0.f, 0.f, 0.7f);
  414. constexpr F32 PAD = 10.f;
  415. F32 window_center_x = (F32)(gViewerWindowp->getWindowWidth() / 2);
  416. F32 window_center_y = (F32)(gViewerWindowp->getWindowHeight() / 2);
  417. F32 vertical_offset = window_center_y - VERTICAL_OFFSET;
  418. F32 center_y = window_center_y + vertical_offset;
  419. LLWString str_x = utf8str_to_wstring(llformat("X: %.3f", vec.mV[VX]));
  420. LLWString str_y = utf8str_to_wstring(llformat("Y: %.3f", vec.mV[VY]));
  421. LLWString str_z = utf8str_to_wstring(llformat("Z: %.3f", vec.mV[VZ]));
  422. gGL.pushMatrix();
  423. {
  424. gViewerWindowp->setup2DRender();
  425. gGL.color4f(0.f, 0.f, 0.f, 0.7f);
  426. constexpr F32 y_factor = PAD * 2.f + 10.f;
  427. LLUIImage::sRoundedSquare->draw((window_center_x - 115.f) *
  428. LLFontGL::sScaleX,
  429. (center_y - PAD) * LLFontGL::sScaleY,
  430. 235.f * LLFontGL::sScaleX,
  431. y_factor * LLFontGL::sScaleY,
  432. color_bg);
  433. LLLocale locale(LLLocale::USER_LOCALE);
  434. LLGLDepthTest gls_depth(GL_FALSE);
  435. // Render drop shadowed text (manually because of bigger 'distance')
  436. F32 right_x;
  437. font->render(str_x, 0, window_center_x - 101.f, center_y - 2.f,
  438. LLColor4::black, LLFontGL::LEFT, LLFontGL::BASELINE,
  439. LLFontGL::NORMAL, S32_MAX, 1000, &right_x);
  440. font->render(str_y, 0, window_center_x - 26.f, center_y - 2.f,
  441. LLColor4::black, LLFontGL::LEFT, LLFontGL::BASELINE,
  442. LLFontGL::NORMAL, S32_MAX, 1000, &right_x);
  443. font->render(str_z, 0, window_center_x + 49.f, center_y - 2.f,
  444. LLColor4::black, LLFontGL::LEFT, LLFontGL::BASELINE,
  445. LLFontGL::NORMAL, S32_MAX, 1000, &right_x);
  446. // Render text on top
  447. font->render(str_x, 0, window_center_x - 102.f, center_y, color_x,
  448. LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL,
  449. S32_MAX, 1000, &right_x);
  450. font->render(str_y, 0, window_center_x - 27.f, center_y, color_y,
  451. LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL,
  452. S32_MAX, 1000, &right_x);
  453. font->render(str_z, 0, window_center_x + 48.f, center_y, color_z,
  454. LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL,
  455. S32_MAX, 1000, &right_x);
  456. }
  457. gGL.popMatrix();
  458. gViewerWindowp->setup3DRender();
  459. }
  460. void LLManip::renderTickText(const LLVector3& pos, const std::string& text)
  461. {
  462. static const LLFontGL* big_fontp = LLFontGL::getFontSansSerif();
  463. bool is_hud = mObjectSelection->getSelectType() == SELECT_TYPE_HUD;
  464. gGL.matrixMode(LLRender::MM_MODELVIEW);
  465. gGL.pushMatrix();
  466. LLVector3 render_pos = pos;
  467. if (is_hud)
  468. {
  469. F32 zoom_amt = gAgent.mHUDCurZoom;
  470. F32 inv_zoom_amt = 1.f / zoom_amt;
  471. // scale text back up to counter-act zoom level
  472. render_pos = pos * zoom_amt;
  473. gGL.scalef(inv_zoom_amt, inv_zoom_amt, inv_zoom_amt);
  474. }
  475. // Render shadow first
  476. const LLColor4& color = LLColor4::white;
  477. LLColor4 shadow_color = LLColor4::black;
  478. shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f;
  479. gViewerWindowp->setupViewport(1, -1);
  480. LLWString wstr(utf8str_to_wstring(text));
  481. F32 text_width = -0.5f * big_fontp->getWidthF32(wstr.c_str());
  482. hud_render_text(wstr, render_pos, *big_fontp, LLFontGL::NORMAL, text_width,
  483. 3.f, shadow_color, is_hud);
  484. gViewerWindowp->setupViewport();
  485. hud_render_text(wstr, render_pos, *big_fontp, LLFontGL::NORMAL, text_width,
  486. 3.f, color, is_hud);
  487. gGL.popMatrix();
  488. }
  489. void LLManip::renderTickValue(const LLVector3& pos, F32 value,
  490. const std::string& suffix,
  491. const LLColor4& color)
  492. {
  493. LLLocale locale(LLLocale::USER_LOCALE);
  494. static const LLFontGL* big_fontp = LLFontGL::getFontSansSerif();
  495. static const LLFontGL* small_fontp = LLFontGL::getFontSansSerifSmall();
  496. std::string val_string;
  497. std::string fraction_string;
  498. F32 val_to_print = ll_round(value, 0.001f);
  499. S32 fractional_portion = ll_round(fmodf(fabsf(val_to_print), 1.f) * 100.f);
  500. if (val_to_print < 0.f)
  501. {
  502. if (fractional_portion == 0)
  503. {
  504. val_string = llformat("-%d%s", lltrunc(fabsf(val_to_print)),
  505. suffix.c_str());
  506. }
  507. else
  508. {
  509. val_string = llformat("-%d", lltrunc(fabsf(val_to_print)));
  510. }
  511. }
  512. else if (fractional_portion == 0)
  513. {
  514. val_string = llformat("%d%s", lltrunc(fabsf(val_to_print)),
  515. suffix.c_str());
  516. }
  517. else
  518. {
  519. val_string = llformat("%d", lltrunc(val_to_print));
  520. }
  521. F32 val_str_width = big_fontp->getWidthF32(val_string);
  522. bool is_hud = mObjectSelection->getSelectType() == SELECT_TYPE_HUD;
  523. gGL.matrixMode(LLRender::MM_MODELVIEW);
  524. gGL.pushMatrix();
  525. LLVector3 render_pos = pos;
  526. if (is_hud)
  527. {
  528. F32 zoom_amt = gAgent.mHUDCurZoom;
  529. F32 inv_zoom_amt = 1.f / zoom_amt;
  530. // Scale text back up to counter-act zoom level
  531. render_pos = pos * zoom_amt;
  532. gGL.scalef(inv_zoom_amt, inv_zoom_amt, inv_zoom_amt);
  533. }
  534. LLColor4 shadow_color = LLColor4::black;
  535. shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f;
  536. LLWString wstr(utf8str_to_wstring(val_string));
  537. if (fractional_portion != 0)
  538. {
  539. fraction_string = llformat("%c%02d%s", LLLocale::getDecimalPoint(),
  540. fractional_portion, suffix.c_str());
  541. LLWString wstr2(utf8str_to_wstring(fraction_string));
  542. gViewerWindowp->setupViewport(1, -1);
  543. hud_render_text(wstr, render_pos, *big_fontp, LLFontGL::NORMAL,
  544. -val_str_width, 3.f, shadow_color, is_hud);
  545. hud_render_text(wstr2, render_pos, *small_fontp, LLFontGL::NORMAL,
  546. 1.f, 3.f, shadow_color, is_hud);
  547. gViewerWindowp->setupViewport();
  548. hud_render_text(wstr, render_pos, *big_fontp, LLFontGL::NORMAL,
  549. -val_str_width, 3.f, color, is_hud);
  550. hud_render_text(wstr2, render_pos, *small_fontp, LLFontGL::NORMAL,
  551. 1.f, 3.f, color, is_hud);
  552. }
  553. else
  554. {
  555. gViewerWindowp->setupViewport(1, -1);
  556. hud_render_text(wstr, render_pos, *big_fontp, LLFontGL::NORMAL,
  557. -0.5f * val_str_width, 3.f, shadow_color, is_hud);
  558. gViewerWindowp->setupViewport();
  559. hud_render_text(wstr, render_pos, *big_fontp, LLFontGL::NORMAL,
  560. -0.5f * val_str_width, 3.f, color, is_hud);
  561. }
  562. gGL.popMatrix();
  563. }
  564. LLColor4 LLManip::setupSnapGuideRenderPass(S32 pass)
  565. {
  566. static LLCachedControl<LLColor4U> grid_color_fg(gColors, "GridlineColor");
  567. static LLCachedControl<LLColor4U> grid_color_bg(gColors,
  568. "GridlineBGColor");
  569. static LLCachedControl<LLColor4U> grid_color_shadow(gColors,
  570. "GridlineShadowColor");
  571. static LLCachedControl<F32> line_alpha(gSavedSettings, "GridOpacity");
  572. LLColor4 line_color;
  573. switch (pass)
  574. {
  575. case 0: // Shadow
  576. gViewerWindowp->setupViewport(1, -1);
  577. line_color = LLColor4(grid_color_shadow);
  578. line_color.mV[VALPHA] *= (F32)line_alpha;
  579. LLUI::setLineWidth(2.f);
  580. break;
  581. case 1: // Hidden lines
  582. gViewerWindowp->setupViewport();
  583. line_color = LLColor4(grid_color_bg);
  584. line_color.mV[VALPHA] *= (F32)line_alpha;
  585. LLUI::setLineWidth(1.f);
  586. break;
  587. case 2: // Visible lines
  588. line_color = LLColor4(grid_color_fg);
  589. line_color.mV[VALPHA] *= (F32)line_alpha;
  590. }
  591. return line_color;
  592. }