lltoolplacer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /**
  2. * @file lltoolplacer.cpp
  3. * @brief Tool for placing new objects into the world
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "lltoolplacer.h"
  34. #include "llaudioengine.h"
  35. #include "llbutton.h"
  36. #include "llparcel.h"
  37. #include "llprimitive.h"
  38. #include "roles_constants.h"
  39. #include "llagent.h"
  40. #include "llfirstuse.h"
  41. #include "llfloatertools.h"
  42. #include "llhudeffectspiral.h"
  43. //MK
  44. #include "mkrlinterface.h"
  45. //mk
  46. #include "llselectmgr.h"
  47. #include "llstatusbar.h"
  48. #include "lltoolcomp.h"
  49. #include "lltoolmgr.h"
  50. #include "llviewercamera.h"
  51. #include "llviewercontrol.h"
  52. #include "llviewerobjectlist.h"
  53. #include "llviewerparcelmgr.h"
  54. #include "llviewerregion.h"
  55. #include "llviewerstats.h"
  56. #include "llviewerwindow.h"
  57. #include "llvoavatarself.h"
  58. #include "llvograss.h"
  59. #include "llvolumemessage.h"
  60. #include "llvotree.h"
  61. #include "llworld.h"
  62. const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f);
  63. //static
  64. LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE;
  65. LLToolPlacer::LLToolPlacer()
  66. : LLTool("Create")
  67. {
  68. }
  69. bool LLToolPlacer::raycastForNewObjPos(S32 x, S32 y, LLViewerObject** hit_obj,
  70. S32* hit_face, bool* b_hit_land,
  71. LLVector3* ray_start_region,
  72. LLVector3* ray_end_region,
  73. LLViewerRegion** region)
  74. {
  75. F32 max_dist_from_camera = gSavedSettings.getF32("MaxSelectDistance") - 1.f;
  76. // Viewer-side pick to find the right sim to create the object on. First
  77. // find the surface the object will be created on.
  78. LLPickInfo pick = gViewerWindowp->pickImmediate(x, y);
  79. // Note: use the frontmost non-flora version because (a) plants usually
  80. // have lots of alpha and (b) pants' Havok
  81. // representations (if any) are NOT the same as their viewer representation.
  82. if (pick.mPickType == LLPickInfo::PICK_FLORA)
  83. {
  84. *hit_obj = NULL;
  85. *hit_face = -1;
  86. }
  87. else
  88. {
  89. *hit_obj = pick.getObject();
  90. *hit_face = pick.mObjectFace;
  91. }
  92. *b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero();
  93. LLVector3d land_pos_global = pick.mPosGlobal;
  94. // Make sure there's a surface to place the new object on.
  95. bool bypass_sim_raycast = false;
  96. LLVector3d surf_pos_global;
  97. if (*b_hit_land)
  98. {
  99. surf_pos_global = land_pos_global;
  100. bypass_sim_raycast = true;
  101. }
  102. else if (*hit_obj)
  103. {
  104. surf_pos_global = (*hit_obj)->getPositionGlobal();
  105. }
  106. else
  107. {
  108. return false;
  109. }
  110. // Make sure the surface isn't too far away.
  111. LLVector3d ray_start_global = gAgent.getCameraPositionGlobal();
  112. F32 dist_to_surface_sq = (F32)((surf_pos_global - ray_start_global).lengthSquared());
  113. if (dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera))
  114. {
  115. return false;
  116. }
  117. // Find the sim where the surface lives.
  118. LLViewerRegion* regionp = gWorld.getRegionFromPosGlobal(surf_pos_global);
  119. if (!regionp)
  120. {
  121. llwarns << "Trying to add object outside of all known regions !"
  122. << llendl;
  123. return false;
  124. }
  125. // Find the simulator-side ray that will be used to place the object
  126. // accurately
  127. LLVector3d mouse_direction;
  128. mouse_direction.set(gViewerWindowp->mouseDirectionGlobal(x, y));
  129. *region = regionp;
  130. *ray_start_region = regionp->getPosRegionFromGlobal(ray_start_global);
  131. // Include an epsilon to avoid rounding issues.
  132. F32 near_clip = gViewerCamera.getNear() + 0.01f;
  133. *ray_start_region += gViewerCamera.getAtAxis() * near_clip;
  134. if (bypass_sim_raycast)
  135. {
  136. // Hack to work around Havok's inability to ray cast onto height fields
  137. // ray end is the viewer's intersection point
  138. *ray_end_region = regionp->getPosRegionFromGlobal(surf_pos_global);
  139. }
  140. else
  141. {
  142. // Add an epsilon to the sim version of the ray to avoid rounding
  143. // problems.
  144. LLVector3d ray_end_global = ray_start_global +
  145. (1.f + max_dist_from_camera) * mouse_direction;
  146. *ray_end_region = regionp->getPosRegionFromGlobal(ray_end_global);
  147. }
  148. return true;
  149. }
  150. S32 LLToolPlacer::getTreeGrassSpecies(std::map<std::string, S32> &table,
  151. const char *control, S32 max)
  152. {
  153. const std::string& species = gSavedSettings.getString(control);
  154. std::map<std::string, S32>::iterator it;
  155. it = table.find(species);
  156. if (it != table.end())
  157. {
  158. return it->second;
  159. }
  160. // If saved species not found, default to "Random"
  161. return rand() % max;
  162. }
  163. bool LLToolPlacer::addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics)
  164. {
  165. LLVector3 ray_start_region;
  166. LLVector3 ray_end_region;
  167. LLViewerRegion* regionp = NULL;
  168. bool b_hit_land = false;
  169. S32 hit_face = -1;
  170. LLViewerObject* hit_obj = NULL;
  171. U8 state = 0;
  172. bool success = raycastForNewObjPos(x, y, &hit_obj, &hit_face, &b_hit_land,
  173. &ray_start_region, &ray_end_region,
  174. &regionp);
  175. if (!success)
  176. {
  177. return false;
  178. }
  179. if (hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()))
  180. {
  181. // Cannot create objects on avatars or attachments
  182. return false;
  183. }
  184. if (!regionp)
  185. {
  186. llwarns << "Region was NULL, aborting." << llendl;
  187. return false;
  188. }
  189. if (regionp->getRegionFlag(REGION_FLAGS_SANDBOX))
  190. {
  191. LLFirstUse::useSandbox();
  192. }
  193. // Set params for new object based on its PCode.
  194. LLQuaternion rotation;
  195. LLVector3 scale = DEFAULT_OBJECT_SCALE;
  196. U8 material = LL_MCODE_WOOD;
  197. bool create_selected = false;
  198. LLVolumeParams volume_params;
  199. switch (pcode)
  200. {
  201. case LL_PCODE_LEGACY_GRASS:
  202. // Randomize size of grass patch
  203. scale.set(10.f + ll_frand(20.f),
  204. 10.f + ll_frand(20.f),
  205. 1.f + ll_frand(2.f));
  206. state = getTreeGrassSpecies(LLVOGrass::sSpeciesNames,
  207. "LastGrass",
  208. LLVOGrass::sMaxGrassSpecies);
  209. break;
  210. case LL_PCODE_LEGACY_TREE:
  211. state = getTreeGrassSpecies(LLVOTree::sSpeciesNames,
  212. "LastTree",
  213. LLVOTree::sMaxTreeSpecies);
  214. break;
  215. case LL_PCODE_SPHERE:
  216. case LL_PCODE_CONE:
  217. case LL_PCODE_CUBE:
  218. case LL_PCODE_CYLINDER:
  219. case LL_PCODE_TORUS:
  220. case LLViewerObject::LL_VO_SQUARE_TORUS:
  221. case LLViewerObject::LL_VO_TRIANGLE_TORUS:
  222. default:
  223. create_selected = true;
  224. break;
  225. }
  226. // Play creation sound
  227. if (gAudiop)
  228. {
  229. gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndObjectCreate")),
  230. gAgentID, 1.f, LLAudioEngine::AUDIO_TYPE_UI);
  231. }
  232. LLMessageSystem* msg = gMessageSystemp;
  233. msg->newMessageFast(_PREHASH_ObjectAdd);
  234. msg->nextBlockFast(_PREHASH_AgentData);
  235. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  236. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  237. LLUUID group_id = gAgent.getGroupID();
  238. LLParcel* parcel = gViewerParcelMgr.getAgentParcel();
  239. if (gSavedSettings.getBool("RezWithLandGroup"))
  240. {
  241. if (gAgent.isInGroup(parcel->getGroupID()))
  242. {
  243. group_id = parcel->getGroupID();
  244. }
  245. else if (gAgent.isInGroup(parcel->getOwnerID()))
  246. {
  247. group_id = parcel->getOwnerID();
  248. }
  249. }
  250. else if (gAgent.hasPowerInGroup(parcel->getGroupID(),
  251. GP_LAND_ALLOW_CREATE) &&
  252. !parcel->getIsGroupOwned())
  253. {
  254. group_id = parcel->getGroupID();
  255. }
  256. msg->addUUIDFast(_PREHASH_GroupID, group_id);
  257. msg->nextBlockFast(_PREHASH_ObjectData);
  258. msg->addU8Fast(_PREHASH_Material, material);
  259. U32 flags = 0; // not selected
  260. if (use_physics)
  261. {
  262. flags |= FLAGS_USE_PHYSICS;
  263. }
  264. if (create_selected)
  265. {
  266. flags |= FLAGS_CREATE_SELECTED;
  267. }
  268. msg->addU32Fast(_PREHASH_AddFlags, flags);
  269. LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error
  270. switch (pcode)
  271. {
  272. case LL_PCODE_SPHERE:
  273. rotation.setAngleAxis(90.f * DEG_TO_RAD, LLVector3::y_axis);
  274. volume_params.setType(LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE);
  275. volume_params.setBeginAndEndS(0.f, 1.f);
  276. volume_params.setBeginAndEndT(0.f, 1.f);
  277. volume_params.setRatio(1.f, 1.f);
  278. volume_params.setShear(0.f, 0.f);
  279. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  280. volume_pcode = LL_PCODE_VOLUME;
  281. break;
  282. case LL_PCODE_TORUS:
  283. rotation.setAngleAxis(90.f * DEG_TO_RAD, LLVector3::y_axis);
  284. volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE);
  285. volume_params.setBeginAndEndS(0.f, 1.f);
  286. volume_params.setBeginAndEndT(0.f, 1.f);
  287. volume_params.setRatio(1.f, 0.25f); // "top size"
  288. volume_params.setShear(0.f, 0.f);
  289. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  290. volume_pcode = LL_PCODE_VOLUME;
  291. break;
  292. case LLViewerObject::LL_VO_SQUARE_TORUS:
  293. rotation.setAngleAxis(90.f * DEG_TO_RAD, LLVector3::y_axis);
  294. volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE);
  295. volume_params.setBeginAndEndS(0.f, 1.f);
  296. volume_params.setBeginAndEndT(0.f, 1.f);
  297. volume_params.setRatio(1.f, 0.25f); // "top size"
  298. volume_params.setShear(0.f, 0.f);
  299. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  300. volume_pcode = LL_PCODE_VOLUME;
  301. break;
  302. case LLViewerObject::LL_VO_TRIANGLE_TORUS:
  303. rotation.setAngleAxis(90.f * DEG_TO_RAD, LLVector3::y_axis);
  304. volume_params.setType(LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE);
  305. volume_params.setBeginAndEndS(0.f, 1.f);
  306. volume_params.setBeginAndEndT(0.f, 1.f);
  307. volume_params.setRatio(1.f, 0.25f); // "top size"
  308. volume_params.setShear(0.f, 0.f);
  309. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  310. volume_pcode = LL_PCODE_VOLUME;
  311. break;
  312. case LL_PCODE_SPHERE_HEMI:
  313. volume_params.setType(LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE);
  314. //volume_params.setBeginAndEndS(0.5f, 1.f);
  315. volume_params.setBeginAndEndT(0.f, 0.5f);
  316. volume_params.setRatio(1.f, 1.f);
  317. volume_params.setShear(0.f, 0.f);
  318. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  319. volume_pcode = LL_PCODE_VOLUME;
  320. break;
  321. case LL_PCODE_CUBE:
  322. volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
  323. volume_params.setBeginAndEndS(0.f, 1.f);
  324. volume_params.setBeginAndEndT(0.f, 1.f);
  325. volume_params.setRatio(1.f, 1.f);
  326. volume_params.setShear(0.f, 0.f);
  327. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  328. volume_pcode = LL_PCODE_VOLUME;
  329. break;
  330. case LL_PCODE_PRISM:
  331. volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
  332. volume_params.setBeginAndEndS(0.f, 1.f);
  333. volume_params.setBeginAndEndT(0.f, 1.f);
  334. volume_params.setRatio(0.f, 1.f);
  335. volume_params.setShear(-0.5f, 0.f);
  336. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  337. volume_pcode = LL_PCODE_VOLUME;
  338. break;
  339. case LL_PCODE_PYRAMID:
  340. volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
  341. volume_params.setBeginAndEndS(0.f, 1.f);
  342. volume_params.setBeginAndEndT(0.f, 1.f);
  343. volume_params.setRatio(0.f, 0.f);
  344. volume_params.setShear(0.f, 0.f);
  345. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  346. volume_pcode = LL_PCODE_VOLUME;
  347. break;
  348. case LL_PCODE_TETRAHEDRON:
  349. volume_params.setType(LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE);
  350. volume_params.setBeginAndEndS(0.f, 1.f);
  351. volume_params.setBeginAndEndT(0.f, 1.f);
  352. volume_params.setRatio(0.f, 0.f);
  353. volume_params.setShear(0.f, 0.f);
  354. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  355. volume_pcode = LL_PCODE_VOLUME;
  356. break;
  357. case LL_PCODE_CYLINDER:
  358. volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE);
  359. volume_params.setBeginAndEndS(0.f, 1.f);
  360. volume_params.setBeginAndEndT(0.f, 1.f);
  361. volume_params.setRatio(1.f, 1.f);
  362. volume_params.setShear(0.f, 0.f);
  363. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  364. volume_pcode = LL_PCODE_VOLUME;
  365. break;
  366. case LL_PCODE_CYLINDER_HEMI:
  367. volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE);
  368. volume_params.setBeginAndEndS(0.25f, 0.75f);
  369. volume_params.setBeginAndEndT(0.f, 1.f);
  370. volume_params.setRatio(1.f, 1.f);
  371. volume_params.setShear(0.f, 0.f);
  372. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  373. volume_pcode = LL_PCODE_VOLUME;
  374. break;
  375. case LL_PCODE_CONE:
  376. volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE);
  377. volume_params.setBeginAndEndS(0.f, 1.f);
  378. volume_params.setBeginAndEndT(0.f, 1.f);
  379. volume_params.setRatio(0.f, 0.f);
  380. volume_params.setShear(0.f, 0.f);
  381. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  382. volume_pcode = LL_PCODE_VOLUME;
  383. break;
  384. case LL_PCODE_CONE_HEMI:
  385. volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE);
  386. volume_params.setBeginAndEndS(0.25f, 0.75f);
  387. volume_params.setBeginAndEndT(0.f, 1.f);
  388. volume_params.setRatio(0.f, 0.f);
  389. volume_params.setShear(0.f, 0.f);
  390. LLVolumeMessage::packVolumeParams(&volume_params, msg);
  391. volume_pcode = LL_PCODE_VOLUME;
  392. break;
  393. default:
  394. LLVolumeMessage::packVolumeParams(0, msg);
  395. volume_pcode = pcode;
  396. break;
  397. }
  398. msg->addU8Fast(_PREHASH_PCode, volume_pcode);
  399. msg->addVector3Fast(_PREHASH_Scale, scale);
  400. msg->addQuatFast(_PREHASH_Rotation, rotation);
  401. msg->addVector3Fast(_PREHASH_RayStart, ray_start_region);
  402. msg->addVector3Fast(_PREHASH_RayEnd, ray_end_region);
  403. msg->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land);
  404. msg->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)false);
  405. msg->addU8Fast(_PREHASH_State, state);
  406. // Limit raycast to a single object.
  407. // Speeds up server raycast + avoid problems with server ray hitting objects
  408. // that were clipped by the near plane or culled on the viewer.
  409. LLUUID ray_target_id;
  410. if (hit_obj)
  411. {
  412. ray_target_id = hit_obj->getID();
  413. }
  414. else
  415. {
  416. ray_target_id.setNull();
  417. }
  418. msg->addUUIDFast(_PREHASH_RayTargetID, ray_target_id);
  419. // Pack in name value pairs
  420. msg->sendReliable(regionp->getHost());
  421. // Spawns a message, so must be after above send
  422. if (create_selected)
  423. {
  424. gSelectMgr.deselectAll();
  425. gWindowp->incBusyCount();
  426. }
  427. // VEFFECT: AddObject
  428. LLHUDEffectSpiral::agentBeamToPosition(regionp->getPosGlobalFromRegion(ray_end_region));
  429. gViewerStats.incStat(LLViewerStats::ST_CREATE_COUNT);
  430. return true;
  431. }
  432. // Used by the placer tool to add copies of the current selection.
  433. bool LLToolPlacer::addDuplicate(S32 x, S32 y)
  434. {
  435. LLVector3 ray_start_region;
  436. LLVector3 ray_end_region;
  437. LLViewerRegion* regionp = NULL;
  438. bool b_hit_land = false;
  439. S32 hit_face = -1;
  440. LLViewerObject* hit_obj = NULL;
  441. bool success = raycastForNewObjPos(x, y, &hit_obj, &hit_face, &b_hit_land,
  442. &ray_start_region, &ray_end_region,
  443. &regionp);
  444. if (!success)
  445. {
  446. make_ui_sound("UISndInvalidOp");
  447. return false;
  448. }
  449. if (hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()))
  450. {
  451. // Can't create objects on avatars or attachments
  452. make_ui_sound("UISndInvalidOp");
  453. return false;
  454. }
  455. // Limit raycast to a single object.
  456. // Speeds up server raycast + avoid problems with server ray hitting objects
  457. // that were clipped by the near plane or culled on the viewer.
  458. LLUUID ray_target_id;
  459. if (hit_obj)
  460. {
  461. ray_target_id = hit_obj->getID();
  462. }
  463. else
  464. {
  465. ray_target_id.setNull();
  466. }
  467. gSelectMgr.selectDuplicateOnRay(ray_start_region, ray_end_region,
  468. b_hit_land, // Suppress raycast
  469. false, // Intersection
  470. ray_target_id,
  471. gSavedSettings.getBool("CreateToolCopyCenters"),
  472. gSavedSettings.getBool("CreateToolCopyRotates"),
  473. false); // Select copy
  474. if (regionp && regionp->getRegionFlag(REGION_FLAGS_SANDBOX))
  475. {
  476. LLFirstUse::useSandbox();
  477. }
  478. return true;
  479. }
  480. bool LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
  481. {
  482. bool added = true;
  483. //MK
  484. if (gRLenabled &&
  485. (gRLInterface.mContainsEdit || gRLInterface.mContainsRez ||
  486. gRLInterface.mContainsInteract))
  487. {
  488. return true;
  489. }
  490. //mk
  491. if (gSavedSettings.getBool("CreateToolCopySelection"))
  492. {
  493. added = addDuplicate(x, y);
  494. }
  495. else
  496. {
  497. added = addObject(sObjectType, x, y, false);
  498. }
  499. // ...and go back to the default tool
  500. if (added && !gSavedSettings.getBool("CreateToolKeepSelected"))
  501. {
  502. gToolMgr.getCurrentToolset()->selectTool(&gToolCompTranslate);
  503. }
  504. return added;
  505. }
  506. bool LLToolPlacer::handleHover(S32 x, S32 y, MASK mask)
  507. {
  508. LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL;
  509. gWindowp->setCursor(UI_CURSOR_TOOLCREATE);
  510. return true;
  511. }
  512. void LLToolPlacer::handleSelect()
  513. {
  514. if (gFloaterToolsp)
  515. {
  516. gFloaterToolsp->setStatusText("place");
  517. }
  518. }
  519. void LLToolPlacer::handleDeselect()
  520. {
  521. }
  522. //////////////////////////////////////////////////////
  523. // LLToolPlacerPanel
  524. // static
  525. LLPCode LLToolPlacerPanel::sCube = LL_PCODE_CUBE;
  526. LLPCode LLToolPlacerPanel::sPrism = LL_PCODE_PRISM;
  527. LLPCode LLToolPlacerPanel::sPyramid = LL_PCODE_PYRAMID;
  528. LLPCode LLToolPlacerPanel::sTetrahedron = LL_PCODE_TETRAHEDRON;
  529. LLPCode LLToolPlacerPanel::sCylinder = LL_PCODE_CYLINDER;
  530. LLPCode LLToolPlacerPanel::sCylinderHemi= LL_PCODE_CYLINDER_HEMI;
  531. LLPCode LLToolPlacerPanel::sCone = LL_PCODE_CONE;
  532. LLPCode LLToolPlacerPanel::sConeHemi = LL_PCODE_CONE_HEMI;
  533. LLPCode LLToolPlacerPanel::sTorus = LL_PCODE_TORUS;
  534. LLPCode LLToolPlacerPanel::sSquareTorus = LLViewerObject::LL_VO_SQUARE_TORUS;
  535. LLPCode LLToolPlacerPanel::sTriangleTorus =
  536. LLViewerObject::LL_VO_TRIANGLE_TORUS;
  537. LLPCode LLToolPlacerPanel::sSphere = LL_PCODE_SPHERE;
  538. LLPCode LLToolPlacerPanel::sSphereHemi = LL_PCODE_SPHERE_HEMI;
  539. LLPCode LLToolPlacerPanel::sTree = LL_PCODE_LEGACY_TREE;
  540. LLPCode LLToolPlacerPanel::sGrass = LL_PCODE_LEGACY_GRASS;
  541. S32 LLToolPlacerPanel::sButtonsAdded = 0;
  542. LLButton* LLToolPlacerPanel::sButtons[TOOL_PLACER_NUM_BUTTONS];
  543. LLToolPlacerPanel::LLToolPlacerPanel(const std::string& name,
  544. const LLRect& rect)
  545. : LLPanel(name, rect)
  546. {
  547. }
  548. void LLToolPlacerPanel::addButton(const std::string& up_state,
  549. const std::string& down_state,
  550. LLPCode* pcode)
  551. {
  552. constexpr S32 TOOL_SIZE = 32;
  553. constexpr S32 HORIZ_SPACING = TOOL_SIZE + 5;
  554. constexpr S32 VERT_SPACING = TOOL_SIZE + 5;
  555. constexpr S32 VPAD = 10;
  556. constexpr S32 HPAD = 7;
  557. S32 row = sButtonsAdded / 4;
  558. S32 column = sButtonsAdded % 4;
  559. LLRect help_rect = gSavedSettings.getRect("ToolHelpRect");
  560. // Build the rectangle, recalling the origin is at lower left and we want
  561. // the icons to build down from the top.
  562. LLRect rect;
  563. rect.setLeftTopAndSize(HPAD + column * HORIZ_SPACING,
  564. help_rect.mBottom - VPAD - row * VERT_SPACING,
  565. TOOL_SIZE, TOOL_SIZE);
  566. LLButton* btn = new LLButton("ToolPlacerOptBtn", rect,
  567. up_state, down_state, NULL,
  568. &LLToolPlacerPanel::setObjectType, pcode,
  569. LLFontGL::getFontSansSerif());
  570. btn->setFollowsBottom();
  571. btn->setFollowsLeft();
  572. addChild(btn);
  573. sButtons[sButtonsAdded++] = btn;
  574. }
  575. //static
  576. void LLToolPlacerPanel::setObjectType(void* data)
  577. {
  578. LLPCode pcode = *(LLPCode*) data;
  579. LLToolPlacer::setObjectType(pcode);
  580. }