00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "lltoolbrush.h"
00035 #include "lltoolselectland.h"
00036
00037 #include "llgl.h"
00038 #include "llglimmediate.h"
00039
00040 #include "message.h"
00041
00042 #include "llagent.h"
00043 #include "llcallbacklist.h"
00044 #include "llviewercontrol.h"
00045 #include "llfloatertools.h"
00046 #include "llregionposition.h"
00047 #include "llstatusbar.h"
00048 #include "llsurface.h"
00049 #include "llsurfacepatch.h"
00050 #include "lltoolmgr.h"
00051 #include "llui.h"
00052 #include "llviewerparcelmgr.h"
00053 #include "llviewerparceloverlay.h"
00054 #include "llviewerregion.h"
00055 #include "llviewerwindow.h"
00056 #include "llworld.h"
00057 #include "llappviewer.h"
00058 #include "llparcel.h"
00059
00060 #include "llglheaders.h"
00061
00062 const std::string REGION_BLOCKS_TERRAFORM_MSG = "This region does not allow terraforming.\n"
00063 "You will need to buy land in another part of the world to terraform it.";
00064
00065
00069
00070 const S32 LAND_BRUSH_SIZE_COUNT = 3;
00071 const F32 LAND_BRUSH_SIZE[LAND_BRUSH_SIZE_COUNT] = {1.0f, 2.0f, 4.0f};
00072 const S32 LAND_STEPS = 3;
00073 const F32 LAND_METERS_PER_SECOND = 1.0f;
00074 enum
00075 {
00076 E_LAND_LEVEL = 0,
00077 E_LAND_RAISE = 1,
00078 E_LAND_LOWER = 2,
00079 E_LAND_SMOOTH = 3,
00080 E_LAND_NOISE = 4,
00081 E_LAND_REVERT = 5,
00082 E_LAND_INVALID = 6,
00083 };
00084 const LLColor4 OVERLAY_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
00085
00089
00090
00091 LLToolBrushLand::LLToolBrushLand()
00092 : LLTool("Land"),
00093 mStartingZ( 0.0f ),
00094 mMouseX( 0 ),
00095 mMouseY(0),
00096 mGotHover(FALSE),
00097 mLastShowParcelOwners(FALSE),
00098 mBrushSelected(FALSE)
00099 {
00100 mBrushIndex = gSavedSettings.getS32("RadioLandBrushSize");
00101 }
00102
00103 void LLToolBrushLand::modifyLandAtPointGlobal(const LLVector3d &pos_global,
00104 MASK mask)
00105 {
00106 S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction");
00107
00108 determineAffectedRegions(mLastAffectedRegions, pos_global);
00109 for(region_list_t::iterator iter = mLastAffectedRegions.begin();
00110 iter != mLastAffectedRegions.end(); ++iter)
00111 {
00112 LLViewerRegion* regionp = *iter;
00113
00114 LLVector3 pos_region = regionp->getPosRegionFromGlobal(pos_global);
00115 LLSurface &land = regionp->getLand();
00116 char action = E_LAND_LEVEL;
00117 switch (radioAction)
00118 {
00119 case 0:
00120
00121 action = E_LAND_LEVEL;
00122 break;
00123 case 1:
00124 action = E_LAND_RAISE;
00125 break;
00126 case 2:
00127 action = E_LAND_LOWER;
00128 break;
00129 case 3:
00130 action = E_LAND_SMOOTH;
00131 break;
00132 case 4:
00133 action = E_LAND_NOISE;
00134 break;
00135 case 5:
00136 action = E_LAND_REVERT;
00137 break;
00138 default:
00139 action = E_LAND_INVALID;
00140 break;
00141 }
00142
00143
00144
00145
00146
00147 LLSurfacePatch *patchp= land.resolvePatchRegion(pos_region);
00148 if (patchp)
00149 {
00150 patchp->dirtyZ();
00151 }
00152
00153
00154 regionp->forceUpdate();
00155
00156
00157 F32 seconds = 1.0f / gFPSClamped;
00158 F32 x_pos = (F32)pos_region.mV[VX];
00159 F32 y_pos = (F32)pos_region.mV[VY];
00160 U8 brush_size = (U8)mBrushIndex;
00161 LLMessageSystem* msg = gMessageSystem;
00162 msg->newMessageFast(_PREHASH_ModifyLand);
00163 msg->nextBlockFast(_PREHASH_AgentData);
00164 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00165 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00166 msg->nextBlockFast(_PREHASH_ModifyBlock);
00167 msg->addU8Fast(_PREHASH_Action, (U8)action);
00168 msg->addU8Fast(_PREHASH_BrushSize, brush_size);
00169 msg->addF32Fast(_PREHASH_Seconds, seconds);
00170 msg->addF32Fast(_PREHASH_Height, mStartingZ);
00171 msg->nextBlockFast(_PREHASH_ParcelData);
00172 msg->addS32Fast(_PREHASH_LocalID, -1);
00173 msg->addF32Fast(_PREHASH_West, x_pos );
00174 msg->addF32Fast(_PREHASH_South, y_pos );
00175 msg->addF32Fast(_PREHASH_East, x_pos );
00176 msg->addF32Fast(_PREHASH_North, y_pos );
00177 msg->sendMessage(regionp->getHost());
00178 }
00179 }
00180
00181 void LLToolBrushLand::modifyLandInSelectionGlobal()
00182 {
00183 if (LLViewerParcelMgr::getInstance()->selectionEmpty())
00184 {
00185 return;
00186 }
00187
00188 if (LLToolMgr::getInstance()->getCurrentTool() == LLToolSelectLand::getInstance())
00189 {
00190
00191 return;
00192 }
00193
00194 LLVector3d min;
00195 LLVector3d max;
00196
00197 LLViewerParcelMgr::getInstance()->getSelection(min, max);
00198
00199 S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction");
00200
00201 mLastAffectedRegions.clear();
00202
00203 determineAffectedRegions(mLastAffectedRegions, LLVector3d(min.mdV[VX], min.mdV[VY], 0));
00204 determineAffectedRegions(mLastAffectedRegions, LLVector3d(min.mdV[VX], max.mdV[VY], 0));
00205 determineAffectedRegions(mLastAffectedRegions, LLVector3d(max.mdV[VX], min.mdV[VY], 0));
00206 determineAffectedRegions(mLastAffectedRegions, LLVector3d(max.mdV[VX], max.mdV[VY], 0));
00207
00208 LLRegionPosition mid_point_region((min + max) * 0.5);
00209 LLViewerRegion* center_region = mid_point_region.getRegion();
00210 if (center_region)
00211 {
00212 LLVector3 pos_region = mid_point_region.getPositionRegion();
00213 U32 grids = center_region->getLand().mGridsPerEdge;
00214 S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids );
00215 S32 j = llclamp( (S32)pos_region.mV[VY], 0, (S32)grids );
00216 mStartingZ = center_region->getLand().getZ(i+j*grids);
00217 }
00218 else
00219 {
00220 mStartingZ = 0.f;
00221 }
00222
00223
00224 for(region_list_t::iterator iter = mLastAffectedRegions.begin();
00225 iter != mLastAffectedRegions.end(); ++iter)
00226 {
00227 LLViewerRegion* regionp = *iter;
00228 if (!canTerraform(regionp))
00229 {
00230 alertNoTerraform(regionp);
00231 return;
00232 }
00233 }
00234
00235 for(region_list_t::iterator iter = mLastAffectedRegions.begin();
00236 iter != mLastAffectedRegions.end(); ++iter)
00237 {
00238 LLViewerRegion* regionp = *iter;
00239
00240 LLVector3 min_region = regionp->getPosRegionFromGlobal(min);
00241 LLVector3 max_region = regionp->getPosRegionFromGlobal(max);
00242
00243 min_region.clamp(0.f, regionp->getWidth());
00244 max_region.clamp(0.f, regionp->getWidth());
00245 F32 seconds = 1.0f;
00246
00247 LLSurface &land = regionp->getLand();
00248 char action = E_LAND_LEVEL;
00249 switch (radioAction)
00250 {
00251 case 0:
00252
00253 action = E_LAND_LEVEL;
00254 seconds = 1.f;
00255 break;
00256 case 1:
00257 action = E_LAND_RAISE;
00258 break;
00259 case 2:
00260 action = E_LAND_LOWER;
00261 break;
00262 case 3:
00263 action = E_LAND_SMOOTH;
00264 seconds = 10.f;
00265 break;
00266 case 4:
00267 action = E_LAND_NOISE;
00268 seconds = 0.5f;
00269 break;
00270 case 5:
00271 action = E_LAND_REVERT;
00272 seconds = 0.5f;
00273 break;
00274 default:
00275
00276
00277 return;
00278 break;
00279 }
00280
00281
00282
00283
00284
00285 LLSurfacePatch *patchp= land.resolvePatchRegion(min_region);
00286 if (patchp)
00287 {
00288 patchp->dirtyZ();
00289 }
00290
00291
00292 regionp->forceUpdate();
00293
00294
00295 U8 brush_size = (U8)mBrushIndex;
00296 LLMessageSystem* msg = gMessageSystem;
00297 msg->newMessageFast(_PREHASH_ModifyLand);
00298 msg->nextBlockFast(_PREHASH_AgentData);
00299 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00300 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00301 msg->nextBlockFast(_PREHASH_ModifyBlock);
00302 msg->addU8Fast(_PREHASH_Action, (U8)action);
00303 msg->addU8Fast(_PREHASH_BrushSize, brush_size);
00304 msg->addF32Fast(_PREHASH_Seconds, seconds);
00305 msg->addF32Fast(_PREHASH_Height, mStartingZ);
00306
00307 BOOL parcel_selected = LLViewerParcelMgr::getInstance()->getParcelSelection()->getWholeParcelSelected();
00308 LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel();
00309
00310 if (parcel_selected && selected_parcel)
00311 {
00312 msg->nextBlockFast(_PREHASH_ParcelData);
00313 msg->addS32Fast(_PREHASH_LocalID, selected_parcel->getLocalID());
00314 msg->addF32Fast(_PREHASH_West, min_region.mV[VX] );
00315 msg->addF32Fast(_PREHASH_South, min_region.mV[VY] );
00316 msg->addF32Fast(_PREHASH_East, max_region.mV[VX] );
00317 msg->addF32Fast(_PREHASH_North, max_region.mV[VY] );
00318 }
00319 else
00320 {
00321 msg->nextBlockFast(_PREHASH_ParcelData);
00322 msg->addS32Fast(_PREHASH_LocalID, -1);
00323 msg->addF32Fast(_PREHASH_West, min_region.mV[VX] );
00324 msg->addF32Fast(_PREHASH_South, min_region.mV[VY] );
00325 msg->addF32Fast(_PREHASH_East, max_region.mV[VX] );
00326 msg->addF32Fast(_PREHASH_North, max_region.mV[VY] );
00327 }
00328
00329 msg->sendMessage(regionp->getHost());
00330 }
00331 }
00332
00333 void LLToolBrushLand::brush( void )
00334 {
00335 LLVector3d spot;
00336 if( gViewerWindow->mousePointOnLandGlobal( mMouseX, mMouseY, &spot ) )
00337 {
00338
00339 spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
00340 spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
00341
00342 modifyLandAtPointGlobal(spot, gKeyboard->currentMask(TRUE));
00343 }
00344 }
00345
00346 BOOL LLToolBrushLand::handleMouseDown(S32 x, S32 y, MASK mask)
00347 {
00348 BOOL handled = FALSE;
00349
00350
00351 LLVector3d spot;
00352 if( gViewerWindow->mousePointOnLandGlobal( x, y, &spot ) )
00353 {
00354
00355 spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
00356 spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
00357
00358 LLRegionPosition region_position( spot );
00359 LLViewerRegion* regionp = region_position.getRegion();
00360
00361 if (!canTerraform(regionp))
00362 {
00363 alertNoTerraform(regionp);
00364 return TRUE;
00365 }
00366
00367 LLVector3 pos_region = region_position.getPositionRegion();
00368 U32 grids = regionp->getLand().mGridsPerEdge;
00369 S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids );
00370 S32 j = llclamp( (S32)pos_region.mV[VY], 0, (S32)grids );
00371 mStartingZ = regionp->getLand().getZ(i+j*grids);
00372 mMouseX = x;
00373 mMouseY = y;
00374 gIdleCallbacks.addFunction( &LLToolBrushLand::onIdle, (void*)this );
00375 setMouseCapture( TRUE );
00376
00377 LLViewerParcelMgr::getInstance()->setSelectionVisible(FALSE);
00378 handled = TRUE;
00379 }
00380
00381 return handled;
00382 }
00383
00384 BOOL LLToolBrushLand::handleHover( S32 x, S32 y, MASK mask )
00385 {
00386 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolBrushLand ("
00387 << (hasMouseCapture() ? "active":"inactive")
00388 << ")" << llendl;
00389 mMouseX = x;
00390 mMouseY = y;
00391 mGotHover = TRUE;
00392 gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLLAND);
00393 return TRUE;
00394 }
00395
00396 BOOL LLToolBrushLand::handleMouseUp(S32 x, S32 y, MASK mask)
00397 {
00398 BOOL handled = FALSE;
00399 mLastAffectedRegions.clear();
00400 if( hasMouseCapture() )
00401 {
00402
00403 setMouseCapture( FALSE );
00404
00405 LLViewerParcelMgr::getInstance()->setSelectionVisible(TRUE);
00406
00407 gIdleCallbacks.deleteFunction( &LLToolBrushLand::onIdle, (void*)this );
00408 handled = TRUE;
00409 }
00410
00411 return handled;
00412 }
00413
00414 void LLToolBrushLand::handleSelect()
00415 {
00416 gEditMenuHandler = this;
00417
00418 gFloaterTools->setStatusText("modifyland");
00419
00420 {
00421 mLastShowParcelOwners = gSavedSettings.getBOOL("ShowParcelOwners");
00422 gSavedSettings.setBOOL("ShowParcelOwners", mLastShowParcelOwners);
00423 mBrushSelected = TRUE;
00424 }
00425 }
00426
00427
00428 void LLToolBrushLand::handleDeselect()
00429 {
00430 if( gEditMenuHandler == this )
00431 {
00432 gEditMenuHandler = NULL;
00433 }
00434 mLastShowParcelOwners = gSavedSettings.getBOOL("ShowParcelOwners");
00435 gSavedSettings.setBOOL("ShowParcelOwners", mLastShowParcelOwners);
00436 LLViewerParcelMgr::getInstance()->setSelectionVisible(TRUE);
00437 mBrushSelected = FALSE;
00438 }
00439
00440
00441 void LLToolBrushLand::render()
00442 {
00443 if(mGotHover)
00444 {
00445
00446 LLVector3d spot;
00447 if(gViewerWindow->mousePointOnLandGlobal(mMouseX, mMouseY, &spot))
00448 {
00449 spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 );
00450 spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 );
00451
00452 mBrushIndex = gSavedSettings.getS32("RadioLandBrushSize");
00453 region_list_t regions;
00454 determineAffectedRegions(regions, spot);
00455
00456
00457 LLVector3 pos_world = gAgent.getRegion()->getPosRegionFromGlobal(spot);
00458 for(region_list_t::iterator iter = regions.begin();
00459 iter != regions.end(); ++iter)
00460 {
00461 LLViewerRegion* region = *iter;
00462 renderOverlay(region->getLand(),
00463 region->getPosRegionFromGlobal(spot),
00464 pos_world);
00465 }
00466 }
00467 mGotHover = FALSE;
00468 }
00469 }
00470
00471 void LLToolBrushLand::renderOverlay(LLSurface& land, const LLVector3& pos_region,
00472 const LLVector3& pos_world)
00473 {
00474 glMatrixMode(GL_MODELVIEW);
00475 LLGLSNoTexture gls_no_texture;
00476 LLGLDepthTest mDepthTest(GL_TRUE);
00477 glPushMatrix();
00478 gGL.color4fv(OVERLAY_COLOR.mV);
00479 glTranslatef(0.0f, 0.0f, 1.0f);
00480
00481 S32 i = (S32) pos_region.mV[VX];
00482 S32 j = (S32) pos_region.mV[VY];
00483 S32 half_edge = llfloor(LAND_BRUSH_SIZE[mBrushIndex]);
00484
00485 gGL.begin(LLVertexBuffer::POINTS);
00486 for(S32 di = -half_edge; di <= half_edge; di++)
00487 {
00488 if((i+di) < 0 || (i+di) >= (S32)land.mGridsPerEdge) continue;
00489 for(S32 dj = -half_edge; dj <= half_edge; dj++)
00490 {
00491 if( (j+dj) < 0 || (j+dj) >= (S32)land.mGridsPerEdge ) continue;
00492 gGL.vertex3f(pos_world.mV[VX] + di, pos_world.mV[VY] + dj,
00493 land.getZ((i+di)+(j+dj)*land.mGridsPerEdge));
00494 }
00495 }
00496 gGL.end();
00497 glPopMatrix();
00498 }
00499
00500 void LLToolBrushLand::determineAffectedRegions(region_list_t& regions,
00501 const LLVector3d& spot ) const
00502 {
00503 LLVector3d corner(spot);
00504 corner.mdV[VX] -= (LAND_BRUSH_SIZE[mBrushIndex] / 2);
00505 corner.mdV[VY] -= (LAND_BRUSH_SIZE[mBrushIndex] / 2);
00506 LLViewerRegion* region = NULL;
00507 region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
00508 if(region && regions.find(region) == regions.end())
00509 {
00510 regions.insert(region);
00511 }
00512 corner.mdV[VY] += LAND_BRUSH_SIZE[mBrushIndex];
00513 region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
00514 if(region && regions.find(region) == regions.end())
00515 {
00516 regions.insert(region);
00517 }
00518 corner.mdV[VX] += LAND_BRUSH_SIZE[mBrushIndex];
00519 region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
00520 if(region && regions.find(region) == regions.end())
00521 {
00522 regions.insert(region);
00523 }
00524 corner.mdV[VY] -= LAND_BRUSH_SIZE[mBrushIndex];
00525 region = LLWorld::getInstance()->getRegionFromPosGlobal(corner);
00526 if(region && regions.find(region) == regions.end())
00527 {
00528 regions.insert(region);
00529 }
00530 }
00531
00532
00533 void LLToolBrushLand::onIdle( void* brush_tool )
00534 {
00535 LLToolBrushLand* self = reinterpret_cast<LLToolBrushLand*>(brush_tool);
00536
00537 if( LLToolMgr::getInstance()->getCurrentTool() == self )
00538 {
00539 self->brush();
00540 }
00541 else
00542 {
00543 gIdleCallbacks.deleteFunction( &LLToolBrushLand::onIdle, self );
00544 }
00545 }
00546
00547 void LLToolBrushLand::onMouseCaptureLost()
00548 {
00549 gIdleCallbacks.deleteFunction(&LLToolBrushLand::onIdle, this);
00550 }
00551
00552
00553 void LLToolBrushLand::undo()
00554 {
00555 for(region_list_t::iterator iter = mLastAffectedRegions.begin();
00556 iter != mLastAffectedRegions.end(); ++iter)
00557 {
00558 LLViewerRegion* regionp = *iter;
00559 gMessageSystem->newMessageFast(_PREHASH_UndoLand);
00560 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
00561 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
00562 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00563 gMessageSystem->sendMessage(regionp->getHost());
00564 }
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 bool LLToolBrushLand::canTerraform(LLViewerRegion* regionp) const
00585 {
00586 if (!regionp) return false;
00587 if (regionp->canManageEstate()) return true;
00588 return !(regionp->getRegionFlags() & REGION_FLAGS_BLOCK_TERRAFORM);
00589 }
00590
00591
00592 void LLToolBrushLand::alertNoTerraform(LLViewerRegion* regionp)
00593 {
00594 if (!regionp) return;
00595
00596 LLStringBase<char>::format_map_t args;
00597 args["[REGION]"] = regionp->getName();
00598 gViewerWindow->alertXml("RegionNoTerraforming", args);
00599
00600 }
00601