diff options
Diffstat (limited to 'linden/indra/llcharacter/lleditingmotion.cpp')
-rw-r--r-- | linden/indra/llcharacter/lleditingmotion.cpp | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/lleditingmotion.cpp b/linden/indra/llcharacter/lleditingmotion.cpp new file mode 100644 index 0000000..66608f8 --- /dev/null +++ b/linden/indra/llcharacter/lleditingmotion.cpp | |||
@@ -0,0 +1,253 @@ | |||
1 | /** | ||
2 | * @file lleditingmotion.cpp | ||
3 | * @brief Implementation of LLEditingMotion class. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | //----------------------------------------------------------------------------- | ||
29 | // Header Files | ||
30 | //----------------------------------------------------------------------------- | ||
31 | #include "linden_common.h" | ||
32 | |||
33 | #include "lleditingmotion.h" | ||
34 | #include "llcharacter.h" | ||
35 | #include "llhandmotion.h" | ||
36 | #include "llcriticaldamp.h" | ||
37 | |||
38 | //----------------------------------------------------------------------------- | ||
39 | // Constants | ||
40 | //----------------------------------------------------------------------------- | ||
41 | const LLQuaternion EDIT_MOTION_WRIST_ROTATION(F_PI_BY_TWO * 0.7f, LLVector3(1.0f, 0.0f, 0.0f)); | ||
42 | const F32 TARGET_LAG_HALF_LIFE = 0.1f; // half-life of IK targeting | ||
43 | const F32 TORSO_LAG_HALF_LIFE = 0.2f; | ||
44 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
45 | |||
46 | S32 LLEditingMotion::sHandPose = LLHandMotion::HAND_POSE_RELAXED_R; | ||
47 | S32 LLEditingMotion::sHandPosePriority = 3; | ||
48 | |||
49 | //----------------------------------------------------------------------------- | ||
50 | // LLEditingMotion() | ||
51 | // Class Constructor | ||
52 | //----------------------------------------------------------------------------- | ||
53 | LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id) | ||
54 | { | ||
55 | mCharacter = NULL; | ||
56 | |||
57 | // create kinematic chain | ||
58 | mParentJoint.addChild( &mShoulderJoint ); | ||
59 | mShoulderJoint.addChild( &mElbowJoint ); | ||
60 | mElbowJoint.addChild( &mWristJoint ); | ||
61 | |||
62 | mName = "editing"; | ||
63 | } | ||
64 | |||
65 | |||
66 | //----------------------------------------------------------------------------- | ||
67 | // ~LLEditingMotion() | ||
68 | // Class Destructor | ||
69 | //----------------------------------------------------------------------------- | ||
70 | LLEditingMotion::~LLEditingMotion() | ||
71 | { | ||
72 | } | ||
73 | |||
74 | //----------------------------------------------------------------------------- | ||
75 | // LLEditingMotion::onInitialize(LLCharacter *character) | ||
76 | //----------------------------------------------------------------------------- | ||
77 | LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *character) | ||
78 | { | ||
79 | // save character for future use | ||
80 | mCharacter = character; | ||
81 | |||
82 | // make sure character skeleton is copacetic | ||
83 | if (!mCharacter->getJoint("mShoulderLeft") || | ||
84 | !mCharacter->getJoint("mElbowLeft") || | ||
85 | !mCharacter->getJoint("mWristLeft")) | ||
86 | { | ||
87 | llwarns << "Invalid skeleton for editing motion!" << llendl; | ||
88 | return STATUS_FAILURE; | ||
89 | } | ||
90 | |||
91 | // get the shoulder, elbow, wrist joints from the character | ||
92 | mParentState.setJoint( mCharacter->getJoint("mShoulderLeft")->getParent() ); | ||
93 | mShoulderState.setJoint( mCharacter->getJoint("mShoulderLeft") ); | ||
94 | mElbowState.setJoint( mCharacter->getJoint("mElbowLeft") ); | ||
95 | mWristState.setJoint( mCharacter->getJoint("mWristLeft") ); | ||
96 | mTorsoState.setJoint( mCharacter->getJoint("mTorso")); | ||
97 | |||
98 | if ( ! mParentState.getJoint() ) | ||
99 | { | ||
100 | llinfos << getName() << ": Can't get parent joint." << llendl; | ||
101 | return STATUS_FAILURE; | ||
102 | } | ||
103 | |||
104 | mWristOffset = LLVector3(0.0f, 0.2f, 0.0f); | ||
105 | |||
106 | // add joint states to the pose | ||
107 | mShoulderState.setUsage(LLJointState::ROT); | ||
108 | mElbowState.setUsage(LLJointState::ROT); | ||
109 | mTorsoState.setUsage(LLJointState::ROT); | ||
110 | mWristState.setUsage(LLJointState::ROT); | ||
111 | addJointState( &mShoulderState ); | ||
112 | addJointState( &mElbowState ); | ||
113 | addJointState( &mTorsoState ); | ||
114 | addJointState( &mWristState ); | ||
115 | |||
116 | // propagate joint positions to kinematic chain | ||
117 | mParentJoint.setPosition( mParentState.getJoint()->getWorldPosition() ); | ||
118 | mShoulderJoint.setPosition( mShoulderState.getJoint()->getPosition() ); | ||
119 | mElbowJoint.setPosition( mElbowState.getJoint()->getPosition() ); | ||
120 | mWristJoint.setPosition( mWristState.getJoint()->getPosition() + mWristOffset ); | ||
121 | |||
122 | // propagate current joint rotations to kinematic chain | ||
123 | mParentJoint.setRotation( mParentState.getJoint()->getWorldRotation() ); | ||
124 | mShoulderJoint.setRotation( mShoulderState.getJoint()->getRotation() ); | ||
125 | mElbowJoint.setRotation( mElbowState.getJoint()->getRotation() ); | ||
126 | |||
127 | // connect the ikSolver to the chain | ||
128 | mIKSolver.setPoleVector( LLVector3( -1.0f, 1.0f, 0.0f ) ); | ||
129 | // specifying the elbow's axis will prevent bad IK for the more | ||
130 | // singular configurations, but the axis is limb-specific -- Leviathan | ||
131 | mIKSolver.setBAxis( LLVector3( -0.682683f, 0.0f, -0.730714f ) ); | ||
132 | mIKSolver.setupJoints( &mShoulderJoint, &mElbowJoint, &mWristJoint, &mTarget ); | ||
133 | |||
134 | return STATUS_SUCCESS; | ||
135 | } | ||
136 | |||
137 | //----------------------------------------------------------------------------- | ||
138 | // LLEditingMotion::onActivate() | ||
139 | //----------------------------------------------------------------------------- | ||
140 | BOOL LLEditingMotion::onActivate() | ||
141 | { | ||
142 | // propagate joint positions to kinematic chain | ||
143 | mParentJoint.setPosition( mParentState.getJoint()->getWorldPosition() ); | ||
144 | mShoulderJoint.setPosition( mShoulderState.getJoint()->getPosition() ); | ||
145 | mElbowJoint.setPosition( mElbowState.getJoint()->getPosition() ); | ||
146 | mWristJoint.setPosition( mWristState.getJoint()->getPosition() + mWristOffset ); | ||
147 | |||
148 | // propagate current joint rotations to kinematic chain | ||
149 | mParentJoint.setRotation( mParentState.getJoint()->getWorldRotation() ); | ||
150 | mShoulderJoint.setRotation( mShoulderState.getJoint()->getRotation() ); | ||
151 | mElbowJoint.setRotation( mElbowState.getJoint()->getRotation() ); | ||
152 | |||
153 | return TRUE; | ||
154 | } | ||
155 | |||
156 | //----------------------------------------------------------------------------- | ||
157 | // LLEditingMotion::onUpdate() | ||
158 | //----------------------------------------------------------------------------- | ||
159 | BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) | ||
160 | { | ||
161 | LLVector3 focus_pt; | ||
162 | LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint"); | ||
163 | |||
164 | |||
165 | BOOL result = TRUE; | ||
166 | |||
167 | if (!pointAtPt) | ||
168 | { | ||
169 | focus_pt = mLastSelectPt; | ||
170 | result = FALSE; | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | focus_pt = *pointAtPt; | ||
175 | mLastSelectPt = focus_pt; | ||
176 | } | ||
177 | |||
178 | focus_pt += mCharacter->getCharacterPosition(); | ||
179 | |||
180 | // propagate joint positions to kinematic chain | ||
181 | mParentJoint.setPosition( mParentState.getJoint()->getWorldPosition() ); | ||
182 | mShoulderJoint.setPosition( mShoulderState.getJoint()->getPosition() ); | ||
183 | mElbowJoint.setPosition( mElbowState.getJoint()->getPosition() ); | ||
184 | mWristJoint.setPosition( mWristState.getJoint()->getPosition() + mWristOffset ); | ||
185 | |||
186 | // propagate current joint rotations to kinematic chain | ||
187 | mParentJoint.setRotation( mParentState.getJoint()->getWorldRotation() ); | ||
188 | mShoulderJoint.setRotation( mShoulderState.getJoint()->getRotation() ); | ||
189 | mElbowJoint.setRotation( mElbowState.getJoint()->getRotation() ); | ||
190 | |||
191 | // update target position from character | ||
192 | LLVector3 target = focus_pt - mParentJoint.getPosition(); | ||
193 | F32 target_dist = target.normVec(); | ||
194 | |||
195 | LLVector3 edit_plane_normal(1.f / F_SQRT2, 1.f / F_SQRT2, 0.f); | ||
196 | edit_plane_normal.normVec(); | ||
197 | |||
198 | edit_plane_normal.rotVec(mTorsoState.getJoint()->getWorldRotation()); | ||
199 | |||
200 | F32 dot = edit_plane_normal * target; | ||
201 | |||
202 | if (dot < 0.f) | ||
203 | { | ||
204 | target = target + (edit_plane_normal * (dot * 2.f)); | ||
205 | target.mV[VZ] += clamp_rescale(dot, 0.f, -1.f, 0.f, 5.f); | ||
206 | target.normVec(); | ||
207 | } | ||
208 | |||
209 | target = target * target_dist; | ||
210 | if (!target.isFinite()) | ||
211 | { | ||
212 | llerrs << "Non finite target in editing motion with target distance of " << target_dist << | ||
213 | " and focus point " << focus_pt << llendl; | ||
214 | } | ||
215 | |||
216 | mTarget.setPosition( target + mParentJoint.getPosition()); | ||
217 | |||
218 | // llinfos << "Point At: " << mTarget.getPosition() << llendl; | ||
219 | |||
220 | // update the ikSolver | ||
221 | if (!mTarget.getPosition().isExactlyZero()) | ||
222 | { | ||
223 | LLQuaternion shoulderRot = mShoulderJoint.getRotation(); | ||
224 | LLQuaternion elbowRot = mElbowJoint.getRotation(); | ||
225 | mIKSolver.solve(); | ||
226 | |||
227 | // use blending... | ||
228 | F32 slerp_amt = LLCriticalDamp::getInterpolant(TARGET_LAG_HALF_LIFE); | ||
229 | shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot); | ||
230 | elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot); | ||
231 | |||
232 | // now put blended values back into joints | ||
233 | llassert(shoulderRot.isFinite()); | ||
234 | llassert(elbowRot.isFinite()); | ||
235 | mShoulderState.setRotation(shoulderRot); | ||
236 | mElbowState.setRotation(elbowRot); | ||
237 | mWristState.setRotation(LLQuaternion::DEFAULT); | ||
238 | } | ||
239 | |||
240 | mCharacter->setAnimationData("Hand Pose", &sHandPose); | ||
241 | mCharacter->setAnimationData("Hand Pose Priority", &sHandPosePriority); | ||
242 | return result; | ||
243 | } | ||
244 | |||
245 | //----------------------------------------------------------------------------- | ||
246 | // LLEditingMotion::onDeactivate() | ||
247 | //----------------------------------------------------------------------------- | ||
248 | void LLEditingMotion::onDeactivate() | ||
249 | { | ||
250 | } | ||
251 | |||
252 | |||
253 | // End | ||