diff options
Diffstat (limited to 'indra/newview/lltoolbrush.cpp')
| -rw-r--r-- | indra/newview/lltoolbrush.cpp | 1436 |
1 files changed, 718 insertions, 718 deletions
diff --git a/indra/newview/lltoolbrush.cpp b/indra/newview/lltoolbrush.cpp index 86acb1963e..e2b6924aeb 100644 --- a/indra/newview/lltoolbrush.cpp +++ b/indra/newview/lltoolbrush.cpp @@ -1,718 +1,718 @@ -/**
- * @file lltoolbrush.cpp
- * @brief Implementation of the toolbrushes
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "lltoolbrush.h"
-#include "lltoolselectland.h"
-
-// library headers
-#include "llgl.h"
-#include "llnotificationsutil.h"
-#include "llrender.h"
-#include "message.h"
-
-#include "llagent.h"
-#include "llcallbacklist.h"
-#include "llviewercontrol.h"
-#include "llfloatertools.h"
-#include "llregionposition.h"
-#include "llstatusbar.h"
-#include "llsurface.h"
-#include "llsurfacepatch.h"
-#include "lltoolmgr.h"
-#include "llui.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerparceloverlay.h"
-#include "llviewerregion.h"
-#include "llviewerwindow.h"
-#include "llworld.h"
-#include "llappviewer.h"
-#include "llparcel.h"
-#include "roles_constants.h"
-#include "llglheaders.h"
-
-const std::string REGION_BLOCKS_TERRAFORM_MSG = "This region does not allow terraforming.\n"
- "You will need to buy land in another part of the world to terraform it.";
-
-
-///============================================================================
-/// Local function declarations, constants, enums, and typedefs
-///============================================================================
-
-const S32 LAND_BRUSH_SIZE_COUNT = 3;
-const F32 LAND_BRUSH_SIZE[LAND_BRUSH_SIZE_COUNT] = {1.0f, 2.0f, 4.0f};
-
-enum
-{
- E_LAND_LEVEL = 0,
- E_LAND_RAISE = 1,
- E_LAND_LOWER = 2,
- E_LAND_SMOOTH = 3,
- E_LAND_NOISE = 4,
- E_LAND_REVERT = 5,
- E_LAND_INVALID = 6,
-};
-const LLColor4 OVERLAY_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
-
-///============================================================================
-/// Class LLToolBrushLand
-///============================================================================
-
-// constructor
-LLToolBrushLand::LLToolBrushLand()
-: LLTool(std::string("Land")),
- mStartingZ( 0.0f ),
- mMouseX( 0 ),
- mMouseY(0),
- mGotHover(false),
- mBrushSelected(false)
-{
- mBrushSize = gSavedSettings.getF32("LandBrushSize");
-}
-
-
-U8 LLToolBrushLand::getBrushIndex()
-{
- // find the best index for desired size
- // (compatibility with old sims, brush_index is now depricated - DEV-8252)
- U8 index = 0;
- for (U8 i = 0; i < LAND_BRUSH_SIZE_COUNT; i++)
- {
- if (mBrushSize > LAND_BRUSH_SIZE[i])
- {
- index = i;
- }
- }
-
- return index;
-}
-
-void LLToolBrushLand::modifyLandAtPointGlobal(const LLVector3d &pos_global,
- MASK mask)
-{
- S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction");
-
- mLastAffectedRegions.clear();
- determineAffectedRegions(mLastAffectedRegions, pos_global);
- for(region_list_t::iterator iter = mLastAffectedRegions.begin();
- iter != mLastAffectedRegions.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- //bool is_changed = false;
- LLVector3 pos_region = regionp->getPosRegionFromGlobal(pos_global);
- LLSurface &land = regionp->getLand();
- char action = E_LAND_LEVEL;
- switch (radioAction)
- {
- case 0:
- // // average toward mStartingZ
- action = E_LAND_LEVEL;
- break;
- case 1:
- action = E_LAND_RAISE;
- break;
- case 2:
- action = E_LAND_LOWER;
- break;
- case 3:
- action = E_LAND_SMOOTH;
- break;
- case 4:
- action = E_LAND_NOISE;
- break;
- case 5:
- action = E_LAND_REVERT;
- break;
- default:
- action = E_LAND_INVALID;
- break;
- }
-
- // Don't send a message to the region if nothing changed.
- //if(!is_changed) continue;
-
- // Now to update the patch information so it will redraw correctly.
- LLSurfacePatch *patchp= land.resolvePatchRegion(pos_region);
- if (patchp)
- {
- patchp->dirtyZ();
- }
-
- // Also force the property lines to update, normals to recompute, etc.
- regionp->forceUpdate();
-
- // tell the simulator what we've done
- F32 seconds = (1.0f / gFPSClamped) * gSavedSettings.getF32("LandBrushForce");
- F32 x_pos = (F32)pos_region.mV[VX];
- F32 y_pos = (F32)pos_region.mV[VY];
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ModifyLand);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_ModifyBlock);
- msg->addU8Fast(_PREHASH_Action, (U8)action);
- msg->addU8Fast(_PREHASH_BrushSize, getBrushIndex());
- msg->addF32Fast(_PREHASH_Seconds, seconds);
- msg->addF32Fast(_PREHASH_Height, mStartingZ);
- msg->nextBlockFast(_PREHASH_ParcelData);
- msg->addS32Fast(_PREHASH_LocalID, -1);
- msg->addF32Fast(_PREHASH_West, x_pos );
- msg->addF32Fast(_PREHASH_South, y_pos );
- msg->addF32Fast(_PREHASH_East, x_pos );
- msg->addF32Fast(_PREHASH_North, y_pos );
- msg->nextBlock("ModifyBlockExtended");
- msg->addF32("BrushSize", mBrushSize);
- msg->sendMessage(regionp->getHost());
- }
-}
-
-void LLToolBrushLand::modifyLandInSelectionGlobal()
-{
- if (LLViewerParcelMgr::getInstance()->selectionEmpty())
- {
- return;
- }
-
- if (LLToolMgr::getInstance()->getCurrentTool() == LLToolSelectLand::getInstance())
- {
- // selecting land, don't do anything
- return;
- }
-
- LLVector3d min;
- LLVector3d max;
-
- LLViewerParcelMgr::getInstance()->getSelection(min, max);
-
- S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction");
-
- mLastAffectedRegions.clear();
-
- determineAffectedRegions(mLastAffectedRegions, LLVector3d(min.mdV[VX], min.mdV[VY], 0));
- determineAffectedRegions(mLastAffectedRegions, LLVector3d(min.mdV[VX], max.mdV[VY], 0));
- determineAffectedRegions(mLastAffectedRegions, LLVector3d(max.mdV[VX], min.mdV[VY], 0));
- determineAffectedRegions(mLastAffectedRegions, LLVector3d(max.mdV[VX], max.mdV[VY], 0));
-
- LLRegionPosition mid_point_region((min + max) * 0.5);
- LLViewerRegion* center_region = mid_point_region.getRegion();
- if (center_region)
- {
- LLVector3 pos_region = mid_point_region.getPositionRegion();
- U32 grids = center_region->getLand().mGridsPerEdge;
- S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids );
- S32 j = llclamp( (S32)pos_region.mV[VY], 0, (S32)grids );
- mStartingZ = center_region->getLand().getZ(i+j*grids);
- }
- else
- {
- mStartingZ = 0.f;
- }
-
- // Stop if our selection include a no-terraform region
- for(region_list_t::iterator iter = mLastAffectedRegions.begin();
- iter != mLastAffectedRegions.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- if (!canTerraformRegion(regionp))
- {
- alertNoTerraformRegion(regionp);
- return;
- }
- }
-
- for(region_list_t::iterator iter = mLastAffectedRegions.begin();
- iter != mLastAffectedRegions.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- //bool is_changed = false;
- LLVector3 min_region = regionp->getPosRegionFromGlobal(min);
- LLVector3 max_region = regionp->getPosRegionFromGlobal(max);
-
- min_region.clamp(0.f, regionp->getWidth());
- max_region.clamp(0.f, regionp->getWidth());
- F32 seconds = gSavedSettings.getF32("LandBrushForce");
-
- LLSurface &land = regionp->getLand();
- char action = E_LAND_LEVEL;
- switch (radioAction)
- {
- case 0:
- // // average toward mStartingZ
- action = E_LAND_LEVEL;
- seconds *= 0.25f;
- break;
- case 1:
- action = E_LAND_RAISE;
- seconds *= 0.25f;
- break;
- case 2:
- action = E_LAND_LOWER;
- seconds *= 0.25f;
- break;
- case 3:
- action = E_LAND_SMOOTH;
- seconds *= 5.0f;
- break;
- case 4:
- action = E_LAND_NOISE;
- seconds *= 0.5f;
- break;
- case 5:
- action = E_LAND_REVERT;
- seconds = 0.5f;
- break;
- default:
- //action = E_LAND_INVALID;
- //seconds = 0.0f;
- return;
- break;
- }
-
- // Don't send a message to the region if nothing changed.
- //if(!is_changed) continue;
-
- // Now to update the patch information so it will redraw correctly.
- LLSurfacePatch *patchp= land.resolvePatchRegion(min_region);
- if (patchp)
- {
- patchp->dirtyZ();
- }
-
- // Also force the property lines to update, normals to recompute, etc.
- regionp->forceUpdate();
-
- // tell the simulator what we've done
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ModifyLand);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_ModifyBlock);
- msg->addU8Fast(_PREHASH_Action, (U8)action);
- msg->addU8Fast(_PREHASH_BrushSize, getBrushIndex());
- msg->addF32Fast(_PREHASH_Seconds, seconds);
- msg->addF32Fast(_PREHASH_Height, mStartingZ);
-
- bool parcel_selected = LLViewerParcelMgr::getInstance()->getParcelSelection()->getWholeParcelSelected();
- LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel();
-
- if (parcel_selected && selected_parcel)
- {
- msg->nextBlockFast(_PREHASH_ParcelData);
- msg->addS32Fast(_PREHASH_LocalID, selected_parcel->getLocalID());
- msg->addF32Fast(_PREHASH_West, min_region.mV[VX] );
- msg->addF32Fast(_PREHASH_South, min_region.mV[VY] );
- msg->addF32Fast(_PREHASH_East, max_region.mV[VX] );
- msg->addF32Fast(_PREHASH_North, max_region.mV[VY] );
- }
- else
- {
- msg->nextBlockFast(_PREHASH_ParcelData);
- msg->addS32Fast(_PREHASH_LocalID, -1);
- msg->addF32Fast(_PREHASH_West, min_region.mV[VX] );
- msg->addF32Fast(_PREHASH_South, min_region.mV[VY] );
- msg->addF32Fast(_PREHASH_East, max_region.mV[VX] );
- msg->addF32Fast(_PREHASH_North, max_region.mV[VY] );
- }
-
- msg->nextBlock("ModifyBlockExtended");
- msg->addF32("BrushSize", mBrushSize);
-
- msg->sendMessage(regionp->getHost());
- }
-}
-
-void LLToolBrushLand::brush( void )
-{
- LLVector3d spot;
- if( gViewerWindow->mousePointOnLandGlobal( mMouseX, mMouseY, &spot ) )
- {
- // Round to nearest X,Y grid
- spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
- spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
-
- modifyLandAtPointGlobal(spot, gKeyboard->currentMask(true));
- }
-}
-
-bool LLToolBrushLand::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- bool handled = false;
-
- // Find the z value of the initial click.
- LLVector3d spot;
- if( gViewerWindow->mousePointOnLandGlobal( x, y, &spot ) )
- {
- // Round to nearest X,Y grid
- spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
- spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
-
- LLRegionPosition region_position( spot );
- LLViewerRegion* regionp = region_position.getRegion();
-
- if (!canTerraformRegion(regionp))
- {
- alertNoTerraformRegion(regionp);
- return true;
- }
-
- if (!canTerraformParcel(regionp))
- {
- alertNoTerraformParcel();
- }
-
- LLVector3 pos_region = region_position.getPositionRegion();
- U32 grids = regionp->getLand().mGridsPerEdge;
- S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids );
- S32 j = llclamp( (S32)pos_region.mV[VY], 0, (S32)grids );
- mStartingZ = regionp->getLand().getZ(i+j*grids);
- mMouseX = x;
- mMouseY = y;
- gIdleCallbacks.addFunction( &LLToolBrushLand::onIdle, (void*)this );
- setMouseCapture( true );
-
- LLViewerParcelMgr::getInstance()->setSelectionVisible(false);
- handled = true;
- }
-
- return handled;
-}
-
-bool LLToolBrushLand::handleHover( S32 x, S32 y, MASK mask )
-{
- LL_DEBUGS("UserInput") << "hover handled by LLToolBrushLand ("
- << (hasMouseCapture() ? "active":"inactive")
- << ")" << LL_ENDL;
- mMouseX = x;
- mMouseY = y;
- mGotHover = true;
- gViewerWindow->setCursor(UI_CURSOR_TOOLLAND);
-
- LLVector3d spot;
- if( gViewerWindow->mousePointOnLandGlobal( mMouseX, mMouseY, &spot ) )
- {
-
- spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
- spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
-
- LLViewerParcelMgr::getInstance()->setHoverParcel(spot);
- }
- return true;
-}
-
-bool LLToolBrushLand::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- bool handled = false;
- mLastAffectedRegions.clear();
- if( hasMouseCapture() )
- {
- // Release the mouse
- setMouseCapture( false );
-
- LLViewerParcelMgr::getInstance()->setSelectionVisible(true);
-
- gIdleCallbacks.deleteFunction( &LLToolBrushLand::onIdle, (void*)this );
- handled = true;
- }
-
- return handled;
-}
-
-void LLToolBrushLand::handleSelect()
-{
- gEditMenuHandler = this;
-
- gFloaterTools->setStatusText("modifyland");
-// if (!mBrushSelected)
- {
- mBrushSelected = true;
- }
-}
-
-
-void LLToolBrushLand::handleDeselect()
-{
- if( gEditMenuHandler == this )
- {
- gEditMenuHandler = NULL;
- }
- LLViewerParcelMgr::getInstance()->setSelectionVisible(true);
- mBrushSelected = false;
-}
-
-// Draw the area that will be affected.
-void LLToolBrushLand::render()
-{
- if(mGotHover)
- {
- //LL_INFOS() << "LLToolBrushLand::render()" << LL_ENDL;
- LLVector3d spot;
- if(gViewerWindow->mousePointOnLandGlobal(mMouseX, mMouseY, &spot))
- {
- spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
- spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
-
- mBrushSize = gSavedSettings.getF32("LandBrushSize");
-
- region_list_t regions;
- determineAffectedRegions(regions, spot);
-
- // Now, for each region, render the overlay
- LLVector3 pos_world = gAgent.getRegion()->getPosRegionFromGlobal(spot);
- for(region_list_t::iterator iter = regions.begin();
- iter != regions.end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- renderOverlay(region->getLand(),
- region->getPosRegionFromGlobal(spot),
- pos_world);
- }
- }
- mGotHover = false;
- }
-}
-
-/*
- * Draw vertical lines from each vertex straight up in world space
- * with lengths indicating the current "strength" slider.
- * Decorate the tops and bottoms of the lines like this:
- *
- * Raise Revert
- * /|\ ___
- * | |
- * | |
- *
- * Rough Smooth
- * /|\ ___
- * | |
- * | |
- * \|/..........._|_
- *
- * Lower Flatten
- * | |
- * | |
- * \|/..........._|_
- */
-void LLToolBrushLand::renderOverlay(LLSurface& land, const LLVector3& pos_region,
- const LLVector3& pos_world)
-{
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest mDepthTest(GL_TRUE);
- gGL.pushMatrix();
- gGL.color4fv(OVERLAY_COLOR.mV);
- gGL.translatef(0.0f, 0.0f, 1.0f);
-
- S32 i = (S32) pos_region.mV[VX];
- S32 j = (S32) pos_region.mV[VY];
- S32 half_edge = llfloor(mBrushSize);
- S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction");
- F32 force = gSavedSettings.getF32("LandBrushForce"); // .1 to 100?
-
- gGL.begin(LLRender::LINES);
- for(S32 di = -half_edge; di <= half_edge; di++)
- {
- if((i+di) < 0 || (i+di) >= (S32)land.mGridsPerEdge) continue;
- for(S32 dj = -half_edge; dj <= half_edge; dj++)
- {
- if( (j+dj) < 0 || (j+dj) >= (S32)land.mGridsPerEdge ) continue;
- const F32
- wx = pos_world.mV[VX] + di,
- wy = pos_world.mV[VY] + dj,
- wz = land.getZ((i+di)+(j+dj)*land.mGridsPerEdge),
- norm_dist = sqrt((float)di*di + dj*dj) / half_edge,
- force_scale = sqrt(2.f) - norm_dist, // 1 at center, 0 at corner
- wz2 = wz + .2 + (.2 + force/100) * force_scale, // top vertex
- tic = .075f; // arrowhead size
- // vertical line
- gGL.vertex3f(wx, wy, wz);
- gGL.vertex3f(wx, wy, wz2);
- if(radioAction == E_LAND_RAISE || radioAction == E_LAND_NOISE) // up arrow
- {
- gGL.vertex3f(wx, wy, wz2);
- gGL.vertex3f(wx+tic, wy, wz2-tic);
- gGL.vertex3f(wx, wy, wz2);
- gGL.vertex3f(wx-tic, wy, wz2-tic);
- }
- if(radioAction == E_LAND_LOWER || radioAction == E_LAND_NOISE) // down arrow
- {
- gGL.vertex3f(wx, wy, wz);
- gGL.vertex3f(wx+tic, wy, wz+tic);
- gGL.vertex3f(wx, wy, wz);
- gGL.vertex3f(wx-tic, wy, wz+tic);
- }
- if(radioAction == E_LAND_REVERT || radioAction == E_LAND_SMOOTH) // flat top
- {
- gGL.vertex3f(wx-tic, wy, wz2);
- gGL.vertex3f(wx+tic, wy, wz2);
- }
- if(radioAction == E_LAND_LEVEL || radioAction == E_LAND_SMOOTH) // flat bottom
- {
- gGL.vertex3f(wx-tic, wy, wz);
- gGL.vertex3f(wx+tic, wy, wz);
- }
- }
- }
- gGL.end();
-
- gGL.popMatrix();
-}
-
-void LLToolBrushLand::determineAffectedRegions(region_list_t& regions,
- const LLVector3d& spot ) const
-{
- LLVector3d corner(spot);
- corner.mdV[VX] -= (mBrushSize / 2);
- corner.mdV[VY] -= (mBrushSize / 2);
- LLViewerRegion* region = NULL;
- region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
- if(region && regions.find(region) == regions.end())
- {
- regions.insert(region);
- }
- corner.mdV[VY] += mBrushSize;
- region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
- if(region && regions.find(region) == regions.end())
- {
- regions.insert(region);
- }
- corner.mdV[VX] += mBrushSize;
- region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
- if(region && regions.find(region) == regions.end())
- {
- regions.insert(region);
- }
- corner.mdV[VY] -= mBrushSize;
- region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
- if(region && regions.find(region) == regions.end())
- {
- regions.insert(region);
- }
-}
-
-// static
-void LLToolBrushLand::onIdle( void* brush_tool )
-{
- LLToolBrushLand* self = reinterpret_cast<LLToolBrushLand*>(brush_tool);
-
- if( LLToolMgr::getInstance()->getCurrentTool() == self )
- {
- self->brush();
- }
- else
- {
- gIdleCallbacks.deleteFunction( &LLToolBrushLand::onIdle, self );
- }
-}
-
-void LLToolBrushLand::onMouseCaptureLost()
-{
- gIdleCallbacks.deleteFunction(&LLToolBrushLand::onIdle, this);
-}
-
-// static
-void LLToolBrushLand::undo()
-{
- for(region_list_t::iterator iter = mLastAffectedRegions.begin();
- iter != mLastAffectedRegions.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- gMessageSystem->newMessageFast(_PREHASH_UndoLand);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->sendMessage(regionp->getHost());
- }
-}
-
-// static
-/*
-void LLToolBrushLand::redo()
-{
- for(region_list_t::iterator iter = mLastAffectedRegions.begin();
- iter != mLastAffectedRegions.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- gMessageSystem->newMessageFast(_PREHASH_RedoLand);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->sendMessage(regionp->getHost());
- }
-}*/
-
-// static
-bool LLToolBrushLand::canTerraformRegion(LLViewerRegion* regionp) const
-{
- if (!regionp) return false;
- if (regionp->canManageEstate()) return true;
- return !regionp->getRegionFlag(REGION_FLAGS_BLOCK_TERRAFORM);
-}
-
-// static
-bool LLToolBrushLand::canTerraformParcel(LLViewerRegion* regionp) const
-{
- LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel();
- bool is_terraform_allowed = false;
- if (selected_parcel)
- {
- bool owner_release = LLViewerParcelMgr::isParcelOwnedByAgent(selected_parcel, GP_LAND_ALLOW_EDIT_LAND);
- is_terraform_allowed = ( gAgent.canManageEstate() || (selected_parcel->getOwnerID() == regionp->getOwner()) || owner_release);
- }
-
- return is_terraform_allowed;
-}
-
-
-// static
-void LLToolBrushLand::alertNoTerraformRegion(LLViewerRegion* regionp)
-{
- if (!regionp) return;
-
- LLSD args;
- args["REGION"] = regionp->getName();
- LLNotificationsUtil::add("RegionNoTerraforming", args);
-
-}
-
-// static
-void LLToolBrushLand::alertNoTerraformParcel()
-{
- LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel();
- if (selected_parcel)
- {
- LLSD args;
- args["PARCEL"] = selected_parcel->getName();
- LLNotificationsUtil::add("ParcelNoTerraforming", args);
- }
-
-}
-
-///============================================================================
-/// Local function definitions
-///============================================================================
+/** + * @file lltoolbrush.cpp + * @brief Implementation of the toolbrushes + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltoolbrush.h" +#include "lltoolselectland.h" + +// library headers +#include "llgl.h" +#include "llnotificationsutil.h" +#include "llrender.h" +#include "message.h" + +#include "llagent.h" +#include "llcallbacklist.h" +#include "llviewercontrol.h" +#include "llfloatertools.h" +#include "llregionposition.h" +#include "llstatusbar.h" +#include "llsurface.h" +#include "llsurfacepatch.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llviewerparcelmgr.h" +#include "llviewerparceloverlay.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llworld.h" +#include "llappviewer.h" +#include "llparcel.h" +#include "roles_constants.h" +#include "llglheaders.h" + +const std::string REGION_BLOCKS_TERRAFORM_MSG = "This region does not allow terraforming.\n" + "You will need to buy land in another part of the world to terraform it."; + + +///============================================================================ +/// Local function declarations, constants, enums, and typedefs +///============================================================================ + +const S32 LAND_BRUSH_SIZE_COUNT = 3; +const F32 LAND_BRUSH_SIZE[LAND_BRUSH_SIZE_COUNT] = {1.0f, 2.0f, 4.0f}; + +enum +{ + E_LAND_LEVEL = 0, + E_LAND_RAISE = 1, + E_LAND_LOWER = 2, + E_LAND_SMOOTH = 3, + E_LAND_NOISE = 4, + E_LAND_REVERT = 5, + E_LAND_INVALID = 6, +}; +const LLColor4 OVERLAY_COLOR(1.0f, 1.0f, 1.0f, 1.0f); + +///============================================================================ +/// Class LLToolBrushLand +///============================================================================ + +// constructor +LLToolBrushLand::LLToolBrushLand() +: LLTool(std::string("Land")), + mStartingZ( 0.0f ), + mMouseX( 0 ), + mMouseY(0), + mGotHover(false), + mBrushSelected(false) +{ + mBrushSize = gSavedSettings.getF32("LandBrushSize"); +} + + +U8 LLToolBrushLand::getBrushIndex() +{ + // find the best index for desired size + // (compatibility with old sims, brush_index is now depricated - DEV-8252) + U8 index = 0; + for (U8 i = 0; i < LAND_BRUSH_SIZE_COUNT; i++) + { + if (mBrushSize > LAND_BRUSH_SIZE[i]) + { + index = i; + } + } + + return index; +} + +void LLToolBrushLand::modifyLandAtPointGlobal(const LLVector3d &pos_global, + MASK mask) +{ + S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction"); + + mLastAffectedRegions.clear(); + determineAffectedRegions(mLastAffectedRegions, pos_global); + for(region_list_t::iterator iter = mLastAffectedRegions.begin(); + iter != mLastAffectedRegions.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + //bool is_changed = false; + LLVector3 pos_region = regionp->getPosRegionFromGlobal(pos_global); + LLSurface &land = regionp->getLand(); + char action = E_LAND_LEVEL; + switch (radioAction) + { + case 0: + // // average toward mStartingZ + action = E_LAND_LEVEL; + break; + case 1: + action = E_LAND_RAISE; + break; + case 2: + action = E_LAND_LOWER; + break; + case 3: + action = E_LAND_SMOOTH; + break; + case 4: + action = E_LAND_NOISE; + break; + case 5: + action = E_LAND_REVERT; + break; + default: + action = E_LAND_INVALID; + break; + } + + // Don't send a message to the region if nothing changed. + //if(!is_changed) continue; + + // Now to update the patch information so it will redraw correctly. + LLSurfacePatch *patchp= land.resolvePatchRegion(pos_region); + if (patchp) + { + patchp->dirtyZ(); + } + + // Also force the property lines to update, normals to recompute, etc. + regionp->forceUpdate(); + + // tell the simulator what we've done + F32 seconds = (1.0f / gFPSClamped) * gSavedSettings.getF32("LandBrushForce"); + F32 x_pos = (F32)pos_region.mV[VX]; + F32 y_pos = (F32)pos_region.mV[VY]; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ModifyLand); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ModifyBlock); + msg->addU8Fast(_PREHASH_Action, (U8)action); + msg->addU8Fast(_PREHASH_BrushSize, getBrushIndex()); + msg->addF32Fast(_PREHASH_Seconds, seconds); + msg->addF32Fast(_PREHASH_Height, mStartingZ); + msg->nextBlockFast(_PREHASH_ParcelData); + msg->addS32Fast(_PREHASH_LocalID, -1); + msg->addF32Fast(_PREHASH_West, x_pos ); + msg->addF32Fast(_PREHASH_South, y_pos ); + msg->addF32Fast(_PREHASH_East, x_pos ); + msg->addF32Fast(_PREHASH_North, y_pos ); + msg->nextBlock("ModifyBlockExtended"); + msg->addF32("BrushSize", mBrushSize); + msg->sendMessage(regionp->getHost()); + } +} + +void LLToolBrushLand::modifyLandInSelectionGlobal() +{ + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) + { + return; + } + + if (LLToolMgr::getInstance()->getCurrentTool() == LLToolSelectLand::getInstance()) + { + // selecting land, don't do anything + return; + } + + LLVector3d min; + LLVector3d max; + + LLViewerParcelMgr::getInstance()->getSelection(min, max); + + S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction"); + + mLastAffectedRegions.clear(); + + determineAffectedRegions(mLastAffectedRegions, LLVector3d(min.mdV[VX], min.mdV[VY], 0)); + determineAffectedRegions(mLastAffectedRegions, LLVector3d(min.mdV[VX], max.mdV[VY], 0)); + determineAffectedRegions(mLastAffectedRegions, LLVector3d(max.mdV[VX], min.mdV[VY], 0)); + determineAffectedRegions(mLastAffectedRegions, LLVector3d(max.mdV[VX], max.mdV[VY], 0)); + + LLRegionPosition mid_point_region((min + max) * 0.5); + LLViewerRegion* center_region = mid_point_region.getRegion(); + if (center_region) + { + LLVector3 pos_region = mid_point_region.getPositionRegion(); + U32 grids = center_region->getLand().mGridsPerEdge; + S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids ); + S32 j = llclamp( (S32)pos_region.mV[VY], 0, (S32)grids ); + mStartingZ = center_region->getLand().getZ(i+j*grids); + } + else + { + mStartingZ = 0.f; + } + + // Stop if our selection include a no-terraform region + for(region_list_t::iterator iter = mLastAffectedRegions.begin(); + iter != mLastAffectedRegions.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + if (!canTerraformRegion(regionp)) + { + alertNoTerraformRegion(regionp); + return; + } + } + + for(region_list_t::iterator iter = mLastAffectedRegions.begin(); + iter != mLastAffectedRegions.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + //bool is_changed = false; + LLVector3 min_region = regionp->getPosRegionFromGlobal(min); + LLVector3 max_region = regionp->getPosRegionFromGlobal(max); + + min_region.clamp(0.f, regionp->getWidth()); + max_region.clamp(0.f, regionp->getWidth()); + F32 seconds = gSavedSettings.getF32("LandBrushForce"); + + LLSurface &land = regionp->getLand(); + char action = E_LAND_LEVEL; + switch (radioAction) + { + case 0: + // // average toward mStartingZ + action = E_LAND_LEVEL; + seconds *= 0.25f; + break; + case 1: + action = E_LAND_RAISE; + seconds *= 0.25f; + break; + case 2: + action = E_LAND_LOWER; + seconds *= 0.25f; + break; + case 3: + action = E_LAND_SMOOTH; + seconds *= 5.0f; + break; + case 4: + action = E_LAND_NOISE; + seconds *= 0.5f; + break; + case 5: + action = E_LAND_REVERT; + seconds = 0.5f; + break; + default: + //action = E_LAND_INVALID; + //seconds = 0.0f; + return; + break; + } + + // Don't send a message to the region if nothing changed. + //if(!is_changed) continue; + + // Now to update the patch information so it will redraw correctly. + LLSurfacePatch *patchp= land.resolvePatchRegion(min_region); + if (patchp) + { + patchp->dirtyZ(); + } + + // Also force the property lines to update, normals to recompute, etc. + regionp->forceUpdate(); + + // tell the simulator what we've done + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ModifyLand); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ModifyBlock); + msg->addU8Fast(_PREHASH_Action, (U8)action); + msg->addU8Fast(_PREHASH_BrushSize, getBrushIndex()); + msg->addF32Fast(_PREHASH_Seconds, seconds); + msg->addF32Fast(_PREHASH_Height, mStartingZ); + + bool parcel_selected = LLViewerParcelMgr::getInstance()->getParcelSelection()->getWholeParcelSelected(); + LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); + + if (parcel_selected && selected_parcel) + { + msg->nextBlockFast(_PREHASH_ParcelData); + msg->addS32Fast(_PREHASH_LocalID, selected_parcel->getLocalID()); + msg->addF32Fast(_PREHASH_West, min_region.mV[VX] ); + msg->addF32Fast(_PREHASH_South, min_region.mV[VY] ); + msg->addF32Fast(_PREHASH_East, max_region.mV[VX] ); + msg->addF32Fast(_PREHASH_North, max_region.mV[VY] ); + } + else + { + msg->nextBlockFast(_PREHASH_ParcelData); + msg->addS32Fast(_PREHASH_LocalID, -1); + msg->addF32Fast(_PREHASH_West, min_region.mV[VX] ); + msg->addF32Fast(_PREHASH_South, min_region.mV[VY] ); + msg->addF32Fast(_PREHASH_East, max_region.mV[VX] ); + msg->addF32Fast(_PREHASH_North, max_region.mV[VY] ); + } + + msg->nextBlock("ModifyBlockExtended"); + msg->addF32("BrushSize", mBrushSize); + + msg->sendMessage(regionp->getHost()); + } +} + +void LLToolBrushLand::brush( void ) +{ + LLVector3d spot; + if( gViewerWindow->mousePointOnLandGlobal( mMouseX, mMouseY, &spot ) ) + { + // Round to nearest X,Y grid + spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 ); + spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 ); + + modifyLandAtPointGlobal(spot, gKeyboard->currentMask(true)); + } +} + +bool LLToolBrushLand::handleMouseDown(S32 x, S32 y, MASK mask) +{ + bool handled = false; + + // Find the z value of the initial click. + LLVector3d spot; + if( gViewerWindow->mousePointOnLandGlobal( x, y, &spot ) ) + { + // Round to nearest X,Y grid + spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 ); + spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 ); + + LLRegionPosition region_position( spot ); + LLViewerRegion* regionp = region_position.getRegion(); + + if (!canTerraformRegion(regionp)) + { + alertNoTerraformRegion(regionp); + return true; + } + + if (!canTerraformParcel(regionp)) + { + alertNoTerraformParcel(); + } + + LLVector3 pos_region = region_position.getPositionRegion(); + U32 grids = regionp->getLand().mGridsPerEdge; + S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids ); + S32 j = llclamp( (S32)pos_region.mV[VY], 0, (S32)grids ); + mStartingZ = regionp->getLand().getZ(i+j*grids); + mMouseX = x; + mMouseY = y; + gIdleCallbacks.addFunction( &LLToolBrushLand::onIdle, (void*)this ); + setMouseCapture( true ); + + LLViewerParcelMgr::getInstance()->setSelectionVisible(false); + handled = true; + } + + return handled; +} + +bool LLToolBrushLand::handleHover( S32 x, S32 y, MASK mask ) +{ + LL_DEBUGS("UserInput") << "hover handled by LLToolBrushLand (" + << (hasMouseCapture() ? "active":"inactive") + << ")" << LL_ENDL; + mMouseX = x; + mMouseY = y; + mGotHover = true; + gViewerWindow->setCursor(UI_CURSOR_TOOLLAND); + + LLVector3d spot; + if( gViewerWindow->mousePointOnLandGlobal( mMouseX, mMouseY, &spot ) ) + { + + spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 ); + spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 ); + + LLViewerParcelMgr::getInstance()->setHoverParcel(spot); + } + return true; +} + +bool LLToolBrushLand::handleMouseUp(S32 x, S32 y, MASK mask) +{ + bool handled = false; + mLastAffectedRegions.clear(); + if( hasMouseCapture() ) + { + // Release the mouse + setMouseCapture( false ); + + LLViewerParcelMgr::getInstance()->setSelectionVisible(true); + + gIdleCallbacks.deleteFunction( &LLToolBrushLand::onIdle, (void*)this ); + handled = true; + } + + return handled; +} + +void LLToolBrushLand::handleSelect() +{ + gEditMenuHandler = this; + + gFloaterTools->setStatusText("modifyland"); +// if (!mBrushSelected) + { + mBrushSelected = true; + } +} + + +void LLToolBrushLand::handleDeselect() +{ + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } + LLViewerParcelMgr::getInstance()->setSelectionVisible(true); + mBrushSelected = false; +} + +// Draw the area that will be affected. +void LLToolBrushLand::render() +{ + if(mGotHover) + { + //LL_INFOS() << "LLToolBrushLand::render()" << LL_ENDL; + LLVector3d spot; + if(gViewerWindow->mousePointOnLandGlobal(mMouseX, mMouseY, &spot)) + { + spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 ); + spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 ); + + mBrushSize = gSavedSettings.getF32("LandBrushSize"); + + region_list_t regions; + determineAffectedRegions(regions, spot); + + // Now, for each region, render the overlay + LLVector3 pos_world = gAgent.getRegion()->getPosRegionFromGlobal(spot); + for(region_list_t::iterator iter = regions.begin(); + iter != regions.end(); ++iter) + { + LLViewerRegion* region = *iter; + renderOverlay(region->getLand(), + region->getPosRegionFromGlobal(spot), + pos_world); + } + } + mGotHover = false; + } +} + +/* + * Draw vertical lines from each vertex straight up in world space + * with lengths indicating the current "strength" slider. + * Decorate the tops and bottoms of the lines like this: + * + * Raise Revert + * /|\ ___ + * | | + * | | + * + * Rough Smooth + * /|\ ___ + * | | + * | | + * \|/..........._|_ + * + * Lower Flatten + * | | + * | | + * \|/..........._|_ + */ +void LLToolBrushLand::renderOverlay(LLSurface& land, const LLVector3& pos_region, + const LLVector3& pos_world) +{ + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLDepthTest mDepthTest(GL_TRUE); + gGL.pushMatrix(); + gGL.color4fv(OVERLAY_COLOR.mV); + gGL.translatef(0.0f, 0.0f, 1.0f); + + S32 i = (S32) pos_region.mV[VX]; + S32 j = (S32) pos_region.mV[VY]; + S32 half_edge = llfloor(mBrushSize); + S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction"); + F32 force = gSavedSettings.getF32("LandBrushForce"); // .1 to 100? + + gGL.begin(LLRender::LINES); + for(S32 di = -half_edge; di <= half_edge; di++) + { + if((i+di) < 0 || (i+di) >= (S32)land.mGridsPerEdge) continue; + for(S32 dj = -half_edge; dj <= half_edge; dj++) + { + if( (j+dj) < 0 || (j+dj) >= (S32)land.mGridsPerEdge ) continue; + const F32 + wx = pos_world.mV[VX] + di, + wy = pos_world.mV[VY] + dj, + wz = land.getZ((i+di)+(j+dj)*land.mGridsPerEdge), + norm_dist = sqrt((float)di*di + dj*dj) / half_edge, + force_scale = sqrt(2.f) - norm_dist, // 1 at center, 0 at corner + wz2 = wz + .2 + (.2 + force/100) * force_scale, // top vertex + tic = .075f; // arrowhead size + // vertical line + gGL.vertex3f(wx, wy, wz); + gGL.vertex3f(wx, wy, wz2); + if(radioAction == E_LAND_RAISE || radioAction == E_LAND_NOISE) // up arrow + { + gGL.vertex3f(wx, wy, wz2); + gGL.vertex3f(wx+tic, wy, wz2-tic); + gGL.vertex3f(wx, wy, wz2); + gGL.vertex3f(wx-tic, wy, wz2-tic); + } + if(radioAction == E_LAND_LOWER || radioAction == E_LAND_NOISE) // down arrow + { + gGL.vertex3f(wx, wy, wz); + gGL.vertex3f(wx+tic, wy, wz+tic); + gGL.vertex3f(wx, wy, wz); + gGL.vertex3f(wx-tic, wy, wz+tic); + } + if(radioAction == E_LAND_REVERT || radioAction == E_LAND_SMOOTH) // flat top + { + gGL.vertex3f(wx-tic, wy, wz2); + gGL.vertex3f(wx+tic, wy, wz2); + } + if(radioAction == E_LAND_LEVEL || radioAction == E_LAND_SMOOTH) // flat bottom + { + gGL.vertex3f(wx-tic, wy, wz); + gGL.vertex3f(wx+tic, wy, wz); + } + } + } + gGL.end(); + + gGL.popMatrix(); +} + +void LLToolBrushLand::determineAffectedRegions(region_list_t& regions, + const LLVector3d& spot ) const +{ + LLVector3d corner(spot); + corner.mdV[VX] -= (mBrushSize / 2); + corner.mdV[VY] -= (mBrushSize / 2); + LLViewerRegion* region = NULL; + region = LLWorld::getInstance()->getRegionFromPosGlobal(corner); + if(region && regions.find(region) == regions.end()) + { + regions.insert(region); + } + corner.mdV[VY] += mBrushSize; + region = LLWorld::getInstance()->getRegionFromPosGlobal(corner); + if(region && regions.find(region) == regions.end()) + { + regions.insert(region); + } + corner.mdV[VX] += mBrushSize; + region = LLWorld::getInstance()->getRegionFromPosGlobal(corner); + if(region && regions.find(region) == regions.end()) + { + regions.insert(region); + } + corner.mdV[VY] -= mBrushSize; + region = LLWorld::getInstance()->getRegionFromPosGlobal(corner); + if(region && regions.find(region) == regions.end()) + { + regions.insert(region); + } +} + +// static +void LLToolBrushLand::onIdle( void* brush_tool ) +{ + LLToolBrushLand* self = reinterpret_cast<LLToolBrushLand*>(brush_tool); + + if( LLToolMgr::getInstance()->getCurrentTool() == self ) + { + self->brush(); + } + else + { + gIdleCallbacks.deleteFunction( &LLToolBrushLand::onIdle, self ); + } +} + +void LLToolBrushLand::onMouseCaptureLost() +{ + gIdleCallbacks.deleteFunction(&LLToolBrushLand::onIdle, this); +} + +// static +void LLToolBrushLand::undo() +{ + for(region_list_t::iterator iter = mLastAffectedRegions.begin(); + iter != mLastAffectedRegions.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + gMessageSystem->newMessageFast(_PREHASH_UndoLand); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->sendMessage(regionp->getHost()); + } +} + +// static +/* +void LLToolBrushLand::redo() +{ + for(region_list_t::iterator iter = mLastAffectedRegions.begin(); + iter != mLastAffectedRegions.end(); ++iter) + { + LLViewerRegion* regionp = *iter; + gMessageSystem->newMessageFast(_PREHASH_RedoLand); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->sendMessage(regionp->getHost()); + } +}*/ + +// static +bool LLToolBrushLand::canTerraformRegion(LLViewerRegion* regionp) const +{ + if (!regionp) return false; + if (regionp->canManageEstate()) return true; + return !regionp->getRegionFlag(REGION_FLAGS_BLOCK_TERRAFORM); +} + +// static +bool LLToolBrushLand::canTerraformParcel(LLViewerRegion* regionp) const +{ + LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel(); + bool is_terraform_allowed = false; + if (selected_parcel) + { + bool owner_release = LLViewerParcelMgr::isParcelOwnedByAgent(selected_parcel, GP_LAND_ALLOW_EDIT_LAND); + is_terraform_allowed = ( gAgent.canManageEstate() || (selected_parcel->getOwnerID() == regionp->getOwner()) || owner_release); + } + + return is_terraform_allowed; +} + + +// static +void LLToolBrushLand::alertNoTerraformRegion(LLViewerRegion* regionp) +{ + if (!regionp) return; + + LLSD args; + args["REGION"] = regionp->getName(); + LLNotificationsUtil::add("RegionNoTerraforming", args); + +} + +// static +void LLToolBrushLand::alertNoTerraformParcel() +{ + LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel(); + if (selected_parcel) + { + LLSD args; + args["PARCEL"] = selected_parcel->getName(); + LLNotificationsUtil::add("ParcelNoTerraforming", args); + } + +} + +///============================================================================ +/// Local function definitions +///============================================================================ |
