PageRenderTime 101ms CodeModel.GetById 31ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/lltoolbrush.cpp

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