PageRenderTime 65ms CodeModel.GetById 19ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llflexibleobject.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 848 lines | 571 code | 139 blank | 138 comment | 83 complexity | c4e4d131f0078bbca37ae5879ee2a70f MD5 | raw file
  1/** 
  2 * @file llflexibleobject.cpp
  3 * @brief Flexible object implementation
  4 *
  5 * $LicenseInfo:firstyear=2006&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#include "pipeline.h"
 30#include "lldrawpoolbump.h"
 31#include "llface.h"
 32#include "llflexibleobject.h"
 33#include "llglheaders.h"
 34#include "llrendersphere.h"
 35#include "llviewerobject.h"
 36#include "llagent.h"
 37#include "llsky.h"
 38#include "llviewercamera.h"
 39#include "llviewertexturelist.h"
 40#include "llviewercontrol.h"
 41#include "llviewerobjectlist.h"
 42#include "llviewerregion.h"
 43#include "llworld.h"
 44#include "llvoavatar.h"
 45
 46/*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f;
 47
 48static LLFastTimer::DeclareTimer FTM_FLEXIBLE_REBUILD("Rebuild");
 49static LLFastTimer::DeclareTimer FTM_DO_FLEXIBLE_UPDATE("Update");
 50
 51// LLFlexibleObjectData::pack/unpack now in llprimitive.cpp
 52
 53//-----------------------------------------------
 54// constructor
 55//-----------------------------------------------
 56LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectData* attributes) :
 57		mVO(vo), mAttributes(attributes)
 58{
 59	static U32 seed = 0;
 60	mID = seed++;
 61	mInitialized = FALSE;
 62	mUpdated = FALSE;
 63	mInitializedRes = -1;
 64	mSimulateRes = 0;
 65	mFrameNum = 0;
 66	mCollisionSphereRadius = 0.f;
 67	mRenderRes = 1;
 68
 69	if(mVO->mDrawable.notNull())
 70	{
 71		mVO->mDrawable->makeActive() ;
 72	}
 73}//-----------------------------------------------
 74
 75LLVector3 LLVolumeImplFlexible::getFramePosition() const
 76{
 77	return mVO->getRenderPosition();
 78}
 79
 80LLQuaternion LLVolumeImplFlexible::getFrameRotation() const
 81{
 82	return mVO->getRenderRotation();
 83}
 84
 85void LLVolumeImplFlexible::onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin)
 86{
 87	if (param_type == LLNetworkData::PARAMS_FLEXIBLE)
 88	{
 89		mAttributes = (LLFlexibleObjectData*)data;
 90		setAttributesOfAllSections();
 91	}
 92}
 93
 94void LLVolumeImplFlexible::onShift(const LLVector4a &shift_vector)
 95{	
 96	//VECTORIZE THIS
 97	LLVector3 shift(shift_vector.getF32ptr());
 98	for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section)
 99	{
100		mSection[section].mPosition += shift;	
101	}
102}
103
104//-----------------------------------------------------------------------------------------------
105void LLVolumeImplFlexible::setParentPositionAndRotationDirectly( LLVector3 p, LLQuaternion r )
106{
107	mParentPosition = p;
108	mParentRotation = r;
109
110}//-----------------------------------------------------------------------------------------------------
111
112void LLVolumeImplFlexible::remapSections(LLFlexibleObjectSection *source, S32 source_sections,
113										 LLFlexibleObjectSection *dest, S32 dest_sections)
114{	
115	S32 num_output_sections = 1<<dest_sections;
116	LLVector3 scale = mVO->mDrawable->getScale();
117	F32 source_section_length = scale.mV[VZ] / (F32)(1<<source_sections);
118	F32 section_length = scale.mV[VZ] / (F32)num_output_sections;
119	if (source_sections == -1)
120	{
121		// Generate all from section 0
122		dest[0] = source[0];
123		for (S32 section=0; section<num_output_sections; ++section)
124		{
125			dest[section+1] = dest[section];
126			dest[section+1].mPosition += dest[section].mDirection * section_length;
127			dest[section+1].mVelocity.setVec( LLVector3::zero );
128		}
129	}
130	else if (source_sections > dest_sections)
131	{
132		// Copy, skipping sections
133
134		S32 num_steps = 1<<(source_sections-dest_sections);
135
136		// Copy from left to right since it may be an in-place computation
137		for (S32 section=0; section<num_output_sections; ++section)
138		{
139			dest[section+1] = source[(section+1)*num_steps];
140		}
141		dest[0] = source[0];
142	}
143	else if (source_sections < dest_sections)
144	{
145		// Interpolate section info
146		// Iterate from right to left since it may be an in-place computation
147		S32 step_shift = dest_sections-source_sections;
148		S32 num_steps = 1<<step_shift;
149		for (S32 section=num_output_sections-num_steps; section>=0; section -= num_steps)
150		{
151			LLFlexibleObjectSection *last_source_section = &source[section>>step_shift];
152			LLFlexibleObjectSection *source_section = &source[(section>>step_shift)+1];
153
154			// Cubic interpolation of position
155			// At^3 + Bt^2 + Ct + D = f(t)
156			LLVector3 D = last_source_section->mPosition;
157			LLVector3 C = last_source_section->mdPosition * source_section_length;
158			LLVector3 Y = source_section->mdPosition * source_section_length - C; // Helper var
159			LLVector3 X = (source_section->mPosition - D - C); // Helper var
160			LLVector3 A = Y - 2*X;
161			LLVector3 B = X - A;
162
163			F32 t_inc = 1.f/F32(num_steps);
164			F32 t = t_inc;
165			for (S32 step=1; step<num_steps; ++step)
166			{
167				dest[section+step].mScale = 
168					lerp(last_source_section->mScale, source_section->mScale, t);
169				dest[section+step].mAxisRotation = 
170					slerp(t, last_source_section->mAxisRotation, source_section->mAxisRotation);
171
172				// Evaluate output interpolated values
173				F32 t_sq = t*t;
174				dest[section+step].mPosition = t_sq*(t*A + B) + t*C + D;
175				dest[section+step].mRotation = 
176					slerp(t, last_source_section->mRotation, source_section->mRotation);
177				dest[section+step].mVelocity = lerp(last_source_section->mVelocity, source_section->mVelocity, t);
178				dest[section+step].mDirection = lerp(last_source_section->mDirection, source_section->mDirection, t);
179				dest[section+step].mdPosition = lerp(last_source_section->mdPosition, source_section->mdPosition, t);
180				dest[section+num_steps] = *source_section;
181				t += t_inc;
182			}
183		}
184		dest[0] = source[0];
185	}
186	else
187	{
188		// numbers are equal. copy info
189		for (S32 section=0; section <= num_output_sections; ++section)
190		{
191			dest[section] = source[section];
192		}
193	}
194}
195
196//-----------------------------------------------------------------------------
197void LLVolumeImplFlexible::setAttributesOfAllSections(LLVector3* inScale)
198{
199	LLVector2 bottom_scale, top_scale;
200	F32 begin_rot = 0, end_rot = 0;
201	if (mVO->getVolume())
202	{
203		const LLPathParams &params = mVO->getVolume()->getParams().getPathParams();
204		bottom_scale = params.getBeginScale();
205		top_scale = params.getEndScale();
206		begin_rot = F_PI * params.getTwistBegin();
207		end_rot = F_PI * params.getTwist();
208	}
209
210	if (!mVO->mDrawable)
211	{
212		return;
213	}
214	
215	S32 num_sections = 1 << mSimulateRes;
216
217	LLVector3 scale;
218	if (inScale == (LLVector3*)NULL)
219	{
220		scale = mVO->mDrawable->getScale();
221	}
222	else
223	{
224		scale = *inScale;
225	}
226
227	mSection[0].mPosition = getAnchorPosition();
228	mSection[0].mDirection = LLVector3::z_axis * getFrameRotation();
229	mSection[0].mdPosition = mSection[0].mDirection;
230	mSection[0].mScale.setVec(scale.mV[VX]*bottom_scale.mV[0], scale.mV[VY]*bottom_scale.mV[1]);
231	mSection[0].mVelocity.setVec(0,0,0);
232	mSection[0].mAxisRotation.setQuat(begin_rot,0,0,1);
233
234	LLVector3 parentSectionPosition = mSection[0].mPosition;
235	LLVector3 last_direction = mSection[0].mDirection;
236
237	remapSections(mSection, mInitializedRes, mSection, mSimulateRes);
238	mInitializedRes = mSimulateRes;
239
240	F32 t_inc = 1.f/F32(num_sections);
241	F32 t = t_inc;
242
243	for ( int i=1; i<= num_sections; i++)
244	{
245		mSection[i].mAxisRotation.setQuat(lerp(begin_rot,end_rot,t),0,0,1);
246		mSection[i].mScale = LLVector2(
247			scale.mV[VX] * lerp(bottom_scale.mV[0], top_scale.mV[0], t), 
248			scale.mV[VY] * lerp(bottom_scale.mV[1], top_scale.mV[1], t));
249		t += t_inc;
250	}
251}//-----------------------------------------------------------------------------------
252
253
254void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail)
255{
256}
257
258//---------------------------------------------------------------------------------
259// This calculates the physics of the flexible object. Note that it has to be 0
260// updated every time step. In the future, perhaps there could be an 
261// optimization similar to what Havok does for objects that are stationary. 
262//---------------------------------------------------------------------------------
263static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies");
264BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
265{
266	if (mVO->mDrawable.isNull())
267	{
268		// Don't do anything until we have a drawable
269		return FALSE; // (we are not initialized or updated)
270	}
271
272	BOOL force_update = mSimulateRes == 0 ? TRUE : FALSE;
273
274	//flexible objects never go static
275	mVO->mDrawable->mQuietCount = 0;
276	if (!mVO->mDrawable->isRoot())
277	{
278		LLViewerObject* parent = (LLViewerObject*) mVO->getParent();
279		parent->mDrawable->mQuietCount = 0;
280	}
281
282	LLFastTimer ftm(FTM_FLEXIBLE_UPDATE);
283		
284	S32 new_res = mAttributes->getSimulateLOD();
285
286	//number of segments only cares about z axis
287	F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, mVO->mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
288
289	// Rendering sections increases with visible angle on the screen
290	mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView());
291	if (mRenderRes > FLEXIBLE_OBJECT_MAX_SECTIONS)
292	{
293		mRenderRes = FLEXIBLE_OBJECT_MAX_SECTIONS;
294	}
295
296
297	// Bottom cap at 1/4 the original number of sections
298	if (mRenderRes < mAttributes->getSimulateLOD()-1)
299	{
300		mRenderRes = mAttributes->getSimulateLOD()-1;
301	}
302	// Throttle back simulation of segments we're not rendering
303	if (mRenderRes < new_res)
304	{
305		new_res = mRenderRes;
306	}
307
308	if (!mInitialized || (mSimulateRes != new_res))
309	{
310		mSimulateRes = new_res;
311		setAttributesOfAllSections();
312		mInitialized = TRUE;
313	}
314	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE))
315	{
316		return FALSE; // (we are not initialized or updated)
317	}
318
319	bool visible = mVO->mDrawable->isVisible();
320
321	if (force_update && visible)
322	{
323		gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE);
324	}
325	else if	(visible &&
326		!mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) &&
327		mVO->getPixelArea() > 256.f)
328	{
329		U32 id;
330		F32 pixel_area = mVO->getPixelArea();
331
332		if (mVO->isRootEdit())
333		{
334			id = mID;
335		}
336		else
337		{
338			LLVOVolume* parent = (LLVOVolume*) mVO->getParent();
339			id = parent->getVolumeInterfaceID();
340		}
341
342		U32 update_period = (U32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f)))+1;
343
344		if ((LLDrawable::getCurrentFrame()+id)%update_period == 0)
345		{
346			gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE);
347		}
348	}
349	
350	return force_update;
351}
352
353inline S32 log2(S32 x)
354{
355	S32 ret = 0;
356	while (x > 1)
357	{
358		++ret;
359		x >>= 1;
360	}
361	return ret;
362}
363
364void LLVolumeImplFlexible::doFlexibleUpdate()
365{
366	LLFastTimer ftm(FTM_DO_FLEXIBLE_UPDATE);
367	LLVolume* volume = mVO->getVolume();
368	LLPath *path = &volume->getPath();
369	if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) 
370	{
371		mVO->markForUpdate(TRUE);
372		if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0))
373		{
374			return;	// we did not get updated or initialized, proceeding without can be dangerous
375		}
376	}
377
378	if(!mInitialized)
379	{
380		//the object is not visible
381		return ;
382	}
383	
384	S32 num_sections = 1 << mSimulateRes;
385
386    F32 secondsThisFrame = mTimer.getElapsedTimeAndResetF32();
387	if (secondsThisFrame > 0.2f)
388	{
389		secondsThisFrame = 0.2f;
390	}
391
392	LLVector3 BasePosition = getFramePosition();
393	LLQuaternion BaseRotation = getFrameRotation();
394	LLQuaternion parentSegmentRotation = BaseRotation;
395	LLVector3 anchorDirectionRotated = LLVector3::z_axis * parentSegmentRotation;
396	LLVector3 anchorScale = mVO->mDrawable->getScale();
397	
398	F32 section_length = anchorScale.mV[VZ] / (F32)num_sections;
399	F32 inv_section_length = 1.f / section_length;
400
401	S32 i;
402
403	// ANCHOR position is offset from BASE position (centroid) by half the length
404	LLVector3 AnchorPosition = BasePosition - (anchorScale.mV[VZ]/2 * anchorDirectionRotated);
405	
406	mSection[0].mPosition = AnchorPosition;
407	mSection[0].mDirection = anchorDirectionRotated;
408	mSection[0].mRotation = BaseRotation;
409
410	LLQuaternion deltaRotation;
411
412	LLVector3 lastPosition;
413
414	// Coefficients which are constant across sections
415	F32 t_factor = mAttributes->getTension() * 0.1f;
416	t_factor = t_factor*(1 - pow(0.85f, secondsThisFrame*30));
417	if ( t_factor > FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE )
418	{
419		t_factor = FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE;
420	}
421
422	F32 friction_coeff = (mAttributes->getAirFriction()*2+1);
423	friction_coeff = pow(10.f, friction_coeff*secondsThisFrame);
424	friction_coeff = (friction_coeff > 1) ? friction_coeff : 1;
425	F32 momentum = 1.0f / friction_coeff;
426
427	F32 wind_factor = (mAttributes->getWindSensitivity()*0.1f) * section_length * secondsThisFrame;
428	F32 max_angle = atan(section_length*2.f);
429
430	F32 force_factor = section_length * secondsThisFrame;
431
432	// Update simulated sections
433	for (i=1; i<=num_sections; ++i)
434	{
435		LLVector3 parentSectionVector;
436		LLVector3 parentSectionPosition;
437		LLVector3 parentDirection;
438
439		//---------------------------------------------------
440		// save value of position as lastPosition
441		//---------------------------------------------------
442		lastPosition = mSection[i].mPosition;
443
444		//------------------------------------------------------------------------------------------
445		// gravity
446		//------------------------------------------------------------------------------------------
447		mSection[i].mPosition.mV[2] -= mAttributes->getGravity() * force_factor;
448
449		//------------------------------------------------------------------------------------------
450		// wind force
451		//------------------------------------------------------------------------------------------
452		if (mAttributes->getWindSensitivity() > 0.001f)
453		{
454			mSection[i].mPosition += gAgent.getRegion()->mWind.getVelocity( mSection[i].mPosition ) * wind_factor;
455		}
456
457		//------------------------------------------------------------------------------------------
458		// user-defined force
459		//------------------------------------------------------------------------------------------
460		mSection[i].mPosition += mAttributes->getUserForce() * force_factor;
461
462		//---------------------------------------------------
463		// tension (rigidity, stiffness)
464		//---------------------------------------------------
465		parentSectionPosition = mSection[i-1].mPosition;
466		parentDirection = mSection[i-1].mDirection;
467
468		if ( i == 1 )
469		{
470			parentSectionVector = mSection[0].mDirection;
471		}
472		else
473		{
474			parentSectionVector = mSection[i-2].mDirection;
475		}
476
477		LLVector3 currentVector = mSection[i].mPosition - parentSectionPosition;
478
479		LLVector3 difference = (parentSectionVector*section_length) - currentVector;
480		LLVector3 tensionForce = difference * t_factor;
481
482		mSection[i].mPosition += tensionForce;
483
484		//------------------------------------------------------------------------------------------
485		// sphere collision, currently not used
486		//------------------------------------------------------------------------------------------
487		/*if ( mAttributes->mUsingCollisionSphere )
488		{
489			LLVector3 vectorToCenterOfCollisionSphere = mCollisionSpherePosition - mSection[i].mPosition;
490			if ( vectorToCenterOfCollisionSphere.magVecSquared() < mCollisionSphereRadius * mCollisionSphereRadius )
491			{
492				F32 distanceToCenterOfCollisionSphere = vectorToCenterOfCollisionSphere.magVec();
493				F32 penetration = mCollisionSphereRadius - distanceToCenterOfCollisionSphere;
494
495				LLVector3 normalToCenterOfCollisionSphere;
496				
497				if ( distanceToCenterOfCollisionSphere > 0.0f )
498				{
499					normalToCenterOfCollisionSphere = vectorToCenterOfCollisionSphere / distanceToCenterOfCollisionSphere;
500				}
501				else // rare
502				{
503					normalToCenterOfCollisionSphere = LLVector3::x_axis; // arbitrary
504				}
505
506				// push the position out to the surface of the collision sphere
507				mSection[i].mPosition -= normalToCenterOfCollisionSphere * penetration;
508			}
509		}*/
510
511		//------------------------------------------------------------------------------------------
512		// inertia
513		//------------------------------------------------------------------------------------------
514		mSection[i].mPosition += mSection[i].mVelocity * momentum;
515
516		//------------------------------------------------------------------------------------------
517		// clamp length & rotation
518		//------------------------------------------------------------------------------------------
519		mSection[i].mDirection = mSection[i].mPosition - parentSectionPosition;
520		mSection[i].mDirection.normVec();
521		deltaRotation.shortestArc( parentDirection, mSection[i].mDirection );
522
523		F32 angle;
524		LLVector3 axis;
525		deltaRotation.getAngleAxis(&angle, axis);
526		if (angle > F_PI) angle -= 2.f*F_PI;
527		if (angle < -F_PI) angle += 2.f*F_PI;
528		if (angle > max_angle)
529		{
530			//angle = 0.5f*(angle+max_angle);
531			deltaRotation.setQuat(max_angle, axis);
532		} else if (angle < -max_angle)
533		{
534			//angle = 0.5f*(angle-max_angle);
535			deltaRotation.setQuat(-max_angle, axis);
536		}
537		LLQuaternion segment_rotation = parentSegmentRotation * deltaRotation;
538		parentSegmentRotation = segment_rotation;
539
540		mSection[i].mDirection = (parentDirection * deltaRotation);
541		mSection[i].mPosition = parentSectionPosition + mSection[i].mDirection * section_length;
542		mSection[i].mRotation = segment_rotation;
543
544		if (i > 1)
545		{
546			// Propogate half the rotation up to the parent
547			LLQuaternion halfDeltaRotation(angle/2, axis);
548			mSection[i-1].mRotation = mSection[i-1].mRotation * halfDeltaRotation;
549		}
550
551		//------------------------------------------------------------------------------------------
552		// calculate velocity
553		//------------------------------------------------------------------------------------------
554		mSection[i].mVelocity = mSection[i].mPosition - lastPosition;
555		if (mSection[i].mVelocity.magVecSquared() > 1.f)
556		{
557			mSection[i].mVelocity.normVec();
558		}
559	}
560
561	// Calculate derivatives (not necessary until normals are automagically generated)
562	mSection[0].mdPosition = (mSection[1].mPosition - mSection[0].mPosition) * inv_section_length;
563	// i = 1..NumSections-1
564	for (i=1; i<num_sections; ++i)
565	{
566		// Quadratic numerical derivative of position
567
568		// f(-L1) = aL1^2 - bL1 + c = f1
569		// f(0)   =               c = f2
570		// f(L2)  = aL2^2 + bL2 + c = f3
571		// f = ax^2 + bx + c
572		// d/dx f = 2ax + b
573		// d/dx f(0) = b
574
575		// c = f2
576		// a = [(f1-c)/L1 + (f3-c)/L2] / (L1+L2)
577		// b = (f3-c-aL2^2)/L2
578
579		LLVector3 a = (mSection[i-1].mPosition-mSection[i].mPosition +
580					mSection[i+1].mPosition-mSection[i].mPosition) * 0.5f * inv_section_length * inv_section_length;
581		LLVector3 b = (mSection[i+1].mPosition-mSection[i].mPosition - a*(section_length*section_length));
582		b *= inv_section_length;
583
584		mSection[i].mdPosition = b;
585	}
586
587	// i = NumSections
588	mSection[i].mdPosition = (mSection[i].mPosition - mSection[i-1].mPosition) * inv_section_length;
589
590	// Create points
591	S32 num_render_sections = 1<<mRenderRes;
592	if (path->getPathLength() != num_render_sections+1)
593	{
594		((LLVOVolume*) mVO)->mVolumeChanged = TRUE;
595		volume->resizePath(num_render_sections+1);
596	}
597
598	LLPath::PathPt *new_point;
599
600	LLFlexibleObjectSection newSection[ (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1 ];
601	remapSections(mSection, mSimulateRes, newSection, mRenderRes);
602
603	//generate transform from global to prim space
604	LLVector3 delta_scale = LLVector3(1,1,1);
605	LLVector3 delta_pos;
606	LLQuaternion delta_rot;
607
608	delta_rot = ~getFrameRotation();
609	delta_pos = -getFramePosition()*delta_rot;
610		
611	// Vertex transform (4x4)
612	LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
613	LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
614	LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
615
616	LLMatrix4 rel_xform;
617	rel_xform.initRows(LLVector4(x_axis, 0.f),
618								LLVector4(y_axis, 0.f),
619								LLVector4(z_axis, 0.f),
620								LLVector4(delta_pos, 1.f));
621			
622	for (i=0; i<=num_render_sections; ++i)
623	{
624		new_point = &path->mPath[i];
625		LLVector3 pos = newSection[i].mPosition * rel_xform;
626		LLQuaternion rot = mSection[i].mAxisRotation * newSection[i].mRotation * delta_rot;
627		
628		if (!mUpdated || (new_point->mPos-pos).magVec()/mVO->mDrawable->mDistanceWRTCamera > 0.001f)
629		{
630			new_point->mPos = newSection[i].mPosition * rel_xform;
631			mUpdated = FALSE;
632		}
633
634		new_point->mRot = rot;
635		new_point->mScale = newSection[i].mScale;
636		new_point->mTexT = ((F32)i)/(num_render_sections);
637	}
638
639	mLastSegmentRotation = parentSegmentRotation;
640}
641
642void LLVolumeImplFlexible::preRebuild()
643{
644	if (!mUpdated)
645	{
646		doFlexibleRebuild();
647	}
648}
649
650void LLVolumeImplFlexible::doFlexibleRebuild()
651{
652	LLVolume* volume = mVO->getVolume();
653	volume->regen();
654	
655	mUpdated = TRUE;
656}
657
658//------------------------------------------------------------------
659
660void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped)
661{
662	setAttributesOfAllSections((LLVector3*) &scale);
663}
664
665BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
666{
667	LLVOVolume *volume = (LLVOVolume*)mVO;
668
669	if (mVO->isAttachment())
670	{	//don't update flexible attachments for impostored avatars unless the 
671		//impostor is being updated this frame (w00!)
672		LLViewerObject* parent = (LLViewerObject*) mVO->getParent();
673		while (parent && !parent->isAvatar())
674		{
675			parent = (LLViewerObject*) parent->getParent();
676		}
677		
678		if (parent)
679		{
680			LLVOAvatar* avatar = (LLVOAvatar*) parent;
681			if (avatar->isImpostor() && !avatar->needsImpostorUpdate())
682			{
683				return TRUE;
684			}
685		}
686	}
687
688	if (volume->mDrawable.isNull())
689	{
690		return TRUE; // No update to complete
691	}
692
693	if (volume->mLODChanged)
694	{
695		LLVolumeParams volume_params = volume->getVolume()->getParams();
696		volume->setVolume(volume_params, 0);
697		mUpdated = FALSE;
698	}
699
700	volume->updateRelativeXform();
701
702	if (mRenderRes > -1)
703	{
704		LLFastTimer t(FTM_DO_FLEXIBLE_UPDATE);
705		doFlexibleUpdate();
706	}
707	
708	// Object may have been rotated, which means it needs a rebuild.  See SL-47220
709	BOOL	rotated = FALSE;
710	LLQuaternion cur_rotation = getFrameRotation();
711	if ( cur_rotation != mLastFrameRotation )
712	{
713		mLastFrameRotation = cur_rotation;
714		rotated = TRUE;
715	}
716
717	if (volume->mLODChanged || volume->mFaceMappingChanged ||
718		volume->mVolumeChanged || drawable->isState(LLDrawable::REBUILD_MATERIAL))
719	{
720		volume->regenFaces();
721		volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME);
722		volume->dirtySpatialGroup();
723		{
724			LLFastTimer t(FTM_FLEXIBLE_REBUILD);
725			doFlexibleRebuild();
726		}
727		volume->genBBoxes(isVolumeGlobal());
728	}
729	else if (!mUpdated || rotated)
730	{
731		volume->mDrawable->setState(LLDrawable::REBUILD_POSITION);
732		volume->dirtyMesh();
733		volume->genBBoxes(isVolumeGlobal());
734	}
735			
736	volume->mVolumeChanged = FALSE;
737	volume->mLODChanged = FALSE;
738	volume->mFaceMappingChanged = FALSE;
739
740	// clear UV flag
741	drawable->clearState(LLDrawable::UV);
742	
743	return TRUE;
744}
745
746//----------------------------------------------------------------------------------
747void LLVolumeImplFlexible::setCollisionSphere( LLVector3 p, F32 r )
748{
749	mCollisionSpherePosition = p;
750	mCollisionSphereRadius   = r;
751
752}//------------------------------------------------------------------
753
754
755//----------------------------------------------------------------------------------
756void LLVolumeImplFlexible::setUsingCollisionSphere( bool u )
757{
758}//------------------------------------------------------------------
759
760
761//----------------------------------------------------------------------------------
762void LLVolumeImplFlexible::setRenderingCollisionSphere( bool r )
763{
764}//------------------------------------------------------------------
765
766//------------------------------------------------------------------
767LLVector3 LLVolumeImplFlexible::getEndPosition()
768{
769	S32 num_sections = 1 << mAttributes->getSimulateLOD();
770	return mSection[ num_sections ].mPosition;
771
772}//------------------------------------------------------------------
773
774
775//------------------------------------------------------------------
776LLVector3 LLVolumeImplFlexible::getNodePosition( int nodeIndex )
777{
778	S32 num_sections = 1 << mAttributes->getSimulateLOD();
779	if ( nodeIndex > num_sections - 1 )
780	{
781		nodeIndex = num_sections - 1;
782	}
783	else if ( nodeIndex < 0 ) 
784	{
785		nodeIndex = 0;
786	}
787
788	return mSection[ nodeIndex ].mPosition;
789
790}//------------------------------------------------------------------
791
792LLVector3 LLVolumeImplFlexible::getPivotPosition() const
793{
794	return getAnchorPosition();
795}
796
797//------------------------------------------------------------------
798LLVector3 LLVolumeImplFlexible::getAnchorPosition() const
799{
800	LLVector3 BasePosition = getFramePosition();
801	LLQuaternion parentSegmentRotation = getFrameRotation();
802	LLVector3 anchorDirectionRotated = LLVector3::z_axis * parentSegmentRotation;
803	LLVector3 anchorScale = mVO->mDrawable->getScale();
804	return BasePosition - (anchorScale.mV[VZ]/2 * anchorDirectionRotated);
805
806}//------------------------------------------------------------------
807
808
809//------------------------------------------------------------------
810LLQuaternion LLVolumeImplFlexible::getEndRotation()
811{
812	return mLastSegmentRotation;
813
814}//------------------------------------------------------------------
815
816
817void LLVolumeImplFlexible::updateRelativeXform()
818{
819	LLQuaternion delta_rot;
820	LLVector3 delta_pos, delta_scale;
821	LLVOVolume* vo = (LLVOVolume*) mVO;
822
823	//matrix from local space to parent relative/global space
824	delta_rot = vo->mDrawable->isSpatialRoot() ? LLQuaternion() : vo->mDrawable->getRotation();
825	delta_pos = vo->mDrawable->isSpatialRoot() ? LLVector3(0,0,0) : vo->mDrawable->getPosition();
826	delta_scale = LLVector3(1,1,1);
827
828	// Vertex transform (4x4)
829	LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
830	LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
831	LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
832
833	vo->mRelativeXform.initRows(LLVector4(x_axis, 0.f),
834							LLVector4(y_axis, 0.f),
835							LLVector4(z_axis, 0.f),
836							LLVector4(delta_pos, 1.f));
837			
838	x_axis.normVec();
839	y_axis.normVec();
840	z_axis.normVec();
841	
842	vo->mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
843}
844
845const LLMatrix4& LLVolumeImplFlexible::getWorldMatrix(LLXformMatrix* xform) const
846{
847	return xform->getWorldMatrix();
848}