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

