lltoolselectrect.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /**
  2. * @file lltoolselectrect.cpp
  3. * @brief A tool to select multiple objects with a screen-space rectangle.
  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 "lltoolselectrect.h"
  34. #include "llgl.h"
  35. #include "llrender.h"
  36. #include "llagent.h"
  37. #include "lldrawable.h"
  38. //MK
  39. #include "mkrlinterface.h"
  40. //mk
  41. #include "llselectmgr.h"
  42. #include "lltoolmgr.h"
  43. #include "lltoolview.h"
  44. #include "llviewercamera.h"
  45. #include "llviewercontrol.h"
  46. #include "llviewerobjectlist.h"
  47. #include "llviewerregion.h"
  48. #include "llviewerwindow.h"
  49. #include "llworld.h"
  50. // Globals
  51. constexpr S32 SLOP_RADIUS = 5;
  52. //
  53. // Member functions
  54. //
  55. LLToolSelectRect::LLToolSelectRect(LLToolComposite* composite)
  56. : LLToolSelect(composite),
  57. mDragStartX(0),
  58. mDragStartY(0),
  59. mDragEndX(0),
  60. mDragEndY(0),
  61. mDragLastWidth(0),
  62. mDragLastHeight(0),
  63. mMouseOutsideSlop(false)
  64. {
  65. }
  66. bool LLToolSelectRect::handleMouseDown(S32 x, S32 y, MASK mask)
  67. {
  68. handlePick(gViewerWindowp->pickImmediate(x, y, true));
  69. LLTool::handleMouseDown(x, y, mask);
  70. return mPick.getObject().notNull();
  71. }
  72. void LLToolSelectRect::handlePick(const LLPickInfo& pick)
  73. {
  74. mPick = pick;
  75. // start dragging rectangle
  76. setMouseCapture(true);
  77. mDragStartX = pick.mMousePt.mX;
  78. mDragStartY = pick.mMousePt.mY;
  79. mDragEndX = pick.mMousePt.mX;
  80. mDragEndY = pick.mMousePt.mY;
  81. mMouseOutsideSlop = false;
  82. }
  83. bool LLToolSelectRect::handleMouseUp(S32 x, S32 y, MASK mask)
  84. {
  85. setMouseCapture(false);
  86. if (mMouseOutsideSlop)
  87. {
  88. mDragLastWidth = 0;
  89. mDragLastHeight = 0;
  90. mMouseOutsideSlop = false;
  91. if (mask == MASK_CONTROL)
  92. {
  93. gSelectMgr.deselectHighlightedObjects();
  94. }
  95. else
  96. {
  97. gSelectMgr.selectHighlightedObjects();
  98. }
  99. // *HACK: needed now (post GLTF preview selection changes) since
  100. // otherwise the lasso-selected objects are immovable. HB
  101. gSelectMgr.demoteSelectionToIndividuals();
  102. gSelectMgr.promoteSelectionToRoot();
  103. return true;
  104. }
  105. return LLToolSelect::handleMouseUp(x, y, mask);
  106. }
  107. bool LLToolSelectRect::handleHover(S32 x, S32 y, MASK mask)
  108. {
  109. if (hasMouseCapture())
  110. {
  111. if (mMouseOutsideSlop || outsideSlop(x, y, mDragStartX, mDragStartY))
  112. {
  113. if (!mMouseOutsideSlop && !(mask & MASK_SHIFT) &&
  114. !(mask & MASK_CONTROL))
  115. {
  116. // just started rect select, and not adding to current
  117. // selection
  118. gSelectMgr.deselectAll();
  119. }
  120. mMouseOutsideSlop = true;
  121. mDragEndX = x;
  122. mDragEndY = y;
  123. handleRectangleSelection(x, y, mask);
  124. }
  125. else
  126. {
  127. return LLToolSelect::handleHover(x, y, mask);
  128. }
  129. LL_DEBUGS("UserInput") << "hover handled by LLToolSelectRect (active)"
  130. << LL_ENDL;
  131. }
  132. else
  133. {
  134. LL_DEBUGS("UserInput") << "hover handled by LLToolSelectRect (inactive)"
  135. << LL_ENDL;
  136. }
  137. gWindowp->setCursor(UI_CURSOR_ARROW);
  138. return true;
  139. }
  140. void LLToolSelectRect::draw()
  141. {
  142. if (hasMouseCapture() && mMouseOutsideSlop)
  143. {
  144. bool has_ctrl_mask = gKeyboardp &&
  145. gKeyboardp->currentMask(true) == MASK_CONTROL;
  146. if (has_ctrl_mask)
  147. {
  148. gGL.color4f(1.f, 0.f, 0.f, 1.f);
  149. }
  150. else
  151. {
  152. gGL.color4f(1.f, 1.f, 0.f, 1.f);
  153. }
  154. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  155. gl_rect_2d(llmin(mDragStartX, mDragEndX),
  156. llmax(mDragStartY, mDragEndY),
  157. llmax(mDragStartX, mDragEndX),
  158. llmin(mDragStartY, mDragEndY), false);
  159. if (has_ctrl_mask)
  160. {
  161. gGL.color4f(1.f, 0.f, 0.f, 0.1f);
  162. }
  163. else
  164. {
  165. gGL.color4f(1.f, 1.f, 0.f, 0.1f);
  166. }
  167. gl_rect_2d(llmin(mDragStartX, mDragEndX),
  168. llmax(mDragStartY, mDragEndY),
  169. llmax(mDragStartX, mDragEndX),
  170. llmin(mDragStartY, mDragEndY));
  171. }
  172. }
  173. // true if x,y outside small box around start_x,start_y
  174. bool LLToolSelectRect::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y)
  175. {
  176. S32 dx = x - start_x;
  177. S32 dy = y - start_y;
  178. return dx <= -SLOP_RADIUS || SLOP_RADIUS <= dx || dy <= -SLOP_RADIUS ||
  179. SLOP_RADIUS <= dy;
  180. }
  181. // Returns true if you got at least one object (used to be in llglsandbox.cpp).
  182. void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
  183. {
  184. //MK
  185. if (gRLenabled && gRLInterface.mContainsInteract) return;
  186. //mk
  187. LLVector3 av_pos = gAgent.getPositionAgent();
  188. static LLCachedControl<F32> max_select_distance(gSavedSettings, "MaxSelectDistance");
  189. F32 select_dist_squared = max_select_distance * max_select_distance;
  190. bool deselect = (mask == MASK_CONTROL);
  191. S32 left = llmin(x, mDragStartX);
  192. S32 right = llmax(x, mDragStartX);
  193. S32 top = llmax(y, mDragStartY);
  194. S32 bottom =llmin(y, mDragStartY);
  195. left = ll_round((F32) left * LLUI::sGLScaleFactor.mV[VX]);
  196. right = ll_round((F32) right * LLUI::sGLScaleFactor.mV[VX]);
  197. top = ll_round((F32) top * LLUI::sGLScaleFactor.mV[VY]);
  198. bottom = ll_round((F32) bottom * LLUI::sGLScaleFactor.mV[VY]);
  199. F32 old_far_plane = gViewerCamera.getFar();
  200. F32 old_near_plane = gViewerCamera.getNear();
  201. S32 width = right - left + 1;
  202. S32 height = top - bottom + 1;
  203. bool grow_selection = false;
  204. bool shrink_selection = false;
  205. if (height > mDragLastHeight || width > mDragLastWidth)
  206. {
  207. grow_selection = true;
  208. }
  209. if (height < mDragLastHeight || width < mDragLastWidth)
  210. {
  211. shrink_selection = true;
  212. }
  213. if (!grow_selection && !shrink_selection)
  214. {
  215. // nothing to do
  216. return;
  217. }
  218. mDragLastHeight = height;
  219. mDragLastWidth = width;
  220. S32 center_x = (left + right) / 2;
  221. S32 center_y = (top + bottom) / 2;
  222. // save drawing mode
  223. gGL.matrixMode(LLRender::MM_PROJECTION);
  224. gGL.pushMatrix();
  225. static LLCachedControl<bool> limit_select_distance(gSavedSettings,
  226. "LimitSelectDistance");
  227. if (limit_select_distance)
  228. {
  229. // ...select distance from control
  230. LLVector3 relative_av_pos = av_pos;
  231. relative_av_pos -= gViewerCamera.getOrigin();
  232. F32 new_far = relative_av_pos * gViewerCamera.getAtAxis() +
  233. max_select_distance;
  234. F32 new_near = relative_av_pos * gViewerCamera.getAtAxis() -
  235. max_select_distance;
  236. new_near = llmax(new_near, 0.1f);
  237. gViewerCamera.setFar(new_far);
  238. gViewerCamera.setNear(new_near);
  239. }
  240. //MK
  241. if (gRLenabled && gRLInterface.mFartouchMax < EXTREMUM)
  242. {
  243. // don't allow select by rectangle while under fartouch
  244. gViewerCamera.setFar(0.0f);
  245. gViewerCamera.setNear(0.0f);
  246. }
  247. //mk
  248. gViewerCamera.setPerspective(FOR_SELECTION, center_x - width / 2,
  249. center_y - height / 2, width, height,
  250. limit_select_distance);
  251. if (shrink_selection)
  252. {
  253. struct f final : public LLSelectedObjectFunctor
  254. {
  255. bool apply(LLViewerObject* vobjp) override
  256. {
  257. LLDrawable* drawable = vobjp->mDrawable;
  258. if (!drawable || vobjp->isAttachment() ||
  259. (vobjp->getPCode() != LL_PCODE_VOLUME &&
  260. vobjp->getPCode() != LL_PCODE_LEGACY_TREE &&
  261. vobjp->getPCode() != LL_PCODE_LEGACY_GRASS))
  262. {
  263. return true;
  264. }
  265. //MK
  266. if (gRLenabled && !gRLInterface.canEdit(vobjp))
  267. {
  268. return true;
  269. }
  270. //mk
  271. S32 result = gViewerCamera.sphereInFrustum(drawable->getPositionAgent(),
  272. drawable->getRadius());
  273. switch (result)
  274. {
  275. case 0:
  276. gSelectMgr.unhighlightObjectOnly(vobjp);
  277. break;
  278. case 1:
  279. // check vertices
  280. if (!gViewerCamera.areVertsVisible(vobjp,
  281. LLSelectMgr::sRectSelectInclusive))
  282. {
  283. gSelectMgr.unhighlightObjectOnly(vobjp);
  284. }
  285. break;
  286. default:
  287. break;
  288. }
  289. return true;
  290. }
  291. } func;
  292. gSelectMgr.getHighlightedObjects()->applyToObjects(&func);
  293. }
  294. if (grow_selection)
  295. {
  296. std::vector<LLDrawable*> potentials;
  297. for (LLWorld::region_list_t::const_iterator
  298. iter = gWorld.getRegionList().begin(),
  299. end = gWorld.getRegionList().end();
  300. iter != end; ++iter)
  301. {
  302. LLViewerRegion* region = *iter;
  303. for (U32 i = 0; i < LLViewerRegion::PARTITION_VO_CACHE; ++i)
  304. {
  305. LLSpatialPartition* part = region->getSpatialPartition(i);
  306. // None of the partitions under PARTITION_VO_CACHE can be NULL
  307. llassert(part);
  308. part->cull(gViewerCamera, &potentials, true);
  309. }
  310. }
  311. for (std::vector<LLDrawable*>::iterator iter = potentials.begin(),
  312. end = potentials.end();
  313. iter != end; ++iter)
  314. {
  315. LLDrawable* drawable = *iter;
  316. LLViewerObject* vobjp = drawable->getVObj();
  317. if (!drawable || !vobjp || vobjp->isAttachment() ||
  318. (vobjp->getPCode() != LL_PCODE_VOLUME &&
  319. vobjp->getPCode() != LL_PCODE_LEGACY_TREE &&
  320. vobjp->getPCode() != LL_PCODE_LEGACY_GRASS) ||
  321. (deselect && !vobjp->isSelected()))
  322. {
  323. continue;
  324. }
  325. //MK
  326. if (gRLenabled && !gRLInterface.canEdit(vobjp))
  327. {
  328. continue;
  329. }
  330. //mk
  331. if (limit_select_distance &&
  332. dist_vec_squared(drawable->getWorldPosition(),
  333. av_pos) > select_dist_squared)
  334. {
  335. continue;
  336. }
  337. S32 result = gViewerCamera.sphereInFrustum(drawable->getPositionAgent(),
  338. drawable->getRadius());
  339. if (result)
  340. {
  341. switch (result)
  342. {
  343. case 1:
  344. // check vertices
  345. if (gViewerCamera.areVertsVisible(vobjp,
  346. LLSelectMgr::sRectSelectInclusive))
  347. {
  348. gSelectMgr.highlightObjectOnly(vobjp);
  349. }
  350. break;
  351. case 2:
  352. gSelectMgr.highlightObjectOnly(vobjp);
  353. break;
  354. default:
  355. break;
  356. }
  357. }
  358. }
  359. }
  360. // restore drawing mode
  361. gGL.matrixMode(LLRender::MM_PROJECTION);
  362. gGL.popMatrix();
  363. gGL.matrixMode(LLRender::MM_MODELVIEW);
  364. // restore camera
  365. gViewerCamera.setFar(old_far_plane);
  366. gViewerCamera.setNear(old_near_plane);
  367. gViewerWindowp->setup3DRender();
  368. }