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

Generated on Thu Jul 1 06:09:20 2010 for Second Life Viewer by  doxygen 1.4.7