PageRenderTime 79ms CodeModel.GetById 14ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/lltoolplacer.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 534 lines | 403 code | 71 blank | 60 comment | 33 complexity | 6617eedd05afa4e20075c694ba3b2406 MD5 | raw file
  1/** 
  2 * @file lltoolplacer.cpp
  3 * @brief Tool for placing new objects into the world
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28
 29// self header
 30#include "lltoolplacer.h"
 31
 32// viewer headers
 33#include "llbutton.h"
 34#include "llviewercontrol.h"
 35//#include "llfirstuse.h"
 36#include "llfloatertools.h"
 37#include "llselectmgr.h"
 38#include "llstatusbar.h"
 39#include "lltoolcomp.h"
 40#include "lltoolmgr.h"
 41#include "llviewerobject.h"
 42#include "llviewerregion.h"
 43#include "llviewerwindow.h"
 44#include "llworld.h"
 45#include "llui.h"
 46
 47//Headers added for functions moved from viewer.cpp
 48#include "llvograss.h"
 49#include "llvotree.h"
 50#include "llvolumemessage.h"
 51#include "llhudmanager.h"
 52#include "llagent.h"
 53#include "llagentcamera.h"
 54#include "llaudioengine.h"
 55#include "llhudeffecttrail.h"
 56#include "llviewerobjectlist.h"
 57#include "llviewercamera.h"
 58#include "llviewerstats.h"
 59#include "llvoavatarself.h"
 60
 61// linden library headers
 62#include "llprimitive.h"
 63#include "llwindow.h"			// incBusyCount()
 64#include "material_codes.h"
 65
 66const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f);
 67
 68//static 
 69LLPCode	LLToolPlacer::sObjectType = LL_PCODE_CUBE;
 70
 71LLToolPlacer::LLToolPlacer()
 72:	LLTool( "Create" )
 73{
 74}
 75
 76BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, 
 77							 BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region )
 78{
 79	F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f;
 80
 81	// Viewer-side pick to find the right sim to create the object on.  
 82	// First find the surface the object will be created on.
 83	LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE);
 84	
 85	// Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok
 86	// representations (if any) are NOT the same as their viewer representation.
 87	if (pick.mPickType == LLPickInfo::PICK_FLORA)
 88	{
 89		*hit_obj = NULL;
 90		*hit_face = -1;
 91	}
 92	else
 93	{
 94		*hit_obj = pick.getObject();
 95		*hit_face = pick.mObjectFace;
 96	}
 97	*b_hit_land = !(*hit_obj) && !pick.mPosGlobal.isExactlyZero();
 98	LLVector3d land_pos_global = pick.mPosGlobal;
 99
100	// Make sure there's a surface to place the new object on.
101	BOOL bypass_sim_raycast = FALSE;
102	LLVector3d	surface_pos_global;
103	if (*b_hit_land)
104	{
105		surface_pos_global = land_pos_global; 
106		bypass_sim_raycast = TRUE;
107	}
108	else 
109	if (*hit_obj)
110	{
111		surface_pos_global = (*hit_obj)->getPositionGlobal();
112	}
113	else
114	{
115		return FALSE;
116	}
117
118	// Make sure the surface isn't too far away.
119	LLVector3d ray_start_global = gAgentCamera.getCameraPositionGlobal();
120	F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared());
121	if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) )
122	{
123		return FALSE;
124	}
125
126	// Find the sim where the surface lives.
127	LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global);
128	if (!regionp)
129	{
130		llwarns << "Trying to add object outside of all known regions!" << llendl;
131		return FALSE;
132	}
133
134	// Find the simulator-side ray that will be used to place the object accurately
135	LLVector3d		mouse_direction;
136	mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) );
137
138	*region = regionp;
139	*ray_start_region =	regionp->getPosRegionFromGlobal( ray_start_global );
140	F32 near_clip = LLViewerCamera::getInstance()->getNear() + 0.01f;  // Include an epsilon to avoid rounding issues.
141	*ray_start_region += LLViewerCamera::getInstance()->getAtAxis() * near_clip;
142
143	if( bypass_sim_raycast )
144	{
145		// Hack to work around Havok's inability to ray cast onto height fields
146		*ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global );  // ray end is the viewer's intersection point
147	}
148	else
149	{
150		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.
151		*ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global );
152	}
153
154	return TRUE;
155}
156
157
158BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
159{
160	LLVector3 ray_start_region;
161	LLVector3 ray_end_region;
162	LLViewerRegion* regionp = NULL;
163	BOOL b_hit_land = FALSE;
164	S32 hit_face = -1;
165	LLViewerObject* hit_obj = NULL;
166	U8 state = 0;
167	BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
168	if( !success )
169	{
170		return FALSE;
171	}
172
173	if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
174	{
175		// Can't create objects on avatars or attachments
176		return FALSE;
177	}
178
179	if (NULL == regionp)
180	{
181		llwarns << "regionp was NULL; aborting function." << llendl;
182		return FALSE;
183	}
184
185	if (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX)
186	{
187		//LLFirstUse::useSandbox();
188	}
189
190	// Set params for new object based on its PCode.
191	LLQuaternion	rotation;
192	LLVector3		scale = DEFAULT_OBJECT_SCALE;
193	U8				material = LL_MCODE_WOOD;
194	BOOL			create_selected = FALSE;
195	LLVolumeParams	volume_params;
196	
197	switch (pcode) 
198	{
199	case LL_PCODE_LEGACY_GRASS:
200		//  Randomize size of grass patch 
201		scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f),  1.f + ll_frand(2.f));
202		state = rand() % LLVOGrass::sMaxGrassSpecies;
203		break;
204
205
206	case LL_PCODE_LEGACY_TREE:
207	case LL_PCODE_TREE_NEW:
208		state = rand() % LLVOTree::sMaxTreeSpecies;
209		break;
210
211	case LL_PCODE_SPHERE:
212	case LL_PCODE_CONE:
213	case LL_PCODE_CUBE:
214	case LL_PCODE_CYLINDER:
215	case LL_PCODE_TORUS:
216	case LLViewerObject::LL_VO_SQUARE_TORUS:
217	case LLViewerObject::LL_VO_TRIANGLE_TORUS:
218	default:
219		create_selected = TRUE;
220		break;
221	}
222
223	// Play creation sound
224	if (gAudiop)
225	{
226		gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")),
227							   gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
228	}
229
230	gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
231	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
232	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
233	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
234	gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
235	gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
236	gMessageSystem->addU8Fast(_PREHASH_Material,	material);
237
238	U32 flags = 0;		// not selected
239	if (use_physics)
240	{
241		flags |= FLAGS_USE_PHYSICS;
242	}
243	if (create_selected)
244	{
245		flags |= FLAGS_CREATE_SELECTED;
246	}
247	gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags );
248
249	LLPCode volume_pcode;	// ...PCODE_VOLUME, or the original on error
250	switch (pcode)
251	{
252	case LL_PCODE_SPHERE:
253		rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
254
255		volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
256		volume_params.setBeginAndEndS( 0.f, 1.f );
257		volume_params.setBeginAndEndT( 0.f, 1.f );
258		volume_params.setRatio	( 1, 1 );
259		volume_params.setShear	( 0, 0 );
260		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
261		volume_pcode = LL_PCODE_VOLUME;
262		break;
263
264	case LL_PCODE_TORUS:
265		rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
266
267		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE );
268		volume_params.setBeginAndEndS( 0.f, 1.f );
269		volume_params.setBeginAndEndT( 0.f, 1.f );
270		volume_params.setRatio	( 1.f, 0.25f );	// "top size"
271		volume_params.setShear	( 0, 0 );
272		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
273		volume_pcode = LL_PCODE_VOLUME;
274		break;
275
276	case LLViewerObject::LL_VO_SQUARE_TORUS:
277		rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
278
279		volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE );
280		volume_params.setBeginAndEndS( 0.f, 1.f );
281		volume_params.setBeginAndEndT( 0.f, 1.f );
282		volume_params.setRatio	( 1.f, 0.25f );	// "top size"
283		volume_params.setShear	( 0, 0 );
284		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
285		volume_pcode = LL_PCODE_VOLUME;
286		break;
287
288	case LLViewerObject::LL_VO_TRIANGLE_TORUS:
289		rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
290
291		volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE );
292		volume_params.setBeginAndEndS( 0.f, 1.f );
293		volume_params.setBeginAndEndT( 0.f, 1.f );
294		volume_params.setRatio	( 1.f, 0.25f );	// "top size"
295		volume_params.setShear	( 0, 0 );
296		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
297		volume_pcode = LL_PCODE_VOLUME;
298		break;
299
300	case LL_PCODE_SPHERE_HEMI:
301		volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
302		//volume_params.setBeginAndEndS( 0.5f, 1.f );
303		volume_params.setBeginAndEndT( 0.f, 0.5f );
304		volume_params.setRatio	( 1, 1 );
305		volume_params.setShear	( 0, 0 );
306		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
307		volume_pcode = LL_PCODE_VOLUME;
308		break;
309
310	case LL_PCODE_CUBE:
311		volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
312		volume_params.setBeginAndEndS( 0.f, 1.f );
313		volume_params.setBeginAndEndT( 0.f, 1.f );
314		volume_params.setRatio	( 1, 1 );
315		volume_params.setShear	( 0, 0 );
316		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
317		volume_pcode = LL_PCODE_VOLUME;
318		break;
319
320	case LL_PCODE_PRISM:
321		volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
322		volume_params.setBeginAndEndS( 0.f, 1.f );
323		volume_params.setBeginAndEndT( 0.f, 1.f );
324		volume_params.setRatio	( 0, 1 );
325		volume_params.setShear	( -0.5f, 0 );
326		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
327		volume_pcode = LL_PCODE_VOLUME;
328		break;
329
330	case LL_PCODE_PYRAMID:
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, 0 );
335		volume_params.setShear	( 0, 0 );
336		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
337		volume_pcode = LL_PCODE_VOLUME;
338		break;
339
340	case LL_PCODE_TETRAHEDRON:
341		volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE );
342		volume_params.setBeginAndEndS( 0.f, 1.f );
343		volume_params.setBeginAndEndT( 0.f, 1.f );
344		volume_params.setRatio	( 0, 0 );
345		volume_params.setShear	( 0, 0 );
346		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
347		volume_pcode = LL_PCODE_VOLUME;
348		break;
349
350	case LL_PCODE_CYLINDER:
351		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
352		volume_params.setBeginAndEndS( 0.f, 1.f );
353		volume_params.setBeginAndEndT( 0.f, 1.f );
354		volume_params.setRatio	( 1, 1 );
355		volume_params.setShear	( 0, 0 );
356		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
357		volume_pcode = LL_PCODE_VOLUME;
358		break;
359
360	case LL_PCODE_CYLINDER_HEMI:
361		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
362		volume_params.setBeginAndEndS( 0.25f, 0.75f );
363		volume_params.setBeginAndEndT( 0.f, 1.f );
364		volume_params.setRatio	( 1, 1 );
365		volume_params.setShear	( 0, 0 );
366		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
367		volume_pcode = LL_PCODE_VOLUME;
368		break;
369
370	case LL_PCODE_CONE:
371		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
372		volume_params.setBeginAndEndS( 0.f, 1.f );
373		volume_params.setBeginAndEndT( 0.f, 1.f );
374		volume_params.setRatio	( 0, 0 );
375		volume_params.setShear	( 0, 0 );
376		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
377		volume_pcode = LL_PCODE_VOLUME;
378		break;
379
380	case LL_PCODE_CONE_HEMI:
381		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
382		volume_params.setBeginAndEndS( 0.25f, 0.75f );
383		volume_params.setBeginAndEndT( 0.f, 1.f );
384		volume_params.setRatio	( 0, 0 );
385		volume_params.setShear	( 0, 0 );
386		LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
387		volume_pcode = LL_PCODE_VOLUME;
388		break;
389
390	default:
391		LLVolumeMessage::packVolumeParams(0, gMessageSystem);
392		volume_pcode = pcode;
393		break;
394	}
395	gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode);
396
397	gMessageSystem->addVector3Fast(_PREHASH_Scale,			scale );
398	gMessageSystem->addQuatFast(_PREHASH_Rotation,			rotation );
399	gMessageSystem->addVector3Fast(_PREHASH_RayStart,		ray_start_region );
400	gMessageSystem->addVector3Fast(_PREHASH_RayEnd,			ray_end_region );
401	gMessageSystem->addU8Fast(_PREHASH_BypassRaycast,		(U8)b_hit_land );
402	gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE );
403	gMessageSystem->addU8Fast(_PREHASH_State, state);
404
405	// Limit raycast to a single object.  
406	// Speeds up server raycast + avoid problems with server ray hitting objects
407	// that were clipped by the near plane or culled on the viewer.
408	LLUUID ray_target_id;
409	if( hit_obj )
410	{
411		ray_target_id = hit_obj->getID();
412	}
413	else
414	{
415		ray_target_id.setNull();
416	}
417	gMessageSystem->addUUIDFast(_PREHASH_RayTargetID,			ray_target_id );
418	
419	// Pack in name value pairs
420	gMessageSystem->sendReliable(regionp->getHost());
421
422	// Spawns a message, so must be after above send
423	if (create_selected)
424	{
425		LLSelectMgr::getInstance()->deselectAll();
426		gViewerWindow->getWindow()->incBusyCount();
427	}
428
429	// VEFFECT: AddObject
430	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
431	effectp->setSourceObject((LLViewerObject*)gAgentAvatarp);
432	effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region));
433	effectp->setDuration(LL_HUD_DUR_SHORT);
434	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
435
436	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CREATE_COUNT);
437
438	return TRUE;
439}
440
441// Used by the placer tool to add copies of the current selection.
442// Inspired by add_object().  JC
443BOOL LLToolPlacer::addDuplicate(S32 x, S32 y)
444{
445	LLVector3 ray_start_region;
446	LLVector3 ray_end_region;
447	LLViewerRegion* regionp = NULL;
448	BOOL b_hit_land = FALSE;
449	S32 hit_face = -1;
450	LLViewerObject* hit_obj = NULL;
451	BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
452	if( !success )
453	{
454		make_ui_sound("UISndInvalidOp");
455		return FALSE;
456	}
457	if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
458	{
459		// Can't create objects on avatars or attachments
460		make_ui_sound("UISndInvalidOp");
461		return FALSE;
462	}
463
464
465	// Limit raycast to a single object.  
466	// Speeds up server raycast + avoid problems with server ray hitting objects
467	// that were clipped by the near plane or culled on the viewer.
468	LLUUID ray_target_id;
469	if( hit_obj )
470	{
471		ray_target_id = hit_obj->getID();
472	}
473	else
474	{
475		ray_target_id.setNull();
476	}
477
478	LLSelectMgr::getInstance()->selectDuplicateOnRay(ray_start_region,
479										ray_end_region,
480										b_hit_land,			// suppress raycast
481										FALSE,				// intersection
482										ray_target_id,
483										gSavedSettings.getBOOL("CreateToolCopyCenters"),
484										gSavedSettings.getBOOL("CreateToolCopyRotates"),
485										FALSE);				// select copy
486
487	if (regionp
488		&& (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
489	{
490		//LLFirstUse::useSandbox();
491	}
492
493	return TRUE;
494}
495
496
497BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
498{
499	BOOL added = TRUE;
500	
501	if (gSavedSettings.getBOOL("CreateToolCopySelection"))
502	{
503		added = addDuplicate(x, y);
504	}
505	else
506	{
507		added = addObject( sObjectType, x, y, FALSE );
508	}
509
510	// ...and go back to the default tool
511	if (added && !gSavedSettings.getBOOL("CreateToolKeepSelected"))
512	{
513		LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() );
514	}
515
516	return added;
517}
518
519BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask)
520{
521	lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPlacer" << llendl;		
522	gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE);
523	return TRUE;
524}
525
526void LLToolPlacer::handleSelect()
527{
528	gFloaterTools->setStatusText("place");
529}
530
531void LLToolPlacer::handleDeselect()
532{
533}
534