summaryrefslogtreecommitdiff
path: root/indra/newview/llflexibleobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llflexibleobject.cpp')
-rw-r--r--indra/newview/llflexibleobject.cpp832
1 files changed, 832 insertions, 0 deletions
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
new file mode 100644
index 0000000000..4f821a7978
--- /dev/null
+++ b/indra/newview/llflexibleobject.cpp
@@ -0,0 +1,832 @@
+/**
+ * @file llflexibleobject.cpp
+ * @brief Flexible object implementation
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "pipeline.h"
+#include "lldrawpoolbump.h"
+#include "llface.h"
+#include "llflexibleobject.h"
+#include "llglheaders.h"
+#include "llsphere.h"
+#include "llviewerobject.h"
+#include "llimagegl.h"
+#include "llagent.h"
+#include "llsky.h"
+#include "llviewercamera.h"
+#include "llviewerimagelist.h"
+#include "llviewercontrol.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llworld.h"
+
+/*static*/ LLVolumeImplFlexible::lodset_t LLVolumeImplFlexible::sLODBins[ FLEXIBLE_OBJECT_MAX_LOD ];
+/*static*/ U64 LLVolumeImplFlexible::sCurrentUpdateFrame = 0;
+/*static*/ U32 LLVolumeImplFlexible::sDebugInserted = 0;
+/*static*/ U32 LLVolumeImplFlexible::sDebugVisible = 0;
+
+/*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f;
+
+// LLFlexibleObjectData::pack/unpack now in llprimitive.cpp
+
+//-----------------------------------------------
+// constructor
+//-----------------------------------------------
+LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectData* attributes) :
+ mVO(vo), mAttributes(attributes)
+{
+ mInitialized = FALSE;
+ mUpdated = FALSE;
+ mJustShifted = FALSE;
+ mInitializedRes = -1;
+ mSimulateRes = 0;
+ mFrameNum = 0;
+ mLastUpdate = 0;
+
+}//-----------------------------------------------
+
+LLVector3 LLVolumeImplFlexible::getFramePosition() const
+{
+ return mVO->getRenderPosition();
+}
+
+LLQuaternion LLVolumeImplFlexible::getFrameRotation() const
+{
+ return mVO->getRenderRotation();
+}
+
+void LLVolumeImplFlexible::onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin)
+{
+ if (param_type == LLNetworkData::PARAMS_FLEXIBLE)
+ {
+ mAttributes = (LLFlexibleObjectData*)data;
+ setAttributesOfAllSections();
+ }
+}
+
+void LLVolumeImplFlexible::onShift(const LLVector3 &shift_vector)
+{
+ for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section)
+ {
+ mSection[section].mPosition += shift_vector;
+ }
+ mVO->getVolume()->mBounds[0] += shift_vector;
+}
+
+//-----------------------------------------------------------------------------------------------
+void LLVolumeImplFlexible::setParentPositionAndRotationDirectly( LLVector3 p, LLQuaternion r )
+{
+ mParentPosition = p;
+ mParentRotation = r;
+
+}//-----------------------------------------------------------------------------------------------------
+
+void LLVolumeImplFlexible::remapSections(LLFlexibleObjectSection *source, S32 source_sections,
+ LLFlexibleObjectSection *dest, S32 dest_sections)
+{
+ S32 num_output_sections = 1<<dest_sections;
+ LLVector3 scale = mVO->mDrawable->getScale();
+ F32 source_section_length = scale.mV[VZ] / (F32)(1<<source_sections);
+ F32 section_length = scale.mV[VZ] / (F32)num_output_sections;
+ if (source_sections == -1)
+ {
+ // Generate all from section 0
+ dest[0] = source[0];
+ for (S32 section=0; section<num_output_sections; ++section)
+ {
+ dest[section+1] = dest[section];
+ dest[section+1].mPosition += dest[section].mDirection * section_length;
+ dest[section+1].mVelocity.setVec( LLVector3::zero );
+ }
+ }
+ else if (source_sections > dest_sections)
+ {
+ // Copy, skipping sections
+
+ S32 num_steps = 1<<(source_sections-dest_sections);
+
+ // Copy from left to right since it may be an in-place computation
+ for (S32 section=0; section<num_output_sections; ++section)
+ {
+ dest[section+1] = source[(section+1)*num_steps];
+ }
+ dest[0] = source[0];
+ }
+ else if (source_sections < dest_sections)
+ {
+ // Interpolate section info
+ // Iterate from right to left since it may be an in-place computation
+ S32 step_shift = dest_sections-source_sections;
+ S32 num_steps = 1<<step_shift;
+ for (S32 section=num_output_sections-num_steps; section>=0; section -= num_steps)
+ {
+ LLFlexibleObjectSection *last_source_section = &source[section>>step_shift];
+ LLFlexibleObjectSection *source_section = &source[(section>>step_shift)+1];
+
+ // Cubic interpolation of position
+ // At^3 + Bt^2 + Ct + D = f(t)
+ LLVector3 D = last_source_section->mPosition;
+ LLVector3 C = last_source_section->mdPosition * source_section_length;
+ LLVector3 Y = source_section->mdPosition * source_section_length - C; // Helper var
+ LLVector3 X = (source_section->mPosition - D - C); // Helper var
+ LLVector3 A = Y - 2*X;
+ LLVector3 B = X - A;
+
+ F32 t_inc = 1.f/F32(num_steps);
+ F32 t = t_inc;
+ for (S32 step=1; step<num_steps; ++step)
+ {
+ dest[section+step].mScale =
+ lerp(last_source_section->mScale, source_section->mScale, t);
+ dest[section+step].mAxisRotation =
+ slerp(t, last_source_section->mAxisRotation, source_section->mAxisRotation);
+
+ // Evaluate output interpolated values
+ F32 t_sq = t*t;
+ dest[section+step].mPosition = t_sq*(t*A + B) + t*C + D;
+ dest[section+step].mRotation =
+ slerp(t, last_source_section->mRotation, source_section->mRotation);
+ dest[section+step].mVelocity = lerp(last_source_section->mVelocity, source_section->mVelocity, t);
+ dest[section+step].mDirection = lerp(last_source_section->mDirection, source_section->mDirection, t);
+ dest[section+step].mdPosition = lerp(last_source_section->mdPosition, source_section->mdPosition, t);
+ dest[section+num_steps] = *source_section;
+ t += t_inc;
+ }
+ }
+ dest[0] = source[0];
+ }
+ else
+ {
+ // numbers are equal. copy info
+ for (S32 section=0; section <= num_output_sections; ++section)
+ {
+ dest[section] = source[section];
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void LLVolumeImplFlexible::setAttributesOfAllSections()
+{
+ LLVector2 bottom_scale, top_scale;
+ F32 begin_rot = 0, end_rot = 0;
+ if (mVO->getVolume())
+ {
+ const LLPathParams &params = mVO->getVolume()->getParams().getPathParams();
+ bottom_scale = params.getBeginScale();
+ top_scale = params.getEndScale();
+ begin_rot = F_PI * params.getTwistBegin();
+ end_rot = F_PI * params.getTwist();
+ }
+
+ S32 num_sections = 1 << mSimulateRes;
+
+
+ LLVector3 scale = mVO->mDrawable->getScale();
+
+ mSection[0].mPosition = getAnchorPosition();
+ mSection[0].mDirection = LLVector3::z_axis * getFrameRotation();
+ mSection[0].mdPosition = mSection[0].mDirection;
+ mSection[0].mScale.setVec(scale.mV[VX]*bottom_scale.mV[0], scale.mV[VY]*bottom_scale.mV[1]);
+ mSection[0].mVelocity.setVec(0,0,0);
+ mSection[0].mAxisRotation.setQuat(begin_rot,0,0,1);
+
+ LLVector3 parentSectionPosition = mSection[0].mPosition;
+ LLVector3 last_direction = mSection[0].mDirection;
+
+ remapSections(mSection, mInitializedRes, mSection, mSimulateRes);
+ mInitializedRes = mSimulateRes;
+
+ F32 t_inc = 1.f/F32(num_sections);
+ F32 t = t_inc;
+ for ( int i=1; i<= num_sections; i++)
+ {
+ mSection[i].mAxisRotation.setQuat(lerp(begin_rot,end_rot,t),0,0,1);
+ mSection[i].mScale = LLVector2(
+ scale.mV[VX] * lerp(bottom_scale.mV[0], top_scale.mV[0], t),
+ scale.mV[VY] * lerp(bottom_scale.mV[1], top_scale.mV[1], t));
+ t += t_inc;
+ }
+ mLastUpdate = 0;
+}//-----------------------------------------------------------------------------------
+
+
+void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail)
+{
+ doIdleUpdate(gAgent, *gWorldp, 0.0);
+ if (mVO && mVO->mDrawable.notNull())
+ {
+ gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+ gPipeline.markMoved(mVO->mDrawable);
+ }
+}
+
+//---------------------------------------------------------------------------------
+// This calculates the physics of the flexible object. Note that it has to be 0
+// updated every time step. In the future, perhaps there could be an
+// optimization similar to what Havok does for objects that are stationary.
+//---------------------------------------------------------------------------------
+BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+ if (mVO->mDrawable.isNull())
+ {
+ // Don't do anything until we have a drawable
+ return TRUE;
+ }
+
+ //flexible objects never go static
+ mVO->mDrawable->mQuietCount = 0;
+ if (!mVO->mDrawable->isRoot())
+ {
+ mVO->mDrawable->getParent()->mQuietCount = 0;
+ }
+
+ if (((LLVOVolume*)mVO)->mLODChanged ||
+ mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1))
+ {
+ mLastUpdate = 0; // Force an immediate update
+ }
+ // Relegate invisible objects to the lowest priority bin
+ S32 lod = 0;
+ F32 app_angle = mVO->getAppAngle()*DEG_TO_RAD/gCamera->getView();
+ if (mVO->mDrawable->isVisible())
+ {
+ sDebugVisible++;
+ if (mVO->isSelected())
+ {
+ // Force selected objects to update *every* frame
+ lod = FLEXIBLE_OBJECT_MAX_LOD-1;
+ }
+ else
+ {
+ if (app_angle > 0)
+ {
+ lod = 5 - (S32)(1.0f/sqrtf(app_angle));
+ if (lod < 1)
+ {
+ lod = 1;
+ }
+ }
+
+ if (mVO->isAttachment())
+ {
+ lod += 3;
+ }
+ }
+ }
+
+ S32 new_res = mAttributes->getSimulateLOD();
+ // Rendering sections increases with visible angle on the screen
+ mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle);
+ if (mRenderRes > FLEXIBLE_OBJECT_MAX_SECTIONS)
+ {
+ mRenderRes = FLEXIBLE_OBJECT_MAX_SECTIONS;
+ }
+ // Bottom cap at 1/4 the original number of sections
+ if (mRenderRes < mAttributes->getSimulateLOD()-1)
+ {
+ mRenderRes = mAttributes->getSimulateLOD()-1;
+ }
+ // Throttle back simulation of segments we're not rendering
+ if (mRenderRes < new_res)
+ {
+ new_res = mRenderRes;
+ }
+
+ if (!mInitialized || (mSimulateRes != new_res))
+ {
+ mSimulateRes = new_res;
+ setAttributesOfAllSections();
+ mInitialized = TRUE;
+ }
+
+ sLODBins[lod].insert(this);
+ sDebugInserted++;
+ return TRUE;
+}
+
+// static
+void LLVolumeImplFlexible::resetUpdateBins()
+{
+ U32 lod;
+ for (lod=0; lod<FLEXIBLE_OBJECT_MAX_LOD; ++lod)
+ {
+ sLODBins[lod].clear();
+ }
+ ++sCurrentUpdateFrame;
+ sDebugInserted = 0;
+ sDebugVisible = 0;
+}
+
+inline S32 log2(S32 x)
+{
+ S32 ret = 0;
+ while (x > 1)
+ {
+ ++ret;
+ x >>= 1;
+ }
+ return ret;
+}
+
+// static
+void LLVolumeImplFlexible::doFlexibleUpdateBins()
+{
+ U32 lod;
+ U32 updated = 0;
+ U32 regen = 0;
+ U32 newflexies = 0;
+ F32 time_alloc[FLEXIBLE_OBJECT_MAX_LOD];
+ F32 total_time_alloc = 0;
+
+ bool new_objects_only = false;
+
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE))
+ {
+ new_objects_only = true;
+ }
+
+ for (lod=0; lod<FLEXIBLE_OBJECT_MAX_LOD; ++lod)
+ {
+ int count = sLODBins[lod].size();
+ if (count > 0)
+ {
+ time_alloc[lod] = (F32)((lod+1)*(log2(count)));
+ }
+ else
+ {
+ time_alloc[lod] = 0;
+ }
+ total_time_alloc += time_alloc[lod];
+ }
+ total_time_alloc = FLEXIBLE_OBJECT_TIMESLICE * (sUpdateFactor+0.01f) / total_time_alloc;
+
+ {
+ LLFastTimer t(LLFastTimer::FTM_FLEXIBLE_UPDATE);
+ LLTimer timer;
+ for (lod=0; lod<FLEXIBLE_OBJECT_MAX_LOD; ++lod)
+ {
+ LLVolumeImplFlexible::lodset_t::iterator itor = sLODBins[lod].begin();
+ int bin_count = 0;
+ if (!new_objects_only)
+ {
+ timer.reset();
+ double end_time = time_alloc[lod] * total_time_alloc;
+ for (; itor!=sLODBins[lod].end(); ++itor)
+ {
+
+ (*itor)->doFlexibleUpdate();
+ ++updated;
+ (*itor)->doFlexibleRebuild();
+ ++bin_count;
+ ++regen;
+ if (timer.getElapsedTimeF64() > end_time)
+ {
+ break;
+ }
+ }
+ }
+ for (; itor != sLODBins[lod].end(); ++itor)
+ {
+ if ((*itor)->getLastUpdate() == 0)
+ {
+ // *Always* update newly-created objects, or objects which have changed LOD
+ (*itor)->doFlexibleUpdate();
+ (*itor)->doFlexibleRebuild();
+ ++newflexies;
+ }
+ }
+ }
+ }
+}
+
+void LLVolumeImplFlexible::doFlexibleUpdate()
+{
+ LLPath *path = &mVO->getVolume()->getPath();
+ S32 num_sections = 1 << mSimulateRes;
+
+ F32 secondsThisFrame = mTimer.getElapsedTimeAndResetF32();
+ if (secondsThisFrame > 0.2f)
+ {
+ secondsThisFrame = 0.2f;
+ }
+
+ LLVector3 BasePosition = getFramePosition();
+ LLQuaternion BaseRotation = getFrameRotation();
+ LLQuaternion parentSegmentRotation = BaseRotation;
+ LLVector3 anchorDirectionRotated = LLVector3::z_axis * parentSegmentRotation;
+ LLVector3 anchorScale = mVO->mDrawable->getScale();
+
+ F32 section_length = anchorScale.mV[VZ] / (F32)num_sections;
+ F32 inv_section_length = 1.f / section_length;
+
+ S32 i;
+
+ // ANCHOR position is offset from BASE position (centroid) by half the length
+ LLVector3 AnchorPosition = BasePosition - (anchorScale.mV[VZ]/2 * anchorDirectionRotated);
+
+ mSection[0].mPosition = AnchorPosition;
+ mSection[0].mDirection = anchorDirectionRotated;
+ mSection[0].mRotation = BaseRotation;
+
+ LLQuaternion deltaRotation;
+
+ LLVector3 lastPosition;
+
+ // Coefficients which are constant across sections
+ F32 t_factor = mAttributes->getTension() * 0.1f;
+ t_factor = t_factor*(1 - pow(0.85f, secondsThisFrame*30));
+ if ( t_factor > FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE )
+ {
+ t_factor = FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE;
+ }
+
+ F32 friction_coeff = (mAttributes->getAirFriction()*2+1);
+ friction_coeff = pow(10.f, friction_coeff*secondsThisFrame);
+ friction_coeff = (friction_coeff > 1) ? friction_coeff : 1;
+ F32 momentum = 1.0f / friction_coeff;
+
+ F32 wind_factor = (mAttributes->getWindSensitivity()*0.1f) * section_length * secondsThisFrame;
+ F32 max_angle = atan(section_length*2.f);
+
+ F32 force_factor = section_length * secondsThisFrame;
+
+ // Update simulated sections
+ for (i=1; i<=num_sections; ++i)
+ {
+ LLVector3 parentSectionVector;
+ LLVector3 parentSectionPosition;
+ LLVector3 parentDirection;
+
+ //---------------------------------------------------
+ // save value of position as lastPosition
+ //---------------------------------------------------
+ lastPosition = mSection[i].mPosition;
+
+ //------------------------------------------------------------------------------------------
+ // gravity
+ //------------------------------------------------------------------------------------------
+ mSection[i].mPosition.mV[2] -= mAttributes->getGravity() * force_factor;
+
+ //------------------------------------------------------------------------------------------
+ // wind force
+ //------------------------------------------------------------------------------------------
+ if (mAttributes->getWindSensitivity() > 0.001f)
+ {
+ mSection[i].mPosition += gAgent.getRegion()->mWind.getVelocity( mSection[i].mPosition ) * wind_factor;
+ }
+
+ //------------------------------------------------------------------------------------------
+ // user-defined force
+ //------------------------------------------------------------------------------------------
+ mSection[i].mPosition += mAttributes->getUserForce() * force_factor;
+
+ //---------------------------------------------------
+ // tension (rigidity, stiffness)
+ //---------------------------------------------------
+ parentSectionPosition = mSection[i-1].mPosition;
+ parentDirection = mSection[i-1].mDirection;
+
+ if ( i == 1 )
+ {
+ parentSectionVector = mSection[0].mDirection;
+ }
+ else
+ {
+ parentSectionVector = mSection[i-2].mDirection;
+ }
+
+ LLVector3 currentVector = mSection[i].mPosition - parentSectionPosition;
+
+ LLVector3 difference = (parentSectionVector*section_length) - currentVector;
+ LLVector3 tensionForce = difference * t_factor;
+
+ mSection[i].mPosition += tensionForce;
+
+ //------------------------------------------------------------------------------------------
+ // sphere collision, currently not used
+ //------------------------------------------------------------------------------------------
+ /*if ( mAttributes->mUsingCollisionSphere )
+ {
+ LLVector3 vectorToCenterOfCollisionSphere = mCollisionSpherePosition - mSection[i].mPosition;
+ if ( vectorToCenterOfCollisionSphere.magVecSquared() < mCollisionSphereRadius * mCollisionSphereRadius )
+ {
+ F32 distanceToCenterOfCollisionSphere = vectorToCenterOfCollisionSphere.magVec();
+ F32 penetration = mCollisionSphereRadius - distanceToCenterOfCollisionSphere;
+
+ LLVector3 normalToCenterOfCollisionSphere;
+
+ if ( distanceToCenterOfCollisionSphere > 0.0f )
+ {
+ normalToCenterOfCollisionSphere = vectorToCenterOfCollisionSphere / distanceToCenterOfCollisionSphere;
+ }
+ else // rare
+ {
+ normalToCenterOfCollisionSphere = LLVector3::x_axis; // arbitrary
+ }
+
+ // push the position out to the surface of the collision sphere
+ mSection[i].mPosition -= normalToCenterOfCollisionSphere * penetration;
+ }
+ }*/
+
+ //------------------------------------------------------------------------------------------
+ // inertia
+ //------------------------------------------------------------------------------------------
+ mSection[i].mPosition += mSection[i].mVelocity * momentum;
+
+ //------------------------------------------------------------------------------------------
+ // clamp length & rotation
+ //------------------------------------------------------------------------------------------
+ mSection[i].mDirection = mSection[i].mPosition - parentSectionPosition;
+ mSection[i].mDirection.normVec();
+ deltaRotation.shortestArc( parentDirection, mSection[i].mDirection );
+
+ F32 angle;
+ LLVector3 axis;
+ deltaRotation.getAngleAxis(&angle, axis);
+ if (angle > F_PI) angle -= 2.f*F_PI;
+ if (angle < -F_PI) angle += 2.f*F_PI;
+ if (angle > max_angle)
+ {
+ //angle = 0.5f*(angle+max_angle);
+ deltaRotation.setQuat(max_angle, axis);
+ } else if (angle < -max_angle)
+ {
+ //angle = 0.5f*(angle-max_angle);
+ deltaRotation.setQuat(-max_angle, axis);
+ }
+ LLQuaternion segment_rotation = parentSegmentRotation * deltaRotation;
+ parentSegmentRotation = segment_rotation;
+
+ mSection[i].mDirection = (parentDirection * deltaRotation);
+ mSection[i].mPosition = parentSectionPosition + mSection[i].mDirection * section_length;
+ mSection[i].mRotation = segment_rotation;
+
+ if (i > 1)
+ {
+ // Propogate half the rotation up to the parent
+ LLQuaternion halfDeltaRotation(angle/2, axis);
+ mSection[i-1].mRotation = mSection[i-1].mRotation * halfDeltaRotation;
+ }
+
+ //------------------------------------------------------------------------------------------
+ // calculate velocity
+ //------------------------------------------------------------------------------------------
+ mSection[i].mVelocity = mSection[i].mPosition - lastPosition;
+ }
+
+ // Calculate derivatives (not necessary until normals are automagically generated)
+ mSection[0].mdPosition = (mSection[1].mPosition - mSection[0].mPosition) * inv_section_length;
+ // i = 1..NumSections-1
+ for (i=1; i<num_sections; ++i)
+ {
+ // Quadratic numerical derivative of position
+
+ // f(-L1) = aL1^2 - bL1 + c = f1
+ // f(0) = c = f2
+ // f(L2) = aL2^2 + bL2 + c = f3
+ // f = ax^2 + bx + c
+ // d/dx f = 2ax + b
+ // d/dx f(0) = b
+
+ // c = f2
+ // a = [(f1-c)/L1 + (f3-c)/L2] / (L1+L2)
+ // b = (f3-c-aL2^2)/L2
+
+ LLVector3 a = (mSection[i-1].mPosition-mSection[i].mPosition +
+ mSection[i+1].mPosition-mSection[i].mPosition) * 0.5f * inv_section_length * inv_section_length;
+ LLVector3 b = (mSection[i+1].mPosition-mSection[i].mPosition - a*(section_length*section_length));
+ b *= inv_section_length;
+
+ mSection[i].mdPosition = b;
+ }
+
+ // i = NumSections
+ mSection[i].mdPosition = (mSection[i].mPosition - mSection[i-1].mPosition) * inv_section_length;
+
+ // Create points
+ S32 num_render_sections = 1<<mRenderRes;
+ path->resizePath(num_render_sections+1);
+
+ LLPath::PathPt *new_point;
+
+ LLFlexibleObjectSection newSection[ (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1 ];
+ remapSections(mSection, mSimulateRes, newSection, mRenderRes);
+
+ for (i=0; i<=num_render_sections; ++i)
+ {
+ new_point = &path->mPath[i];
+ new_point->mPos = newSection[i].mPosition;
+ new_point->mRot = mSection[i].mAxisRotation * newSection[i].mRotation;
+ new_point->mScale = newSection[i].mScale;
+ new_point->mTexT = ((F32)i)/(num_render_sections);
+ }
+
+ mLastSegmentRotation = parentSegmentRotation;
+}
+
+void LLVolumeImplFlexible::doFlexibleRebuild()
+{
+ mVO->getVolume()->regen();
+
+ mVO->markForUpdate(TRUE);
+
+ mUpdated = TRUE;
+
+ mLastUpdate = sCurrentUpdateFrame;
+}//------------------------------------------------------------------
+
+void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped)
+{
+ setAttributesOfAllSections();
+}
+
+BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
+{
+ BOOL compiled = FALSE;
+
+ LLVOVolume *volume = (LLVOVolume*)mVO;
+
+ if (volume->mDrawable.isNull()) // Not sure why this is happening, but it is...
+ {
+ return TRUE; // No update to complete
+ }
+
+ volume->calcAllTEsSame();
+
+ if (volume->mVolumeChanged || volume->mFaceMappingChanged)
+ {
+ compiled = TRUE;
+ volume->regenFaces();
+ }
+ else if (volume->mLODChanged)
+ {
+ LLPointer<LLVolume> old_volumep, new_volumep;
+ F32 old_lod, new_lod;
+
+ old_volumep = volume->getVolume();
+ old_lod = old_volumep->getDetail();
+
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ volume->setVolume(volume_params, 0);
+ doFlexibleUpdate();
+ volume->getVolume()->regen();
+
+ new_volumep = volume->getVolume();
+ new_lod = new_volumep->getDetail();
+
+ if (new_lod != old_lod)
+ {
+ compiled = TRUE;
+ if (new_volumep->getNumFaces() != old_volumep->getNumFaces())
+ {
+ volume->regenFaces();
+ }
+ }
+ }
+
+ if (mUpdated)
+ {
+ compiled = TRUE;
+ mUpdated = FALSE;
+ }
+
+ if(compiled)
+ {
+ volume->updateRelativeXform(isVolumeGlobal());
+ volume->genTriangles(isVolumeGlobal());
+ LLPipeline::sCompiles++;
+ }
+
+ volume->mVolumeChanged = FALSE;
+ volume->mLODChanged = FALSE;
+ volume->mFaceMappingChanged = FALSE;
+
+ // clear UV flag
+ drawable->clearState(LLDrawable::UV);
+
+ drawable->movePartition();
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------------
+void LLVolumeImplFlexible::setCollisionSphere( LLVector3 p, F32 r )
+{
+ mCollisionSpherePosition = p;
+ mCollisionSphereRadius = r;
+
+}//------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------------
+void LLVolumeImplFlexible::setUsingCollisionSphere( bool u )
+{
+}//------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------------
+void LLVolumeImplFlexible::setRenderingCollisionSphere( bool r )
+{
+}//------------------------------------------------------------------
+
+//------------------------------------------------------------------
+LLVector3 LLVolumeImplFlexible::getEndPosition()
+{
+ S32 num_sections = 1 << mAttributes->getSimulateLOD();
+ return mSection[ num_sections ].mPosition;
+
+}//------------------------------------------------------------------
+
+
+//------------------------------------------------------------------
+LLVector3 LLVolumeImplFlexible::getNodePosition( int nodeIndex )
+{
+ S32 num_sections = 1 << mAttributes->getSimulateLOD();
+ if ( nodeIndex > num_sections - 1 )
+ {
+ nodeIndex = num_sections - 1;
+ }
+ else if ( nodeIndex < 0 )
+ {
+ nodeIndex = 0;
+ }
+
+ return mSection[ nodeIndex ].mPosition;
+
+}//------------------------------------------------------------------
+
+LLVector3 LLVolumeImplFlexible::getPivotPosition() const
+{
+ return getAnchorPosition();
+}
+
+//------------------------------------------------------------------
+LLVector3 LLVolumeImplFlexible::getAnchorPosition() const
+{
+ LLVector3 BasePosition = getFramePosition();
+ LLQuaternion parentSegmentRotation = getFrameRotation();
+ LLVector3 anchorDirectionRotated = LLVector3::z_axis * parentSegmentRotation;
+ LLVector3 anchorScale = mVO->mDrawable->getScale();
+ return BasePosition - (anchorScale.mV[VZ]/2 * anchorDirectionRotated);
+
+}//------------------------------------------------------------------
+
+
+//------------------------------------------------------------------
+LLQuaternion LLVolumeImplFlexible::getEndRotation()
+{
+ return mLastSegmentRotation;
+
+}//------------------------------------------------------------------
+
+
+void LLVolumeImplFlexible::updateRelativeXform(BOOL global_volume)
+{
+ LLVOVolume* vo = (LLVOVolume*) mVO;
+
+ LLVector3 delta_scale = LLVector3(1,1,1);
+ LLVector3 delta_pos;
+ LLQuaternion delta_rot;
+
+ if (!mVO->mDrawable->isRoot())
+ { //global to parent relative
+ LLViewerObject* parent = (LLViewerObject*) vo->getParent();
+ delta_rot = ~parent->getRenderRotation();
+ delta_pos = -parent->getRenderPosition()*delta_rot;
+ }
+ else
+ { //global to local
+ delta_rot = ~getFrameRotation();
+ delta_pos = -getFramePosition()*delta_rot;
+ }
+
+ // Vertex transform (4x4)
+ LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
+ LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
+ LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
+
+ vo->mRelativeXform.initRows(LLVector4(x_axis, 0.f),
+ LLVector4(y_axis, 0.f),
+ LLVector4(z_axis, 0.f),
+ LLVector4(delta_pos, 1.f));
+
+ x_axis.normVec();
+ y_axis.normVec();
+ z_axis.normVec();
+
+ vo->mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
+
+}
+
+const LLMatrix4& LLVolumeImplFlexible::getWorldMatrix(LLXformMatrix* xform) const
+{
+ return xform->getWorldMatrix();
+}