aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltoolplacer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/lltoolplacer.cpp380
1 files changed, 375 insertions, 5 deletions
diff --git a/linden/indra/newview/lltoolplacer.cpp b/linden/indra/newview/lltoolplacer.cpp
index ee5d08f..d26bdab 100644
--- a/linden/indra/newview/lltoolplacer.cpp
+++ b/linden/indra/newview/lltoolplacer.cpp
@@ -50,9 +50,22 @@
50#include "llviewerregion.h" 50#include "llviewerregion.h"
51#include "llviewerwindow.h" 51#include "llviewerwindow.h"
52#include "llworld.h" 52#include "llworld.h"
53#include "viewer.h"
54#include "llui.h" 53#include "llui.h"
55 54
55//Headers added for functions moved from viewer.cpp
56#include "llvograss.h"
57#include "llvotree.h"
58#include "llvolumemessage.h"
59#include "llhudmanager.h"
60#include "llagent.h"
61#include "audioengine.h"
62#include "llhudeffecttrail.h"
63#include "llviewerobjectlist.h"
64#include "llviewercamera.h"
65#include "llviewerstats.h"
66
67const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f);
68
56//static 69//static
57LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; 70LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE;
58 71
@@ -61,9 +74,366 @@ LLToolPlacer::LLToolPlacer()
61{ 74{
62} 75}
63 76
77BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face,
78 BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region )
79{
80 F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f;
81
82 // Viewer-side pick to find the right sim to create the object on.
83 // First find the surface the object will be created on.
84 gViewerWindow->hitObjectOrLandGlobalImmediate(x, y, NULL, FALSE);
85
86 // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok
87 // representations (if any) are NOT the same as their viewer representation.
88 *hit_obj = gObjectList.findObject( gLastHitNonFloraObjectID );
89 *hit_face = gLastHitNonFloraObjectFace;
90 *b_hit_land = !(*hit_obj) && !gLastHitNonFloraPosGlobal.isExactlyZero();
91 LLVector3d land_pos_global = gLastHitNonFloraPosGlobal;
92
93 // Make sure there's a surface to place the new object on.
94 BOOL bypass_sim_raycast = FALSE;
95 LLVector3d surface_pos_global;
96 if (*b_hit_land)
97 {
98 surface_pos_global = land_pos_global;
99 bypass_sim_raycast = TRUE;
100 }
101 else
102 if (*hit_obj)
103 {
104 surface_pos_global = (*hit_obj)->getPositionGlobal();
105 }
106 else
107 {
108 return FALSE;
109 }
110
111 // Make sure the surface isn't too far away.
112 LLVector3d ray_start_global = gAgent.getCameraPositionGlobal();
113 F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared());
114 if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) )
115 {
116 return FALSE;
117 }
118
119 // Find the sim where the surface lives.
120 LLViewerRegion *regionp = gWorldp->getRegionFromPosGlobal(surface_pos_global);
121 if (!regionp)
122 {
123 llwarns << "Trying to add object outside of all known regions!" << llendl;
124 return FALSE;
125 }
126
127 // Find the simulator-side ray that will be used to place the object accurately
128 LLVector3d mouse_direction;
129 mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) );
130
131 *region = regionp;
132 *ray_start_region = regionp->getPosRegionFromGlobal( ray_start_global );
133 F32 near_clip = gCamera->getNear() + 0.01f; // Include an epsilon to avoid rounding issues.
134 *ray_start_region += gCamera->getAtAxis() * near_clip;
135
136 if( bypass_sim_raycast )
137 {
138 // Hack to work around Havok's inability to ray cast onto height fields
139 *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global ); // ray end is the viewer's intersection point
140 }
141 else
142 {
143 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.
144 *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global );
145 }
146
147 return TRUE;
148}
149
150
151BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
152{
153 LLVector3 ray_start_region;
154 LLVector3 ray_end_region;
155 LLViewerRegion* regionp = NULL;
156 BOOL b_hit_land = FALSE;
157 S32 hit_face = -1;
158 LLViewerObject* hit_obj = NULL;
159 U8 state = 0;
160 BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
161 if( !success )
162 {
163 return FALSE;
164 }
165
166 if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
167 {
168 // Can't create objects on avatars or attachments
169 return FALSE;
170 }
171
172 if (NULL == regionp)
173 {
174 llwarns << "regionp was NULL; aborting function." << llendl;
175 return FALSE;
176 }
177
178 if (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX)
179 {
180 LLFirstUse::useSandbox();
181 }
182
183 // Set params for new object based on its PCode.
184 LLQuaternion rotation;
185 LLVector3 scale = DEFAULT_OBJECT_SCALE;
186 U8 material = LL_MCODE_WOOD;
187 BOOL create_selected = FALSE;
188 LLVolumeParams volume_params;
189
190 switch (pcode)
191 {
192 case LL_PCODE_LEGACY_GRASS:
193 // Randomize size of grass patch
194 scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f));
195 state = rand() % LLVOGrass::sMaxGrassSpecies;
196 break;
197
198
199 case LL_PCODE_LEGACY_TREE:
200 case LL_PCODE_TREE_NEW:
201 state = rand() % LLVOTree::sMaxTreeSpecies;
202 break;
203
204 case LL_PCODE_SPHERE:
205 case LL_PCODE_CONE:
206 case LL_PCODE_CUBE:
207 case LL_PCODE_CYLINDER:
208 case LL_PCODE_TORUS:
209 case LLViewerObject::LL_VO_SQUARE_TORUS:
210 case LLViewerObject::LL_VO_TRIANGLE_TORUS:
211 default:
212 create_selected = TRUE;
213 break;
214 }
215
216 // Play creation sound
217 if (gAudiop)
218 {
219 F32 volume = gSavedSettings.getF32("AudioLevelUI");
220 gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), gAgent.getID(), volume);
221 }
222
223 gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
224 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
225 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
226 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
227 gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
228 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
229 gMessageSystem->addU8Fast(_PREHASH_Material, material);
230
231 U32 flags = 0; // not selected
232 if (use_physics)
233 {
234 flags |= FLAGS_USE_PHYSICS;
235 }
236 if (create_selected)
237 {
238 flags |= FLAGS_CREATE_SELECTED;
239 }
240 gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags );
241
242 LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error
243 switch (pcode)
244 {
245 case LL_PCODE_SPHERE:
246 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
247
248 volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
249 volume_params.setBeginAndEndS( 0.f, 1.f );
250 volume_params.setBeginAndEndT( 0.f, 1.f );
251 volume_params.setRatio ( 1, 1 );
252 volume_params.setShear ( 0, 0 );
253 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
254 volume_pcode = LL_PCODE_VOLUME;
255 break;
256
257 case LL_PCODE_TORUS:
258 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
259
260 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE );
261 volume_params.setBeginAndEndS( 0.f, 1.f );
262 volume_params.setBeginAndEndT( 0.f, 1.f );
263 volume_params.setRatio ( 1.f, 0.25f ); // "top size"
264 volume_params.setShear ( 0, 0 );
265 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
266 volume_pcode = LL_PCODE_VOLUME;
267 break;
268
269 case LLViewerObject::LL_VO_SQUARE_TORUS:
270 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
271
272 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE );
273 volume_params.setBeginAndEndS( 0.f, 1.f );
274 volume_params.setBeginAndEndT( 0.f, 1.f );
275 volume_params.setRatio ( 1.f, 0.25f ); // "top size"
276 volume_params.setShear ( 0, 0 );
277 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
278 volume_pcode = LL_PCODE_VOLUME;
279 break;
280
281 case LLViewerObject::LL_VO_TRIANGLE_TORUS:
282 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
283
284 volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, 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, 0 );
289 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
290 volume_pcode = LL_PCODE_VOLUME;
291 break;
292
293 case LL_PCODE_SPHERE_HEMI:
294 volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
295 //volume_params.setBeginAndEndS( 0.5f, 1.f );
296 volume_params.setBeginAndEndT( 0.f, 0.5f );
297 volume_params.setRatio ( 1, 1 );
298 volume_params.setShear ( 0, 0 );
299 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
300 volume_pcode = LL_PCODE_VOLUME;
301 break;
302
303 case LL_PCODE_CUBE:
304 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
305 volume_params.setBeginAndEndS( 0.f, 1.f );
306 volume_params.setBeginAndEndT( 0.f, 1.f );
307 volume_params.setRatio ( 1, 1 );
308 volume_params.setShear ( 0, 0 );
309 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
310 volume_pcode = LL_PCODE_VOLUME;
311 break;
312
313 case LL_PCODE_PRISM:
314 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
315 volume_params.setBeginAndEndS( 0.f, 1.f );
316 volume_params.setBeginAndEndT( 0.f, 1.f );
317 volume_params.setRatio ( 0, 1 );
318 volume_params.setShear ( -0.5f, 0 );
319 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
320 volume_pcode = LL_PCODE_VOLUME;
321 break;
322
323 case LL_PCODE_PYRAMID:
324 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
325 volume_params.setBeginAndEndS( 0.f, 1.f );
326 volume_params.setBeginAndEndT( 0.f, 1.f );
327 volume_params.setRatio ( 0, 0 );
328 volume_params.setShear ( 0, 0 );
329 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
330 volume_pcode = LL_PCODE_VOLUME;
331 break;
332
333 case LL_PCODE_TETRAHEDRON:
334 volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE );
335 volume_params.setBeginAndEndS( 0.f, 1.f );
336 volume_params.setBeginAndEndT( 0.f, 1.f );
337 volume_params.setRatio ( 0, 0 );
338 volume_params.setShear ( 0, 0 );
339 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
340 volume_pcode = LL_PCODE_VOLUME;
341 break;
342
343 case LL_PCODE_CYLINDER:
344 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
345 volume_params.setBeginAndEndS( 0.f, 1.f );
346 volume_params.setBeginAndEndT( 0.f, 1.f );
347 volume_params.setRatio ( 1, 1 );
348 volume_params.setShear ( 0, 0 );
349 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
350 volume_pcode = LL_PCODE_VOLUME;
351 break;
352
353 case LL_PCODE_CYLINDER_HEMI:
354 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
355 volume_params.setBeginAndEndS( 0.25f, 0.75f );
356 volume_params.setBeginAndEndT( 0.f, 1.f );
357 volume_params.setRatio ( 1, 1 );
358 volume_params.setShear ( 0, 0 );
359 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
360 volume_pcode = LL_PCODE_VOLUME;
361 break;
362
363 case LL_PCODE_CONE:
364 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
365 volume_params.setBeginAndEndS( 0.f, 1.f );
366 volume_params.setBeginAndEndT( 0.f, 1.f );
367 volume_params.setRatio ( 0, 0 );
368 volume_params.setShear ( 0, 0 );
369 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
370 volume_pcode = LL_PCODE_VOLUME;
371 break;
372
373 case LL_PCODE_CONE_HEMI:
374 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
375 volume_params.setBeginAndEndS( 0.25f, 0.75f );
376 volume_params.setBeginAndEndT( 0.f, 1.f );
377 volume_params.setRatio ( 0, 0 );
378 volume_params.setShear ( 0, 0 );
379 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
380 volume_pcode = LL_PCODE_VOLUME;
381 break;
382
383 default:
384 LLVolumeMessage::packVolumeParams(0, gMessageSystem);
385 volume_pcode = pcode;
386 break;
387 }
388 gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode);
389
390 gMessageSystem->addVector3Fast(_PREHASH_Scale, scale );
391 gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation );
392 gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region );
393 gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region );
394 gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land );
395 gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE );
396 gMessageSystem->addU8Fast(_PREHASH_State, state);
397
398 // Limit raycast to a single object.
399 // Speeds up server raycast + avoid problems with server ray hitting objects
400 // that were clipped by the near plane or culled on the viewer.
401 LLUUID ray_target_id;
402 if( hit_obj )
403 {
404 ray_target_id = hit_obj->getID();
405 }
406 else
407 {
408 ray_target_id.setNull();
409 }
410 gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id );
411
412 // Pack in name value pairs
413 gMessageSystem->sendReliable(regionp->getHost());
414
415 // Spawns a message, so must be after above send
416 if (create_selected)
417 {
418 gSelectMgr->deselectAll();
419 gViewerWindow->getWindow()->incBusyCount();
420 }
421
422 // VEFFECT: AddObject
423 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
424 effectp->setSourceObject((LLViewerObject*)gAgent.getAvatarObject());
425 effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region));
426 effectp->setDuration(LL_HUD_DUR_SHORT);
427 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
428
429 gViewerStats->incStat(LLViewerStats::ST_CREATE_COUNT);
430
431 return TRUE;
432}
433
64// Used by the placer tool to add copies of the current selection. 434// Used by the placer tool to add copies of the current selection.
65// Inspired by add_object(). JC 435// Inspired by add_object(). JC
66BOOL add_duplicate(S32 x, S32 y) 436BOOL LLToolPlacer::addDuplicate(S32 x, S32 y)
67{ 437{
68 LLVector3 ray_start_region; 438 LLVector3 ray_start_region;
69 LLVector3 ray_end_region; 439 LLVector3 ray_end_region;
@@ -71,7 +441,7 @@ BOOL add_duplicate(S32 x, S32 y)
71 BOOL b_hit_land = FALSE; 441 BOOL b_hit_land = FALSE;
72 S32 hit_face = -1; 442 S32 hit_face = -1;
73 LLViewerObject* hit_obj = NULL; 443 LLViewerObject* hit_obj = NULL;
74 BOOL success = raycast_for_new_obj_pos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp ); 444 BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
75 if( !success ) 445 if( !success )
76 { 446 {
77 make_ui_sound("UISndInvalidOp"); 447 make_ui_sound("UISndInvalidOp");
@@ -123,11 +493,11 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
123 493
124 if (gSavedSettings.getBOOL("CreateToolCopySelection")) 494 if (gSavedSettings.getBOOL("CreateToolCopySelection"))
125 { 495 {
126 added = add_duplicate(x, y); 496 added = addDuplicate(x, y);
127 } 497 }
128 else 498 else
129 { 499 {
130 added = add_object( sObjectType, x, y, NO_PHYSICS ); 500 added = addObject( sObjectType, x, y, FALSE );
131 } 501 }
132 502
133 // ...and go back to the default tool 503 // ...and go back to the default tool