lltoolbrushland.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. /**
  2. * @file lltoolbrushland.cpp
  3. * @brief Implementation of the LLToolBrushLand class
  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 "lltoolbrushland.h"
  34. #include "llcallbacklist.h"
  35. #include "llgl.h"
  36. #include "llparcel.h"
  37. #include "llrender.h"
  38. #include "llmessage.h"
  39. #include "llagent.h"
  40. #include "llappviewer.h"
  41. #include "llfloatertools.h"
  42. #include "llstatusbar.h"
  43. #include "llsurface.h"
  44. #include "llsurfacepatch.h"
  45. #include "lltoolmgr.h"
  46. #include "lltoolselectland.h"
  47. #include "llviewercontrol.h"
  48. #include "llviewerparcelmgr.h"
  49. #include "llviewerparceloverlay.h"
  50. #include "llviewerregion.h"
  51. #include "llviewerwindow.h"
  52. #include "llworld.h"
  53. constexpr S32 LAND_BRUSH_SIZE_COUNT = 3;
  54. static const F32 LAND_BRUSH_SIZE[LAND_BRUSH_SIZE_COUNT] = { 1.f, 2.f, 4.f };
  55. const LLColor4 OVERLAY_COLOR(1.f, 1.f, 1.f, 1.f);
  56. enum
  57. {
  58. E_LAND_LEVEL = 0,
  59. E_LAND_RAISE = 1,
  60. E_LAND_LOWER = 2,
  61. E_LAND_SMOOTH = 3,
  62. E_LAND_NOISE = 4,
  63. E_LAND_REVERT = 5,
  64. E_LAND_INVALID = 6,
  65. };
  66. ///////////////////////////////////////////////////////////////////////////////
  67. // Helper LLRegionPosition class
  68. ///////////////////////////////////////////////////////////////////////////////
  69. class LLRegionPosition
  70. {
  71. protected:
  72. LOG_CLASS(LLRegionPosition);
  73. public:
  74. LLRegionPosition()
  75. : mRegionp(NULL),
  76. mPositionRegion(LLVector3(0.f, 0.f, 0.f))
  77. {
  78. }
  79. LLRegionPosition(LLViewerRegion* regionp, const LLVector3& position)
  80. : mRegionp(regionp),
  81. mPositionRegion(position)
  82. {
  83. }
  84. // From global coords ONLY !
  85. LLRegionPosition(const LLVector3d& global_position)
  86. {
  87. setPositionGlobal(global_position);
  88. }
  89. LL_INLINE LLViewerRegion* getRegion() const { return mRegionp; }
  90. void setPositionGlobal(const LLVector3d& global_pos);
  91. LLVector3d getPositionGlobal() const;
  92. LL_INLINE const LLVector3& getPositionRegion() const
  93. {
  94. return mPositionRegion;
  95. }
  96. LL_INLINE const LLVector3 getPositionAgent() const
  97. {
  98. return mRegionp->getPosAgentFromRegion(mPositionRegion);
  99. }
  100. LL_INLINE void clear()
  101. {
  102. mRegionp = NULL;
  103. mPositionRegion.clear();
  104. }
  105. public:
  106. LLVector3 mPositionRegion;
  107. private:
  108. LLViewerRegion* mRegionp;
  109. };
  110. LLVector3d LLRegionPosition::getPositionGlobal() const
  111. {
  112. if (mRegionp)
  113. {
  114. return mRegionp->getPosGlobalFromRegion(mPositionRegion);
  115. }
  116. return LLVector3d(mPositionRegion);
  117. }
  118. void LLRegionPosition::setPositionGlobal(const LLVector3d& position_global)
  119. {
  120. mRegionp = gWorld.getRegionFromPosGlobal(position_global);
  121. if (!mRegionp)
  122. {
  123. mRegionp = gAgent.getRegion();
  124. if (!mRegionp)
  125. {
  126. llwarns << "NULL agent region ! Position not set." << llendl;
  127. return;
  128. }
  129. }
  130. mPositionRegion = mRegionp->getPosRegionFromGlobal(position_global);
  131. }
  132. ///////////////////////////////////////////////////////////////////////////////
  133. // LLToolBrushLand class
  134. ///////////////////////////////////////////////////////////////////////////////
  135. LLToolBrushLand gToolBrushLand;
  136. // constructor
  137. LLToolBrushLand::LLToolBrushLand()
  138. : LLTool("Land"),
  139. mStartingZ(0.f),
  140. mMouseX(0),
  141. mMouseY(0),
  142. mGotHover(false),
  143. mBrushSelected(false)
  144. {
  145. }
  146. U8 LLToolBrushLand::getBrushIndex()
  147. {
  148. static LLCachedControl<F32> land_brush_size(gSavedSettings,
  149. "LandBrushSize");
  150. // Find the best index for desired size (compatibility with old sims,
  151. // brush_index is now depricated - DEV-8252)
  152. U8 index = 0;
  153. for (U8 i = 0; i < LAND_BRUSH_SIZE_COUNT; ++i)
  154. {
  155. if (land_brush_size > LAND_BRUSH_SIZE[i])
  156. {
  157. index = i;
  158. }
  159. }
  160. return index;
  161. }
  162. void LLToolBrushLand::modifyLandAtPointGlobal(const LLVector3d& pos_global,
  163. MASK mask)
  164. {
  165. static LLCachedControl<S32> radio_action(gSavedSettings,
  166. "RadioLandBrushAction");
  167. static LLCachedControl<F32> land_brush_size(gSavedSettings,
  168. "LandBrushSize");
  169. mLastAffectedRegions.clear();
  170. determineAffectedRegions(mLastAffectedRegions, pos_global);
  171. for (region_list_t::iterator iter = mLastAffectedRegions.begin(),
  172. end = mLastAffectedRegions.end();
  173. iter != end; ++iter)
  174. {
  175. LLViewerRegion* regionp = *iter;
  176. #if 0
  177. bool is_changed = false;
  178. #endif
  179. LLVector3 pos_region = regionp->getPosRegionFromGlobal(pos_global);
  180. LLSurface& land = regionp->getLand();
  181. char action = E_LAND_LEVEL;
  182. switch (radio_action)
  183. {
  184. case 0:
  185. // average toward mStartingZ
  186. action = E_LAND_LEVEL;
  187. break;
  188. case 1:
  189. action = E_LAND_RAISE;
  190. break;
  191. case 2:
  192. action = E_LAND_LOWER;
  193. break;
  194. case 3:
  195. action = E_LAND_SMOOTH;
  196. break;
  197. case 4:
  198. action = E_LAND_NOISE;
  199. break;
  200. case 5:
  201. action = E_LAND_REVERT;
  202. break;
  203. default:
  204. action = E_LAND_INVALID;
  205. }
  206. #if 0
  207. // Don't send a message to the region if nothing changed.
  208. if (!is_changed) continue;
  209. #endif
  210. // Now to update the patch information so it will redraw correctly.
  211. LLSurfacePatch *patchp = land.resolvePatchRegion(pos_region);
  212. if (patchp)
  213. {
  214. patchp->dirtyZ();
  215. }
  216. // Also force the property lines to update, normals to recompute, etc.
  217. regionp->forceUpdate();
  218. // tell the simulator what we've done
  219. F32 seconds = gSavedSettings.getF32("LandBrushForce") / gFPSClamped;
  220. F32 x_pos = (F32)pos_region.mV[VX];
  221. F32 y_pos = (F32)pos_region.mV[VY];
  222. LLMessageSystem* msg = gMessageSystemp;
  223. msg->newMessageFast(_PREHASH_ModifyLand);
  224. msg->nextBlockFast(_PREHASH_AgentData);
  225. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  226. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  227. msg->nextBlockFast(_PREHASH_ModifyBlock);
  228. msg->addU8Fast(_PREHASH_Action, (U8)action);
  229. msg->addU8Fast(_PREHASH_BrushSize, getBrushIndex());
  230. msg->addF32Fast(_PREHASH_Seconds, seconds);
  231. msg->addF32Fast(_PREHASH_Height, mStartingZ);
  232. msg->nextBlockFast(_PREHASH_ParcelData);
  233. msg->addS32Fast(_PREHASH_LocalID, -1);
  234. msg->addF32Fast(_PREHASH_West, x_pos);
  235. msg->addF32Fast(_PREHASH_South, y_pos);
  236. msg->addF32Fast(_PREHASH_East, x_pos);
  237. msg->addF32Fast(_PREHASH_North, y_pos);
  238. msg->nextBlock("ModifyBlockExtended");
  239. msg->addF32("BrushSize", land_brush_size);
  240. msg->sendMessage(regionp->getHost());
  241. }
  242. }
  243. void LLToolBrushLand::modifyLandInSelectionGlobal()
  244. {
  245. static LLCachedControl<F32> land_brush_size(gSavedSettings,
  246. "LandBrushSize");
  247. if (gViewerParcelMgr.selectionEmpty() ||
  248. // Selecting land; do not do anything
  249. gToolMgr.isCurrentTool(&gToolSelectLand))
  250. {
  251. return;
  252. }
  253. LLVector3d min;
  254. LLVector3d max;
  255. gViewerParcelMgr.getSelection(min, max);
  256. S32 radio_action = gSavedSettings.getS32("RadioLandBrushAction");
  257. mLastAffectedRegions.clear();
  258. determineAffectedRegions(mLastAffectedRegions,
  259. LLVector3d(min.mdV[VX], min.mdV[VY], 0));
  260. determineAffectedRegions(mLastAffectedRegions,
  261. LLVector3d(min.mdV[VX], max.mdV[VY], 0));
  262. determineAffectedRegions(mLastAffectedRegions,
  263. LLVector3d(max.mdV[VX], min.mdV[VY], 0));
  264. determineAffectedRegions(mLastAffectedRegions,
  265. LLVector3d(max.mdV[VX], max.mdV[VY], 0));
  266. LLRegionPosition mid_point_region((min + max) * 0.5);
  267. LLViewerRegion* center_region = mid_point_region.getRegion();
  268. if (center_region)
  269. {
  270. LLVector3 pos_region = mid_point_region.getPositionRegion();
  271. U32 grids = center_region->getLand().mGridsPerEdge;
  272. S32 i = llclamp((S32)pos_region.mV[VX], 0, (S32)grids);
  273. S32 j = llclamp((S32)pos_region.mV[VY], 0, (S32)grids);
  274. mStartingZ = center_region->getLand().getZ(i + j * grids);
  275. }
  276. else
  277. {
  278. mStartingZ = 0.f;
  279. }
  280. // Stop if our selection include a no-terraform region
  281. for (region_list_t::iterator iter = mLastAffectedRegions.begin();
  282. iter != mLastAffectedRegions.end(); ++iter)
  283. {
  284. LLViewerRegion* regionp = *iter;
  285. if (!canTerraform(regionp))
  286. {
  287. alertNoTerraform(regionp);
  288. return;
  289. }
  290. }
  291. for (region_list_t::iterator iter = mLastAffectedRegions.begin(),
  292. end = mLastAffectedRegions.end();
  293. iter != end; ++iter)
  294. {
  295. LLViewerRegion* regionp = *iter;
  296. #if 0
  297. bool is_changed = false;
  298. #endif
  299. LLVector3 min_region = regionp->getPosRegionFromGlobal(min);
  300. LLVector3 max_region = regionp->getPosRegionFromGlobal(max);
  301. min_region.clamp(0.f, regionp->getWidth());
  302. max_region.clamp(0.f, regionp->getWidth());
  303. F32 seconds = gSavedSettings.getF32("LandBrushForce");
  304. LLSurface &land = regionp->getLand();
  305. char action = E_LAND_LEVEL;
  306. switch (radio_action)
  307. {
  308. case 0:
  309. // average toward mStartingZ
  310. action = E_LAND_LEVEL;
  311. seconds *= 0.25f;
  312. break;
  313. case 1:
  314. action = E_LAND_RAISE;
  315. seconds *= 0.25f;
  316. break;
  317. case 2:
  318. action = E_LAND_LOWER;
  319. seconds *= 0.25f;
  320. break;
  321. case 3:
  322. action = E_LAND_SMOOTH;
  323. seconds *= 5.0f;
  324. break;
  325. case 4:
  326. action = E_LAND_NOISE;
  327. seconds *= 0.5f;
  328. break;
  329. case 5:
  330. action = E_LAND_REVERT;
  331. seconds = 0.5f;
  332. break;
  333. default:
  334. #if 0
  335. action = E_LAND_INVALID;
  336. seconds = 0.0f;
  337. #endif
  338. return;
  339. }
  340. #if 0
  341. // Don't send a message to the region if nothing changed.
  342. if (!is_changed) continue;
  343. #endif
  344. // Now to update the patch information so it will redraw correctly.
  345. LLSurfacePatch *patchp= land.resolvePatchRegion(min_region);
  346. if (patchp)
  347. {
  348. patchp->dirtyZ();
  349. }
  350. // Also force the property lines to update, normals to recompute, etc.
  351. regionp->forceUpdate();
  352. // tell the simulator what we've done
  353. LLMessageSystem* msg = gMessageSystemp;
  354. msg->newMessageFast(_PREHASH_ModifyLand);
  355. msg->nextBlockFast(_PREHASH_AgentData);
  356. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  357. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  358. msg->nextBlockFast(_PREHASH_ModifyBlock);
  359. msg->addU8Fast(_PREHASH_Action, (U8)action);
  360. msg->addU8Fast(_PREHASH_BrushSize, getBrushIndex());
  361. msg->addF32Fast(_PREHASH_Seconds, seconds);
  362. msg->addF32Fast(_PREHASH_Height, mStartingZ);
  363. bool parcel_selected =
  364. gViewerParcelMgr.getParcelSelection()->getWholeParcelSelected();
  365. LLParcel* selected_parcel =
  366. gViewerParcelMgr.getParcelSelection()->getParcel();
  367. if (parcel_selected && selected_parcel)
  368. {
  369. msg->nextBlockFast(_PREHASH_ParcelData);
  370. msg->addS32Fast(_PREHASH_LocalID, selected_parcel->getLocalID());
  371. msg->addF32Fast(_PREHASH_West, min_region.mV[VX]);
  372. msg->addF32Fast(_PREHASH_South, min_region.mV[VY]);
  373. msg->addF32Fast(_PREHASH_East, max_region.mV[VX]);
  374. msg->addF32Fast(_PREHASH_North, max_region.mV[VY]);
  375. }
  376. else
  377. {
  378. msg->nextBlockFast(_PREHASH_ParcelData);
  379. msg->addS32Fast(_PREHASH_LocalID, -1);
  380. msg->addF32Fast(_PREHASH_West, min_region.mV[VX]);
  381. msg->addF32Fast(_PREHASH_South, min_region.mV[VY]);
  382. msg->addF32Fast(_PREHASH_East, max_region.mV[VX]);
  383. msg->addF32Fast(_PREHASH_North, max_region.mV[VY]);
  384. }
  385. msg->nextBlock("ModifyBlockExtended");
  386. msg->addF32("BrushSize", land_brush_size);
  387. msg->sendMessage(regionp->getHost());
  388. }
  389. }
  390. void LLToolBrushLand::brush()
  391. {
  392. LLVector3d spot;
  393. if (gKeyboardp &&
  394. gViewerWindowp->mousePointOnLandGlobal(mMouseX, mMouseY, &spot))
  395. {
  396. // Round to nearest X,Y grid
  397. spot.mdV[VX] = floor(spot.mdV[VX] + 0.5);
  398. spot.mdV[VY] = floor(spot.mdV[VY] + 0.5);
  399. modifyLandAtPointGlobal(spot, gKeyboardp->currentMask(true));
  400. }
  401. }
  402. bool LLToolBrushLand::handleMouseDown(S32 x, S32 y, MASK mask)
  403. {
  404. bool handled = false;
  405. LLVector3d spot;
  406. // Find the z value of the initial click.
  407. if (gViewerWindowp->mousePointOnLandGlobal(x, y, &spot))
  408. {
  409. // Round to nearest X,Y grid
  410. spot.mdV[VX] = floor(spot.mdV[VX] + 0.5);
  411. spot.mdV[VY] = floor(spot.mdV[VY] + 0.5);
  412. LLRegionPosition region_position(spot);
  413. LLViewerRegion* regionp = region_position.getRegion();
  414. if (!canTerraform(regionp))
  415. {
  416. alertNoTerraform(regionp);
  417. return true;
  418. }
  419. LLVector3 pos_region = region_position.getPositionRegion();
  420. U32 grids = regionp->getLand().mGridsPerEdge;
  421. S32 i = llclamp((S32)pos_region.mV[VX], 0, (S32)grids);
  422. S32 j = llclamp((S32)pos_region.mV[VY], 0, (S32)grids);
  423. mStartingZ = regionp->getLand().getZ(i + j * grids);
  424. mMouseX = x;
  425. mMouseY = y;
  426. gIdleCallbacks.addFunction(onIdle, this);
  427. setMouseCapture(true);
  428. gViewerParcelMgr.setSelectionVisible(false);
  429. handled = true;
  430. }
  431. return handled;
  432. }
  433. bool LLToolBrushLand::handleHover(S32 x, S32 y, MASK mask)
  434. {
  435. LL_DEBUGS("UserInput") << "hover handled by LLToolBrushLand ("
  436. << (hasMouseCapture() ? "active":"inactive") << ")"
  437. << LL_ENDL;
  438. mMouseX = x;
  439. mMouseY = y;
  440. mGotHover = true;
  441. gWindowp->setCursor(UI_CURSOR_TOOLLAND);
  442. return true;
  443. }
  444. bool LLToolBrushLand::handleMouseUp(S32 x, S32 y, MASK mask)
  445. {
  446. bool handled = false;
  447. mLastAffectedRegions.clear();
  448. if (hasMouseCapture())
  449. {
  450. // Release the mouse
  451. setMouseCapture(false);
  452. gViewerParcelMgr.setSelectionVisible(true);
  453. gIdleCallbacks.deleteFunction(onIdle, this);
  454. handled = true;
  455. }
  456. return handled;
  457. }
  458. void LLToolBrushLand::handleSelect()
  459. {
  460. grabMenuHandler();
  461. if (gFloaterToolsp)
  462. {
  463. gFloaterToolsp->setStatusText("modifyland");
  464. }
  465. mBrushSelected = true;
  466. }
  467. void LLToolBrushLand::handleDeselect()
  468. {
  469. releaseMenuHandler();
  470. gViewerParcelMgr.setSelectionVisible(true);
  471. mBrushSelected = false;
  472. }
  473. // Draw the area that will be affected.
  474. void LLToolBrushLand::render()
  475. {
  476. static LLCachedControl<F32> land_brush_size(gSavedSettings,
  477. "LandBrushSize");
  478. if (mGotHover && gAgent.getRegion())
  479. {
  480. LLVector3d spot;
  481. if (gViewerWindowp->mousePointOnLandGlobal(mMouseX, mMouseY, &spot))
  482. {
  483. spot.mdV[VX] = floor(spot.mdV[VX] + 0.5);
  484. spot.mdV[VY] = floor(spot.mdV[VY] + 0.5);
  485. region_list_t regions;
  486. determineAffectedRegions(regions, spot);
  487. // Now, for each region, render the overlay
  488. LLVector3 pos_world = gAgent.getRegion()->getPosRegionFromGlobal(spot);
  489. for (region_list_t::iterator iter = regions.begin(),
  490. end = regions.end();
  491. iter != end; ++iter)
  492. {
  493. LLViewerRegion* region = *iter;
  494. renderOverlay(region->getLand(),
  495. region->getPosRegionFromGlobal(spot), pos_world);
  496. }
  497. }
  498. mGotHover = false;
  499. }
  500. }
  501. /*
  502. * Draw vertical lines from each vertex straight up in world space
  503. * with lengths indicating the current "strength" slider.
  504. * Decorate the tops and bottoms of the lines like this:
  505. *
  506. * Raise Revert
  507. * /|\ ___
  508. * | |
  509. * | |
  510. *
  511. * Rough Smooth
  512. * /|\ ___
  513. * | |
  514. * | |
  515. * \|/..........._|_
  516. *
  517. * Lower Flatten
  518. * | |
  519. * | |
  520. * \|/..........._|_
  521. */
  522. void LLToolBrushLand::renderOverlay(LLSurface& land,
  523. const LLVector3& pos_region,
  524. const LLVector3& pos_world)
  525. {
  526. static LLCachedControl<F32> land_brush_size(gSavedSettings,
  527. "LandBrushSize");
  528. static LLCachedControl<S32> radio_action(gSavedSettings,
  529. "RadioLandBrushAction");
  530. static LLCachedControl<F32> force(gSavedSettings, "LandBrushForce");
  531. gGL.matrixMode(LLRender::MM_MODELVIEW);
  532. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  533. LLGLDepthTest mDepthTest(GL_TRUE);
  534. gGL.pushMatrix();
  535. gGL.color4fv(OVERLAY_COLOR.mV);
  536. gGL.translatef(0.f, 0.f, 1.f);
  537. S32 i = (S32) pos_region.mV[VX];
  538. S32 j = (S32) pos_region.mV[VY];
  539. S32 half_edge = llfloor(land_brush_size);
  540. constexpr F32 tic = .075f; // arrowhead size
  541. gGL.begin(LLRender::LINES);
  542. for (S32 di = -half_edge; di <= half_edge; ++di)
  543. {
  544. if (i + di < 0 || i + di >= (S32)land.mGridsPerEdge) continue;
  545. for (S32 dj = -half_edge; dj <= half_edge; dj++)
  546. {
  547. if (j + dj < 0 || j + dj >= (S32)land.mGridsPerEdge) continue;
  548. const F32 wx = pos_world.mV[VX] + di;
  549. const F32 wy = pos_world.mV[VY] + dj;
  550. const F32 wz = land.getZ(i + di + (j + dj) * land.mGridsPerEdge);
  551. const F32 norm_dist = sqrtf((F32)(di * di + dj * dj)) / half_edge;
  552. // 1 at center, 0 at corner
  553. const F32 force_scale = F_SQRT2 - norm_dist;
  554. // top vertex
  555. const F32 wz2 = wz + 0.2f + (0.2f + force * 0.01f) * force_scale;
  556. // vertical line
  557. gGL.vertex3f(wx, wy, wz);
  558. gGL.vertex3f(wx, wy, wz2);
  559. if (radio_action == E_LAND_RAISE || radio_action == E_LAND_NOISE)
  560. {
  561. // up arrow
  562. gGL.vertex3f(wx, wy, wz2);
  563. gGL.vertex3f(wx + tic, wy, wz2 - tic);
  564. gGL.vertex3f(wx, wy, wz2);
  565. gGL.vertex3f(wx - tic, wy, wz2 - tic);
  566. }
  567. if (radio_action == E_LAND_LOWER || radio_action == E_LAND_NOISE)
  568. {
  569. // down arrow
  570. gGL.vertex3f(wx, wy, wz);
  571. gGL.vertex3f(wx + tic, wy, wz + tic);
  572. gGL.vertex3f(wx, wy, wz);
  573. gGL.vertex3f(wx - tic, wy, wz + tic);
  574. }
  575. if (radio_action == E_LAND_REVERT || radio_action == E_LAND_SMOOTH)
  576. {
  577. // flat top
  578. gGL.vertex3f(wx - tic, wy, wz2);
  579. gGL.vertex3f(wx + tic, wy, wz2);
  580. }
  581. if (radio_action == E_LAND_LEVEL || radio_action == E_LAND_SMOOTH)
  582. {
  583. // flat bottom
  584. gGL.vertex3f(wx - tic, wy, wz);
  585. gGL.vertex3f(wx + tic, wy, wz);
  586. }
  587. }
  588. }
  589. gGL.end();
  590. gGL.popMatrix();
  591. }
  592. void LLToolBrushLand::determineAffectedRegions(region_list_t& regions,
  593. const LLVector3d& spot) const
  594. {
  595. static LLCachedControl<F32> land_brush_size(gSavedSettings,
  596. "LandBrushSize");
  597. LLVector3d corner(spot);
  598. corner.mdV[VX] -= land_brush_size * 0.5f;
  599. corner.mdV[VY] -= land_brush_size * 0.5f;
  600. LLViewerRegion* region = NULL;
  601. region = gWorld.getRegionFromPosGlobal(corner);
  602. if (region && regions.find(region) == regions.end())
  603. {
  604. regions.insert(region);
  605. }
  606. corner.mdV[VY] += land_brush_size;
  607. region = gWorld.getRegionFromPosGlobal(corner);
  608. if (region && regions.find(region) == regions.end())
  609. {
  610. regions.insert(region);
  611. }
  612. corner.mdV[VX] += land_brush_size;
  613. region = gWorld.getRegionFromPosGlobal(corner);
  614. if (region && regions.find(region) == regions.end())
  615. {
  616. regions.insert(region);
  617. }
  618. corner.mdV[VY] -= land_brush_size;
  619. region = gWorld.getRegionFromPosGlobal(corner);
  620. if (region && regions.find(region) == regions.end())
  621. {
  622. regions.insert(region);
  623. }
  624. }
  625. //static
  626. void LLToolBrushLand::onIdle(void* user_data)
  627. {
  628. LLToolBrushLand* self = (LLToolBrushLand*)user_data;
  629. if (gToolMgr.isCurrentTool(self))
  630. {
  631. self->brush();
  632. }
  633. else
  634. {
  635. gIdleCallbacks.deleteFunction(onIdle, self);
  636. }
  637. }
  638. void LLToolBrushLand::onMouseCaptureLost()
  639. {
  640. gIdleCallbacks.deleteFunction(onIdle, this);
  641. }
  642. //static
  643. void LLToolBrushLand::undo()
  644. {
  645. LLMessageSystem* msg = gMessageSystemp;
  646. for (region_list_t::iterator iter = mLastAffectedRegions.begin();
  647. iter != mLastAffectedRegions.end(); ++iter)
  648. {
  649. LLViewerRegion* regionp = *iter;
  650. msg->newMessageFast(_PREHASH_UndoLand);
  651. msg->nextBlockFast(_PREHASH_AgentData);
  652. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  653. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  654. msg->sendMessage(regionp->getHost());
  655. }
  656. }
  657. #if 0
  658. //static
  659. void LLToolBrushLand::redo()
  660. {
  661. LLMessageSystem* msg = gMessageSystemp;
  662. for (region_list_t::iterator iter = mLastAffectedRegions.begin();
  663. iter != mLastAffectedRegions.end(); ++iter)
  664. {
  665. LLViewerRegion* regionp = *iter;
  666. msg->newMessageFast(_PREHASH_RedoLand);
  667. msg->nextBlockFast(_PREHASH_AgentData);
  668. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  669. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  670. msg->sendMessage(regionp->getHost());
  671. }
  672. }
  673. #endif
  674. //static
  675. bool LLToolBrushLand::canTerraform(LLViewerRegion* regionp) const
  676. {
  677. if (!regionp) return false;
  678. if (regionp->canManageEstate()) return true;
  679. return !regionp->getRegionFlag(REGION_FLAGS_BLOCK_TERRAFORM);
  680. }
  681. //static
  682. void LLToolBrushLand::alertNoTerraform(LLViewerRegion* regionp)
  683. {
  684. if (!regionp) return;
  685. LLSD args;
  686. args["REGION"] = regionp->getName();
  687. gNotifications.add("RegionNoTerraforming", args);
  688. }