diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llflexibleobject.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llflexibleobject.cpp')
-rw-r--r-- | indra/newview/llflexibleobject.cpp | 1878 |
1 files changed, 939 insertions, 939 deletions
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index cef4bd284d..4d82611def 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -1,939 +1,939 @@ -/**
- * @file llflexibleobject.cpp
- * @brief Flexible object implementation
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "pipeline.h"
-#include "lldrawpoolbump.h"
-#include "llface.h"
-#include "llflexibleobject.h"
-#include "llglheaders.h"
-#include "llrendersphere.h"
-#include "llviewerobject.h"
-#include "llagent.h"
-#include "llsky.h"
-#include "llviewercamera.h"
-#include "llviewertexturelist.h"
-#include "llviewercontrol.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llworld.h"
-#include "llvoavatar.h"
-
-static const F32 SEC_PER_FLEXI_FRAME = 1.f / 60.f; // 60 flexi updates per second
-/*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f;
-std::vector<LLVolumeImplFlexible*> LLVolumeImplFlexible::sInstanceList;
-
-// LLFlexibleObjectData::pack/unpack now in llprimitive.cpp
-
-//-----------------------------------------------
-// constructor
-//-----------------------------------------------
-LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectData* attributes) :
- mVO(vo),
- mAttributes(attributes),
- mLastFrameNum(0),
- mLastUpdatePeriod(0)
-{
- static U32 seed = 0;
- mID = seed++;
- mInitialized = false;
- mUpdated = false;
- mInitializedRes = -1;
- mSimulateRes = 0;
- mCollisionSphereRadius = 0.f;
- mRenderRes = -1;
-
- if(mVO->mDrawable.notNull())
- {
- mVO->mDrawable->makeActive() ;
- }
-
- mInstanceIndex = sInstanceList.size();
- sInstanceList.push_back(this);
-}//-----------------------------------------------
-
-LLVolumeImplFlexible::~LLVolumeImplFlexible()
-{
- S32 end_idx = sInstanceList.size()-1;
-
- if (end_idx != mInstanceIndex)
- {
- sInstanceList[mInstanceIndex] = sInstanceList[end_idx];
- sInstanceList[mInstanceIndex]->mInstanceIndex = mInstanceIndex;
- }
-
- sInstanceList.pop_back();
-}
-
-//static
-void LLVolumeImplFlexible::updateClass()
-{
- LL_PROFILE_ZONE_SCOPED;
-
- U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME;
- for (std::vector<LLVolumeImplFlexible*>::iterator iter = sInstanceList.begin();
- iter != sInstanceList.end();
- ++iter)
- {
- // Note: by now update period might have changed
- if ((*iter)->mRenderRes == -1
- || (*iter)->mLastFrameNum + (*iter)->mLastUpdatePeriod <= virtual_frame_num
- || (*iter)->mLastFrameNum > virtual_frame_num) //time issues, overflow
- {
- (*iter)->doIdleUpdate();
- }
- }
-}
-
-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 LLVector4a &shift_vector)
-{
- //VECTORIZE THIS
- LLVector3 shift(shift_vector.getF32ptr());
- for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section)
- {
- mSection[section].mPosition += shift;
- }
-}
-
-//-----------------------------------------------------------------------------------------------
-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(LLVector3* inScale)
-{
- LLVector2 bottom_scale, top_scale;
- F32 begin_rot = 0, end_rot = 0;
- if (mVO->getVolume())
- {
- const LLPathParams ¶ms = mVO->getVolume()->getParams().getPathParams();
- bottom_scale = params.getBeginScale();
- top_scale = params.getEndScale();
- begin_rot = F_PI * params.getTwistBegin();
- end_rot = F_PI * params.getTwist();
- }
-
- if (!mVO->mDrawable)
- {
- return;
- }
-
- S32 num_sections = 1 << mSimulateRes;
-
- LLVector3 scale;
- if (inScale == (LLVector3*)NULL)
- {
- scale = mVO->mDrawable->getScale();
- }
- else
- {
- scale = *inScale;
- }
-
- 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);
-
- 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;
- }
-}//-----------------------------------------------------------------------------------
-
-
-void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail)
-{
-}
-
-
-void LLVolumeImplFlexible::updateRenderRes()
-{
- if (!mAttributes)
- return;
-
- LLDrawable* drawablep = mVO->mDrawable;
-
- S32 new_res = mAttributes->getSimulateLOD();
-
-#if 1 //optimal approximation of previous behavior that doesn't rely on atan2
- F32 app_angle = mVO->getScale().mV[2]/drawablep->mDistanceWRTCamera;
-
- // Rendering sections increases with visible angle on the screen
- mRenderRes = (S32) (12.f*app_angle);
-#else //legacy behavior
- //number of segments only cares about z axis
- F32 app_angle = ll_round((F32) atan2( mVO->getScale().mV[2]*2.f, drawablep->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
-
- // Rendering sections increases with visible angle on the screen
- mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView());
-#endif
-
- mRenderRes = llclamp(mRenderRes, new_res-1, (S32) FLEXIBLE_OBJECT_MAX_SECTIONS);
-
- // 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;
- }
-}
-//---------------------------------------------------------------------------------
-// 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.
-//---------------------------------------------------------------------------------
-void LLVolumeImplFlexible::doIdleUpdate()
-{
- LLDrawable* drawablep = mVO->mDrawable;
-
- if (drawablep)
- {
- //ensure drawable is active
- drawablep->makeActive();
-
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE))
- {
- bool visible = drawablep->isVisible();
-
- if (mRenderRes == -1)
- {
- updateRenderRes();
- gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION);
- }
- else
- {
- F32 pixel_area = mVO->getPixelArea();
-
- // Note: Flexies afar will be rarely updated, closer ones will be updated more frequently.
- // But frequency differences are extremely noticeable, so consider modifying update factor,
- // or at least clamping value a bit more from both sides.
- U32 update_period = (U32) (llmax((S32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f))),0)+1);
- // MAINT-1890 Clamp the update period to ensure that the update_period is no greater than 32 frames
- update_period = llclamp(update_period, 1U, 32U);
-
- // We control how fast flexies update, buy splitting updates among frames
- U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME;
-
- if (visible)
- {
- if (!drawablep->isState(LLDrawable::IN_REBUILD_Q) &&
- pixel_area > 256.f)
- {
- U32 id;
- if (mVO->isRootEdit())
- {
- id = mID;
- }
- else
- {
- LLVOVolume* parent = (LLVOVolume*)mVO->getParent();
- id = parent->getVolumeInterfaceID();
- }
-
-
- // Throttle flexies and spread load by preventing flexies from updating in same frame
- // Shows how many frames we need to wait before next update
- U64 throttling_delay = (virtual_frame_num + id) % update_period;
-
- if ((throttling_delay == 0 && mLastFrameNum < virtual_frame_num) //one or more virtual frames per frame
- || (mLastFrameNum + update_period < virtual_frame_num) // missed virtual frame
- || mLastFrameNum > virtual_frame_num) // overflow
- {
- // We need mLastFrameNum to compensate for 'unreliable time' and to filter 'duplicate' frames
- // If happened too late, subtract throttling_delay (it is zero otherwise)
- mLastFrameNum = virtual_frame_num - throttling_delay;
-
- // Store update period for updateClass()
- // Note: Consider substituting update_period with mLastUpdatePeriod everywhere.
- mLastUpdatePeriod = update_period;
-
- updateRenderRes();
-
- mVO->shrinkWrap();
- gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION);
- }
- }
- }
- else
- {
- mLastFrameNum = virtual_frame_num;
- mLastUpdatePeriod = update_period;
- }
- }
-
- }
- }
-}
-
-inline S32 log2(S32 x)
-{
- S32 ret = 0;
- while (x > 1)
- {
- ++ret;
- x >>= 1;
- }
- return ret;
-}
-
-void LLVolumeImplFlexible::doFlexibleUpdate()
-{
- LL_PROFILE_ZONE_SCOPED;
- LLVolume* volume = mVO->getVolume();
- LLPath *path = &volume->getPath();
- if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible())
- {
- bool force_update = mSimulateRes == 0;
- doIdleUpdate();
-
- if (!force_update || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE))
- {
- return; // we did not get updated or initialized, proceeding without can be dangerous
- }
- }
-
- if (!mInitialized || !mAttributes)
- {
- //the object is not visible
- return;
- }
-
- // Fix for MAINT-1894
- // Skipping the flexible update if render res is negative. If we were to continue with a negative value,
- // the subsequent S32 num_render_sections = 1<<mRenderRes; code will specify a really large number of
- // render sections which will then create a length exception in the std::vector::resize() method.
- if (mRenderRes < 0)
- {
- return;
- }
-
- 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;
- if (mSection[i].mVelocity.magVecSquared() > 1.f)
- {
- mSection[i].mVelocity.normVec();
- }
- }
-
- // 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
- llassert(mRenderRes > -1);
- S32 num_render_sections = 1<<mRenderRes;
- if (path->getPathLength() != num_render_sections+1)
- {
- ((LLVOVolume*) mVO)->mVolumeChanged = true;
- volume->resizePath(num_render_sections+1);
- }
-
- LLPath::PathPt *new_point;
-
- LLFlexibleObjectSection newSection[ (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1 ];
- remapSections(mSection, mSimulateRes, newSection, mRenderRes);
-
- //generate transform from global to prim space
- LLVector3 delta_scale = LLVector3(1,1,1);
- LLVector3 delta_pos;
- LLQuaternion delta_rot;
-
- 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;
-
- LLMatrix4 rel_xform;
- rel_xform.initRows(LLVector4(x_axis, 0.f),
- LLVector4(y_axis, 0.f),
- LLVector4(z_axis, 0.f),
- LLVector4(delta_pos, 1.f));
-
- LL_CHECK_MEMORY
- for (i=0; i<=num_render_sections; ++i)
- {
- new_point = &path->mPath[i];
- LLVector3 pos = newSection[i].mPosition * rel_xform;
- LLQuaternion rot = mSection[i].mAxisRotation * newSection[i].mRotation * delta_rot;
-
- LLVector3 np(new_point->mPos.getF32ptr());
-
- if (!mUpdated || (np-pos).magVec()/mVO->mDrawable->mDistanceWRTCamera > 0.001f)
- {
- new_point->mPos.load3((newSection[i].mPosition * rel_xform).mV);
- mUpdated = false;
- }
-
- new_point->mRot.loadu(LLMatrix3(rot));
- new_point->mScale.set(newSection[i].mScale.mV[0], newSection[i].mScale.mV[1], 0,1);
- new_point->mTexT = ((F32)i)/(num_render_sections);
- }
- LL_CHECK_MEMORY
- mLastSegmentRotation = parentSegmentRotation;
-}
-
-
-void LLVolumeImplFlexible::preRebuild()
-{
- if (!mUpdated)
- {
- LL_PROFILE_ZONE_SCOPED;
- doFlexibleRebuild(false);
- }
-}
-
-void LLVolumeImplFlexible::doFlexibleRebuild(bool rebuild_volume)
-{
- LLVolume* volume = mVO->getVolume();
- if (volume)
- {
- if (rebuild_volume)
- {
- volume->setDirty();
- }
- volume->regen();
- }
-
- mUpdated = true;
-}
-
-//------------------------------------------------------------------
-
-void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, bool damped)
-{
- setAttributesOfAllSections((LLVector3*) &scale);
-}
-
-bool LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLVOVolume *volume = (LLVOVolume*)mVO;
-
- if (mVO->isAttachment())
- { //don't update flexible attachments for impostored avatars unless the
- //impostor is being updated this frame (w00!)
- LLViewerObject* parent = (LLViewerObject*) mVO->getParent();
- while (parent && !parent->isAvatar())
- {
- parent = (LLViewerObject*) parent->getParent();
- }
-
- if (parent)
- {
- LLVOAvatar* avatar = (LLVOAvatar*) parent;
- if (avatar->isImpostor() && !avatar->needsImpostorUpdate())
- {
- return true;
- }
- }
- }
-
- if (volume->mDrawable.isNull())
- {
- return true; // No update to complete
- }
-
- if (volume->mLODChanged)
- {
- LLVolumeParams volume_params = volume->getVolume()->getParams();
- volume->setVolume(volume_params, 0);
- mUpdated = false;
- }
-
- volume->updateRelativeXform();
-
- doFlexibleUpdate();
-
- // Object may have been rotated, which means it needs a rebuild. See SL-47220
- bool rotated = false;
- LLQuaternion cur_rotation = getFrameRotation();
- if ( cur_rotation != mLastFrameRotation )
- {
- mLastFrameRotation = cur_rotation;
- rotated = true;
- }
-
- if (volume->mLODChanged || volume->mFaceMappingChanged ||
- volume->mVolumeChanged || drawable->isState(LLDrawable::REBUILD_MATERIAL))
- {
- volume->regenFaces();
- volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME);
- volume->dirtySpatialGroup();
- {
- doFlexibleRebuild(volume->mVolumeChanged);
- }
- volume->genBBoxes(isVolumeGlobal());
- }
- else if (!mUpdated || rotated)
- {
- volume->mDrawable->setState(LLDrawable::REBUILD_POSITION);
- LLSpatialGroup* group = volume->mDrawable->getSpatialGroup();
- if (group)
- {
- group->dirtyMesh();
- }
- volume->genBBoxes(isVolumeGlobal());
- }
-
- volume->mVolumeChanged = false;
- volume->mLODChanged = false;
- volume->mFaceMappingChanged = false;
-
- // clear UV flag
- drawable->clearState(LLDrawable::UV);
-
- 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 force_identity)
-{
- LLQuaternion delta_rot;
- LLVector3 delta_pos, delta_scale;
- LLVOVolume* vo = (LLVOVolume*) mVO;
-
- bool use_identity = vo->mDrawable->isSpatialRoot() || force_identity;
-
- //matrix from local space to parent relative/global space
- delta_rot = use_identity ? LLQuaternion() : vo->mDrawable->getRotation();
- delta_pos = use_identity ? LLVector3(0,0,0) : vo->mDrawable->getPosition();
- delta_scale = LLVector3(1,1,1);
-
- // 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();
-}
+/** + * @file llflexibleobject.cpp + * @brief Flexible object implementation + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "pipeline.h" +#include "lldrawpoolbump.h" +#include "llface.h" +#include "llflexibleobject.h" +#include "llglheaders.h" +#include "llrendersphere.h" +#include "llviewerobject.h" +#include "llagent.h" +#include "llsky.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewercontrol.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llworld.h" +#include "llvoavatar.h" + +static const F32 SEC_PER_FLEXI_FRAME = 1.f / 60.f; // 60 flexi updates per second +/*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f; +std::vector<LLVolumeImplFlexible*> LLVolumeImplFlexible::sInstanceList; + +// LLFlexibleObjectData::pack/unpack now in llprimitive.cpp + +//----------------------------------------------- +// constructor +//----------------------------------------------- +LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectData* attributes) : + mVO(vo), + mAttributes(attributes), + mLastFrameNum(0), + mLastUpdatePeriod(0) +{ + static U32 seed = 0; + mID = seed++; + mInitialized = false; + mUpdated = false; + mInitializedRes = -1; + mSimulateRes = 0; + mCollisionSphereRadius = 0.f; + mRenderRes = -1; + + if(mVO->mDrawable.notNull()) + { + mVO->mDrawable->makeActive() ; + } + + mInstanceIndex = sInstanceList.size(); + sInstanceList.push_back(this); +}//----------------------------------------------- + +LLVolumeImplFlexible::~LLVolumeImplFlexible() +{ + S32 end_idx = sInstanceList.size()-1; + + if (end_idx != mInstanceIndex) + { + sInstanceList[mInstanceIndex] = sInstanceList[end_idx]; + sInstanceList[mInstanceIndex]->mInstanceIndex = mInstanceIndex; + } + + sInstanceList.pop_back(); +} + +//static +void LLVolumeImplFlexible::updateClass() +{ + LL_PROFILE_ZONE_SCOPED; + + U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME; + for (std::vector<LLVolumeImplFlexible*>::iterator iter = sInstanceList.begin(); + iter != sInstanceList.end(); + ++iter) + { + // Note: by now update period might have changed + if ((*iter)->mRenderRes == -1 + || (*iter)->mLastFrameNum + (*iter)->mLastUpdatePeriod <= virtual_frame_num + || (*iter)->mLastFrameNum > virtual_frame_num) //time issues, overflow + { + (*iter)->doIdleUpdate(); + } + } +} + +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 LLVector4a &shift_vector) +{ + //VECTORIZE THIS + LLVector3 shift(shift_vector.getF32ptr()); + for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section) + { + mSection[section].mPosition += shift; + } +} + +//----------------------------------------------------------------------------------------------- +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(LLVector3* inScale) +{ + LLVector2 bottom_scale, top_scale; + F32 begin_rot = 0, end_rot = 0; + if (mVO->getVolume()) + { + const LLPathParams ¶ms = mVO->getVolume()->getParams().getPathParams(); + bottom_scale = params.getBeginScale(); + top_scale = params.getEndScale(); + begin_rot = F_PI * params.getTwistBegin(); + end_rot = F_PI * params.getTwist(); + } + + if (!mVO->mDrawable) + { + return; + } + + S32 num_sections = 1 << mSimulateRes; + + LLVector3 scale; + if (inScale == (LLVector3*)NULL) + { + scale = mVO->mDrawable->getScale(); + } + else + { + scale = *inScale; + } + + 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); + + 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; + } +}//----------------------------------------------------------------------------------- + + +void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail) +{ +} + + +void LLVolumeImplFlexible::updateRenderRes() +{ + if (!mAttributes) + return; + + LLDrawable* drawablep = mVO->mDrawable; + + S32 new_res = mAttributes->getSimulateLOD(); + +#if 1 //optimal approximation of previous behavior that doesn't rely on atan2 + F32 app_angle = mVO->getScale().mV[2]/drawablep->mDistanceWRTCamera; + + // Rendering sections increases with visible angle on the screen + mRenderRes = (S32) (12.f*app_angle); +#else //legacy behavior + //number of segments only cares about z axis + F32 app_angle = ll_round((F32) atan2( mVO->getScale().mV[2]*2.f, drawablep->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); + + // Rendering sections increases with visible angle on the screen + mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView()); +#endif + + mRenderRes = llclamp(mRenderRes, new_res-1, (S32) FLEXIBLE_OBJECT_MAX_SECTIONS); + + // 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; + } +} +//--------------------------------------------------------------------------------- +// 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. +//--------------------------------------------------------------------------------- +void LLVolumeImplFlexible::doIdleUpdate() +{ + LLDrawable* drawablep = mVO->mDrawable; + + if (drawablep) + { + //ensure drawable is active + drawablep->makeActive(); + + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) + { + bool visible = drawablep->isVisible(); + + if (mRenderRes == -1) + { + updateRenderRes(); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION); + } + else + { + F32 pixel_area = mVO->getPixelArea(); + + // Note: Flexies afar will be rarely updated, closer ones will be updated more frequently. + // But frequency differences are extremely noticeable, so consider modifying update factor, + // or at least clamping value a bit more from both sides. + U32 update_period = (U32) (llmax((S32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f))),0)+1); + // MAINT-1890 Clamp the update period to ensure that the update_period is no greater than 32 frames + update_period = llclamp(update_period, 1U, 32U); + + // We control how fast flexies update, buy splitting updates among frames + U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME; + + if (visible) + { + if (!drawablep->isState(LLDrawable::IN_REBUILD_Q) && + pixel_area > 256.f) + { + U32 id; + if (mVO->isRootEdit()) + { + id = mID; + } + else + { + LLVOVolume* parent = (LLVOVolume*)mVO->getParent(); + id = parent->getVolumeInterfaceID(); + } + + + // Throttle flexies and spread load by preventing flexies from updating in same frame + // Shows how many frames we need to wait before next update + U64 throttling_delay = (virtual_frame_num + id) % update_period; + + if ((throttling_delay == 0 && mLastFrameNum < virtual_frame_num) //one or more virtual frames per frame + || (mLastFrameNum + update_period < virtual_frame_num) // missed virtual frame + || mLastFrameNum > virtual_frame_num) // overflow + { + // We need mLastFrameNum to compensate for 'unreliable time' and to filter 'duplicate' frames + // If happened too late, subtract throttling_delay (it is zero otherwise) + mLastFrameNum = virtual_frame_num - throttling_delay; + + // Store update period for updateClass() + // Note: Consider substituting update_period with mLastUpdatePeriod everywhere. + mLastUpdatePeriod = update_period; + + updateRenderRes(); + + mVO->shrinkWrap(); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION); + } + } + } + else + { + mLastFrameNum = virtual_frame_num; + mLastUpdatePeriod = update_period; + } + } + + } + } +} + +inline S32 log2(S32 x) +{ + S32 ret = 0; + while (x > 1) + { + ++ret; + x >>= 1; + } + return ret; +} + +void LLVolumeImplFlexible::doFlexibleUpdate() +{ + LL_PROFILE_ZONE_SCOPED; + LLVolume* volume = mVO->getVolume(); + LLPath *path = &volume->getPath(); + if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) + { + bool force_update = mSimulateRes == 0; + doIdleUpdate(); + + if (!force_update || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) + { + return; // we did not get updated or initialized, proceeding without can be dangerous + } + } + + if (!mInitialized || !mAttributes) + { + //the object is not visible + return; + } + + // Fix for MAINT-1894 + // Skipping the flexible update if render res is negative. If we were to continue with a negative value, + // the subsequent S32 num_render_sections = 1<<mRenderRes; code will specify a really large number of + // render sections which will then create a length exception in the std::vector::resize() method. + if (mRenderRes < 0) + { + return; + } + + 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; + if (mSection[i].mVelocity.magVecSquared() > 1.f) + { + mSection[i].mVelocity.normVec(); + } + } + + // 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 + llassert(mRenderRes > -1); + S32 num_render_sections = 1<<mRenderRes; + if (path->getPathLength() != num_render_sections+1) + { + ((LLVOVolume*) mVO)->mVolumeChanged = true; + volume->resizePath(num_render_sections+1); + } + + LLPath::PathPt *new_point; + + LLFlexibleObjectSection newSection[ (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1 ]; + remapSections(mSection, mSimulateRes, newSection, mRenderRes); + + //generate transform from global to prim space + LLVector3 delta_scale = LLVector3(1,1,1); + LLVector3 delta_pos; + LLQuaternion delta_rot; + + 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; + + LLMatrix4 rel_xform; + rel_xform.initRows(LLVector4(x_axis, 0.f), + LLVector4(y_axis, 0.f), + LLVector4(z_axis, 0.f), + LLVector4(delta_pos, 1.f)); + + LL_CHECK_MEMORY + for (i=0; i<=num_render_sections; ++i) + { + new_point = &path->mPath[i]; + LLVector3 pos = newSection[i].mPosition * rel_xform; + LLQuaternion rot = mSection[i].mAxisRotation * newSection[i].mRotation * delta_rot; + + LLVector3 np(new_point->mPos.getF32ptr()); + + if (!mUpdated || (np-pos).magVec()/mVO->mDrawable->mDistanceWRTCamera > 0.001f) + { + new_point->mPos.load3((newSection[i].mPosition * rel_xform).mV); + mUpdated = false; + } + + new_point->mRot.loadu(LLMatrix3(rot)); + new_point->mScale.set(newSection[i].mScale.mV[0], newSection[i].mScale.mV[1], 0,1); + new_point->mTexT = ((F32)i)/(num_render_sections); + } + LL_CHECK_MEMORY + mLastSegmentRotation = parentSegmentRotation; +} + + +void LLVolumeImplFlexible::preRebuild() +{ + if (!mUpdated) + { + LL_PROFILE_ZONE_SCOPED; + doFlexibleRebuild(false); + } +} + +void LLVolumeImplFlexible::doFlexibleRebuild(bool rebuild_volume) +{ + LLVolume* volume = mVO->getVolume(); + if (volume) + { + if (rebuild_volume) + { + volume->setDirty(); + } + volume->regen(); + } + + mUpdated = true; +} + +//------------------------------------------------------------------ + +void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, bool damped) +{ + setAttributesOfAllSections((LLVector3*) &scale); +} + +bool LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) +{ + LL_PROFILE_ZONE_SCOPED; + LLVOVolume *volume = (LLVOVolume*)mVO; + + if (mVO->isAttachment()) + { //don't update flexible attachments for impostored avatars unless the + //impostor is being updated this frame (w00!) + LLViewerObject* parent = (LLViewerObject*) mVO->getParent(); + while (parent && !parent->isAvatar()) + { + parent = (LLViewerObject*) parent->getParent(); + } + + if (parent) + { + LLVOAvatar* avatar = (LLVOAvatar*) parent; + if (avatar->isImpostor() && !avatar->needsImpostorUpdate()) + { + return true; + } + } + } + + if (volume->mDrawable.isNull()) + { + return true; // No update to complete + } + + if (volume->mLODChanged) + { + LLVolumeParams volume_params = volume->getVolume()->getParams(); + volume->setVolume(volume_params, 0); + mUpdated = false; + } + + volume->updateRelativeXform(); + + doFlexibleUpdate(); + + // Object may have been rotated, which means it needs a rebuild. See SL-47220 + bool rotated = false; + LLQuaternion cur_rotation = getFrameRotation(); + if ( cur_rotation != mLastFrameRotation ) + { + mLastFrameRotation = cur_rotation; + rotated = true; + } + + if (volume->mLODChanged || volume->mFaceMappingChanged || + volume->mVolumeChanged || drawable->isState(LLDrawable::REBUILD_MATERIAL)) + { + volume->regenFaces(); + volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME); + volume->dirtySpatialGroup(); + { + doFlexibleRebuild(volume->mVolumeChanged); + } + volume->genBBoxes(isVolumeGlobal()); + } + else if (!mUpdated || rotated) + { + volume->mDrawable->setState(LLDrawable::REBUILD_POSITION); + LLSpatialGroup* group = volume->mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } + volume->genBBoxes(isVolumeGlobal()); + } + + volume->mVolumeChanged = false; + volume->mLODChanged = false; + volume->mFaceMappingChanged = false; + + // clear UV flag + drawable->clearState(LLDrawable::UV); + + 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 force_identity) +{ + LLQuaternion delta_rot; + LLVector3 delta_pos, delta_scale; + LLVOVolume* vo = (LLVOVolume*) mVO; + + bool use_identity = vo->mDrawable->isSpatialRoot() || force_identity; + + //matrix from local space to parent relative/global space + delta_rot = use_identity ? LLQuaternion() : vo->mDrawable->getRotation(); + delta_pos = use_identity ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); + delta_scale = LLVector3(1,1,1); + + // 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(); +} |