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 19eb8b8d58..86acb1963e 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
+///============================================================================
|
