diff options
| author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
|---|---|---|
| committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
| commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
| tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/lltoolplacer.cpp | |
| parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
| parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) | |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/lltoolplacer.cpp')
| -rw-r--r-- | indra/newview/lltoolplacer.cpp | 1072 |
1 files changed, 536 insertions, 536 deletions
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 47bc4df4e5..708f3bb579 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -1,536 +1,536 @@ -/** - * @file lltoolplacer.cpp - * @brief Tool for placing new objects into the world - * - * $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" - -// self header -#include "lltoolplacer.h" - -// viewer headers -#include "llbutton.h" -#include "llviewercontrol.h" -//#include "llfirstuse.h" -#include "llfloatertools.h" -#include "llselectmgr.h" -#include "llstatusbar.h" -#include "lltoolcomp.h" -#include "lltoolmgr.h" -#include "llviewerobject.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" -#include "llworld.h" -#include "llui.h" - -//Headers added for functions moved from viewer.cpp -#include "llvograss.h" -#include "llvotree.h" -#include "llvolumemessage.h" -#include "llhudmanager.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llaudioengine.h" -#include "llhudeffecttrail.h" -#include "llviewerobjectlist.h" -#include "llviewercamera.h" -#include "llviewerstats.h" -#include "llvoavatarself.h" - -// linden library headers -#include "llprimitive.h" -#include "llwindow.h" // incBusyCount() -#include "material_codes.h" -#include "lluiusage.h" - -const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f); - -//static -LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; - -LLToolPlacer::LLToolPlacer() -: LLTool( "Create" ) -{ -} - -bool LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, - bool* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region ) -{ - F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f; - - // Viewer-side pick to find the right sim to create the object on. - // First find the surface the object will be created on. - LLPickInfo pick = gViewerWindow->pickImmediate(x, y, false, false); - - // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok - // representations (if any) are NOT the same as their viewer representation. - if (pick.mPickType == LLPickInfo::PICK_FLORA) - { - *hit_obj = NULL; - *hit_face = -1; - } - else - { - *hit_obj = pick.getObject(); - *hit_face = pick.mObjectFace; - } - *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero(); - LLVector3d land_pos_global = pick.mPosGlobal; - - // Make sure there's a surface to place the new object on. - bool bypass_sim_raycast = false; - LLVector3d surface_pos_global; - if (*b_hit_land) - { - surface_pos_global = land_pos_global; - bypass_sim_raycast = true; - } - else - if (*hit_obj) - { - surface_pos_global = (*hit_obj)->getPositionGlobal(); - } - else - { - return false; - } - - // Make sure the surface isn't too far away. - LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal(); - F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared()); - if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) ) - { - return false; - } - - // Find the sim where the surface lives. - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); - if (!regionp) - { - LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; - return false; - } - - // Find the simulator-side ray that will be used to place the object accurately - LLVector3d mouse_direction; - mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) ); - - *region = regionp; - *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global ); - F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues. - *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip; - - if( bypass_sim_raycast ) - { - // Hack to work around Havok's inability to ray cast onto height fields - *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point - } - else - { - LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems. - *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global ); - } - - return true; -} - - -bool LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) -{ - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - bool b_hit_land = false; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - U8 state = 0; - bool success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - return false; - } - - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - return false; - } - - if (NULL == regionp) - { - LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; - return false; - } - - if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)) - { - //LLFirstUse::useSandbox(); - } - - // Set params for new object based on its PCode. - LLQuaternion rotation; - LLVector3 scale = DEFAULT_OBJECT_SCALE; - U8 material = LL_MCODE_WOOD; - bool create_selected = false; - LLVolumeParams volume_params; - - switch (pcode) - { - case LL_PCODE_LEGACY_GRASS: - // Randomize size of grass patch - scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); - state = rand() % LLVOGrass::sMaxGrassSpecies; - break; - - - case LL_PCODE_LEGACY_TREE: - case LL_PCODE_TREE_NEW: - state = rand() % LLVOTree::sMaxTreeSpecies; - break; - - case LL_PCODE_SPHERE: - case LL_PCODE_CONE: - case LL_PCODE_CUBE: - case LL_PCODE_CYLINDER: - case LL_PCODE_TORUS: - case LLViewerObject::LL_VO_SQUARE_TORUS: - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - default: - create_selected = true; - break; - } - - // Play creation sound - if (gAudiop) - { - gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), - gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); - } - - LLUIUsage::instance().logCommand("Build.ObjectAdd"); - gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU8Fast(_PREHASH_Material, material); - - U32 flags = 0; // not selected - if (use_physics) - { - flags |= FLAGS_USE_PHYSICS; - } - if (create_selected) - { - flags |= FLAGS_CREATE_SELECTED; - } - gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); - - LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error - switch (pcode) - { - case LL_PCODE_SPHERE: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_SQUARE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LLViewerObject::LL_VO_TRIANGLE_TORUS: - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1.f, 0.25f ); // "top size" - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_SPHERE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - //volume_params.setBeginAndEndS( 0.5f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 0.5f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CUBE: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PRISM: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 1 ); - volume_params.setShear ( -0.5f, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_PYRAMID: - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_TETRAHEDRON: - volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CYLINDER_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - case LL_PCODE_CONE_HEMI: - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.25f, 0.75f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 0, 0 ); - volume_params.setShear ( 0, 0 ); - LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); - volume_pcode = LL_PCODE_VOLUME; - break; - - default: - LLVolumeMessage::packVolumeParams(0, gMessageSystem); - volume_pcode = pcode; - break; - } - gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); - - gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); - gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); - gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); - gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); - gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); - gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)false ); - gMessageSystem->addU8Fast(_PREHASH_State, state); - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); - - // Pack in name value pairs - gMessageSystem->sendReliable(regionp->getHost()); - - // Spawns a message, so must be after above send - if (create_selected) - { - LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->getWindow()->incBusyCount(); - } - - // VEFFECT: AddObject - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, true); - effectp->setSourceObject((LLViewerObject*)gAgentAvatarp); - effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); - effectp->setDuration(LL_HUD_DUR_SHORT); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - - add(LLStatViewer::OBJECT_CREATE, 1); - - return true; -} - -// Used by the placer tool to add copies of the current selection. -// Inspired by add_object(). JC -bool LLToolPlacer::addDuplicate(S32 x, S32 y) -{ - LLVector3 ray_start_region; - LLVector3 ray_end_region; - LLViewerRegion* regionp = NULL; - bool b_hit_land = false; - S32 hit_face = -1; - LLViewerObject* hit_obj = NULL; - bool success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); - if( !success ) - { - make_ui_sound("UISndInvalidOp"); - return false; - } - if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) - { - // Can't create objects on avatars or attachments - make_ui_sound("UISndInvalidOp"); - return false; - } - - - // Limit raycast to a single object. - // Speeds up server raycast + avoid problems with server ray hitting objects - // that were clipped by the near plane or culled on the viewer. - LLUUID ray_target_id; - if( hit_obj ) - { - ray_target_id = hit_obj->getID(); - } - else - { - ray_target_id.setNull(); - } - - LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region, - ray_end_region, - b_hit_land, // suppress raycast - false, // intersection - ray_target_id, - gSavedSettings.getBOOL("CreateToolCopyCenters"), - gSavedSettings.getBOOL("CreateToolCopyRotates"), - false); // select copy - - if (regionp - && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))) - { - //LLFirstUse::useSandbox(); - } - - return true; -} - - -bool LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) -{ - bool added = true; - - if (gSavedSettings.getBOOL("CreateToolCopySelection")) - { - added = addDuplicate(x, y); - } - else - { - added = addObject( sObjectType, x, y, false ); - } - - // ...and go back to the default tool - if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected")) - { - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); - } - - return added; -} - -bool LLToolPlacer::handleHover(S32 x, S32 y, MASK mask) -{ - LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; - gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); - return true; -} - -void LLToolPlacer::handleSelect() -{ - gFloaterTools->setStatusText("place"); -} - -void LLToolPlacer::handleDeselect() -{ -} - +/**
+ * @file lltoolplacer.cpp
+ * @brief Tool for placing new objects into the world
+ *
+ * $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"
+
+// self header
+#include "lltoolplacer.h"
+
+// viewer headers
+#include "llbutton.h"
+#include "llviewercontrol.h"
+//#include "llfirstuse.h"
+#include "llfloatertools.h"
+#include "llselectmgr.h"
+#include "llstatusbar.h"
+#include "lltoolcomp.h"
+#include "lltoolmgr.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+#include "llviewerwindow.h"
+#include "llworld.h"
+#include "llui.h"
+
+//Headers added for functions moved from viewer.cpp
+#include "llvograss.h"
+#include "llvotree.h"
+#include "llvolumemessage.h"
+#include "llhudmanager.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llaudioengine.h"
+#include "llhudeffecttrail.h"
+#include "llviewerobjectlist.h"
+#include "llviewercamera.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+
+// linden library headers
+#include "llprimitive.h"
+#include "llwindow.h" // incBusyCount()
+#include "material_codes.h"
+#include "lluiusage.h"
+
+const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f);
+
+//static
+LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE;
+
+LLToolPlacer::LLToolPlacer()
+: LLTool( "Create" )
+{
+}
+
+bool LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face,
+ bool* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region )
+{
+ F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f;
+
+ // Viewer-side pick to find the right sim to create the object on.
+ // First find the surface the object will be created on.
+ LLPickInfo pick = gViewerWindow->pickImmediate(x, y, false, false);
+
+ // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok
+ // representations (if any) are NOT the same as their viewer representation.
+ if (pick.mPickType == LLPickInfo::PICK_FLORA)
+ {
+ *hit_obj = NULL;
+ *hit_face = -1;
+ }
+ else
+ {
+ *hit_obj = pick.getObject();
+ *hit_face = pick.mObjectFace;
+ }
+ *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero();
+ LLVector3d land_pos_global = pick.mPosGlobal;
+
+ // Make sure there's a surface to place the new object on.
+ bool bypass_sim_raycast = false;
+ LLVector3d surface_pos_global;
+ if (*b_hit_land)
+ {
+ surface_pos_global = land_pos_global;
+ bypass_sim_raycast = true;
+ }
+ else
+ if (*hit_obj)
+ {
+ surface_pos_global = (*hit_obj)->getPositionGlobal();
+ }
+ else
+ {
+ return false;
+ }
+
+ // Make sure the surface isn't too far away.
+ LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal();
+ F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared());
+ if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) )
+ {
+ return false;
+ }
+
+ // Find the sim where the surface lives.
+ LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global);
+ if (!regionp)
+ {
+ LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL;
+ return false;
+ }
+
+ // Find the simulator-side ray that will be used to place the object accurately
+ LLVector3d mouse_direction;
+ mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) );
+
+ *region = regionp;
+ *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global );
+ F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f; // Include an epsilon to avoid rounding issues.
+ *ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip;
+
+ if( bypass_sim_raycast )
+ {
+ // Hack to work around Havok's inability to ray cast onto height fields
+ *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point
+ }
+ else
+ {
+ LLVector3d ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction; // add an epsilon to the sim version of the ray to avoid rounding problems.
+ *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global );
+ }
+
+ return true;
+}
+
+
+bool LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
+{
+ LLVector3 ray_start_region;
+ LLVector3 ray_end_region;
+ LLViewerRegion* regionp = NULL;
+ bool b_hit_land = false;
+ S32 hit_face = -1;
+ LLViewerObject* hit_obj = NULL;
+ U8 state = 0;
+ bool success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp );
+ if( !success )
+ {
+ return false;
+ }
+
+ if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
+ {
+ // Can't create objects on avatars or attachments
+ return false;
+ }
+
+ if (NULL == regionp)
+ {
+ LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL;
+ return false;
+ }
+
+ if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))
+ {
+ //LLFirstUse::useSandbox();
+ }
+
+ // Set params for new object based on its PCode.
+ LLQuaternion rotation;
+ LLVector3 scale = DEFAULT_OBJECT_SCALE;
+ U8 material = LL_MCODE_WOOD;
+ bool create_selected = false;
+ LLVolumeParams volume_params;
+
+ switch (pcode)
+ {
+ case LL_PCODE_LEGACY_GRASS:
+ // Randomize size of grass patch
+ scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f));
+ state = rand() % LLVOGrass::sMaxGrassSpecies;
+ break;
+
+
+ case LL_PCODE_LEGACY_TREE:
+ case LL_PCODE_TREE_NEW:
+ state = rand() % LLVOTree::sMaxTreeSpecies;
+ break;
+
+ case LL_PCODE_SPHERE:
+ case LL_PCODE_CONE:
+ case LL_PCODE_CUBE:
+ case LL_PCODE_CYLINDER:
+ case LL_PCODE_TORUS:
+ case LLViewerObject::LL_VO_SQUARE_TORUS:
+ case LLViewerObject::LL_VO_TRIANGLE_TORUS:
+ default:
+ create_selected = true;
+ break;
+ }
+
+ // Play creation sound
+ if (gAudiop)
+ {
+ gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")),
+ gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
+ }
+
+ LLUIUsage::instance().logCommand("Build.ObjectAdd");
+ gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addU8Fast(_PREHASH_Material, material);
+
+ U32 flags = 0; // not selected
+ if (use_physics)
+ {
+ flags |= FLAGS_USE_PHYSICS;
+ }
+ if (create_selected)
+ {
+ flags |= FLAGS_CREATE_SELECTED;
+ }
+ gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags );
+
+ LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error
+ switch (pcode)
+ {
+ case LL_PCODE_SPHERE:
+ rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
+
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_TORUS:
+ rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
+
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1.f, 0.25f ); // "top size"
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LLViewerObject::LL_VO_SQUARE_TORUS:
+ rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
+
+ volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1.f, 0.25f ); // "top size"
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LLViewerObject::LL_VO_TRIANGLE_TORUS:
+ rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
+
+ volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1.f, 0.25f ); // "top size"
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_SPHERE_HEMI:
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
+ //volume_params.setBeginAndEndS( 0.5f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 0.5f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_CUBE:
+ volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_PRISM:
+ volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 0, 1 );
+ volume_params.setShear ( -0.5f, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_PYRAMID:
+ volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 0, 0 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_TETRAHEDRON:
+ volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 0, 0 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_CYLINDER:
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_CYLINDER_HEMI:
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.25f, 0.75f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_CONE:
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 0, 0 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ case LL_PCODE_CONE_HEMI:
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.25f, 0.75f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 0, 0 );
+ volume_params.setShear ( 0, 0 );
+ LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
+ volume_pcode = LL_PCODE_VOLUME;
+ break;
+
+ default:
+ LLVolumeMessage::packVolumeParams(0, gMessageSystem);
+ volume_pcode = pcode;
+ break;
+ }
+ gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode);
+
+ gMessageSystem->addVector3Fast(_PREHASH_Scale, scale );
+ gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation );
+ gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region );
+ gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region );
+ gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land );
+ gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)false );
+ gMessageSystem->addU8Fast(_PREHASH_State, state);
+
+ // Limit raycast to a single object.
+ // Speeds up server raycast + avoid problems with server ray hitting objects
+ // that were clipped by the near plane or culled on the viewer.
+ LLUUID ray_target_id;
+ if( hit_obj )
+ {
+ ray_target_id = hit_obj->getID();
+ }
+ else
+ {
+ ray_target_id.setNull();
+ }
+ gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id );
+
+ // Pack in name value pairs
+ gMessageSystem->sendReliable(regionp->getHost());
+
+ // Spawns a message, so must be after above send
+ if (create_selected)
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ gViewerWindow->getWindow()->incBusyCount();
+ }
+
+ // VEFFECT: AddObject
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, true);
+ effectp->setSourceObject((LLViewerObject*)gAgentAvatarp);
+ effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region));
+ effectp->setDuration(LL_HUD_DUR_SHORT);
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+
+ add(LLStatViewer::OBJECT_CREATE, 1);
+
+ return true;
+}
+
+// Used by the placer tool to add copies of the current selection.
+// Inspired by add_object(). JC
+bool LLToolPlacer::addDuplicate(S32 x, S32 y)
+{
+ LLVector3 ray_start_region;
+ LLVector3 ray_end_region;
+ LLViewerRegion* regionp = NULL;
+ bool b_hit_land = false;
+ S32 hit_face = -1;
+ LLViewerObject* hit_obj = NULL;
+ bool success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp );
+ if( !success )
+ {
+ make_ui_sound("UISndInvalidOp");
+ return false;
+ }
+ if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
+ {
+ // Can't create objects on avatars or attachments
+ make_ui_sound("UISndInvalidOp");
+ return false;
+ }
+
+
+ // Limit raycast to a single object.
+ // Speeds up server raycast + avoid problems with server ray hitting objects
+ // that were clipped by the near plane or culled on the viewer.
+ LLUUID ray_target_id;
+ if( hit_obj )
+ {
+ ray_target_id = hit_obj->getID();
+ }
+ else
+ {
+ ray_target_id.setNull();
+ }
+
+ LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region,
+ ray_end_region,
+ b_hit_land, // suppress raycast
+ false, // intersection
+ ray_target_id,
+ gSavedSettings.getBOOL("CreateToolCopyCenters"),
+ gSavedSettings.getBOOL("CreateToolCopyRotates"),
+ false); // select copy
+
+ if (regionp
+ && (regionp->getRegionFlag(REGION_FLAGS_SANDBOX)))
+ {
+ //LLFirstUse::useSandbox();
+ }
+
+ return true;
+}
+
+
+bool LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
+{
+ bool added = true;
+
+ if (gSavedSettings.getBOOL("CreateToolCopySelection"))
+ {
+ added = addDuplicate(x, y);
+ }
+ else
+ {
+ added = addObject( sObjectType, x, y, false );
+ }
+
+ // ...and go back to the default tool
+ if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected"))
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() );
+ }
+
+ return added;
+}
+
+bool LLToolPlacer::handleHover(S32 x, S32 y, MASK mask)
+{
+ LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL;
+ gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE);
+ return true;
+}
+
+void LLToolPlacer::handleSelect()
+{
+ gFloaterTools->setStatusText("place");
+}
+
+void LLToolPlacer::handleDeselect()
+{
+}
+
|
