PageRenderTime 189ms CodeModel.GetById 40ms app.highlight 104ms RepoModel.GetById 37ms app.codeStats 0ms

/indra/newview/llviewerpartsource.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 865 lines | 655 code | 143 blank | 67 comment | 89 complexity | 90516a456c26a0e9ede9a0acf2e989d8 MD5 | raw file
  1/** 
  2 * @file llviewerpartsource.cpp
  3 * @brief LLViewerPartSource class implementation
  4 *
  5 * $LicenseInfo:firstyear=2003&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#include "llviewerpartsource.h"
 29
 30#include "llviewercontrol.h"
 31#include "llrender.h"
 32
 33#include "llagent.h"
 34#include "lldrawable.h"
 35#include "llviewercamera.h"
 36#include "llviewertexturelist.h"
 37#include "llviewerobject.h"
 38#include "llviewerobjectlist.h"
 39#include "llvoavatar.h"
 40#include "llworld.h"
 41#include "pipeline.h"
 42
 43LLViewerPartSource::LLViewerPartSource(const U32 type) :
 44	mType(type),
 45	mOwnerUUID(LLUUID::null),
 46	mPartFlags(0)
 47{
 48	mLastUpdateTime = 0.f;
 49	mLastPartTime = 0.f;
 50	mIsDead = FALSE;
 51	mIsSuspended = FALSE;
 52	static U32 id_seed = 0;
 53	mID = ++id_seed;
 54
 55	mDelay = 0 ;
 56}
 57
 58void LLViewerPartSource::setDead()
 59{
 60	mIsDead = TRUE;
 61}
 62
 63
 64void LLViewerPartSource::updatePart(LLViewerPart &part, const F32 dt)
 65{
 66}
 67
 68void LLViewerPartSource::update(const F32 dt) 
 69{
 70	llerrs << "Creating default part source!" << llendl;
 71}
 72
 73LLUUID LLViewerPartSource::getImageUUID() const
 74{
 75	LLViewerTexture* imagep = mImagep;
 76	if(imagep)
 77	{
 78		return imagep->getID();
 79	}
 80	return LLUUID::null;
 81}
 82void LLViewerPartSource::setStart()
 83{
 84	//cancel delaying to start a new added particle source, because some particle source just emits for a short time.
 85	//however, canceling this might cause overall particle emmitting fluctuate for a while because the new added source jumps to 
 86	//the current particle emmitting settings instantly. -->bao
 87	mDelay = 0 ; //99
 88}
 89
 90LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp) :
 91	LLViewerPartSource(LL_PART_SOURCE_SCRIPT)
 92{
 93	LLMemType mt(LLMemType::MTYPE_PARTICLES);
 94	llassert(source_objp);
 95	mSourceObjectp = source_objp;
 96	mPosAgent = mSourceObjectp->getPositionAgent();
 97	mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
 98	
 99	mImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
100}
101
102
103void LLViewerPartSourceScript::setDead()
104{
105	LLMemType mt(LLMemType::MTYPE_PARTICLES);
106	mIsDead = TRUE;
107	mSourceObjectp = NULL;
108	mTargetObjectp = NULL;
109}
110
111void LLViewerPartSourceScript::update(const F32 dt)
112{
113	if( mIsSuspended )
114		return;
115
116	LLMemType mt(LLMemType::MTYPE_PARTICLES);
117	F32 old_update_time = mLastUpdateTime;
118	mLastUpdateTime += dt;
119
120	F32 ref_rate_travelspeed = llmin(LLViewerPartSim::getInstance()->getRefRate(), 1.f);
121	
122	F32 dt_update = mLastUpdateTime - mLastPartTime;
123
124	// Update this for objects which have the follow flag set...
125	if (!mSourceObjectp.isNull())
126	{
127		if (mSourceObjectp->isDead())
128		{
129			mSourceObjectp = NULL;
130		}
131		else if (mSourceObjectp->mDrawable.notNull())
132		{
133			mPosAgent = mSourceObjectp->getRenderPosition();
134		}
135	}
136
137	if (mTargetObjectp.isNull() 
138		&& mPartSysData.mTargetUUID.notNull())
139	{
140		//
141		// Hmm, missing object, let's see if we can find it...
142		//
143
144		LLViewerObject *target_objp = gObjectList.findObject(mPartSysData.mTargetUUID);
145		setTargetObject(target_objp);
146	}
147
148	if (!mTargetObjectp.isNull())
149	{
150		if (mTargetObjectp->isDead())
151		{
152			mTargetObjectp = NULL;
153		}
154		else if (mTargetObjectp->mDrawable.notNull())
155		{
156			mTargetPosAgent = mTargetObjectp->getRenderPosition();
157		}
158	}
159
160	if (!mTargetObjectp)
161	{
162		mTargetPosAgent = mPosAgent;
163	}
164
165	if (mPartSysData.mMaxAge && ((mPartSysData.mStartAge + mLastUpdateTime + dt_update) > mPartSysData.mMaxAge))
166	{
167		// Kill particle source because it has outlived its max age...
168		setDead();
169		return;
170	}
171
172
173	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PARTICLES))
174	{
175		if (mSourceObjectp.notNull())
176		{
177			std::ostringstream ostr;
178			ostr << mPartSysData;
179			mSourceObjectp->setDebugText(ostr.str());
180		}
181	}
182
183	BOOL first_run = FALSE;
184	if (old_update_time <= 0.f)
185	{
186		first_run = TRUE;
187	}
188
189	F32 max_time = llmax(1.f, 10.f*mPartSysData.mBurstRate);
190	dt_update = llmin(max_time, dt_update);
191	while ((dt_update > mPartSysData.mBurstRate) || first_run)
192	{
193		first_run = FALSE;
194		
195		// Update the rotation of the particle source by the angular velocity
196		// First check to see if there is still an angular velocity.
197		F32 angular_velocity_mag = mPartSysData.mAngularVelocity.magVec();
198		if (angular_velocity_mag != 0.0f)
199		{
200			F32 av_angle = dt * angular_velocity_mag;
201			LLQuaternion dquat(av_angle, mPartSysData.mAngularVelocity);
202			mRotation *= dquat;
203		}
204		else
205		{
206			// No angular velocity.  Reset our rotation.
207			mRotation.setQuat(0, 0, 0);
208		}
209		
210		if (LLViewerPartSim::getInstance()->aboveParticleLimit())
211		{
212			// Don't bother doing any more updates if we're above the particle limit,
213			// just give up.
214			mLastPartTime = mLastUpdateTime;
215            break;
216
217		}
218		
219		// find the greatest length that the shortest side of a system
220		// particle is expected to have
221		F32 max_short_side =
222			llmax(
223			      llmax(llmin(mPartSysData.mPartData.mStartScale[0],
224					  mPartSysData.mPartData.mStartScale[1]),
225				    llmin(mPartSysData.mPartData.mEndScale[0],
226					  mPartSysData.mPartData.mEndScale[1])),
227			      llmin((mPartSysData.mPartData.mStartScale[0]
228				     + mPartSysData.mPartData.mEndScale[0])/2,
229				    (mPartSysData.mPartData.mStartScale[1]
230				     + mPartSysData.mPartData.mEndScale[1])/2));
231		
232		F32 pixel_meter_ratio = LLViewerCamera::getInstance()->getPixelMeterRatio();
233
234		// Maximum distance at which spawned particles will be viewable
235		F32 max_dist = max_short_side * pixel_meter_ratio; 
236
237		if (max_dist < 0.25f)
238		{
239			// < 1 pixel wide at a distance of >=25cm.  Particles
240			// this tiny are useless and mostly spawned by buggy
241			// sources
242			mLastPartTime = mLastUpdateTime;
243			break;
244		}
245
246		// Distance from camera
247		F32 dist = (mPosAgent - LLViewerCamera::getInstance()->getOrigin()).magVec();
248
249		// Particle size vs distance vs maxage throttling
250
251		F32 limited_rate=0.f;
252		if (dist - max_dist > 0.f)
253		{
254			if((dist - max_dist) * ref_rate_travelspeed > mPartSysData.mPartData.mMaxAge - 0.2f )
255			{
256				// You need to travel faster than 1 divided by reference rate m/s directly towards these particles to see them at least 0.2s
257				mLastPartTime = mLastUpdateTime;
258				break;
259			}
260			limited_rate = ((dist - max_dist) * ref_rate_travelspeed) / mPartSysData.mPartData.mMaxAge;
261		}
262		
263		if(mDelay)
264		{			
265			limited_rate = llmax(limited_rate, 0.01f * mDelay--) ;
266		}
267
268		S32 i;
269		for (i = 0; i < mPartSysData.mBurstPartCount; i++)
270		{
271			if (ll_frand() < llmax(1.0f - LLViewerPartSim::getInstance()->getBurstRate(), limited_rate))
272			{
273				// Limit particle generation
274				continue;
275			}
276
277			LLViewerPart* part = new LLViewerPart();
278
279			part->init(this, mImagep, NULL);
280			part->mFlags = mPartSysData.mPartData.mFlags;
281			if (!mSourceObjectp.isNull() && mSourceObjectp->isHUDAttachment())
282			{
283				part->mFlags |= LLPartData::LL_PART_HUD;
284			}
285			part->mMaxAge = mPartSysData.mPartData.mMaxAge;
286			part->mStartColor = mPartSysData.mPartData.mStartColor;
287			part->mEndColor = mPartSysData.mPartData.mEndColor;
288			part->mColor = part->mStartColor;
289
290			part->mStartScale = mPartSysData.mPartData.mStartScale;
291			part->mEndScale = mPartSysData.mPartData.mEndScale;
292			part->mScale = part->mStartScale;
293
294			part->mAccel = mPartSysData.mPartAccel;
295
296			if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_DROP)
297			{
298				part->mPosAgent = mPosAgent;
299				part->mVelocity.setVec(0.f, 0.f, 0.f);
300			}
301			else if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_EXPLODE)
302			{
303				part->mPosAgent = mPosAgent;
304				LLVector3 part_dir_vector;
305
306				F32 mvs;
307				do
308				{
309					part_dir_vector.mV[VX] = ll_frand(2.f) - 1.f;
310					part_dir_vector.mV[VY] = ll_frand(2.f) - 1.f;
311					part_dir_vector.mV[VZ] = ll_frand(2.f) - 1.f;
312					mvs = part_dir_vector.magVecSquared();
313				}
314				while ((mvs > 1.f) || (mvs < 0.01f));
315
316				part_dir_vector.normVec();
317				part->mPosAgent += mPartSysData.mBurstRadius*part_dir_vector;
318				part->mVelocity = part_dir_vector;
319				F32 speed = mPartSysData.mBurstSpeedMin + ll_frand(mPartSysData.mBurstSpeedMax - mPartSysData.mBurstSpeedMin);
320				part->mVelocity *= speed;
321			}
322			else if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_ANGLE
323				|| mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE)
324			{				
325				part->mPosAgent = mPosAgent;
326				
327				// original implemenetation for part_dir_vector was just:					
328				LLVector3 part_dir_vector(0.0, 0.0, 1.0);
329				// params from the script...
330				// outer = outer cone angle
331				// inner = inner cone angle
332				//		between outer and inner there will be particles
333				F32 innerAngle = mPartSysData.mInnerAngle;
334				F32 outerAngle = mPartSysData.mOuterAngle;
335
336				// generate a random angle within the given space...
337				F32 angle = innerAngle + ll_frand(outerAngle - innerAngle);
338				// split which side it will go on randomly...
339				if (ll_frand() < 0.5) 
340				{
341					angle = -angle;
342				}
343				// Both patterns rotate around the x-axis first:
344				part_dir_vector.rotVec(angle, 1.0, 0.0, 0.0);
345
346				// If this is a cone pattern, rotate again to create the cone.
347				if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE)
348				{
349					part_dir_vector.rotVec(ll_frand(4*F_PI), 0.0, 0.0, 1.0);
350				}
351								
352				// Only apply this rotation if using the deprecated angles. 
353				if (! (mPartSysData.mFlags & LLPartSysData::LL_PART_USE_NEW_ANGLE))
354				{
355					// Deprecated...
356					part_dir_vector.rotVec(outerAngle, 1.0, 0.0, 0.0);
357				}
358				
359				if (mSourceObjectp)
360				{
361					part_dir_vector = part_dir_vector * mSourceObjectp->getRenderRotation();
362				}
363								
364				part_dir_vector = part_dir_vector * mRotation;
365								
366				part->mPosAgent += mPartSysData.mBurstRadius*part_dir_vector;
367
368				part->mVelocity = part_dir_vector;
369
370				F32 speed = mPartSysData.mBurstSpeedMin + ll_frand(mPartSysData.mBurstSpeedMax - mPartSysData.mBurstSpeedMin);
371				part->mVelocity *= speed;
372			}
373			else
374			{
375				part->mPosAgent = mPosAgent;
376				part->mVelocity.setVec(0.f, 0.f, 0.f);
377				//llwarns << "Unknown source pattern " << (S32)mPartSysData.mPattern << llendl;
378			}
379
380			if (part->mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK ||	// SVC-193, VWR-717
381				part->mFlags & LLPartData::LL_PART_TARGET_LINEAR_MASK) 
382			{
383				mPartSysData.mBurstRadius = 0; 
384			}
385
386			LLViewerPartSim::getInstance()->addPart(part);
387		}
388
389		mLastPartTime = mLastUpdateTime;
390		dt_update -= mPartSysData.mBurstRate;
391	}
392}
393
394// static
395LLPointer<LLViewerPartSourceScript> LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLPointer<LLViewerPartSourceScript> pssp, const S32 block_num)
396{
397	LLMemType mt(LLMemType::MTYPE_PARTICLES);
398	if (!pssp)
399	{
400		if (LLPartSysData::isNullPS(block_num))
401		{
402			return NULL;
403		}
404		LLPointer<LLViewerPartSourceScript> new_pssp = new LLViewerPartSourceScript(source_objp);
405		if (!new_pssp->mPartSysData.unpackBlock(block_num))
406		{
407			return NULL;
408		}
409		if (new_pssp->mPartSysData.mTargetUUID.notNull())
410		{
411			LLViewerObject *target_objp = gObjectList.findObject(new_pssp->mPartSysData.mTargetUUID);
412			new_pssp->setTargetObject(target_objp);
413		}
414		return new_pssp;
415	}
416	else
417	{
418		if (LLPartSysData::isNullPS(block_num))
419		{
420			return NULL;
421		}
422
423		if (!pssp->mPartSysData.unpackBlock(block_num))
424		{
425			return NULL;
426		}
427		if (pssp->mPartSysData.mTargetUUID.notNull())
428		{
429			LLViewerObject *target_objp = gObjectList.findObject(pssp->mPartSysData.mTargetUUID);
430			pssp->setTargetObject(target_objp);
431		}
432		return pssp;
433	}
434}
435
436
437LLPointer<LLViewerPartSourceScript> LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLPointer<LLViewerPartSourceScript> pssp, LLDataPacker &dp)
438{
439	LLMemType mt(LLMemType::MTYPE_PARTICLES);
440	if (!pssp)
441	{
442		LLPointer<LLViewerPartSourceScript> new_pssp = new LLViewerPartSourceScript(source_objp);
443		if (!new_pssp->mPartSysData.unpack(dp))
444		{
445			return NULL;
446		}
447		if (new_pssp->mPartSysData.mTargetUUID.notNull())
448		{
449			LLViewerObject *target_objp = gObjectList.findObject(new_pssp->mPartSysData.mTargetUUID);
450			new_pssp->setTargetObject(target_objp);
451		}
452		return new_pssp;
453	}
454	else
455	{
456		if (!pssp->mPartSysData.unpack(dp))
457		{
458			return NULL;
459		}
460		if (pssp->mPartSysData.mTargetUUID.notNull())
461		{
462			LLViewerObject *target_objp = gObjectList.findObject(pssp->mPartSysData.mTargetUUID);
463			pssp->setTargetObject(target_objp);
464		}
465		return pssp;
466	}
467}
468
469
470/* static */
471LLPointer<LLViewerPartSourceScript> LLViewerPartSourceScript::createPSS(LLViewerObject *source_objp, const LLPartSysData& particle_parameters)
472{
473	LLMemType mt(LLMemType::MTYPE_PARTICLES);
474
475	LLPointer<LLViewerPartSourceScript> new_pssp = new LLViewerPartSourceScript(source_objp);
476
477	new_pssp->mPartSysData = particle_parameters;
478
479	if (new_pssp->mPartSysData.mTargetUUID.notNull())
480	{
481		LLViewerObject *target_objp = gObjectList.findObject(new_pssp->mPartSysData.mTargetUUID);
482		new_pssp->setTargetObject(target_objp);
483	}
484	return new_pssp;
485}
486
487
488void LLViewerPartSourceScript::setImage(LLViewerTexture *imagep)
489{
490	LLMemType mt(LLMemType::MTYPE_PARTICLES);
491	mImagep = imagep;
492}
493
494void LLViewerPartSourceScript::setTargetObject(LLViewerObject *objp)
495{
496	LLMemType mt(LLMemType::MTYPE_PARTICLES);
497	mTargetObjectp = objp;
498}
499
500
501
502
503
504LLViewerPartSourceSpiral::LLViewerPartSourceSpiral(const LLVector3 &pos) :
505	LLViewerPartSource(LL_PART_SOURCE_CHAT)
506{
507	mPosAgent = pos;
508}
509
510void LLViewerPartSourceSpiral::setDead()
511{
512	LLMemType mt(LLMemType::MTYPE_PARTICLES);
513	mIsDead = TRUE;
514	mSourceObjectp = NULL;
515}
516
517
518void LLViewerPartSourceSpiral::updatePart(LLViewerPart &part, const F32 dt)
519{
520	LLMemType mt(LLMemType::MTYPE_PARTICLES);
521	F32 frac = part.mLastUpdateTime/part.mMaxAge;
522
523	LLVector3 center_pos;
524	LLPointer<LLViewerPartSource>& ps = part.mPartSourcep;
525	LLViewerPartSourceSpiral *pss = (LLViewerPartSourceSpiral *)ps.get();
526	if (!pss->mSourceObjectp.isNull() && !pss->mSourceObjectp->mDrawable.isNull())
527	{
528		part.mPosAgent = pss->mSourceObjectp->getRenderPosition();
529	}
530	else
531	{
532		part.mPosAgent = pss->mPosAgent;
533	}
534	F32 x = sin(F_TWO_PI*frac + part.mParameter);
535	F32 y = cos(F_TWO_PI*frac + part.mParameter);
536
537	part.mPosAgent.mV[VX] += x;
538	part.mPosAgent.mV[VY] += y;
539	part.mPosAgent.mV[VZ] += -0.5f + frac;
540}
541
542
543void LLViewerPartSourceSpiral::update(const F32 dt)
544{
545	LLMemType mt(LLMemType::MTYPE_PARTICLES);
546	if (!mImagep)
547	{
548		mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
549	}
550
551	const F32 RATE = 0.025f;
552
553	mLastUpdateTime += dt;
554
555	F32 dt_update = mLastUpdateTime - mLastPartTime;
556	F32 max_time = llmax(1.f, 10.f*RATE);
557	dt_update = llmin(max_time, dt_update);
558
559	if (dt_update > RATE)
560	{
561		mLastPartTime = mLastUpdateTime;
562		if (!LLViewerPartSim::getInstance()->shouldAddPart())
563		{
564			// Particle simulation says we have too many particles, skip all this
565			return;
566		}
567
568		if (!mSourceObjectp.isNull() && !mSourceObjectp->mDrawable.isNull())
569		{
570			mPosAgent = mSourceObjectp->getRenderPosition();
571		}
572		LLViewerPart* part = new LLViewerPart();
573		part->init(this, mImagep, updatePart);
574		part->mStartColor = mColor;
575		part->mEndColor = mColor;
576		part->mEndColor.mV[3] = 0.f;
577		part->mPosAgent = mPosAgent;
578		part->mMaxAge = 1.f;
579		part->mFlags = LLViewerPart::LL_PART_INTERP_COLOR_MASK;
580		part->mLastUpdateTime = 0.f;
581		part->mScale.mV[0] = 0.25f;
582		part->mScale.mV[1] = 0.25f;
583		part->mParameter = ll_frand(F_TWO_PI);
584
585		LLViewerPartSim::getInstance()->addPart(part);
586	}
587}
588
589void LLViewerPartSourceSpiral::setSourceObject(LLViewerObject *objp)
590{
591	LLMemType mt(LLMemType::MTYPE_PARTICLES);
592	mSourceObjectp = objp;
593}
594
595void LLViewerPartSourceSpiral::setColor(const LLColor4 &color)
596{
597	mColor = color;
598}
599
600
601
602
603
604LLViewerPartSourceBeam::LLViewerPartSourceBeam() :
605	LLViewerPartSource(LL_PART_SOURCE_BEAM)
606{
607}
608
609LLViewerPartSourceBeam::~LLViewerPartSourceBeam()
610{
611}
612
613void LLViewerPartSourceBeam::setDead()
614{
615	LLMemType mt(LLMemType::MTYPE_PARTICLES);
616	mIsDead = TRUE;
617	mSourceObjectp = NULL;
618	mTargetObjectp = NULL;
619}
620
621void LLViewerPartSourceBeam::setColor(const LLColor4 &color)
622{
623	mColor = color;
624}
625
626
627void LLViewerPartSourceBeam::updatePart(LLViewerPart &part, const F32 dt)
628{
629	LLMemType mt(LLMemType::MTYPE_PARTICLES);
630	F32 frac = part.mLastUpdateTime/part.mMaxAge;
631
632	LLViewerPartSource *ps = (LLViewerPartSource*)part.mPartSourcep;
633	LLViewerPartSourceBeam *psb = (LLViewerPartSourceBeam *)ps;
634	if (psb->mSourceObjectp.isNull())
635	{
636		part.mFlags = LLPartData::LL_PART_DEAD_MASK;
637		return;
638	}
639
640	LLVector3 source_pos_agent;
641	LLVector3 target_pos_agent;
642	if (!psb->mSourceObjectp.isNull() && !psb->mSourceObjectp->mDrawable.isNull())
643	{
644		if (psb->mSourceObjectp->isAvatar())
645		{
646			LLViewerObject *objp = psb->mSourceObjectp;
647			LLVOAvatar *avp = (LLVOAvatar *)objp;
648			source_pos_agent = avp->mWristLeftp->getWorldPosition();
649		}
650		else
651		{
652			source_pos_agent = psb->mSourceObjectp->getRenderPosition();
653		}
654	}
655	if (!psb->mTargetObjectp.isNull() && !psb->mTargetObjectp->mDrawable.isNull())
656	{
657		target_pos_agent = psb->mTargetObjectp->getRenderPosition();
658	}
659
660	part.mPosAgent = (1.f - frac) * source_pos_agent;
661	if (psb->mTargetObjectp.isNull())
662	{
663		part.mPosAgent += frac * (gAgent.getPosAgentFromGlobal(psb->mLKGTargetPosGlobal));
664	}
665	else
666	{
667		part.mPosAgent += frac * target_pos_agent;
668	}
669}
670
671
672void LLViewerPartSourceBeam::update(const F32 dt)
673{
674	LLMemType mt(LLMemType::MTYPE_PARTICLES);
675	const F32 RATE = 0.025f;
676
677	mLastUpdateTime += dt;
678
679	if (!mSourceObjectp.isNull() && !mSourceObjectp->mDrawable.isNull())
680	{
681		if (mSourceObjectp->isAvatar())
682		{
683			LLViewerObject *objp = mSourceObjectp;
684			LLVOAvatar *avp = (LLVOAvatar *)objp;
685			mPosAgent = avp->mWristLeftp->getWorldPosition();
686		}
687		else
688		{
689			mPosAgent = mSourceObjectp->getRenderPosition();
690		}
691	}
692
693	if (!mTargetObjectp.isNull() && !mTargetObjectp->mDrawable.isNull())
694	{
695		mTargetPosAgent = mTargetObjectp->getRenderPosition();
696	}
697	else if (!mLKGTargetPosGlobal.isExactlyZero())
698	{
699		mTargetPosAgent = gAgent.getPosAgentFromGlobal(mLKGTargetPosGlobal);
700	}
701
702	F32 dt_update = mLastUpdateTime - mLastPartTime;
703	F32 max_time = llmax(1.f, 10.f*RATE);
704	dt_update = llmin(max_time, dt_update);
705
706	if (dt_update > RATE)
707	{
708		mLastPartTime = mLastUpdateTime;
709		if (!LLViewerPartSim::getInstance()->shouldAddPart())
710		{
711			// Particle simulation says we have too many particles, skip all this
712			return;
713		}
714
715		if (!mImagep)
716		{
717			mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
718		}
719
720		LLViewerPart* part = new LLViewerPart();
721		part->init(this, mImagep, NULL);
722
723		part->mFlags = LLPartData::LL_PART_INTERP_COLOR_MASK |
724						LLPartData::LL_PART_INTERP_SCALE_MASK |
725						LLPartData::LL_PART_TARGET_POS_MASK |
726						LLPartData::LL_PART_FOLLOW_VELOCITY_MASK;
727		part->mMaxAge = 0.5f;
728		part->mStartColor = mColor;
729		part->mEndColor = part->mStartColor;
730		part->mEndColor.mV[3] = 0.4f;
731		part->mColor = part->mStartColor;
732
733		part->mStartScale = LLVector2(0.1f, 0.1f);
734		part->mEndScale = LLVector2(0.1f, 0.1f);
735		part->mScale = part->mStartScale;
736
737		part->mPosAgent = mPosAgent;
738		part->mVelocity = mTargetPosAgent - mPosAgent;
739
740		LLViewerPartSim::getInstance()->addPart(part);
741	}
742}
743
744void LLViewerPartSourceBeam::setSourceObject(LLViewerObject* objp)
745{
746	LLMemType mt(LLMemType::MTYPE_PARTICLES);
747	mSourceObjectp = objp;
748}
749
750void LLViewerPartSourceBeam::setTargetObject(LLViewerObject* objp)
751{
752	LLMemType mt(LLMemType::MTYPE_PARTICLES);
753	mTargetObjectp = objp;
754}
755
756
757
758
759LLViewerPartSourceChat::LLViewerPartSourceChat(const LLVector3 &pos) :
760	LLViewerPartSource(LL_PART_SOURCE_SPIRAL)
761{
762	mPosAgent = pos;
763}
764
765void LLViewerPartSourceChat::setDead()
766{
767	LLMemType mt(LLMemType::MTYPE_PARTICLES);
768	mIsDead = TRUE;
769	mSourceObjectp = NULL;
770}
771
772
773void LLViewerPartSourceChat::updatePart(LLViewerPart &part, const F32 dt)
774{
775	LLMemType mt(LLMemType::MTYPE_PARTICLES);
776	F32 frac = part.mLastUpdateTime/part.mMaxAge;
777
778	LLVector3 center_pos;
779	LLViewerPartSource *ps = (LLViewerPartSource*)part.mPartSourcep;
780	LLViewerPartSourceChat *pss = (LLViewerPartSourceChat *)ps;
781	if (!pss->mSourceObjectp.isNull() && !pss->mSourceObjectp->mDrawable.isNull())
782	{
783		part.mPosAgent = pss->mSourceObjectp->getRenderPosition();
784	}
785	else
786	{
787		part.mPosAgent = pss->mPosAgent;
788	}
789	F32 x = sin(F_TWO_PI*frac + part.mParameter);
790	F32 y = cos(F_TWO_PI*frac + part.mParameter);
791
792	part.mPosAgent.mV[VX] += x;
793	part.mPosAgent.mV[VY] += y;
794	part.mPosAgent.mV[VZ] += -0.5f + frac;
795}
796
797
798void LLViewerPartSourceChat::update(const F32 dt)
799{
800	LLMemType mt(LLMemType::MTYPE_PARTICLES);
801	if (!mImagep)
802	{
803		mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
804	}
805
806
807	const F32 RATE = 0.025f;
808
809	mLastUpdateTime += dt;
810
811	if (mLastUpdateTime > 2.f)
812	{
813		// Kill particle source because it has outlived its max age...
814		setDead();
815		return;
816	}
817
818	F32 dt_update = mLastUpdateTime - mLastPartTime;
819
820	// Clamp us to generating at most one second's worth of particles on a frame.
821	F32 max_time = llmax(1.f, 10.f*RATE);
822	dt_update = llmin(max_time, dt_update);
823
824	if (dt_update > RATE)
825	{
826		mLastPartTime = mLastUpdateTime;
827		if (!LLViewerPartSim::getInstance()->shouldAddPart())
828		{
829			// Particle simulation says we have too many particles, skip all this
830			return;
831		}
832
833		if (!mSourceObjectp.isNull() && !mSourceObjectp->mDrawable.isNull())
834		{
835			mPosAgent = mSourceObjectp->getRenderPosition();
836		}
837		LLViewerPart* part = new LLViewerPart();
838		part->init(this, mImagep, updatePart);
839		part->mStartColor = mColor;
840		part->mEndColor = mColor;
841		part->mEndColor.mV[3] = 0.f;
842		part->mPosAgent = mPosAgent;
843		part->mMaxAge = 1.f;
844		part->mFlags = LLViewerPart::LL_PART_INTERP_COLOR_MASK;
845		part->mLastUpdateTime = 0.f;
846		part->mScale.mV[0] = 0.25f;
847		part->mScale.mV[1] = 0.25f;
848		part->mParameter = ll_frand(F_TWO_PI);
849
850		LLViewerPartSim::getInstance()->addPart(part);
851	}
852}
853
854void LLViewerPartSourceChat::setSourceObject(LLViewerObject *objp)
855{
856	LLMemType mt(LLMemType::MTYPE_PARTICLES);
857	mSourceObjectp = objp;
858}
859
860void LLViewerPartSourceChat::setColor(const LLColor4 &color)
861{
862	mColor = color;
863}
864
865