lltoolbrush.cpp

Go to the documentation of this file.
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 // constructor
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                 //BOOL is_changed = FALSE;
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                 //      // average toward mStartingZ
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                 // Don't send a message to the region if nothing changed.
00144                 //if(!is_changed) continue;
00145 
00146                 // Now to update the patch information so it will redraw correctly.
00147                 LLSurfacePatch *patchp= land.resolvePatchRegion(pos_region);
00148                 if (patchp)
00149                 {
00150                         patchp->dirtyZ();
00151                 }
00152 
00153                 // Also force the property lines to update, normals to recompute, etc.
00154                 regionp->forceUpdate();
00155 
00156                 // tell the simulator what we've done
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                 // selecting land, don't do anything
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         // Stop if our selection include a no-terraform region
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                 //BOOL is_changed = FALSE;
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                 //      // average toward mStartingZ
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                         //action = E_LAND_INVALID;
00276                         //seconds = 0.0f;
00277                         return;
00278                         break;
00279                 }
00280 
00281                 // Don't send a message to the region if nothing changed.
00282                 //if(!is_changed) continue;
00283 
00284                 // Now to update the patch information so it will redraw correctly.
00285                 LLSurfacePatch *patchp= land.resolvePatchRegion(min_region);
00286                 if (patchp)
00287                 {
00288                         patchp->dirtyZ();
00289                 }
00290 
00291                 // Also force the property lines to update, normals to recompute, etc.
00292                 regionp->forceUpdate();
00293 
00294                 // tell the simulator what we've done
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                 // Round to nearest X,Y grid
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         // Find the z value of the initial click. 
00351         LLVector3d spot;
00352         if( gViewerWindow->mousePointOnLandGlobal( x, y, &spot ) )
00353         {
00354                 // Round to nearest X,Y grid
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                 // Release the mouse
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 //      if (!mBrushSelected)
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 // Draw the area that will be affected.
00441 void LLToolBrushLand::render()
00442 {
00443         if(mGotHover)
00444         {
00445                 //llinfos << "LLToolBrushLand::render()" << llendl;
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                         // Now, for each region, render the overlay
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 // static
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 // static
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 // static
00568 /*
00569 void LLToolBrushLand::redo()
00570 {
00571         for(region_list_t::iterator iter = mLastAffectedRegions.begin();
00572                 iter != mLastAffectedRegions.end(); ++iter)
00573         {
00574                 LLViewerRegion* regionp = *iter;
00575                 gMessageSystem->newMessageFast(_PREHASH_RedoLand);
00576                 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
00577                 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
00578                 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00579                 gMessageSystem->sendMessage(regionp->getHost());
00580         }
00581 }*/
00582 
00583 // static
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 // static
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 

Generated on Fri May 16 08:34:06 2008 for SecondLife by  doxygen 1.5.5