aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcharacter
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcharacter')
-rw-r--r--linden/indra/llcharacter/files.lst21
-rw-r--r--linden/indra/llcharacter/llanimationstates.cpp338
-rw-r--r--linden/indra/llcharacter/llanimationstates.h246
-rw-r--r--linden/indra/llcharacter/llbvhloader.cpp1508
-rw-r--r--linden/indra/llcharacter/llbvhloader.h301
-rw-r--r--linden/indra/llcharacter/llcharacter.cpp491
-rw-r--r--linden/indra/llcharacter/llcharacter.h271
-rw-r--r--linden/indra/llcharacter/llcharacter.vcproj294
-rw-r--r--linden/indra/llcharacter/lleditingmotion.cpp253
-rw-r--r--linden/indra/llcharacter/lleditingmotion.h134
-rw-r--r--linden/indra/llcharacter/llgesture.cpp375
-rw-r--r--linden/indra/llcharacter/llgesture.h115
-rw-r--r--linden/indra/llcharacter/llhandmotion.cpp221
-rw-r--r--linden/indra/llcharacter/llhandmotion.h138
-rw-r--r--linden/indra/llcharacter/llheadrotmotion.cpp524
-rw-r--r--linden/indra/llcharacter/llheadrotmotion.h213
-rw-r--r--linden/indra/llcharacter/lljoint.cpp523
-rw-r--r--linden/indra/llcharacter/lljoint.h182
-rw-r--r--linden/indra/llcharacter/lljointsolverrp3.cpp385
-rw-r--r--linden/indra/llcharacter/lljointsolverrp3.h177
-rw-r--r--linden/indra/llcharacter/lljointstate.h125
-rw-r--r--linden/indra/llcharacter/llkeyframefallmotion.cpp142
-rw-r--r--linden/indra/llcharacter/llkeyframefallmotion.h79
-rw-r--r--linden/indra/llcharacter/llkeyframemotion.cpp2138
-rw-r--r--linden/indra/llcharacter/llkeyframemotion.h456
-rw-r--r--linden/indra/llcharacter/llkeyframemotionparam.cpp461
-rw-r--r--linden/indra/llcharacter/llkeyframemotionparam.h157
-rw-r--r--linden/indra/llcharacter/llkeyframestandmotion.cpp339
-rw-r--r--linden/indra/llcharacter/llkeyframestandmotion.h117
-rw-r--r--linden/indra/llcharacter/llkeyframewalkmotion.cpp398
-rw-r--r--linden/indra/llcharacter/llkeyframewalkmotion.h177
-rw-r--r--linden/indra/llcharacter/llmotion.cpp150
-rw-r--r--linden/indra/llcharacter/llmotion.h256
-rw-r--r--linden/indra/llcharacter/llmotioncontroller.cpp946
-rw-r--r--linden/indra/llcharacter/llmotioncontroller.h226
-rw-r--r--linden/indra/llcharacter/llmultigesture.cpp489
-rw-r--r--linden/indra/llcharacter/llmultigesture.h232
-rw-r--r--linden/indra/llcharacter/llpose.cpp563
-rw-r--r--linden/indra/llcharacter/llpose.h139
-rw-r--r--linden/indra/llcharacter/llstatemachine.cpp397
-rw-r--r--linden/indra/llcharacter/llstatemachine.h149
-rw-r--r--linden/indra/llcharacter/lltargetingmotion.cpp170
-rw-r--r--linden/indra/llcharacter/lltargetingmotion.h117
-rw-r--r--linden/indra/llcharacter/llvisualparam.cpp285
-rw-r--r--linden/indra/llcharacter/llvisualparam.h150
45 files changed, 15568 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/files.lst b/linden/indra/llcharacter/files.lst
new file mode 100644
index 0000000..3b7aba2
--- /dev/null
+++ b/linden/indra/llcharacter/files.lst
@@ -0,0 +1,21 @@
1llcharacter/llanimationstates.cpp
2llcharacter/llbvhloader.cpp
3llcharacter/llcharacter.cpp
4llcharacter/lleditingmotion.cpp
5llcharacter/llgesture.cpp
6llcharacter/llhandmotion.cpp
7llcharacter/llheadrotmotion.cpp
8llcharacter/lljoint.cpp
9llcharacter/lljointsolverrp3.cpp
10llcharacter/llkeyframefallmotion.cpp
11llcharacter/llkeyframemotion.cpp
12llcharacter/llkeyframemotionparam.cpp
13llcharacter/llkeyframestandmotion.cpp
14llcharacter/llkeyframewalkmotion.cpp
15llcharacter/llmotioncontroller.cpp
16llcharacter/llmotion.cpp
17llcharacter/llmultigesture.cpp
18llcharacter/llpose.cpp
19llcharacter/llstatemachine.cpp
20llcharacter/lltargetingmotion.cpp
21llcharacter/llvisualparam.cpp
diff --git a/linden/indra/llcharacter/llanimationstates.cpp b/linden/indra/llcharacter/llanimationstates.cpp
new file mode 100644
index 0000000..8687dfb
--- /dev/null
+++ b/linden/indra/llcharacter/llanimationstates.cpp
@@ -0,0 +1,338 @@
1/**
2 * @file llanimationstates.cpp
3 * @brief Implementation of animation state related functions.
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// Agent Animation State
30//-----------------------------------------------------------------------------
31
32#include "linden_common.h"
33
34#include <string.h>
35
36#include "llanimationstates.h"
37#include "llstring.h"
38
39LLUUID AGENT_WALK_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_CROUCHWALK, ANIM_AGENT_TURNLEFT, ANIM_AGENT_TURNRIGHT};
40S32 NUM_AGENT_WALK_ANIMS = sizeof(AGENT_WALK_ANIMS) / sizeof(LLUUID);
41
42LLUUID AGENT_GUN_HOLD_ANIMS[] = {ANIM_AGENT_HOLD_RIFLE_R, ANIM_AGENT_HOLD_HANDGUN_R, ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_AGENT_HOLD_BOW_L};
43S32 NUM_AGENT_GUN_HOLD_ANIMS = sizeof(AGENT_GUN_HOLD_ANIMS) / sizeof(LLUUID);
44
45LLUUID AGENT_GUN_AIM_ANIMS[] = {ANIM_AGENT_AIM_RIFLE_R, ANIM_AGENT_AIM_HANDGUN_R, ANIM_AGENT_AIM_BAZOOKA_R, ANIM_AGENT_AIM_BOW_L};
46S32 NUM_AGENT_GUN_AIM_ANIMS = sizeof(AGENT_GUN_AIM_ANIMS) / sizeof(LLUUID);
47
48LLUUID AGENT_NO_ROTATE_ANIMS[] = {ANIM_AGENT_SIT_GROUND, ANIM_AGENT_SIT_GROUND_CONSTRAINED, ANIM_AGENT_STANDUP};
49S32 NUM_AGENT_NO_ROTATE_ANIMS = sizeof(AGENT_NO_ROTATE_ANIMS) / sizeof(LLUUID);
50
51LLUUID AGENT_STAND_ANIMS[] = {ANIM_AGENT_STAND, ANIM_AGENT_STAND_1, ANIM_AGENT_STAND_2, ANIM_AGENT_STAND_3, ANIM_AGENT_STAND_4};
52S32 NUM_AGENT_STAND_ANIMS = sizeof(AGENT_STAND_ANIMS) / sizeof(LLUUID);
53
54
55LLAnimationLibrary gAnimLibrary;
56
57//-----------------------------------------------------------------------------
58// LLAnimationLibrary()
59//-----------------------------------------------------------------------------
60LLAnimationLibrary::LLAnimationLibrary() :
61 mAnimStringTable(16384)
62{
63 //add animation names to animmap
64 mAnimMap[ANIM_AGENT_AFRAID]= mAnimStringTable.addString("express_afraid");
65 mAnimMap[ANIM_AGENT_AIM_BAZOOKA_R]= mAnimStringTable.addString("aim_r_bazooka");
66 mAnimMap[ANIM_AGENT_AIM_BOW_L]= mAnimStringTable.addString("aim_l_bow");
67 mAnimMap[ANIM_AGENT_AIM_HANDGUN_R]= mAnimStringTable.addString("aim_r_handgun");
68 mAnimMap[ANIM_AGENT_AIM_RIFLE_R]= mAnimStringTable.addString("aim_r_rifle");
69 mAnimMap[ANIM_AGENT_ANGRY]= mAnimStringTable.addString("express_anger");
70 mAnimMap[ANIM_AGENT_AWAY]= mAnimStringTable.addString("away");
71 mAnimMap[ANIM_AGENT_BACKFLIP]= mAnimStringTable.addString("backflip");
72 mAnimMap[ANIM_AGENT_BELLY_LAUGH]= mAnimStringTable.addString("express_laugh");
73 mAnimMap[ANIM_AGENT_BLOW_KISS]= mAnimStringTable.addString("blowkiss");
74 mAnimMap[ANIM_AGENT_BORED]= mAnimStringTable.addString("express_bored");
75 mAnimMap[ANIM_AGENT_BOW]= mAnimStringTable.addString("bow");
76 mAnimMap[ANIM_AGENT_BRUSH]= mAnimStringTable.addString("brush");
77 mAnimMap[ANIM_AGENT_BUSY]= mAnimStringTable.addString("busy");
78 mAnimMap[ANIM_AGENT_CLAP]= mAnimStringTable.addString("clap");
79 mAnimMap[ANIM_AGENT_COURTBOW]= mAnimStringTable.addString("courtbow");
80 mAnimMap[ANIM_AGENT_CROUCH]= mAnimStringTable.addString("crouch");
81 mAnimMap[ANIM_AGENT_CROUCHWALK]= mAnimStringTable.addString("crouchwalk");
82 mAnimMap[ANIM_AGENT_CRY]= mAnimStringTable.addString("express_cry");
83 mAnimMap[ANIM_AGENT_CUSTOMIZE]= mAnimStringTable.addString("turn_180");
84 mAnimMap[ANIM_AGENT_CUSTOMIZE_DONE]= mAnimStringTable.addString("turnback_180");
85 mAnimMap[ANIM_AGENT_DANCE1]= mAnimStringTable.addString("dance1");
86 mAnimMap[ANIM_AGENT_DANCE2]= mAnimStringTable.addString("dance2");
87 mAnimMap[ANIM_AGENT_DANCE3]= mAnimStringTable.addString("dance3");
88 mAnimMap[ANIM_AGENT_DANCE4]= mAnimStringTable.addString("dance4");
89 mAnimMap[ANIM_AGENT_DANCE5]= mAnimStringTable.addString("dance5");
90 mAnimMap[ANIM_AGENT_DANCE6]= mAnimStringTable.addString("dance6");
91 mAnimMap[ANIM_AGENT_DANCE7]= mAnimStringTable.addString("dance7");
92 mAnimMap[ANIM_AGENT_DANCE8]= mAnimStringTable.addString("dance8");
93 mAnimMap[ANIM_AGENT_DEAD]= mAnimStringTable.addString("dead");
94 mAnimMap[ANIM_AGENT_DRINK]= mAnimStringTable.addString("drink");
95 mAnimMap[ANIM_AGENT_EMBARRASSED]= mAnimStringTable.addString("express_embarrased");
96 mAnimMap[ANIM_AGENT_EXPRESS_AFRAID]= mAnimStringTable.addString("express_afraid_emote");
97 mAnimMap[ANIM_AGENT_EXPRESS_ANGER]= mAnimStringTable.addString("express_anger_emote");
98 mAnimMap[ANIM_AGENT_EXPRESS_BORED]= mAnimStringTable.addString("express_bored_emote");
99 mAnimMap[ANIM_AGENT_EXPRESS_CRY]= mAnimStringTable.addString("express_cry_emote");
100 mAnimMap[ANIM_AGENT_EXPRESS_DISDAIN]= mAnimStringTable.addString("express_disdain");
101 mAnimMap[ANIM_AGENT_EXPRESS_EMBARRASSED]= mAnimStringTable.addString("express_embarrassed_emote");
102 mAnimMap[ANIM_AGENT_EXPRESS_FROWN]= mAnimStringTable.addString("express_frown");
103 mAnimMap[ANIM_AGENT_EXPRESS_KISS]= mAnimStringTable.addString("express_kiss");
104 mAnimMap[ANIM_AGENT_EXPRESS_LAUGH]= mAnimStringTable.addString("express_laugh_emote");
105 mAnimMap[ANIM_AGENT_EXPRESS_OPEN_MOUTH]= mAnimStringTable.addString("express_open_mouth");
106 mAnimMap[ANIM_AGENT_EXPRESS_REPULSED]= mAnimStringTable.addString("express_repulsed_emote");
107 mAnimMap[ANIM_AGENT_EXPRESS_SAD]= mAnimStringTable.addString("express_sad_emote");
108 mAnimMap[ANIM_AGENT_EXPRESS_SHRUG]= mAnimStringTable.addString("express_shrug_emote");
109 mAnimMap[ANIM_AGENT_EXPRESS_SMILE]= mAnimStringTable.addString("express_smile");
110 mAnimMap[ANIM_AGENT_EXPRESS_SURPRISE]= mAnimStringTable.addString("express_surprise_emote");
111 mAnimMap[ANIM_AGENT_EXPRESS_TONGUE_OUT]= mAnimStringTable.addString("express_tongue_out");
112 mAnimMap[ANIM_AGENT_EXPRESS_TOOTHSMILE]= mAnimStringTable.addString("express_toothsmile");
113 mAnimMap[ANIM_AGENT_EXPRESS_WINK]= mAnimStringTable.addString("express_wink_emote");
114 mAnimMap[ANIM_AGENT_EXPRESS_WORRY]= mAnimStringTable.addString("express_worry_emote");
115 mAnimMap[ANIM_AGENT_FALLDOWN]= mAnimStringTable.addString("falldown");
116 mAnimMap[ANIM_AGENT_FEMALE_WALK]= mAnimStringTable.addString("female_walk");
117 mAnimMap[ANIM_AGENT_FINGER_WAG]= mAnimStringTable.addString("angry_fingerwag");
118 mAnimMap[ANIM_AGENT_FIST_PUMP]= mAnimStringTable.addString("fist_pump");
119 mAnimMap[ANIM_AGENT_FLY]= mAnimStringTable.addString("fly");
120 mAnimMap[ANIM_AGENT_FLYSLOW]= mAnimStringTable.addString("flyslow");
121 mAnimMap[ANIM_AGENT_HELLO]= mAnimStringTable.addString("hello");
122 mAnimMap[ANIM_AGENT_HOLD_BAZOOKA_R]= mAnimStringTable.addString("hold_r_bazooka");
123 mAnimMap[ANIM_AGENT_HOLD_BOW_L]= mAnimStringTable.addString("hold_l_bow");
124 mAnimMap[ANIM_AGENT_HOLD_HANDGUN_R]= mAnimStringTable.addString("hold_r_handgun");
125 mAnimMap[ANIM_AGENT_HOLD_RIFLE_R]= mAnimStringTable.addString("hold_r_rifle");
126 mAnimMap[ANIM_AGENT_HOLD_THROW_R]= mAnimStringTable.addString("hold_throw_r");
127 mAnimMap[ANIM_AGENT_HOVER]= mAnimStringTable.addString("hover");
128 mAnimMap[ANIM_AGENT_HOVER_DOWN]= mAnimStringTable.addString("hover_down");
129 mAnimMap[ANIM_AGENT_HOVER_UP]= mAnimStringTable.addString("hover_up");
130 mAnimMap[ANIM_AGENT_IMPATIENT]= mAnimStringTable.addString("impatient");
131 mAnimMap[ANIM_AGENT_JUMP]= mAnimStringTable.addString("jump");
132 mAnimMap[ANIM_AGENT_JUMP_FOR_JOY]= mAnimStringTable.addString("jumpforjoy");
133 mAnimMap[ANIM_AGENT_KISS_MY_BUTT]= mAnimStringTable.addString("kissmybutt");
134 mAnimMap[ANIM_AGENT_LAND]= mAnimStringTable.addString("land");
135 mAnimMap[ANIM_AGENT_LAUGH_SHORT]= mAnimStringTable.addString("laugh_short");
136 mAnimMap[ANIM_AGENT_MEDIUM_LAND]= mAnimStringTable.addString("soft_land");
137 mAnimMap[ANIM_AGENT_MOTORCYCLE_SIT]= mAnimStringTable.addString("motorcycle_sit");
138 mAnimMap[ANIM_AGENT_MUSCLE_BEACH]= mAnimStringTable.addString("musclebeach");
139 mAnimMap[ANIM_AGENT_NO]= mAnimStringTable.addString("no_head");
140 mAnimMap[ANIM_AGENT_NO_UNHAPPY]= mAnimStringTable.addString("no_unhappy");
141 mAnimMap[ANIM_AGENT_NYAH_NYAH]= mAnimStringTable.addString("nyanya");
142 mAnimMap[ANIM_AGENT_ONETWO_PUNCH]= mAnimStringTable.addString("punch_onetwo");
143 mAnimMap[ANIM_AGENT_PEACE]= mAnimStringTable.addString("peace");
144 mAnimMap[ANIM_AGENT_POINT_ME]= mAnimStringTable.addString("point_me");
145 mAnimMap[ANIM_AGENT_POINT_YOU]= mAnimStringTable.addString("point_you");
146 mAnimMap[ANIM_AGENT_PRE_JUMP]= mAnimStringTable.addString("prejump");
147 mAnimMap[ANIM_AGENT_PUNCH_LEFT]= mAnimStringTable.addString("punch_l");
148 mAnimMap[ANIM_AGENT_PUNCH_RIGHT]= mAnimStringTable.addString("punch_r");
149 mAnimMap[ANIM_AGENT_REPULSED]= mAnimStringTable.addString("express_repulsed");
150 mAnimMap[ANIM_AGENT_ROUNDHOUSE_KICK]= mAnimStringTable.addString("kick_roundhouse_r");
151 mAnimMap[ANIM_AGENT_RPS_COUNTDOWN]= mAnimStringTable.addString("rps_countdown");
152 mAnimMap[ANIM_AGENT_RPS_PAPER]= mAnimStringTable.addString("rps_paper");
153 mAnimMap[ANIM_AGENT_RPS_ROCK]= mAnimStringTable.addString("rps_rock");
154 mAnimMap[ANIM_AGENT_RPS_SCISSORS]= mAnimStringTable.addString("rps_scissors");
155 mAnimMap[ANIM_AGENT_RUN]= mAnimStringTable.addString("run");
156 mAnimMap[ANIM_AGENT_SAD]= mAnimStringTable.addString("express_sad");
157 mAnimMap[ANIM_AGENT_SALUTE]= mAnimStringTable.addString("salute");
158 mAnimMap[ANIM_AGENT_SHOOT_BOW_L]= mAnimStringTable.addString("shoot_l_bow");
159 mAnimMap[ANIM_AGENT_SHOUT]= mAnimStringTable.addString("shout");
160 mAnimMap[ANIM_AGENT_SHRUG]= mAnimStringTable.addString("express_shrug");
161 mAnimMap[ANIM_AGENT_SIT]= mAnimStringTable.addString("sit");
162 mAnimMap[ANIM_AGENT_SIT_FEMALE]= mAnimStringTable.addString("sit_female");
163 mAnimMap[ANIM_AGENT_SIT_GROUND]= mAnimStringTable.addString("sit_ground");
164 mAnimMap[ANIM_AGENT_SIT_GROUND_CONSTRAINED]= mAnimStringTable.addString("sit_ground_constrained");
165 mAnimMap[ANIM_AGENT_SIT_GENERIC]= mAnimStringTable.addString("sit_generic");
166 mAnimMap[ANIM_AGENT_SIT_TO_STAND]= mAnimStringTable.addString("sit_to_stand");
167 mAnimMap[ANIM_AGENT_SLEEP]= mAnimStringTable.addString("sleep");
168 mAnimMap[ANIM_AGENT_SMOKE_IDLE]= mAnimStringTable.addString("smoke_idle");
169 mAnimMap[ANIM_AGENT_SMOKE_INHALE]= mAnimStringTable.addString("smoke_inhale");
170 mAnimMap[ANIM_AGENT_SMOKE_THROW_DOWN]= mAnimStringTable.addString("smoke_throw_down");
171 mAnimMap[ANIM_AGENT_SNAPSHOT]= mAnimStringTable.addString("snapshot");
172 mAnimMap[ANIM_AGENT_STAND]= mAnimStringTable.addString("stand");
173 mAnimMap[ANIM_AGENT_STANDUP]= mAnimStringTable.addString("standup");
174 mAnimMap[ANIM_AGENT_STAND_1]= mAnimStringTable.addString("stand_1");
175 mAnimMap[ANIM_AGENT_STAND_2]= mAnimStringTable.addString("stand_2");
176 mAnimMap[ANIM_AGENT_STAND_3]= mAnimStringTable.addString("stand_3");
177 mAnimMap[ANIM_AGENT_STAND_4]= mAnimStringTable.addString("stand_4");
178 mAnimMap[ANIM_AGENT_STRETCH]= mAnimStringTable.addString("stretch");
179 mAnimMap[ANIM_AGENT_STRIDE]= mAnimStringTable.addString("stride");
180 mAnimMap[ANIM_AGENT_SURF]= mAnimStringTable.addString("surf");
181 mAnimMap[ANIM_AGENT_SURPRISE]= mAnimStringTable.addString("express_surprise");
182 mAnimMap[ANIM_AGENT_SWORD_STRIKE]= mAnimStringTable.addString("sword_strike_r");
183 mAnimMap[ANIM_AGENT_TALK]= mAnimStringTable.addString("talk");
184 mAnimMap[ANIM_AGENT_TANTRUM]= mAnimStringTable.addString("angry_tantrum");
185 mAnimMap[ANIM_AGENT_THROW_R]= mAnimStringTable.addString("throw_r");
186 mAnimMap[ANIM_AGENT_TRYON_SHIRT]= mAnimStringTable.addString("tryon_shirt");
187 mAnimMap[ANIM_AGENT_TURNLEFT]= mAnimStringTable.addString("turnleft");
188 mAnimMap[ANIM_AGENT_TURNRIGHT]= mAnimStringTable.addString("turnright");
189 mAnimMap[ANIM_AGENT_TYPE]= mAnimStringTable.addString("type");
190 mAnimMap[ANIM_AGENT_WALK]= mAnimStringTable.addString("walk");
191 mAnimMap[ANIM_AGENT_WHISPER]= mAnimStringTable.addString("whisper");
192 mAnimMap[ANIM_AGENT_WHISTLE]= mAnimStringTable.addString("whistle");
193 mAnimMap[ANIM_AGENT_WINK]= mAnimStringTable.addString("express_wink");
194 mAnimMap[ANIM_AGENT_WINK_HOLLYWOOD]= mAnimStringTable.addString("wink_hollywood");
195 mAnimMap[ANIM_AGENT_WORRY]= mAnimStringTable.addString("express_worry");
196 mAnimMap[ANIM_AGENT_YES]= mAnimStringTable.addString("yes_head");
197 mAnimMap[ANIM_AGENT_YES_HAPPY]= mAnimStringTable.addString("yes_happy");
198 mAnimMap[ANIM_AGENT_YOGA_FLOAT]= mAnimStringTable.addString("yoga_float");
199}
200
201//-----------------------------------------------------------------------------
202// ~LLAnimationLibrary()
203//-----------------------------------------------------------------------------
204LLAnimationLibrary::~LLAnimationLibrary()
205{
206}
207
208//-----------------------------------------------------------------------------
209// Return the text name of an animation state
210//-----------------------------------------------------------------------------
211const char *LLAnimationLibrary::animStateToString( const LLUUID& state )
212{
213 if (state.isNull())
214 {
215 return NULL;
216 }
217 if (mAnimMap.count(state))
218 {
219 return mAnimMap[state];
220 }
221
222 return NULL;
223}
224
225
226//-----------------------------------------------------------------------------
227// Return the animation state for a given name
228//-----------------------------------------------------------------------------
229LLUUID LLAnimationLibrary::stringToAnimState( const char *name, BOOL allow_ids )
230{
231 LLString lower_case_name(name);
232 LLString::toLower(lower_case_name);
233
234 char *true_name = mAnimStringTable.checkString(lower_case_name.c_str());
235
236 LLUUID id;
237 id.setNull();
238
239 if (true_name)
240 {
241 for (anim_map_t::iterator iter = mAnimMap.begin();
242 iter != mAnimMap.end(); iter++)
243 {
244 if (iter->second == true_name)
245 {
246 id = iter->first;
247 break;
248 }
249 }
250 }
251 else if (allow_ids)
252 {
253 // try to convert string to LLUUID
254 id.set(name, FALSE);
255 }
256
257 return id;
258}
259
260// Animation states that the user can trigger as part of a gesture
261const LLAnimStateEntry gUserAnimStates[] = {
262 LLAnimStateEntry("Afraid", "express_afraid", ANIM_AGENT_AFRAID),
263 LLAnimStateEntry("Angry", "express_anger", ANIM_AGENT_ANGRY),
264 LLAnimStateEntry("Away", "away", ANIM_AGENT_AWAY),
265 LLAnimStateEntry("Backflip", "backflip", ANIM_AGENT_BACKFLIP),
266 LLAnimStateEntry("Belly Laugh", "express_laugh", ANIM_AGENT_BELLY_LAUGH),
267 LLAnimStateEntry("BigSmile", "express_toothsmile", ANIM_AGENT_EXPRESS_TOOTHSMILE),
268 LLAnimStateEntry("Blow Kiss", "blowkiss", ANIM_AGENT_BLOW_KISS),
269 LLAnimStateEntry("Bored", "express_bored", ANIM_AGENT_BORED),
270 LLAnimStateEntry("Bow", "bow", ANIM_AGENT_BOW),
271 LLAnimStateEntry("Clap", "clap", ANIM_AGENT_CLAP),
272 LLAnimStateEntry("Court Bow", "courtbow", ANIM_AGENT_COURTBOW),
273 LLAnimStateEntry("Cry", "express_cry", ANIM_AGENT_CRY),
274 LLAnimStateEntry("Dance 1", "dance1", ANIM_AGENT_DANCE1),
275 LLAnimStateEntry("Dance 2", "dance2", ANIM_AGENT_DANCE2),
276 LLAnimStateEntry("Dance 3", "dance3", ANIM_AGENT_DANCE3),
277 LLAnimStateEntry("Dance 4", "dance4", ANIM_AGENT_DANCE4),
278 LLAnimStateEntry("Dance 5", "dance5", ANIM_AGENT_DANCE5),
279 LLAnimStateEntry("Dance 6", "dance6", ANIM_AGENT_DANCE6),
280 LLAnimStateEntry("Dance 7", "dance7", ANIM_AGENT_DANCE7),
281 LLAnimStateEntry("Dance 8", "dance8", ANIM_AGENT_DANCE8),
282 LLAnimStateEntry("Disdain", "express_disdain", ANIM_AGENT_EXPRESS_DISDAIN),
283 LLAnimStateEntry("Drink", "drink", ANIM_AGENT_DRINK),
284 LLAnimStateEntry("Embarrassed", "express_embarrased", ANIM_AGENT_EMBARRASSED),
285 LLAnimStateEntry("Finger Wag", "angry_fingerwag", ANIM_AGENT_FINGER_WAG),
286 LLAnimStateEntry("Fist Pump", "fist_pump", ANIM_AGENT_FIST_PUMP),
287 LLAnimStateEntry("Floating Yoga", "yoga_float", ANIM_AGENT_YOGA_FLOAT),
288 LLAnimStateEntry("Frown", "express_frown", ANIM_AGENT_EXPRESS_FROWN),
289 LLAnimStateEntry("Impatient", "impatient", ANIM_AGENT_IMPATIENT),
290 LLAnimStateEntry("Jump For Joy", "jumpforjoy", ANIM_AGENT_JUMP_FOR_JOY),
291 LLAnimStateEntry("Kiss My Butt", "kissmybutt", ANIM_AGENT_KISS_MY_BUTT),
292 LLAnimStateEntry("Kiss", "express_kiss", ANIM_AGENT_EXPRESS_KISS),
293 LLAnimStateEntry("Laugh", "laugh_short", ANIM_AGENT_LAUGH_SHORT),
294 LLAnimStateEntry("Muscle Beach", "musclebeach", ANIM_AGENT_MUSCLE_BEACH),
295 LLAnimStateEntry("No (Unhappy)", "no_unhappy", ANIM_AGENT_NO_UNHAPPY),
296 LLAnimStateEntry("No", "no_head", ANIM_AGENT_NO),
297 LLAnimStateEntry("Nya-nya-nya", "nyanya", ANIM_AGENT_NYAH_NYAH),
298 LLAnimStateEntry("One-Two Punch", "punch_onetwo", ANIM_AGENT_ONETWO_PUNCH),
299 LLAnimStateEntry("Open Mouth", "express_open_mouth", ANIM_AGENT_EXPRESS_OPEN_MOUTH),
300 LLAnimStateEntry("Peace", "peace", ANIM_AGENT_PEACE),
301 LLAnimStateEntry("Point at Other", "point_you", ANIM_AGENT_POINT_YOU),
302 LLAnimStateEntry("Point at Self", "point_me", ANIM_AGENT_POINT_ME),
303 LLAnimStateEntry("Punch Left", "punch_l", ANIM_AGENT_PUNCH_LEFT),
304 LLAnimStateEntry("Punch Right", "punch_r", ANIM_AGENT_PUNCH_RIGHT),
305 LLAnimStateEntry("RPS count", "rps_countdown", ANIM_AGENT_RPS_COUNTDOWN),
306 LLAnimStateEntry("RPS paper", "rps_paper", ANIM_AGENT_RPS_PAPER),
307 LLAnimStateEntry("RPS rock", "rps_rock", ANIM_AGENT_RPS_ROCK),
308 LLAnimStateEntry("RPS scissors", "rps_scissors", ANIM_AGENT_RPS_SCISSORS),
309 LLAnimStateEntry("Repulsed", "express_repulsed", ANIM_AGENT_EXPRESS_REPULSED),
310 LLAnimStateEntry("Roundhouse Kick", "kick_roundhouse_r", ANIM_AGENT_ROUNDHOUSE_KICK),
311 LLAnimStateEntry("Sad", "express_sad", ANIM_AGENT_SAD),
312 LLAnimStateEntry("Salute", "salute", ANIM_AGENT_SALUTE),
313 LLAnimStateEntry("Shout", "shout", ANIM_AGENT_SHOUT),
314 LLAnimStateEntry("Shrug", "express_shrug", ANIM_AGENT_SHRUG),
315 LLAnimStateEntry("Smile", "express_smile", ANIM_AGENT_EXPRESS_SMILE),
316 LLAnimStateEntry("Smoke Idle", "smoke_idle", ANIM_AGENT_SMOKE_IDLE),
317 LLAnimStateEntry("Smoke Inhale", "smoke_inhale", ANIM_AGENT_SMOKE_INHALE),
318 LLAnimStateEntry("Smoke Throw Down","smoke_throw_down", ANIM_AGENT_SMOKE_THROW_DOWN),
319 LLAnimStateEntry("Surprise", "express_surprise", ANIM_AGENT_SURPRISE),
320 LLAnimStateEntry("Sword Strike", "sword_strike_r", ANIM_AGENT_SWORD_STRIKE),
321 LLAnimStateEntry("Tantrum", "angry_tantrum", ANIM_AGENT_TANTRUM),
322 LLAnimStateEntry("TongueOut", "express_tongue_out", ANIM_AGENT_EXPRESS_TONGUE_OUT),
323 LLAnimStateEntry("Wave", "hello", ANIM_AGENT_HELLO),
324 LLAnimStateEntry("Whisper", "whisper", ANIM_AGENT_WHISPER),
325 LLAnimStateEntry("Whistle", "whistle", ANIM_AGENT_WHISTLE),
326 LLAnimStateEntry("Wink", "express_wink", ANIM_AGENT_WINK),
327 LLAnimStateEntry("Wink (Hollywood)","wink_hollywood", ANIM_AGENT_WINK_HOLLYWOOD),
328 LLAnimStateEntry("Worry", "express_worry", ANIM_AGENT_EXPRESS_WORRY),
329 LLAnimStateEntry("Yes (Happy)", "yes_happy", ANIM_AGENT_YES_HAPPY),
330 LLAnimStateEntry("Yes", "yes_head", ANIM_AGENT_YES),
331};
332
333const S32 gUserAnimStatesCount = sizeof(gUserAnimStates) / sizeof(gUserAnimStates[0]);
334
335
336
337// End
338
diff --git a/linden/indra/llcharacter/llanimationstates.h b/linden/indra/llcharacter/llanimationstates.h
new file mode 100644
index 0000000..75e2f67
--- /dev/null
+++ b/linden/indra/llcharacter/llanimationstates.h
@@ -0,0 +1,246 @@
1/**
2 * @file llanimationstates.h
3 * @brief Implementation of animation state support.
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#ifndef LL_LLANIMATIONSTATES_H
29#define LL_LLANIMATIONSTATES_H
30
31#include <map>
32
33#include "string_table.h"
34#include "lluuid.h"
35
36//-----------------------------------------------------------------------------
37// These bit flags are generally used to track the animation state
38// of characters. The simulator and viewer share these flags to interpret
39// the Animation name/value attribute on agents.
40//-----------------------------------------------------------------------------
41
42//-----------------------------------------------------------------------------
43// Agent Animation State
44//-----------------------------------------------------------------------------
45const S32 MAX_CONCURRENT_ANIMS = 16;
46
47
48const LLUUID ANIM_AGENT_AFRAID = LLUUID("6b61c8e8-4747-0d75-12d7-e49ff207a4ca");
49const LLUUID ANIM_AGENT_AIM_BAZOOKA_R = LLUUID("b5b4a67d-0aee-30d2-72cd-77b333e932ef");
50const LLUUID ANIM_AGENT_AIM_BOW_L = LLUUID("46bb4359-de38-4ed8-6a22-f1f52fe8f506");
51const LLUUID ANIM_AGENT_AIM_HANDGUN_R = LLUUID("3147d815-6338-b932-f011-16b56d9ac18b");
52const LLUUID ANIM_AGENT_AIM_RIFLE_R = LLUUID("ea633413-8006-180a-c3ba-96dd1d756720");
53const LLUUID ANIM_AGENT_ANGRY = LLUUID("5747a48e-073e-c331-f6f3-7c2149613d3e");
54const LLUUID ANIM_AGENT_AWAY = LLUUID("fd037134-85d4-f241-72c6-4f42164fedee");
55const LLUUID ANIM_AGENT_BACKFLIP = LLUUID("c4ca6188-9127-4f31-0158-23c4e2f93304");
56const LLUUID ANIM_AGENT_BELLY_LAUGH = LLUUID("18b3a4b5-b463-bd48-e4b6-71eaac76c515");
57const LLUUID ANIM_AGENT_BLOW_KISS = LLUUID("db84829b-462c-ee83-1e27-9bbee66bd624");
58const LLUUID ANIM_AGENT_BORED = LLUUID("b906c4ba-703b-1940-32a3-0c7f7d791510");
59const LLUUID ANIM_AGENT_BOW = LLUUID("82e99230-c906-1403-4d9c-3889dd98daba");
60const LLUUID ANIM_AGENT_BRUSH = LLUUID("349a3801-54f9-bf2c-3bd0-1ac89772af01");
61const LLUUID ANIM_AGENT_BUSY = LLUUID("efcf670c-2d18-8128-973a-034ebc806b67");
62const LLUUID ANIM_AGENT_CLAP = LLUUID("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
63const LLUUID ANIM_AGENT_COURTBOW = LLUUID("9ba1c942-08be-e43a-fb29-16ad440efc50");
64const LLUUID ANIM_AGENT_CROUCH = LLUUID("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
65const LLUUID ANIM_AGENT_CROUCHWALK = LLUUID("47f5f6fb-22e5-ae44-f871-73aaaf4a6022");
66const LLUUID ANIM_AGENT_CRY = LLUUID("92624d3e-1068-f1aa-a5ec-8244585193ed");
67const LLUUID ANIM_AGENT_CUSTOMIZE = LLUUID("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53");
68const LLUUID ANIM_AGENT_CUSTOMIZE_DONE = LLUUID("6883a61a-b27b-5914-a61e-dda118a9ee2c");
69const LLUUID ANIM_AGENT_DANCE1 = LLUUID("b68a3d7c-de9e-fc87-eec8-543d787e5b0d");
70const LLUUID ANIM_AGENT_DANCE2 = LLUUID("928cae18-e31d-76fd-9cc9-2f55160ff818");
71const LLUUID ANIM_AGENT_DANCE3 = LLUUID("30047778-10ea-1af7-6881-4db7a3a5a114");
72const LLUUID ANIM_AGENT_DANCE4 = LLUUID("951469f4-c7b2-c818-9dee-ad7eea8c30b7");
73const LLUUID ANIM_AGENT_DANCE5 = LLUUID("4bd69a1d-1114-a0b4-625f-84e0a5237155");
74const LLUUID ANIM_AGENT_DANCE6 = LLUUID("cd28b69b-9c95-bb78-3f94-8d605ff1bb12");
75const LLUUID ANIM_AGENT_DANCE7 = LLUUID("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6");
76const LLUUID ANIM_AGENT_DANCE8 = LLUUID("b0dc417c-1f11-af36-2e80-7e7489fa7cdc");
77const LLUUID ANIM_AGENT_DEAD = LLUUID("57abaae6-1d17-7b1b-5f98-6d11a6411276");
78const LLUUID ANIM_AGENT_DRINK = LLUUID("0f86e355-dd31-a61c-fdb0-3a96b9aad05f");
79const LLUUID ANIM_AGENT_EMBARRASSED = LLUUID("514af488-9051-044a-b3fc-d4dbf76377c6");
80const LLUUID ANIM_AGENT_EXPRESS_AFRAID = LLUUID("aa2df84d-cf8f-7218-527b-424a52de766e");
81const LLUUID ANIM_AGENT_EXPRESS_ANGER = LLUUID("1a03b575-9634-b62a-5767-3a679e81f4de");
82const LLUUID ANIM_AGENT_EXPRESS_BORED = LLUUID("214aa6c1-ba6a-4578-f27c-ce7688f61d0d");
83const LLUUID ANIM_AGENT_EXPRESS_CRY = LLUUID("d535471b-85bf-3b4d-a542-93bea4f59d33");
84const LLUUID ANIM_AGENT_EXPRESS_DISDAIN = LLUUID("d4416ff1-09d3-300f-4183-1b68a19b9fc1");
85const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED = LLUUID("0b8c8211-d78c-33e8-fa28-c51a9594e424");
86const LLUUID ANIM_AGENT_EXPRESS_FROWN = LLUUID("fee3df48-fa3d-1015-1e26-a205810e3001");
87const LLUUID ANIM_AGENT_EXPRESS_KISS = LLUUID("1e8d90cc-a84e-e135-884c-7c82c8b03a14");
88const LLUUID ANIM_AGENT_EXPRESS_LAUGH = LLUUID("62570842-0950-96f8-341c-809e65110823");
89const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH = LLUUID("d63bc1f9-fc81-9625-a0c6-007176d82eb7");
90const LLUUID ANIM_AGENT_EXPRESS_REPULSED = LLUUID("f76cda94-41d4-a229-2872-e0296e58afe1");
91const LLUUID ANIM_AGENT_EXPRESS_SAD = LLUUID("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7");
92const LLUUID ANIM_AGENT_EXPRESS_SHRUG = LLUUID("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef");
93const LLUUID ANIM_AGENT_EXPRESS_SMILE = LLUUID("b7c7c833-e3d3-c4e3-9fc0-131237446312");
94const LLUUID ANIM_AGENT_EXPRESS_SURPRISE = LLUUID("728646d9-cc79-08b2-32d6-937f0a835c24");
95const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT = LLUUID("835965c6-7f2f-bda2-5deb-2478737f91bf");
96const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE = LLUUID("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e");
97const LLUUID ANIM_AGENT_EXPRESS_WINK = LLUUID("da020525-4d94-59d6-23d7-81fdebf33148");
98const LLUUID ANIM_AGENT_EXPRESS_WORRY = LLUUID("9c05e5c7-6f07-6ca4-ed5a-b230390c3950");
99const LLUUID ANIM_AGENT_FALLDOWN = LLUUID("666307d9-a860-572d-6fd4-c3ab8865c094");
100const LLUUID ANIM_AGENT_FEMALE_WALK = LLUUID("f5fc7433-043d-e819-8298-f519a119b688");
101const LLUUID ANIM_AGENT_FINGER_WAG = LLUUID("c1bc7f36-3ba0-d844-f93c-93be945d644f");
102const LLUUID ANIM_AGENT_FIST_PUMP = LLUUID("7db00ccd-f380-f3ee-439d-61968ec69c8a");
103const LLUUID ANIM_AGENT_FLY = LLUUID("aec4610c-757f-bc4e-c092-c6e9caf18daf");
104const LLUUID ANIM_AGENT_FLYSLOW = LLUUID("2b5a38b2-5e00-3a97-a495-4c826bc443e6");
105const LLUUID ANIM_AGENT_HELLO = LLUUID("9b29cd61-c45b-5689-ded2-91756b8d76a9");
106const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R = LLUUID("ef62d355-c815-4816-2474-b1acc21094a6");
107const LLUUID ANIM_AGENT_HOLD_BOW_L = LLUUID("8b102617-bcba-037b-86c1-b76219f90c88");
108const LLUUID ANIM_AGENT_HOLD_HANDGUN_R = LLUUID("efdc1727-8b8a-c800-4077-975fc27ee2f2");
109const LLUUID ANIM_AGENT_HOLD_RIFLE_R = LLUUID("3d94bad0-c55b-7dcc-8763-033c59405d33");
110const LLUUID ANIM_AGENT_HOLD_THROW_R = LLUUID("7570c7b5-1f22-56dd-56ef-a9168241bbb6");
111const LLUUID ANIM_AGENT_HOVER = LLUUID("4ae8016b-31b9-03bb-c401-b1ea941db41d");
112const LLUUID ANIM_AGENT_HOVER_DOWN = LLUUID("20f063ea-8306-2562-0b07-5c853b37b31e");
113const LLUUID ANIM_AGENT_HOVER_UP = LLUUID("62c5de58-cb33-5743-3d07-9e4cd4352864");
114const LLUUID ANIM_AGENT_IMPATIENT = LLUUID("5ea3991f-c293-392e-6860-91dfa01278a3");
115const LLUUID ANIM_AGENT_JUMP = LLUUID("2305bd75-1ca9-b03b-1faa-b176b8a8c49e");
116const LLUUID ANIM_AGENT_JUMP_FOR_JOY = LLUUID("709ea28e-1573-c023-8bf8-520c8bc637fa");
117const LLUUID ANIM_AGENT_KISS_MY_BUTT = LLUUID("19999406-3a3a-d58c-a2ac-d72e555dcf51");
118const LLUUID ANIM_AGENT_LAND = LLUUID("7a17b059-12b2-41b1-570a-186368b6aa6f");
119const LLUUID ANIM_AGENT_LAUGH_SHORT = LLUUID("ca5b3f14-3194-7a2b-c894-aa699b718d1f");
120const LLUUID ANIM_AGENT_MEDIUM_LAND = LLUUID("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57");
121const LLUUID ANIM_AGENT_MOTORCYCLE_SIT = LLUUID("08464f78-3a8e-2944-cba5-0c94aff3af29");
122const LLUUID ANIM_AGENT_MUSCLE_BEACH = LLUUID("315c3a41-a5f3-0ba4-27da-f893f769e69b");
123const LLUUID ANIM_AGENT_NO = LLUUID("5a977ed9-7f72-44e9-4c4c-6e913df8ae74");
124const LLUUID ANIM_AGENT_NO_UNHAPPY = LLUUID("d83fa0e5-97ed-7eb2-e798-7bd006215cb4");
125const LLUUID ANIM_AGENT_NYAH_NYAH = LLUUID("f061723d-0a18-754f-66ee-29a44795a32f");
126const LLUUID ANIM_AGENT_ONETWO_PUNCH = LLUUID("eefc79be-daae-a239-8c04-890f5d23654a");
127const LLUUID ANIM_AGENT_PEACE = LLUUID("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9");
128const LLUUID ANIM_AGENT_POINT_ME = LLUUID("17c024cc-eef2-f6a0-3527-9869876d7752");
129const LLUUID ANIM_AGENT_POINT_YOU = LLUUID("ec952cca-61ef-aa3b-2789-4d1344f016de");
130const LLUUID ANIM_AGENT_PRE_JUMP = LLUUID("7a4e87fe-de39-6fcb-6223-024b00893244");
131const LLUUID ANIM_AGENT_PUNCH_LEFT = LLUUID("f3300ad9-3462-1d07-2044-0fef80062da0");
132const LLUUID ANIM_AGENT_PUNCH_RIGHT = LLUUID("c8e42d32-7310-6906-c903-cab5d4a34656");
133const LLUUID ANIM_AGENT_REPULSED = LLUUID("36f81a92-f076-5893-dc4b-7c3795e487cf");
134const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK = LLUUID("49aea43b-5ac3-8a44-b595-96100af0beda");
135const LLUUID ANIM_AGENT_RPS_COUNTDOWN = LLUUID("35db4f7e-28c2-6679-cea9-3ee108f7fc7f");
136const LLUUID ANIM_AGENT_RPS_PAPER = LLUUID("0836b67f-7f7b-f37b-c00a-460dc1521f5a");
137const LLUUID ANIM_AGENT_RPS_ROCK = LLUUID("42dd95d5-0bc6-6392-f650-777304946c0f");
138const LLUUID ANIM_AGENT_RPS_SCISSORS = LLUUID("16803a9f-5140-e042-4d7b-d28ba247c325");
139const LLUUID ANIM_AGENT_RUN = LLUUID("05ddbff8-aaa9-92a1-2b74-8fe77a29b445");
140const LLUUID ANIM_AGENT_SAD = LLUUID("0eb702e2-cc5a-9a88-56a5-661a55c0676a");
141const LLUUID ANIM_AGENT_SALUTE = LLUUID("cd7668a6-7011-d7e2-ead8-fc69eff1a104");
142const LLUUID ANIM_AGENT_SHOOT_BOW_L = LLUUID("e04d450d-fdb5-0432-fd68-818aaf5935f8");
143const LLUUID ANIM_AGENT_SHOUT = LLUUID("6bd01860-4ebd-127a-bb3d-d1427e8e0c42");
144const LLUUID ANIM_AGENT_SHRUG = LLUUID("70ea714f-3a97-d742-1b01-590a8fcd1db5");
145const LLUUID ANIM_AGENT_SIT = LLUUID("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
146const LLUUID ANIM_AGENT_SIT_FEMALE = LLUUID("b1709c8d-ecd3-54a1-4f28-d55ac0840782");
147const LLUUID ANIM_AGENT_SIT_GENERIC = LLUUID("245f3c54-f1c0-bf2e-811f-46d8eeb386e7");
148const LLUUID ANIM_AGENT_SIT_GROUND = LLUUID("1c7600d6-661f-b87b-efe2-d7421eb93c86");
149const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED = LLUUID("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e");
150const LLUUID ANIM_AGENT_SIT_TO_STAND = LLUUID("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e");
151const LLUUID ANIM_AGENT_SLEEP = LLUUID("f2bed5f9-9d44-39af-b0cd-257b2a17fe40");
152const LLUUID ANIM_AGENT_SMOKE_IDLE = LLUUID("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a");
153const LLUUID ANIM_AGENT_SMOKE_INHALE = LLUUID("6802d553-49da-0778-9f85-1599a2266526");
154const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN = LLUUID("0a9fb970-8b44-9114-d3a9-bf69cfe804d6");
155const LLUUID ANIM_AGENT_SNAPSHOT = LLUUID("eae8905b-271a-99e2-4c0e-31106afd100c");
156const LLUUID ANIM_AGENT_STAND = LLUUID("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f");
157const LLUUID ANIM_AGENT_STANDUP = LLUUID("3da1d753-028a-5446-24f3-9c9b856d9422");
158const LLUUID ANIM_AGENT_STAND_1 = LLUUID("15468e00-3400-bb66-cecc-646d7c14458e");
159const LLUUID ANIM_AGENT_STAND_2 = LLUUID("370f3a20-6ca6-9971-848c-9a01bc42ae3c");
160const LLUUID ANIM_AGENT_STAND_3 = LLUUID("42b46214-4b44-79ae-deb8-0df61424ff4b");
161const LLUUID ANIM_AGENT_STAND_4 = LLUUID("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f");
162const LLUUID ANIM_AGENT_STRETCH = LLUUID("80700431-74ec-a008-14f8-77575e73693f");
163const LLUUID ANIM_AGENT_STRIDE = LLUUID("1cb562b0-ba21-2202-efb3-30f82cdf9595");
164const LLUUID ANIM_AGENT_SURF = LLUUID("41426836-7437-7e89-025d-0aa4d10f1d69");
165const LLUUID ANIM_AGENT_SURPRISE = LLUUID("313b9881-4302-73c0-c7d0-0e7a36b6c224");
166const LLUUID ANIM_AGENT_SWORD_STRIKE = LLUUID("85428680-6bf9-3e64-b489-6f81087c24bd");
167const LLUUID ANIM_AGENT_TALK = LLUUID("5c682a95-6da4-a463-0bf6-0f5b7be129d1");
168const LLUUID ANIM_AGENT_TANTRUM = LLUUID("11000694-3f41-adc2-606b-eee1d66f3724");
169const LLUUID ANIM_AGENT_THROW_R = LLUUID("aa134404-7dac-7aca-2cba-435f9db875ca");
170const LLUUID ANIM_AGENT_TRYON_SHIRT = LLUUID("83ff59fe-2346-f236-9009-4e3608af64c1");
171const LLUUID ANIM_AGENT_TURNLEFT = LLUUID("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135");
172const LLUUID ANIM_AGENT_TURNRIGHT = LLUUID("2d6daa51-3192-6794-8e2e-a15f8338ec30");
173const LLUUID ANIM_AGENT_TYPE = LLUUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
174const LLUUID ANIM_AGENT_WALK = LLUUID("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0");
175const LLUUID ANIM_AGENT_WHISPER = LLUUID("7693f268-06c7-ea71-fa21-2b30d6533f8f");
176const LLUUID ANIM_AGENT_WHISTLE = LLUUID("b1ed7982-c68e-a982-7561-52a88a5298c0");
177const LLUUID ANIM_AGENT_WINK = LLUUID("869ecdad-a44b-671e-3266-56aef2e3ac2e");
178const LLUUID ANIM_AGENT_WINK_HOLLYWOOD = LLUUID("c0c4030f-c02b-49de-24ba-2331f43fe41c");
179const LLUUID ANIM_AGENT_WORRY = LLUUID("9f496bd2-589a-709f-16cc-69bf7df1d36c");
180const LLUUID ANIM_AGENT_YES = LLUUID("15dd911d-be82-2856-26db-27659b142875");
181const LLUUID ANIM_AGENT_YES_HAPPY = LLUUID("b8c8b2a3-9008-1771-3bfc-90924955ab2d");
182const LLUUID ANIM_AGENT_YOGA_FLOAT = LLUUID("42ecd00b-9947-a97c-400a-bbc9174c7aeb");
183
184extern LLUUID AGENT_WALK_ANIMS[];
185extern S32 NUM_AGENT_WALK_ANIMS;
186
187extern LLUUID AGENT_GUN_HOLD_ANIMS[];
188extern S32 NUM_AGENT_GUN_HOLD_ANIMS;
189
190extern LLUUID AGENT_GUN_AIM_ANIMS[];
191extern S32 NUM_AGENT_GUN_AIM_ANIMS;
192
193extern LLUUID AGENT_NO_ROTATE_ANIMS[];
194extern S32 NUM_AGENT_NO_ROTATE_ANIMS;
195
196extern LLUUID AGENT_STAND_ANIMS[];
197extern S32 NUM_AGENT_STAND_ANIMS;
198
199class LLAnimationLibrary
200{
201private:
202 LLStringTable mAnimStringTable;
203
204 typedef std::map<LLUUID, char *> anim_map_t;
205 anim_map_t mAnimMap;
206
207public:
208 LLAnimationLibrary();
209 ~LLAnimationLibrary();
210
211 //-----------------------------------------------------------------------------
212 // Return the text name of a single animation state,
213 // Return NULL if the state is invalid
214 //-----------------------------------------------------------------------------
215 const char *animStateToString( const LLUUID& state );
216
217 //-----------------------------------------------------------------------------
218 // Return the animation state for the given name.
219 // Retun NULL if the name is invalid.
220 //-----------------------------------------------------------------------------
221 LLUUID stringToAnimState( const char *name, BOOL allow_ids = TRUE );
222};
223
224struct LLAnimStateEntry
225{
226 LLAnimStateEntry(const char* label, const char* name, const LLUUID& id)
227 : mLabel(label),
228 mName(name),
229 mID(id)
230 { }
231
232 const char* mLabel;
233 const char* mName;
234 const LLUUID mID;
235};
236
237// Animation states that the user can trigger
238extern const LLAnimStateEntry gUserAnimStates[];
239extern const S32 gUserAnimStatesCount;
240extern LLAnimationLibrary gAnimLibrary;
241
242
243#endif // LL_LLANIMATIONSTATES_H
244
245
246
diff --git a/linden/indra/llcharacter/llbvhloader.cpp b/linden/indra/llcharacter/llbvhloader.cpp
new file mode 100644
index 0000000..6aa430f
--- /dev/null
+++ b/linden/indra/llcharacter/llbvhloader.cpp
@@ -0,0 +1,1508 @@
1/**
2 * @file llbvhloader.cpp
3 * @brief Translates a BVH files to LindenLabAnimation format.
4 *
5 * Copyright (c) 2004-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#include "linden_common.h"
29
30#include "llbvhloader.h"
31#include "lldatapacker.h"
32#include "lldir.h"
33#include "llkeyframemotion.h"
34#include "llquantize.h"
35#include "llstl.h"
36#include "llapr.h"
37
38#include <stdio.h>
39#include <string.h>
40#include <stdarg.h>
41#include <llquaternion.h>
42#include <boost/tokenizer.hpp>
43
44using namespace std;
45
46#define INCHES_TO_METERS 0.02540005f
47
48const F32 POSITION_KEYFRAME_THRESHOLD = 0.03f;
49const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
50
51const F32 POSITION_MOTION_THRESHOLD = 0.001f;
52const F32 ROTATION_MOTION_THRESHOLD = 0.001f;
53
54char gInFile[1024]; /* Flawfinder: ignore */
55char gOutFile[1024]; /* Flawfinder: ignore */
56
57//------------------------------------------------------------------------
58// Status Codes
59//------------------------------------------------------------------------
60char *LLBVHLoader::ST_OK = "Ok";
61char *LLBVHLoader::ST_EOF = "Premature end of file.";
62char *LLBVHLoader::ST_NO_CONSTRAINT = "Can't read constraint definition.";
63char *LLBVHLoader::ST_NO_FILE = "Can't open BVH file.";
64char *LLBVHLoader::ST_NO_HIER = "Invalid HIERARCHY header.";
65char *LLBVHLoader::ST_NO_JOINT = "Can't find ROOT or JOINT.";
66char *LLBVHLoader::ST_NO_NAME = "Can't get JOINT name.";
67char *LLBVHLoader::ST_NO_OFFSET = "Can't find OFFSET.";
68char *LLBVHLoader::ST_NO_CHANNELS = "Can't find CHANNELS.";
69char *LLBVHLoader::ST_NO_ROTATION = "Can't get rotation order.";
70char *LLBVHLoader::ST_NO_AXIS = "Can't get rotation axis.";
71char *LLBVHLoader::ST_NO_MOTION = "Can't find MOTION.";
72char *LLBVHLoader::ST_NO_FRAMES = "Can't get number of frames.";
73char *LLBVHLoader::ST_NO_FRAME_TIME = "Can't get frame time.";
74char *LLBVHLoader::ST_NO_POS = "Can't get position values.";
75char *LLBVHLoader::ST_NO_ROT = "Can't get rotation values.";
76char *LLBVHLoader::ST_NO_XLT_FILE = "Can't open translation file.";
77char *LLBVHLoader::ST_NO_XLT_HEADER = "Can't read translation header.";
78char *LLBVHLoader::ST_NO_XLT_NAME = "Can't read translation names.";
79char *LLBVHLoader::ST_NO_XLT_IGNORE = "Can't read translation ignore value.";
80char *LLBVHLoader::ST_NO_XLT_RELATIVE = "Can't read translation relative value.";
81char *LLBVHLoader::ST_NO_XLT_OUTNAME = "Can't read translation outname value.";
82char *LLBVHLoader::ST_NO_XLT_MATRIX = "Can't read translation matrix.";
83char *LLBVHLoader::ST_NO_XLT_MERGECHILD = "Can't get mergechild name.";
84char *LLBVHLoader::ST_NO_XLT_MERGEPARENT = "Can't get mergeparent name.";
85char *LLBVHLoader::ST_NO_XLT_PRIORITY = "Can't get priority value.";
86char *LLBVHLoader::ST_NO_XLT_LOOP = "Can't get loop value.";
87char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values.";
88char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values.";
89char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value.";
90char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name.";
91
92//------------------------------------------------------------------------
93// find_next_whitespace()
94//------------------------------------------------------------------------
95const char *find_next_whitespace(const char *p)
96{
97 while(*p && isspace(*p)) p++;
98 while(*p && !isspace(*p)) p++;
99 return p;
100}
101
102
103//------------------------------------------------------------------------
104// bvhStringToOrder()
105//
106// XYZ order in BVH files must be passed to mayaQ() as ZYX.
107// This function reverses the input string before passing it on
108// to StringToOrder().
109//------------------------------------------------------------------------
110LLQuaternion::Order bvhStringToOrder( char *str )
111{
112 char order[4]; /* Flawfinder: ignore */
113 order[0] = str[2];
114 order[1] = str[1];
115 order[2] = str[0];
116 order[3] = 0;
117 LLQuaternion::Order retVal = StringToOrder( order );
118 return retVal;
119}
120
121//-----------------------------------------------------------------------------
122// LLBVHLoader()
123//-----------------------------------------------------------------------------
124LLBVHLoader::LLBVHLoader(const char* buffer)
125{
126 reset();
127
128 mStatus = loadTranslationTable("anim.ini");
129
130 if (mStatus == LLBVHLoader::ST_NO_XLT_FILE)
131 {
132 llwarns << "NOTE: No translation table found." << llendl;
133 return;
134 }
135 else
136 {
137 if (mStatus != LLBVHLoader::ST_OK)
138 {
139 llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl;
140 return;
141 }
142 }
143
144 char error_text[128]; /* Flawfinder: ignore */
145 S32 error_line;
146 mStatus = loadBVHFile(buffer, error_text, error_line);
147 if (mStatus != LLBVHLoader::ST_OK)
148 {
149 llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl;
150 return;
151 }
152
153 applyTranslations();
154 optimize();
155
156 mInitialized = TRUE;
157}
158
159LLBVHLoader::~LLBVHLoader()
160{
161 std::for_each(mJoints.begin(),mJoints.end(),DeletePointer());
162}
163
164//------------------------------------------------------------------------
165// LLBVHLoader::loadTranslationTable()
166//------------------------------------------------------------------------
167LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName)
168{
169 mLineNumber = 0;
170 mTranslations.clear();
171 mConstraints.clear();
172
173 //--------------------------------------------------------------------
174 // open file
175 //--------------------------------------------------------------------
176 char path[LL_MAX_PATH]; /* Flawfinder: ignore */
177
178 snprintf( path, sizeof(path), "%s",
179 gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName).c_str()); /* Flawfinder: ignore */
180
181
182 apr_file_t *fp = ll_apr_file_open(path, LL_APR_R);
183 if (!fp)
184 return ST_NO_XLT_FILE;
185
186 llinfos << "NOTE: Loading translation table: " << fileName << llendl;
187
188 //--------------------------------------------------------------------
189 // register file to be closed on function exit
190 //--------------------------------------------------------------------
191 FileCloser fileCloser(fp);
192
193 //--------------------------------------------------------------------
194 // load header
195 //--------------------------------------------------------------------
196 if ( ! getLine(fp) )
197 return ST_EOF;
198 if ( strncmp(mLine, "Translations 1.0", 16) )
199 return ST_NO_XLT_HEADER;
200
201 //--------------------------------------------------------------------
202 // load data one line at a time
203 //--------------------------------------------------------------------
204 BOOL loadingGlobals = FALSE;
205 Translation *trans = NULL;
206 while ( getLine(fp) )
207 {
208 //----------------------------------------------------------------
209 // check the 1st token on the line to determine if it's empty or a comment
210 //----------------------------------------------------------------
211 char token[128]; /* Flawfinder: ignore */
212 if ( sscanf(mLine, " %127s", token) != 1 )
213 continue;
214
215 if (token[0] == '#')
216 continue;
217
218 //----------------------------------------------------------------
219 // check if a [jointName] or [GLOBALS] was specified.
220 //----------------------------------------------------------------
221 if (token[0] == '[')
222 {
223 char name[128]; /* Flawfinder: ignore */
224 if ( sscanf(mLine, " [%127[^]]", name) != 1 )
225 return ST_NO_XLT_NAME;
226
227 if (strcmp(name, "GLOBALS")==0)
228 {
229 loadingGlobals = TRUE;
230 continue;
231 }
232 else
233 {
234 loadingGlobals = FALSE;
235 Translation &newTrans = mTranslations[ name ];
236 trans = &newTrans;
237 continue;
238 }
239 }
240
241 //----------------------------------------------------------------
242 // check for optional emote
243 //----------------------------------------------------------------
244 if (loadingGlobals && LLString::compareInsensitive(token, "emote")==0)
245 {
246 char emote_str[1024]; /* Flawfinder: ignore */
247 if ( sscanf(mLine, " %*s = %1023s", emote_str) != 1 )
248 return ST_NO_XLT_EMOTE;
249
250 mEmoteName.assign( emote_str );
251// llinfos << "NOTE: Emote: " << mEmoteName.c_str() << llendl;
252 continue;
253 }
254
255
256 //----------------------------------------------------------------
257 // check for global priority setting
258 //----------------------------------------------------------------
259 if (loadingGlobals && LLString::compareInsensitive(token, "priority")==0)
260 {
261 S32 priority;
262 if ( sscanf(mLine, " %*s = %d", &priority) != 1 )
263 return ST_NO_XLT_PRIORITY;
264
265 mPriority = priority;
266// llinfos << "NOTE: Priority: " << mPriority << llendl;
267 continue;
268 }
269
270 //----------------------------------------------------------------
271 // check for global loop setting
272 //----------------------------------------------------------------
273 if (loadingGlobals && LLString::compareInsensitive(token, "loop")==0)
274 {
275 char trueFalse[128]; /* Flawfinder: ignore */
276 trueFalse[0] = '\0';
277
278 F32 loop_in = 0.f;
279 F32 loop_out = 1.f;
280
281 if ( sscanf(mLine, " %*s = %f %f", &loop_in, &loop_out) == 2 )
282 {
283 mLoop = TRUE;
284 }
285 else if ( sscanf(mLine, " %*s = %127s", trueFalse) == 1 )
286 {
287 mLoop = (LLString::compareInsensitive(trueFalse, "true")==0);
288 }
289 else
290 {
291 return ST_NO_XLT_LOOP;
292 }
293
294 mLoopInPoint = loop_in * mDuration;
295 mLoopOutPoint = loop_out * mDuration;
296
297 continue;
298 }
299
300 //----------------------------------------------------------------
301 // check for global easeIn setting
302 //----------------------------------------------------------------
303 if (loadingGlobals && LLString::compareInsensitive(token, "easein")==0)
304 {
305 F32 duration;
306 char type[128]; /* Flawfinder: ignore */
307 if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 )
308 return ST_NO_XLT_EASEIN;
309
310 mEaseIn = duration;
311 continue;
312 }
313
314 //----------------------------------------------------------------
315 // check for global easeOut setting
316 //----------------------------------------------------------------
317 if (loadingGlobals && LLString::compareInsensitive(token, "easeout")==0)
318 {
319 F32 duration;
320 char type[128];
321 if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 )
322 return ST_NO_XLT_EASEOUT;
323
324 mEaseOut = duration;
325 continue;
326 }
327
328 //----------------------------------------------------------------
329 // check for global handMorph setting
330 //----------------------------------------------------------------
331 if (loadingGlobals && LLString::compareInsensitive(token, "hand")==0)
332 {
333 S32 handMorph;
334 if (sscanf(mLine, " %*s = %d", &handMorph) != 1)
335 return ST_NO_XLT_HAND;
336
337 mHand = handMorph;
338 continue;
339 }
340
341 if (loadingGlobals && LLString::compareInsensitive(token, "constraint")==0)
342 {
343 Constraint constraint;
344
345 // try reading optional target direction
346 if(sscanf(
347 mLine,
348 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f",
349 &constraint.mChainLength,
350 &constraint.mEaseInStart,
351 &constraint.mEaseInStop,
352 &constraint.mEaseOutStart,
353 &constraint.mEaseOutStop,
354 constraint.mSourceJointName,
355 &constraint.mSourceOffset.mV[VX],
356 &constraint.mSourceOffset.mV[VY],
357 &constraint.mSourceOffset.mV[VZ],
358 constraint.mTargetJointName,
359 &constraint.mTargetOffset.mV[VX],
360 &constraint.mTargetOffset.mV[VY],
361 &constraint.mTargetOffset.mV[VZ],
362 &constraint.mTargetDir.mV[VX],
363 &constraint.mTargetDir.mV[VY],
364 &constraint.mTargetDir.mV[VZ]) != 16)
365 {
366 if(sscanf(
367 mLine,
368 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f",
369 &constraint.mChainLength,
370 &constraint.mEaseInStart,
371 &constraint.mEaseInStop,
372 &constraint.mEaseOutStart,
373 &constraint.mEaseOutStop,
374 constraint.mSourceJointName,
375 &constraint.mSourceOffset.mV[VX],
376 &constraint.mSourceOffset.mV[VY],
377 &constraint.mSourceOffset.mV[VZ],
378 constraint.mTargetJointName,
379 &constraint.mTargetOffset.mV[VX],
380 &constraint.mTargetOffset.mV[VY],
381 &constraint.mTargetOffset.mV[VZ]) != 13)
382 {
383 return ST_NO_CONSTRAINT;
384 }
385 }
386 else
387 {
388 // normalize direction
389 if (!constraint.mTargetDir.isExactlyZero())
390 {
391 constraint.mTargetDir.normVec();
392 }
393
394 }
395
396 constraint.mConstraintType = CONSTRAINT_TYPE_POINT;
397 mConstraints.push_back(constraint);
398 continue;
399 }
400
401 if (loadingGlobals && LLString::compareInsensitive(token, "planar_constraint")==0)
402 {
403 Constraint constraint;
404
405 // try reading optional target direction
406 if(sscanf(
407 mLine,
408 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f",
409 &constraint.mChainLength,
410 &constraint.mEaseInStart,
411 &constraint.mEaseInStop,
412 &constraint.mEaseOutStart,
413 &constraint.mEaseOutStop,
414 constraint.mSourceJointName,
415 &constraint.mSourceOffset.mV[VX],
416 &constraint.mSourceOffset.mV[VY],
417 &constraint.mSourceOffset.mV[VZ],
418 constraint.mTargetJointName,
419 &constraint.mTargetOffset.mV[VX],
420 &constraint.mTargetOffset.mV[VY],
421 &constraint.mTargetOffset.mV[VZ],
422 &constraint.mTargetDir.mV[VX],
423 &constraint.mTargetDir.mV[VY],
424 &constraint.mTargetDir.mV[VZ]) != 16)
425 {
426 if(sscanf(
427 mLine,
428 " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f",
429 &constraint.mChainLength,
430 &constraint.mEaseInStart,
431 &constraint.mEaseInStop,
432 &constraint.mEaseOutStart,
433 &constraint.mEaseOutStop,
434 constraint.mSourceJointName,
435 &constraint.mSourceOffset.mV[VX],
436 &constraint.mSourceOffset.mV[VY],
437 &constraint.mSourceOffset.mV[VZ],
438 constraint.mTargetJointName,
439 &constraint.mTargetOffset.mV[VX],
440 &constraint.mTargetOffset.mV[VY],
441 &constraint.mTargetOffset.mV[VZ]) != 13)
442 {
443 return ST_NO_CONSTRAINT;
444 }
445 }
446 else
447 {
448 // normalize direction
449 if (!constraint.mTargetDir.isExactlyZero())
450 {
451 constraint.mTargetDir.normVec();
452 }
453
454 }
455
456 constraint.mConstraintType = CONSTRAINT_TYPE_PLANE;
457 mConstraints.push_back(constraint);
458 continue;
459 }
460
461
462 //----------------------------------------------------------------
463 // at this point there must be a valid trans pointer
464 //----------------------------------------------------------------
465 if ( ! trans )
466 return ST_NO_XLT_NAME;
467
468 //----------------------------------------------------------------
469 // check for ignore flag
470 //----------------------------------------------------------------
471 if ( LLString::compareInsensitive(token, "ignore")==0 )
472 {
473 char trueFalse[128]; /* Flawfinder: ignore */
474 if ( sscanf(mLine, " %*s = %127s", trueFalse) != 1 )
475 return ST_NO_XLT_IGNORE;
476
477 trans->mIgnore = (LLString::compareInsensitive(trueFalse, "true")==0);
478 continue;
479 }
480
481 //----------------------------------------------------------------
482 // check for relativepos flag
483 //----------------------------------------------------------------
484 if ( LLString::compareInsensitive(token, "relativepos")==0 )
485 {
486 F32 x, y, z;
487 char relpos[128]; /* Flawfinder: ignore */
488 if ( sscanf(mLine, " %*s = %f %f %f", &x, &y, &z) == 3 )
489 {
490 trans->mRelativePosition.setVec( x, y, z );
491 }
492 else if ( sscanf(mLine, " %*s = %127s", relpos) == 1 )
493 {
494 if ( LLString::compareInsensitive(relpos, "firstkey")==0 )
495 {
496 trans->mRelativePositionKey = TRUE;
497 }
498 else
499 {
500 return ST_NO_XLT_RELATIVE;
501 }
502 }
503 else
504 {
505 return ST_NO_XLT_RELATIVE;
506 }
507
508 continue;
509 }
510
511 //----------------------------------------------------------------
512 // check for relativerot flag
513 //----------------------------------------------------------------
514 if ( LLString::compareInsensitive(token, "relativerot")==0 )
515 {
516 //F32 x, y, z;
517 char relpos[128]; /* Flawfinder: ignore */
518 if ( sscanf(mLine, " %*s = %127s", relpos) == 1 )
519 {
520 if ( LLString::compareInsensitive(relpos, "firstkey")==0 )
521 {
522 trans->mRelativeRotationKey = TRUE;
523 }
524 else
525 {
526 return ST_NO_XLT_RELATIVE;
527 }
528 }
529 else
530 {
531 return ST_NO_XLT_RELATIVE;
532 }
533
534 continue;
535 }
536
537 //----------------------------------------------------------------
538 // check for outname value
539 //----------------------------------------------------------------
540 if ( LLString::compareInsensitive(token, "outname")==0 )
541 {
542 char outName[128]; /* Flawfinder: ignore */
543 if ( sscanf(mLine, " %*s = %127s", outName) != 1 )
544 return ST_NO_XLT_OUTNAME;
545
546 trans->mOutName = outName;
547 continue;
548 }
549
550 //----------------------------------------------------------------
551 // check for frame matrix value
552 //----------------------------------------------------------------
553 if ( LLString::compareInsensitive(token, "frame")==0 )
554 {
555 LLMatrix3 fm;
556 if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f",
557 &fm.mMatrix[0][0], &fm.mMatrix[0][1], &fm.mMatrix[0][2],
558 &fm.mMatrix[1][0], &fm.mMatrix[1][1], &fm.mMatrix[1][2],
559 &fm.mMatrix[2][0], &fm.mMatrix[2][1], &fm.mMatrix[2][2] ) != 9 )
560 return ST_NO_XLT_MATRIX;
561
562 trans->mFrameMatrix = fm;
563 continue;
564 }
565
566 //----------------------------------------------------------------
567 // check for offset matrix value
568 //----------------------------------------------------------------
569 if ( LLString::compareInsensitive(token, "offset")==0 )
570 {
571 LLMatrix3 om;
572 if ( sscanf(mLine, " %*s = %f %f %f, %f %f %f, %f %f %f",
573 &om.mMatrix[0][0], &om.mMatrix[0][1], &om.mMatrix[0][2],
574 &om.mMatrix[1][0], &om.mMatrix[1][1], &om.mMatrix[1][2],
575 &om.mMatrix[2][0], &om.mMatrix[2][1], &om.mMatrix[2][2] ) != 9 )
576 return ST_NO_XLT_MATRIX;
577
578 trans->mOffsetMatrix = om;
579 continue;
580 }
581
582 //----------------------------------------------------------------
583 // check for mergeparent value
584 //----------------------------------------------------------------
585 if ( LLString::compareInsensitive(token, "mergeparent")==0 )
586 {
587 char mergeParentName[128]; /* Flawfinder: ignore */
588 if ( sscanf(mLine, " %*s = %127s", mergeParentName) != 1 )
589 return ST_NO_XLT_MERGEPARENT;
590
591 trans->mMergeParentName = mergeParentName;
592 continue;
593 }
594
595 //----------------------------------------------------------------
596 // check for mergechild value
597 //----------------------------------------------------------------
598 if ( LLString::compareInsensitive(token, "mergechild")==0 )
599 {
600 char mergeChildName[128]; /* Flawfinder: ignore */
601 if ( sscanf(mLine, " %*s = %127s", mergeChildName) != 1 )
602 return ST_NO_XLT_MERGECHILD;
603
604 trans->mMergeChildName = mergeChildName;
605 continue;
606 }
607
608 //----------------------------------------------------------------
609 // check for per-joint priority
610 //----------------------------------------------------------------
611 if ( LLString::compareInsensitive(token, "priority")==0 )
612 {
613 S32 priority;
614 if ( sscanf(mLine, " %*s = %d", &priority) != 1 )
615 return ST_NO_XLT_PRIORITY;
616
617 trans->mPriorityModifier = priority;
618 continue;
619 }
620
621 }
622 return ST_OK;
623}
624
625
626//------------------------------------------------------------------------
627// LLBVHLoader::loadBVHFile()
628//------------------------------------------------------------------------
629LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &err_line)
630{
631 std::string line;
632
633 err_line = 0;
634 error_text[127] = '\0';
635
636 std::string str(buffer);
637 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
638 boost::char_separator<char> sep("\r\n");
639 tokenizer tokens(str, sep);
640 tokenizer::iterator iter = tokens.begin();
641
642 mLineNumber = 0;
643 mJoints.clear();
644
645 std::vector<S32> parent_joints;
646
647 //--------------------------------------------------------------------
648 // consume hierarchy
649 //--------------------------------------------------------------------
650 if (iter == tokens.end())
651 return ST_EOF;
652 line = (*(iter++));
653 err_line++;
654
655 if ( !strstr(line.c_str(), "HIERARCHY") )
656 {
657// llinfos << line << llendl;
658 return ST_NO_HIER;
659 }
660
661 //--------------------------------------------------------------------
662 // consume joints
663 //--------------------------------------------------------------------
664 while (TRUE)
665 {
666 //----------------------------------------------------------------
667 // get next line
668 //----------------------------------------------------------------
669 if (iter == tokens.end())
670 return ST_EOF;
671 line = (*(iter++));
672 err_line++;
673
674 //----------------------------------------------------------------
675 // consume }
676 //----------------------------------------------------------------
677 if ( strstr(line.c_str(), "}") )
678 {
679 if (parent_joints.size() > 0)
680 {
681 parent_joints.pop_back();
682 }
683 continue;
684 }
685
686 //----------------------------------------------------------------
687 // if MOTION, break out
688 //----------------------------------------------------------------
689 if ( strstr(line.c_str(), "MOTION") )
690 break;
691
692 //----------------------------------------------------------------
693 // it must be either ROOT or JOINT or EndSite
694 //----------------------------------------------------------------
695 if ( strstr(line.c_str(), "ROOT") )
696 {
697 }
698 else if ( strstr(line.c_str(), "JOINT") )
699 {
700 }
701 else if ( strstr(line.c_str(), "End Site") )
702 {
703 iter++; // {
704 iter++; // OFFSET
705 S32 depth = 0;
706 for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
707 {
708 Joint *joint = mJoints[parent_joints[j]];
709 if (depth > joint->mChildTreeMaxDepth)
710 {
711 joint->mChildTreeMaxDepth = depth;
712 }
713 depth++;
714 }
715 continue;
716 }
717 else
718 {
719 strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
720 return ST_NO_JOINT;
721 }
722
723 //----------------------------------------------------------------
724 // get the joint name
725 //----------------------------------------------------------------
726 char jointName[80]; /* Flawfinder: ignore */
727 if ( sscanf(line.c_str(), "%*s %79s", jointName) != 1 )
728 {
729 strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
730 return ST_NO_NAME;
731 }
732
733 //----------------------------------------------------------------
734 // add a set of keyframes for this joint
735 //----------------------------------------------------------------
736 mJoints.push_back( new Joint( jointName ) );
737 Joint *joint = mJoints.back();
738
739 S32 depth = 1;
740 for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
741 {
742 Joint *pjoint = mJoints[parent_joints[j]];
743 if (depth > pjoint->mChildTreeMaxDepth)
744 {
745 pjoint->mChildTreeMaxDepth = depth;
746 }
747 depth++;
748 }
749
750 //----------------------------------------------------------------
751 // get next line
752 //----------------------------------------------------------------
753 if (iter == tokens.end())
754 {
755 return ST_EOF;
756 }
757 line = (*(iter++));
758 err_line++;
759
760 //----------------------------------------------------------------
761 // it must be {
762 //----------------------------------------------------------------
763 if ( !strstr(line.c_str(), "{") )
764 {
765 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
766 return ST_NO_OFFSET;
767 }
768 else
769 {
770 parent_joints.push_back((S32)mJoints.size() - 1);
771 }
772
773 //----------------------------------------------------------------
774 // get next line
775 //----------------------------------------------------------------
776 if (iter == tokens.end())
777 {
778 return ST_EOF;
779 }
780 line = (*(iter++));
781 err_line++;
782
783 //----------------------------------------------------------------
784 // it must be OFFSET
785 //----------------------------------------------------------------
786 if ( !strstr(line.c_str(), "OFFSET") )
787 {
788 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
789 return ST_NO_OFFSET;
790 }
791
792 //----------------------------------------------------------------
793 // get next line
794 //----------------------------------------------------------------
795 if (iter == tokens.end())
796 {
797 return ST_EOF;
798 }
799 line = (*(iter++));
800 err_line++;
801
802 //----------------------------------------------------------------
803 // it must be CHANNELS
804 //----------------------------------------------------------------
805 if ( !strstr(line.c_str(), "CHANNELS") )
806 {
807 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
808 return ST_NO_CHANNELS;
809 }
810
811 //----------------------------------------------------------------
812 // get rotation order
813 //----------------------------------------------------------------
814 const char *p = line.c_str();
815 for (S32 i=0; i<3; i++)
816 {
817 p = strstr(p, "rotation");
818 if (!p)
819 {
820 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
821 return ST_NO_ROTATION;
822 }
823
824 const char axis = *(p - 1);
825 if ((axis != 'X') && (axis != 'Y') && (axis != 'Z'))
826 {
827 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
828 return ST_NO_AXIS;
829 }
830
831 joint->mOrder[i] = axis;
832
833 p++;
834 }
835 }
836
837 //--------------------------------------------------------------------
838 // consume motion
839 //--------------------------------------------------------------------
840 if ( !strstr(line.c_str(), "MOTION") )
841 {
842 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
843 return ST_NO_MOTION;
844 }
845
846 //--------------------------------------------------------------------
847 // get number of frames
848 //--------------------------------------------------------------------
849 if (iter == tokens.end())
850 {
851 return ST_EOF;
852 }
853 line = (*(iter++));
854 err_line++;
855
856 if ( !strstr(line.c_str(), "Frames:") )
857 {
858 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
859 return ST_NO_FRAMES;
860 }
861
862 if ( sscanf(line.c_str(), "Frames: %d", &mNumFrames) != 1 )
863 {
864 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
865 return ST_NO_FRAMES;
866 }
867
868 //--------------------------------------------------------------------
869 // get frame time
870 //--------------------------------------------------------------------
871 if (iter == tokens.end())
872 {
873 return ST_EOF;
874 }
875 line = (*(iter++));
876 err_line++;
877
878 if ( !strstr(line.c_str(), "Frame Time:") )
879 {
880 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
881 return ST_NO_FRAME_TIME;
882 }
883
884 if ( sscanf(line.c_str(), "Frame Time: %f", &mFrameTime) != 1 )
885 {
886 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
887 return ST_NO_FRAME_TIME;
888 }
889
890 mDuration = (F32)mNumFrames * mFrameTime;
891 if (!mLoop)
892 {
893 mLoopOutPoint = mDuration;
894 }
895
896 //--------------------------------------------------------------------
897 // load frames
898 //--------------------------------------------------------------------
899 for (S32 i=0; i<mNumFrames; i++)
900 {
901 // get next line
902 if (iter == tokens.end())
903 {
904 return ST_EOF;
905 }
906 line = (*(iter++));
907 err_line++;
908
909 // read and store values
910 const char *p = line.c_str();
911 for (U32 j=0; j<mJoints.size(); j++)
912 {
913 Joint *joint = mJoints[j];
914 joint->mKeys.push_back( Key() );
915 Key &key = joint->mKeys.back();
916
917 // get 3 pos values for root joint only
918 if (j==0)
919 {
920 if ( sscanf(p, "%f %f %f", key.mPos, key.mPos+1, key.mPos+2) != 3 )
921 {
922 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
923 return ST_NO_POS;
924 }
925 }
926
927 // skip to next 3 values in the line
928 p = find_next_whitespace(p);
929 if (!p)
930 {
931 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
932 return ST_NO_ROT;
933 }
934 p = find_next_whitespace(++p);
935 if (!p)
936 {
937 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
938 return ST_NO_ROT;
939 }
940 p = find_next_whitespace(++p);
941 if (!p)
942 {
943 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
944 return ST_NO_ROT;
945 }
946
947 // get 3 rot values for joint
948 F32 rot[3];
949 if ( sscanf(p, " %f %f %f", rot, rot+1, rot+2) != 3 )
950 {
951 strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
952 return ST_NO_ROT;
953 }
954
955 p++;
956
957 key.mRot[ joint->mOrder[0]-'X' ] = rot[0];
958 key.mRot[ joint->mOrder[1]-'X' ] = rot[1];
959 key.mRot[ joint->mOrder[2]-'X' ] = rot[2];
960 }
961 }
962
963 return ST_OK;
964}
965
966
967//------------------------------------------------------------------------
968// LLBVHLoader::applyTranslation()
969//------------------------------------------------------------------------
970void LLBVHLoader::applyTranslations()
971{
972 JointVector::iterator ji;
973 for (ji = mJoints.begin(); ji != mJoints.end(); ++ji )
974 {
975 Joint *joint = *ji;
976 //----------------------------------------------------------------
977 // Look for a translation for this joint.
978 // If none, skip to next joint
979 //----------------------------------------------------------------
980 TranslationMap::iterator ti = mTranslations.find( joint->mName );
981 if ( ti == mTranslations.end() )
982 {
983 continue;
984 }
985
986 Translation &trans = ti->second;
987
988 //----------------------------------------------------------------
989 // Set the ignore flag if necessary
990 //----------------------------------------------------------------
991 if ( trans.mIgnore )
992 {
993 //llinfos << "NOTE: Ignoring " << joint->mName.c_str() << llendl;
994 joint->mIgnore = TRUE;
995 continue;
996 }
997
998 //----------------------------------------------------------------
999 // Set the output name
1000 //----------------------------------------------------------------
1001 if ( ! trans.mOutName.empty() )
1002 {
1003 //llinfos << "NOTE: Changing " << joint->mName.c_str() << " to " << trans.mOutName.c_str() << llendl;
1004 joint->mOutName = trans.mOutName;
1005 }
1006
1007 //----------------------------------------------------------------
1008 // Set the ignorepos flag if necessary
1009 //----------------------------------------------------------------
1010 if ( joint->mOutName == std::string("mPelvis") )
1011 {
1012 joint->mIgnorePositions = FALSE;
1013 }
1014
1015 //----------------------------------------------------------------
1016 // Set the relativepos flags if necessary
1017 //----------------------------------------------------------------
1018 if ( trans.mRelativePositionKey )
1019 {
1020// llinfos << "NOTE: Removing 1st position offset from all keys for " << joint->mOutName.c_str() << llendl;
1021 joint->mRelativePositionKey = TRUE;
1022 }
1023
1024 if ( trans.mRelativeRotationKey )
1025 {
1026// llinfos << "NOTE: Removing 1st rotation from all keys for " << joint->mOutName.c_str() << llendl;
1027 joint->mRelativeRotationKey = TRUE;
1028 }
1029
1030 if ( trans.mRelativePosition.magVec() > 0.0f )
1031 {
1032 joint->mRelativePosition = trans.mRelativePosition;
1033// llinfos << "NOTE: Removing " <<
1034// joint->mRelativePosition.mV[0] << " " <<
1035// joint->mRelativePosition.mV[1] << " " <<
1036// joint->mRelativePosition.mV[2] <<
1037// " from all position keys in " <<
1038// joint->mOutName.c_str() << llendl;
1039 }
1040
1041 //----------------------------------------------------------------
1042 // Set change of coordinate frame
1043 //----------------------------------------------------------------
1044 joint->mFrameMatrix = trans.mFrameMatrix;
1045 joint->mOffsetMatrix = trans.mOffsetMatrix;
1046
1047 //----------------------------------------------------------------
1048 // Set mergeparent name
1049 //----------------------------------------------------------------
1050 if ( ! trans.mMergeParentName.empty() )
1051 {
1052// llinfos << "NOTE: Merging " << joint->mOutName.c_str() <<
1053// " with parent " <<
1054// trans.mMergeParentName.c_str() << llendl;
1055 joint->mMergeParentName = trans.mMergeParentName;
1056 }
1057
1058 //----------------------------------------------------------------
1059 // Set mergechild name
1060 //----------------------------------------------------------------
1061 if ( ! trans.mMergeChildName.empty() )
1062 {
1063// llinfos << "NOTE: Merging " << joint->mName.c_str() <<
1064// " with child " << trans.mMergeChildName.c_str() << llendl;
1065 joint->mMergeChildName = trans.mMergeChildName;
1066 }
1067
1068 //----------------------------------------------------------------
1069 // Set joint priority
1070 //----------------------------------------------------------------
1071 joint->mPriority = mPriority + trans.mPriorityModifier;
1072
1073 }
1074}
1075
1076//-----------------------------------------------------------------------------
1077// LLBVHLoader::optimize()
1078//-----------------------------------------------------------------------------
1079void LLBVHLoader::optimize()
1080{
1081 //RN: assumes motion blend, which is the default now
1082 if (!mLoop && mEaseIn + mEaseOut > mDuration && mDuration != 0.f)
1083 {
1084 F32 factor = mDuration / (mEaseIn + mEaseOut);
1085 mEaseIn *= factor;
1086 mEaseOut *= factor;
1087 }
1088
1089 JointVector::iterator ji;
1090 for (ji = mJoints.begin(); ji != mJoints.end(); ++ji)
1091 {
1092 Joint *joint = *ji;
1093 BOOL pos_changed = FALSE;
1094 BOOL rot_changed = FALSE;
1095
1096 if ( ! joint->mIgnore )
1097 {
1098 joint->mNumPosKeys = 0;
1099 joint->mNumRotKeys = 0;
1100 LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
1101
1102 KeyVector::iterator first_key = joint->mKeys.begin();
1103
1104 // no keys?
1105 if (first_key == joint->mKeys.end())
1106 {
1107 joint->mIgnore = TRUE;
1108 continue;
1109 }
1110
1111 LLVector3 first_frame_pos(first_key->mPos);
1112 LLQuaternion first_frame_rot = mayaQ( first_key->mRot[0], first_key->mRot[1], first_key->mRot[2], order);
1113
1114 // skip first key
1115 KeyVector::iterator ki = joint->mKeys.begin();
1116 if (joint->mKeys.size() == 1)
1117 {
1118 // *FIX: use single frame to move pelvis
1119 // if only one keyframe force output for this joint
1120 rot_changed = TRUE;
1121 }
1122 else
1123 {
1124 // if more than one keyframe, use first frame as reference and skip to second
1125 first_key->mIgnorePos = TRUE;
1126 first_key->mIgnoreRot = TRUE;
1127 ++ki;
1128 }
1129
1130 KeyVector::iterator ki_prev = ki;
1131 KeyVector::iterator ki_last_good_pos = ki;
1132 KeyVector::iterator ki_last_good_rot = ki;
1133 S32 numPosFramesConsidered = 2;
1134 S32 numRotFramesConsidered = 2;
1135
1136 F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)joint->mChildTreeMaxDepth * 0.33f, 1.f);
1137
1138 for (; ki != joint->mKeys.end(); ++ki)
1139 {
1140 if (ki_prev == ki_last_good_pos)
1141 {
1142 joint->mNumPosKeys++;
1143 if (dist_vec(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD)
1144 {
1145 pos_changed = TRUE;
1146 }
1147 }
1148 else
1149 {
1150 //check position for noticeable effect
1151 LLVector3 test_pos(ki_prev->mPos);
1152 LLVector3 last_good_pos(ki_last_good_pos->mPos);
1153 LLVector3 current_pos(ki->mPos);
1154 LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered);
1155
1156 if (dist_vec(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD)
1157 {
1158 pos_changed = TRUE;
1159 }
1160
1161 if (dist_vec(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD)
1162 {
1163 ki_prev->mIgnorePos = TRUE;
1164 numPosFramesConsidered++;
1165 }
1166 else
1167 {
1168 numPosFramesConsidered = 2;
1169 ki_last_good_pos = ki_prev;
1170 joint->mNumPosKeys++;
1171 }
1172 }
1173
1174 if (ki_prev == ki_last_good_rot)
1175 {
1176 joint->mNumRotKeys++;
1177 LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order);
1178 F32 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
1179 F32 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
1180 F32 rot_test = x_delta + y_delta;
1181
1182 if (rot_test > ROTATION_MOTION_THRESHOLD)
1183 {
1184 rot_changed = TRUE;
1185 }
1186 }
1187 else
1188 {
1189 //check rotation for noticeable effect
1190 LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order);
1191 LLQuaternion last_good_rot = mayaQ( ki_last_good_rot->mRot[0], ki_last_good_rot->mRot[1], ki_last_good_rot->mRot[2], order);
1192 LLQuaternion current_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
1193 LLQuaternion interp_rot = lerp(1.f / (F32)numRotFramesConsidered, current_rot, last_good_rot);
1194
1195 F32 x_delta;
1196 F32 y_delta;
1197 F32 rot_test;
1198
1199 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
1200 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
1201 rot_test = x_delta + y_delta;
1202
1203 if (rot_test > ROTATION_MOTION_THRESHOLD)
1204 {
1205 rot_changed = TRUE;
1206 }
1207
1208 x_delta = dist_vec(LLVector3::x_axis * interp_rot, LLVector3::x_axis * test_rot);
1209 y_delta = dist_vec(LLVector3::y_axis * interp_rot, LLVector3::y_axis * test_rot);
1210 rot_test = x_delta + y_delta;
1211
1212 if (rot_test < rot_threshold)
1213 {
1214 ki_prev->mIgnoreRot = TRUE;
1215 numRotFramesConsidered++;
1216 }
1217 else
1218 {
1219 numRotFramesConsidered = 2;
1220 ki_last_good_rot = ki_prev;
1221 joint->mNumRotKeys++;
1222 }
1223 }
1224
1225 ki_prev = ki;
1226 }
1227 }
1228
1229 // don't output joints with no motion
1230 if (!(pos_changed || rot_changed))
1231 {
1232 //llinfos << "Ignoring joint " << joint->mName << llendl;
1233 joint->mIgnore = TRUE;
1234 }
1235 }
1236}
1237
1238void LLBVHLoader::reset()
1239{
1240 mLineNumber = 0;
1241 mNumFrames = 0;
1242 mFrameTime = 0.0f;
1243 mDuration = 0.0f;
1244
1245 mPriority = 2;
1246 mLoop = FALSE;
1247 mLoopInPoint = 0.f;
1248 mLoopOutPoint = 0.f;
1249 mEaseIn = 0.3f;
1250 mEaseOut = 0.3f;
1251 mHand = 1;
1252 mInitialized = FALSE;
1253
1254 mEmoteName = "";
1255}
1256
1257//------------------------------------------------------------------------
1258// LLBVHLoader::getLine()
1259//------------------------------------------------------------------------
1260BOOL LLBVHLoader::getLine(apr_file_t* fp)
1261{
1262 if (apr_file_eof(fp) == APR_EOF)
1263 {
1264 return FALSE;
1265 }
1266 if ( apr_file_gets(mLine, BVH_PARSER_LINE_SIZE, fp) == APR_SUCCESS)
1267 {
1268 mLineNumber++;
1269 return TRUE;
1270 }
1271
1272 return FALSE;
1273}
1274
1275// returns required size of output buffer
1276U32 LLBVHLoader::getOutputSize()
1277{
1278 LLDataPackerBinaryBuffer dp;
1279 serialize(dp);
1280
1281 return dp.getCurrentSize();
1282}
1283
1284// writes contents to datapacker
1285BOOL LLBVHLoader::serialize(LLDataPacker& dp)
1286{
1287 JointVector::iterator ji;
1288 KeyVector::iterator ki;
1289 F32 time;
1290
1291 // count number of non-ignored joints
1292 S32 numJoints = 0;
1293 for (ji=mJoints.begin(); ji!=mJoints.end(); ++ji)
1294 {
1295 Joint *joint = *ji;
1296 if ( ! joint->mIgnore )
1297 numJoints++;
1298 }
1299
1300 // print header
1301 dp.packU16(KEYFRAME_MOTION_VERSION, "version");
1302 dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
1303 dp.packS32(mPriority, "base_priority");
1304 dp.packF32(mDuration, "duration");
1305 dp.packString(mEmoteName.c_str(), "emote_name");
1306 dp.packF32(mLoopInPoint, "loop_in_point");
1307 dp.packF32(mLoopOutPoint, "loop_out_point");
1308 dp.packS32(mLoop, "loop");
1309 dp.packF32(mEaseIn, "ease_in_duration");
1310 dp.packF32(mEaseOut, "ease_out_duration");
1311 dp.packU32(mHand, "hand_pose");
1312 dp.packU32(numJoints, "num_joints");
1313
1314 for ( ji = mJoints.begin();
1315 ji != mJoints.end();
1316 ++ji )
1317 {
1318 Joint *joint = *ji;
1319 // if ignored, skip it
1320 if ( joint->mIgnore )
1321 continue;
1322
1323 LLQuaternion first_frame_rot;
1324 LLQuaternion fixup_rot;
1325
1326 dp.packString(joint->mOutName.c_str(), "joint_name");
1327 dp.packS32(joint->mPriority, "joint_priority");
1328
1329 // compute coordinate frame rotation
1330 LLQuaternion frameRot( joint->mFrameMatrix );
1331 LLQuaternion frameRotInv = ~frameRot;
1332
1333 LLQuaternion offsetRot( joint->mOffsetMatrix );
1334
1335 // find mergechild and mergeparent joints, if specified
1336 LLQuaternion mergeParentRot;
1337 LLQuaternion mergeChildRot;
1338 Joint *mergeParent = NULL;
1339 Joint *mergeChild = NULL;
1340
1341 JointVector::iterator mji;
1342 for (mji=mJoints.begin(); mji!=mJoints.end(); ++mji)
1343 {
1344 Joint *mjoint = *mji;
1345 if ( !joint->mMergeParentName.empty() && (mjoint->mName == joint->mMergeParentName) )
1346 {
1347 mergeParent = *mji;
1348 }
1349 if ( !joint->mMergeChildName.empty() && (mjoint->mName == joint->mMergeChildName) )
1350 {
1351 mergeChild = *mji;
1352 }
1353 }
1354
1355 dp.packS32(joint->mNumRotKeys, "num_rot_keys");
1356
1357 LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
1358 S32 outcount = 0;
1359 S32 frame = 1;
1360 for ( ki = joint->mKeys.begin();
1361 ki != joint->mKeys.end();
1362 ++ki )
1363 {
1364 if ((frame == 1) && joint->mRelativeRotationKey)
1365 {
1366 first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
1367
1368 fixup_rot.shortestArc(LLVector3::z_axis * first_frame_rot * frameRot, LLVector3::z_axis);
1369 }
1370
1371 if (ki->mIgnoreRot)
1372 {
1373 frame++;
1374 continue;
1375 }
1376
1377 time = (F32)frame * mFrameTime;
1378
1379 if (mergeParent)
1380 {
1381 mergeParentRot = mayaQ( mergeParent->mKeys[frame-1].mRot[0],
1382 mergeParent->mKeys[frame-1].mRot[1],
1383 mergeParent->mKeys[frame-1].mRot[2],
1384 bvhStringToOrder(mergeParent->mOrder) );
1385 LLQuaternion parentFrameRot( mergeParent->mFrameMatrix );
1386 LLQuaternion parentOffsetRot( mergeParent->mOffsetMatrix );
1387 mergeParentRot = ~parentFrameRot * mergeParentRot * parentFrameRot * parentOffsetRot;
1388 }
1389 else
1390 {
1391 mergeParentRot.loadIdentity();
1392 }
1393
1394 if (mergeChild)
1395 {
1396 mergeChildRot = mayaQ( mergeChild->mKeys[frame-1].mRot[0],
1397 mergeChild->mKeys[frame-1].mRot[1],
1398 mergeChild->mKeys[frame-1].mRot[2],
1399 bvhStringToOrder(mergeChild->mOrder) );
1400 LLQuaternion childFrameRot( mergeChild->mFrameMatrix );
1401 LLQuaternion childOffsetRot( mergeChild->mOffsetMatrix );
1402 mergeChildRot = ~childFrameRot * mergeChildRot * childFrameRot * childOffsetRot;
1403
1404 }
1405 else
1406 {
1407 mergeChildRot.loadIdentity();
1408 }
1409
1410 LLQuaternion inRot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
1411
1412 LLQuaternion outRot = frameRotInv* mergeChildRot * inRot * mergeParentRot * ~first_frame_rot * frameRot * offsetRot;
1413
1414 U16 time_short = F32_to_U16(time, 0.f, mDuration);
1415 dp.packU16(time_short, "time");
1416 U16 x, y, z;
1417 LLVector3 rot_vec = outRot.packToVector3();
1418 rot_vec.quantize16(-1.f, 1.f, -1.f, 1.f);
1419 x = F32_to_U16(rot_vec.mV[VX], -1.f, 1.f);
1420 y = F32_to_U16(rot_vec.mV[VY], -1.f, 1.f);
1421 z = F32_to_U16(rot_vec.mV[VZ], -1.f, 1.f);
1422 dp.packU16(x, "rot_angle_x");
1423 dp.packU16(y, "rot_angle_y");
1424 dp.packU16(z, "rot_angle_z");
1425 outcount++;
1426 frame++;
1427 }
1428
1429 // output position keys (only for 1st joint)
1430 if ( ji == mJoints.begin() && !joint->mIgnorePositions )
1431 {
1432 dp.packS32(joint->mNumPosKeys, "num_pos_keys");
1433
1434 LLVector3 relPos = joint->mRelativePosition;
1435 LLVector3 relKey;
1436
1437 frame = 1;
1438 for ( ki = joint->mKeys.begin();
1439 ki != joint->mKeys.end();
1440 ++ki )
1441 {
1442 if ((frame == 1) && joint->mRelativePositionKey)
1443 {
1444 relKey.setVec(ki->mPos);
1445 }
1446
1447 if (ki->mIgnorePos)
1448 {
1449 frame++;
1450 continue;
1451 }
1452
1453 time = (F32)frame * mFrameTime;
1454
1455 LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot;
1456 LLVector3 outPos = inPos * frameRot * offsetRot;
1457
1458 outPos *= INCHES_TO_METERS;
1459
1460 outPos -= relPos;
1461 outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1462
1463 U16 time_short = F32_to_U16(time, 0.f, mDuration);
1464 dp.packU16(time_short, "time");
1465
1466 U16 x, y, z;
1467 outPos.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1468 x = F32_to_U16(outPos.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1469 y = F32_to_U16(outPos.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1470 z = F32_to_U16(outPos.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1471 dp.packU16(x, "pos_x");
1472 dp.packU16(y, "pos_y");
1473 dp.packU16(z, "pos_z");
1474
1475 frame++;
1476 }
1477 }
1478 else
1479 {
1480 dp.packS32(0, "num_pos_keys");
1481 }
1482 }
1483
1484 S32 num_constraints = (S32)mConstraints.size();
1485 dp.packS32(num_constraints, "num_constraints");
1486
1487 for (ConstraintVector::iterator constraint_it = mConstraints.begin();
1488 constraint_it != mConstraints.end();
1489 constraint_it++)
1490 {
1491 U8 byte = constraint_it->mChainLength;
1492 dp.packU8(byte, "chain_lenght");
1493
1494 byte = constraint_it->mConstraintType;
1495 dp.packU8(byte, "constraint_type");
1496 dp.packBinaryDataFixed((U8*)constraint_it->mSourceJointName, 16, "source_volume");
1497 dp.packVector3(constraint_it->mSourceOffset, "source_offset");
1498 dp.packBinaryDataFixed((U8*)constraint_it->mTargetJointName, 16, "target_volume");
1499 dp.packVector3(constraint_it->mTargetOffset, "target_offset");
1500 dp.packVector3(constraint_it->mTargetDir, "target_dir");
1501 dp.packF32(constraint_it->mEaseInStart, "ease_in_start");
1502 dp.packF32(constraint_it->mEaseInStop, "ease_in_stop");
1503 dp.packF32(constraint_it->mEaseOutStart, "ease_out_start");
1504 dp.packF32(constraint_it->mEaseOutStop, "ease_out_stop");
1505 }
1506
1507 return TRUE;
1508}
diff --git a/linden/indra/llcharacter/llbvhloader.h b/linden/indra/llcharacter/llbvhloader.h
new file mode 100644
index 0000000..0ae31ef
--- /dev/null
+++ b/linden/indra/llcharacter/llbvhloader.h
@@ -0,0 +1,301 @@
1/**
2 * @file llbvhloader.h
3 * @brief Translates a BVH files to LindenLabAnimation format.
4 *
5 * Copyright (c) 2004-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#ifndef LL_LLBVHLOADER_H
29#define LL_LLBVHLOADER_H
30
31#include <string>
32#include <vector>
33#include <map>
34#include <stdtypes.h>
35#include <stdio.h>
36#include "v3math.h"
37#include "m3math.h"
38#include "llmath.h"
39#include "llapr.h"
40
41const S32 BVH_PARSER_LINE_SIZE = 2048;
42const F32 MAX_ANIM_DURATION = 30.f;
43class LLDataPacker;
44
45//------------------------------------------------------------------------
46// FileCloser
47//------------------------------------------------------------------------
48class FileCloser
49{
50public:
51 FileCloser( apr_file_t *file )
52 {
53 mFile = file;
54 }
55
56 ~FileCloser()
57 {
58 apr_file_close(mFile);
59 }
60protected:
61 apr_file_t* mFile;
62};
63
64
65//------------------------------------------------------------------------
66// Key
67//------------------------------------------------------------------------
68struct Key
69{
70 Key()
71 {
72 mPos[0] = mPos[1] = mPos[2] = 0.0f;
73 mRot[0] = mRot[1] = mRot[2] = 0.0f;
74 mIgnorePos = false;
75 mIgnoreRot = false;
76 }
77
78 F32 mPos[3];
79 F32 mRot[3];
80 BOOL mIgnorePos;
81 BOOL mIgnoreRot;
82};
83
84
85//------------------------------------------------------------------------
86// KeyVector
87//------------------------------------------------------------------------
88typedef std::vector<Key> KeyVector;
89
90//------------------------------------------------------------------------
91// Joint
92//------------------------------------------------------------------------
93struct Joint
94{
95 Joint(const char *name)
96 {
97 mName = name;
98 mIgnore = FALSE;
99 mIgnorePositions = FALSE;
100 mRelativePositionKey = FALSE;
101 mRelativeRotationKey = FALSE;
102 mOutName = name;
103 mOrder[0] = 'X';
104 mOrder[1] = 'Y';
105 mOrder[2] = 'Z';
106 mOrder[3] = 0;
107 mNumPosKeys = 0;
108 mNumRotKeys = 0;
109 mChildTreeMaxDepth = 0;
110 mPriority = 0;
111 }
112
113 // Include aligned members first
114 LLMatrix3 mFrameMatrix;
115 LLMatrix3 mOffsetMatrix;
116 LLVector3 mRelativePosition;
117 //
118 std::string mName;
119 BOOL mIgnore;
120 BOOL mIgnorePositions;
121 BOOL mRelativePositionKey;
122 BOOL mRelativeRotationKey;
123 std::string mOutName;
124 std::string mMergeParentName;
125 std::string mMergeChildName;
126 char mOrder[4]; /* Flawfinder: ignore */
127 KeyVector mKeys;
128 S32 mNumPosKeys;
129 S32 mNumRotKeys;
130 S32 mChildTreeMaxDepth;
131 S32 mPriority;
132};
133
134
135typedef enum e_constraint_type
136{
137 CONSTRAINT_TYPE_POINT,
138 CONSTRAINT_TYPE_PLANE
139} EConstraintType;
140
141struct Constraint
142{
143 char mSourceJointName[16]; /* Flawfinder: ignore */
144 char mTargetJointName[16]; /* Flawfinder: ignore */
145 S32 mChainLength;
146 LLVector3 mSourceOffset;
147 LLVector3 mTargetOffset;
148 LLVector3 mTargetDir;
149 F32 mEaseInStart;
150 F32 mEaseInStop;
151 F32 mEaseOutStart;
152 F32 mEaseOutStop;
153 EConstraintType mConstraintType;
154};
155
156//------------------------------------------------------------------------
157// JointVector
158//------------------------------------------------------------------------
159typedef std::vector<Joint*> JointVector;
160
161//------------------------------------------------------------------------
162// ConstraintVector
163//------------------------------------------------------------------------
164typedef std::vector<Constraint> ConstraintVector;
165
166//------------------------------------------------------------------------
167// Translation
168//------------------------------------------------------------------------
169class Translation
170{
171public:
172 Translation()
173 {
174 mIgnore = FALSE;
175 mRelativePositionKey = FALSE;
176 mRelativeRotationKey = FALSE;
177 mPriorityModifier = 0;
178 }
179
180 std::string mOutName;
181 BOOL mIgnore;
182 BOOL mIgnorePositions;
183 BOOL mRelativePositionKey;
184 BOOL mRelativeRotationKey;
185 LLMatrix3 mFrameMatrix;
186 LLMatrix3 mOffsetMatrix;
187 LLVector3 mRelativePosition;
188 std::string mMergeParentName;
189 std::string mMergeChildName;
190 S32 mPriorityModifier;
191};
192
193//------------------------------------------------------------------------
194// TranslationMap
195//------------------------------------------------------------------------
196typedef std::map<std::string, Translation> TranslationMap;
197
198class LLBVHLoader
199{
200 friend class LLKeyframeMotion;
201public:
202 // Constructor
203 LLBVHLoader(const char* buffer);
204 ~LLBVHLoader();
205
206 // Status Codes
207 typedef char *Status;
208 static char *ST_OK;
209 static char *ST_EOF;
210 static char *ST_NO_CONSTRAINT;
211 static char *ST_NO_FILE;
212 static char *ST_NO_HIER;
213 static char *ST_NO_JOINT;
214 static char *ST_NO_NAME;
215 static char *ST_NO_OFFSET;
216 static char *ST_NO_CHANNELS;
217 static char *ST_NO_ROTATION;
218 static char *ST_NO_AXIS;
219 static char *ST_NO_MOTION;
220 static char *ST_NO_FRAMES;
221 static char *ST_NO_FRAME_TIME;
222 static char *ST_NO_POS;
223 static char *ST_NO_ROT;
224 static char *ST_NO_XLT_FILE;
225 static char *ST_NO_XLT_HEADER;
226 static char *ST_NO_XLT_NAME;
227 static char *ST_NO_XLT_IGNORE;
228 static char *ST_NO_XLT_RELATIVE;
229 static char *ST_NO_XLT_OUTNAME;
230 static char *ST_NO_XLT_MATRIX;
231 static char *ST_NO_XLT_MERGECHILD;
232 static char *ST_NO_XLT_MERGEPARENT;
233 static char *ST_NO_XLT_PRIORITY;
234 static char *ST_NO_XLT_LOOP;
235 static char *ST_NO_XLT_EASEIN;
236 static char *ST_NO_XLT_EASEOUT;
237 static char *ST_NO_XLT_HAND;
238 static char *ST_NO_XLT_EMOTE;
239
240 // Loads the specified translation table.
241 Status loadTranslationTable(const char *fileName);
242
243 // Load the specified BVH file.
244 // Returns status code.
245 Status loadBVHFile(const char *buffer, char *error_text, S32 &error_line);
246
247 // Applies translations to BVH data loaded.
248 void applyTranslations();
249
250 // Returns the number of lines scanned.
251 // Useful for error reporting.
252 S32 getLineNumber() { return mLineNumber; }
253
254 // returns required size of output buffer
255 U32 getOutputSize();
256
257 // writes contents to datapacker
258 BOOL serialize(LLDataPacker& dp);
259
260 // flags redundant keyframe data
261 void optimize();
262
263 void reset();
264
265 F32 getDuration() { return mDuration; }
266
267 BOOL isInitialized() { return mInitialized; }
268
269 Status getStatus() { return mStatus; }
270
271protected:
272 // Consumes one line of input from file.
273 BOOL getLine(apr_file_t *fp);
274
275 // parser state
276 char mLine[BVH_PARSER_LINE_SIZE]; /* Flawfinder: ignore */
277 S32 mLineNumber;
278
279 // parsed values
280 S32 mNumFrames;
281 F32 mFrameTime;
282 JointVector mJoints;
283 ConstraintVector mConstraints;
284 TranslationMap mTranslations;
285
286 S32 mPriority;
287 BOOL mLoop;
288 F32 mLoopInPoint;
289 F32 mLoopOutPoint;
290 F32 mEaseIn;
291 F32 mEaseOut;
292 S32 mHand;
293 std::string mEmoteName;
294
295 BOOL mInitialized;
296 Status mStatus;
297 // computed values
298 F32 mDuration;
299};
300
301#endif // LL_LLBVHLOADER_H
diff --git a/linden/indra/llcharacter/llcharacter.cpp b/linden/indra/llcharacter/llcharacter.cpp
new file mode 100644
index 0000000..45f692c
--- /dev/null
+++ b/linden/indra/llcharacter/llcharacter.cpp
@@ -0,0 +1,491 @@
1/**
2 * @file llcharacter.cpp
3 * @brief Implementation of LLCharacter 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
32#include "linden_common.h"
33
34#include "llcharacter.h"
35#include "llstring.h"
36
37#define SKEL_HEADER "Linden Skeleton 1.0"
38
39LLStringTable LLCharacter::sVisualParamNames(1024);
40
41// helper functions
42BOOL larger_screen_area( LLCharacter* data_new, LLCharacter* data_tested )
43{
44 return data_new->getPixelArea() > data_tested->getPixelArea();
45}
46
47LLLinkedList< LLCharacter > LLCharacter::sInstances( larger_screen_area );
48
49
50//-----------------------------------------------------------------------------
51// LLCharacter()
52// Class Constructor
53//-----------------------------------------------------------------------------
54LLCharacter::LLCharacter()
55 :
56 mPreferredPelvisHeight( 0.f ),
57 mSex( SEX_FEMALE ),
58 mAppearanceSerialNum( 0 ),
59 mSkeletonSerialNum( 0 )
60{
61 mMotionController.setCharacter( this );
62 sInstances.addData(this);
63 mPauseRequest = new LLPauseRequestHandle();
64}
65
66
67//-----------------------------------------------------------------------------
68// ~LLCharacter()
69// Class Destructor
70//-----------------------------------------------------------------------------
71LLCharacter::~LLCharacter()
72{
73 for (LLVisualParam *param = getFirstVisualParam();
74 param;
75 param = getNextVisualParam())
76 {
77 delete param;
78 }
79 sInstances.removeData(this);
80}
81
82
83//-----------------------------------------------------------------------------
84// getJoint()
85//-----------------------------------------------------------------------------
86LLJoint *LLCharacter::getJoint( const std::string &name )
87{
88 LLJoint *joint = NULL;
89
90 LLJoint *root = getRootJoint();
91 if (root)
92 {
93 joint = root->findJoint(name);
94 }
95
96 if (!joint)
97 {
98 llwarns << "Failed to find joint." << llendl;
99 }
100 return joint;
101}
102
103//-----------------------------------------------------------------------------
104// addMotion()
105//-----------------------------------------------------------------------------
106BOOL LLCharacter::addMotion( const LLUUID& id, LLMotionConstructor create )
107{
108 return mMotionController.addMotion(id, create);
109}
110
111//-----------------------------------------------------------------------------
112// removeMotion()
113//-----------------------------------------------------------------------------
114void LLCharacter::removeMotion( const LLUUID& id )
115{
116 mMotionController.removeMotion(id);
117}
118
119//-----------------------------------------------------------------------------
120// getMotion()
121//-----------------------------------------------------------------------------
122LLMotion* LLCharacter::createMotion( const LLUUID &id )
123{
124 return mMotionController.createMotion( id );
125}
126
127//-----------------------------------------------------------------------------
128// startMotion()
129//-----------------------------------------------------------------------------
130BOOL LLCharacter::startMotion(const LLUUID &id, F32 start_offset)
131{
132 return mMotionController.startMotion(id, start_offset);
133}
134
135
136//-----------------------------------------------------------------------------
137// stopMotion()
138//-----------------------------------------------------------------------------
139BOOL LLCharacter::stopMotion(const LLUUID& id, BOOL stop_immediate)
140{
141 return mMotionController.stopMotionLocally(id, stop_immediate);
142}
143
144//-----------------------------------------------------------------------------
145// isMotionActive()
146//-----------------------------------------------------------------------------
147BOOL LLCharacter::isMotionActive(const LLUUID& id)
148{
149 LLMotion *motionp = mMotionController.findMotion(id);
150 if (motionp)
151 {
152 return mMotionController.isMotionActive(motionp);
153 }
154
155 return FALSE;
156}
157
158
159//-----------------------------------------------------------------------------
160// onDeactivateMotion()
161//-----------------------------------------------------------------------------
162void LLCharacter::requestStopMotion( LLMotion* motion)
163{
164// llinfos << "DEBUG: Char::onDeactivateMotion( " << motionName << " )" << llendl;
165}
166
167
168//-----------------------------------------------------------------------------
169// updateMotion()
170//-----------------------------------------------------------------------------
171void LLCharacter::updateMotion(BOOL force_update)
172{
173 // unpause if we're forcing an update or
174 // number of outstanding pause requests has dropped
175 // to the initial one
176 if (mMotionController.isPaused() &&
177 (force_update || mPauseRequest->getNumRefs() == 1))
178 {
179 mMotionController.unpause();
180 }
181
182 mMotionController.updateMotion();
183
184 // pause once again, after forced update, if there are outstanding
185 // pause requests
186 if (force_update && mPauseRequest->getNumRefs() > 1)
187 {
188 mMotionController.pause();
189 }
190}
191
192
193//-----------------------------------------------------------------------------
194// flushAllMotions()
195//-----------------------------------------------------------------------------
196void LLCharacter::flushAllMotions()
197{
198 mMotionController.flushAllMotions();
199}
200
201
202//-----------------------------------------------------------------------------
203// dumpCharacter()
204//-----------------------------------------------------------------------------
205void LLCharacter::dumpCharacter( LLJoint *joint )
206{
207 // handle top level entry into recursion
208 if (joint == NULL)
209 {
210 llinfos << "DEBUG: Dumping Character @" << this << llendl;
211 dumpCharacter( getRootJoint() );
212 llinfos << "DEBUG: Done." << llendl;
213 return;
214 }
215
216 // print joint info
217 llinfos << "DEBUG: " << joint->getName() << " (" << (joint->getParent()?joint->getParent()->getName():std::string("ROOT")) << ")" << llendl;
218
219 // recurse
220 for ( LLJoint *j = joint->mChildren.getFirstData();
221 j != NULL;
222 j = joint->mChildren.getNextData() )
223 {
224 dumpCharacter(j);
225 }
226}
227
228//-----------------------------------------------------------------------------
229// setAnimationData()
230//-----------------------------------------------------------------------------
231void LLCharacter::setAnimationData(std::string name, void *data)
232{
233 if(mAnimationData.getValue(name))
234 {
235 *mAnimationData[name] = data;
236 }
237 else
238 {
239 mAnimationData.addToHead(name, data);
240 }
241}
242
243//-----------------------------------------------------------------------------
244// getAnimationData()
245//-----------------------------------------------------------------------------
246void * LLCharacter::getAnimationData(std::string name)
247{
248 void **result = mAnimationData.getValue(name);
249 void *return_value; // Necessary to suppress VC6 warning. JC
250 if (!result)
251 {
252 return_value = NULL;
253 }
254 else
255 {
256 return_value = *result;
257 }
258
259 return return_value;
260}
261
262//-----------------------------------------------------------------------------
263// removeAnimationData()
264//-----------------------------------------------------------------------------
265void LLCharacter::removeAnimationData(std::string name)
266{
267 mAnimationData.remove(name);
268}
269
270//-----------------------------------------------------------------------------
271// setVisualParamWeight()
272//-----------------------------------------------------------------------------
273BOOL LLCharacter::setVisualParamWeight(LLVisualParam* which_param, F32 weight, BOOL set_by_user)
274{
275 S32 index = which_param->getID();
276 VisualParamIndexMap_t::iterator index_iter = mVisualParamIndexMap.find(index);
277 if (index_iter != mVisualParamIndexMap.end())
278 {
279 index_iter->second->setWeight(weight, set_by_user);
280 return TRUE;
281 }
282 return FALSE;
283}
284
285//-----------------------------------------------------------------------------
286// setVisualParamWeight()
287//-----------------------------------------------------------------------------
288BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL set_by_user)
289{
290 LLString tname(param_name);
291 LLString::toLower(tname);
292 char *tableptr = sVisualParamNames.checkString(tname);
293 VisualParamNameMap_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
294 if (name_iter != mVisualParamNameMap.end())
295 {
296 name_iter->second->setWeight(weight, set_by_user);
297 return TRUE;
298 }
299 llwarns << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << llendl;
300 return FALSE;
301}
302
303//-----------------------------------------------------------------------------
304// setVisualParamWeight()
305//-----------------------------------------------------------------------------
306BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL set_by_user)
307{
308 VisualParamIndexMap_t::iterator index_iter = mVisualParamIndexMap.find(index);
309 if (index_iter != mVisualParamIndexMap.end())
310 {
311 index_iter->second->setWeight(weight, set_by_user);
312 return TRUE;
313 }
314 llwarns << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << llendl;
315 return FALSE;
316}
317
318//-----------------------------------------------------------------------------
319// getVisualParamWeight()
320//-----------------------------------------------------------------------------
321F32 LLCharacter::getVisualParamWeight(LLVisualParam *which_param)
322{
323 S32 index = which_param->getID();
324 VisualParamIndexMap_t::iterator index_iter = mVisualParamIndexMap.find(index);
325 if (index_iter != mVisualParamIndexMap.end())
326 {
327 return index_iter->second->getWeight();
328 }
329 else
330 {
331 llwarns << "LLCharacter::getVisualParamWeight() Invalid visual parameter*, index= " << index << llendl;
332 return 0.f;
333 }
334}
335
336//-----------------------------------------------------------------------------
337// getVisualParamWeight()
338//-----------------------------------------------------------------------------
339F32 LLCharacter::getVisualParamWeight(const char* param_name)
340{
341 LLString tname(param_name);
342 LLString::toLower(tname);
343 char *tableptr = sVisualParamNames.checkString(tname);
344 VisualParamNameMap_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
345 if (name_iter != mVisualParamNameMap.end())
346 {
347 return name_iter->second->getWeight();
348 }
349 llwarns << "LLCharacter::getVisualParamWeight() Invalid visual parameter: " << param_name << llendl;
350 return 0.f;
351}
352
353//-----------------------------------------------------------------------------
354// getVisualParamWeight()
355//-----------------------------------------------------------------------------
356F32 LLCharacter::getVisualParamWeight(S32 index)
357{
358 VisualParamIndexMap_t::iterator index_iter = mVisualParamIndexMap.find(index);
359 if (index_iter != mVisualParamIndexMap.end())
360 {
361 return index_iter->second->getWeight();
362 }
363 else
364 {
365 llwarns << "LLCharacter::getVisualParamWeight() Invalid visual parameter index: " << index << llendl;
366 return 0.f;
367 }
368}
369
370//-----------------------------------------------------------------------------
371// clearVisualParamWeights()
372//-----------------------------------------------------------------------------
373void LLCharacter::clearVisualParamWeights()
374{
375 for (LLVisualParam *param = getFirstVisualParam();
376 param;
377 param = getNextVisualParam())
378 {
379 if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
380 {
381 param->setWeight( param->getDefaultWeight(), FALSE );
382 }
383 }
384}
385
386//-----------------------------------------------------------------------------
387// getVisualParam()
388//-----------------------------------------------------------------------------
389LLVisualParam* LLCharacter::getVisualParam(const char *param_name)
390{
391 LLString tname(param_name);
392 LLString::toLower(tname);
393 char *tableptr = sVisualParamNames.checkString(tname);
394 VisualParamNameMap_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
395 if (name_iter != mVisualParamNameMap.end())
396 {
397 return name_iter->second;
398 }
399 llwarns << "LLCharacter::getVisualParam() Invalid visual parameter: " << param_name << llendl;
400 return NULL;
401}
402
403//-----------------------------------------------------------------------------
404// addSharedVisualParam()
405//-----------------------------------------------------------------------------
406void LLCharacter::addSharedVisualParam(LLVisualParam *param)
407{
408 S32 index = param->getID();
409 VisualParamIndexMap_t::iterator index_iter = mVisualParamIndexMap.find(index);
410 LLVisualParam* current_param = 0;
411 if (index_iter != mVisualParamIndexMap.end())
412 current_param = index_iter->second;
413 if( current_param )
414 {
415 LLVisualParam* next_param = current_param;
416 while(next_param->getNextParam())
417 {
418 next_param = next_param->getNextParam();
419 }
420 next_param->setNextParam(param);
421 }
422 else
423 {
424 llwarns << "Shared visual parameter " << param->getName() << " does not already exist with ID " <<
425 param->getID() << llendl;
426 }
427}
428
429//-----------------------------------------------------------------------------
430// addVisualParam()
431//-----------------------------------------------------------------------------
432void LLCharacter::addVisualParam(LLVisualParam *param)
433{
434 S32 index = param->getID();
435 // Add Index map
436 std::pair<VisualParamIndexMap_t::iterator, bool> idxres;
437 idxres = mVisualParamIndexMap.insert(VisualParamIndexMap_t::value_type(index, param));
438 if (!idxres.second)
439 {
440 llwarns << "Visual parameter " << param->getName() << " already exists with same ID as " <<
441 param->getName() << llendl;
442 VisualParamIndexMap_t::iterator index_iter = idxres.first;
443 index_iter->second = param;
444 }
445
446 if (param->getInfo())
447 {
448 // Add name map
449 LLString tname(param->getName());
450 LLString::toLower(tname);
451 char *tableptr = sVisualParamNames.addString(tname);
452 std::pair<VisualParamNameMap_t::iterator, bool> nameres;
453 nameres = mVisualParamNameMap.insert(VisualParamNameMap_t::value_type(tableptr, param));
454 if (!nameres.second)
455 {
456 // Already exists, copy param
457 VisualParamNameMap_t::iterator name_iter = nameres.first;
458 name_iter->second = param;
459 }
460 }
461 //llinfos << "Adding Visual Param '" << param->getName() << "' ( " << index << " )" << llendl;
462}
463
464//-----------------------------------------------------------------------------
465// updateVisualParams()
466//-----------------------------------------------------------------------------
467void LLCharacter::updateVisualParams()
468{
469 for (LLVisualParam *param = getFirstVisualParam();
470 param;
471 param = getNextVisualParam())
472 {
473 if (param->isAnimating())
474 {
475 continue;
476 }
477 // only apply parameters whose effective weight has changed
478 F32 effective_weight = ( param->getSex() & mSex ) ? param->getWeight() : param->getDefaultWeight();
479 if (effective_weight != param->getLastWeight())
480 {
481 param->apply( mSex );
482 }
483 }
484}
485
486LLAnimPauseRequest LLCharacter::requestPause()
487{
488 mMotionController.pause();
489 return mPauseRequest;
490}
491
diff --git a/linden/indra/llcharacter/llcharacter.h b/linden/indra/llcharacter/llcharacter.h
new file mode 100644
index 0000000..bfe3ffa
--- /dev/null
+++ b/linden/indra/llcharacter/llcharacter.h
@@ -0,0 +1,271 @@
1/**
2 * @file llcharacter.h
3 * @brief Implementation of LLCharacter 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#ifndef LL_LLCHARACTER_H
29#define LL_LLCHARACTER_H
30
31//-----------------------------------------------------------------------------
32// Header Files
33//-----------------------------------------------------------------------------
34#include <string>
35
36#include "lljoint.h"
37#include "llmotioncontroller.h"
38#include "llassoclist.h"
39#include "llvisualparam.h"
40#include "linked_lists.h"
41#include "string_table.h"
42#include "llmemory.h"
43
44class LLPolyMesh;
45
46class LLPauseRequestHandle : public LLThreadSafeRefCount
47{
48public:
49 LLPauseRequestHandle() {};
50};
51
52typedef LLPointer<LLPauseRequestHandle> LLAnimPauseRequest;
53
54//-----------------------------------------------------------------------------
55// class LLCharacter
56//-----------------------------------------------------------------------------
57class LLCharacter
58{
59public:
60 // Constructor
61 LLCharacter();
62
63 // Destructor
64 virtual ~LLCharacter();
65
66 //-------------------------------------------------------------------------
67 // LLCharacter Interface
68 // These functions must be implemented by subclasses.
69 //-------------------------------------------------------------------------
70
71 // get the prefix to be used to lookup motion data files
72 // from the viewer data directory
73 virtual const char *getAnimationPrefix() = 0;
74
75 // get the root joint of the character
76 virtual LLJoint *getRootJoint() = 0;
77
78 // get the specified joint
79 // default implementation does recursive search,
80 // subclasses may optimize/cache results.
81 virtual LLJoint *getJoint( const std::string &name );
82
83 // get the position of the character
84 virtual LLVector3 getCharacterPosition() = 0;
85
86 // get the rotation of the character
87 virtual LLQuaternion getCharacterRotation() = 0;
88
89 // get the velocity of the character
90 virtual LLVector3 getCharacterVelocity() = 0;
91
92 // get the angular velocity of the character
93 virtual LLVector3 getCharacterAngularVelocity() = 0;
94
95 // get the height & normal of the ground under a point
96 virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm) = 0;
97
98 // allocate an array of joints for the character skeleton
99 // this must be overloaded to support joint subclasses,
100 // and is called implicitly from buildSkeleton().
101 // Note this must handle reallocation as it will be called
102 // each time buildSkeleton() is called.
103 virtual BOOL allocateCharacterJoints( U32 num ) = 0;
104
105 // skeleton joint accessor to support joint subclasses
106 virtual LLJoint *getCharacterJoint( U32 i ) = 0;
107
108 // get the physics time dilation for the simulator
109 virtual F32 getTimeDilation() = 0;
110
111 // gets current pixel area of this character
112 virtual F32 getPixelArea() = 0;
113
114 // gets the head mesh of the character
115 virtual LLPolyMesh* getHeadMesh() = 0;
116
117 // gets the upper body mesh of the character
118 virtual LLPolyMesh* getUpperBodyMesh() = 0;
119
120 // gets global coordinates from agent local coordinates
121 virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position) = 0;
122
123 // gets agent local coordinates from global coordinates
124 virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position) = 0;
125
126 // updates all visual parameters for this character
127 virtual void updateVisualParams();
128
129 virtual void addDebugText( const char* text ) = 0;
130
131 virtual const LLUUID& getID() = 0;
132 //-------------------------------------------------------------------------
133 // End Interface
134 //-------------------------------------------------------------------------
135 // registers a motion with the character
136 // returns true if successfull
137 BOOL addMotion( const LLUUID& id, LLMotionConstructor create );
138
139 void removeMotion( const LLUUID& id );
140
141 // returns an instance of a registered motion
142 LLMotion* createMotion( const LLUUID &id );
143
144 // start a motion
145 // returns true if successful, false if an error occurred
146 virtual BOOL startMotion( const LLUUID& id, F32 start_offset = 0.f);
147
148 // stop a motion
149 virtual BOOL stopMotion( const LLUUID& id, BOOL stop_immediate = FALSE );
150
151 // is this motion active?
152 BOOL isMotionActive( const LLUUID& id );
153
154 // Event handler for motion deactivation.
155 // Called when a motion has completely stopped and has been deactivated.
156 // Subclasses may optionally override this.
157 // The default implementation does nothing.
158 virtual void requestStopMotion( LLMotion* motion );
159
160 // periodic update function, steps the motion controller
161 void updateMotion(BOOL force_update = FALSE);
162
163 LLAnimPauseRequest requestPause();
164 BOOL areAnimationsPaused() { return mMotionController.isPaused(); }
165 void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); }
166 void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); }
167 // Releases all motion instances which should result in
168 // no cached references to character joint data. This is
169 // useful if a character wants to rebuild it's skeleton.
170 virtual void flushAllMotions();
171
172 // dumps information for debugging
173 virtual void dumpCharacter( LLJoint *joint = NULL );
174
175 virtual F32 getPreferredPelvisHeight() { return mPreferredPelvisHeight; }
176
177 virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) { return LLVector3::zero; }
178
179 virtual LLJoint* findCollisionVolume(U32 volume_id) { return NULL; }
180
181 virtual S32 getCollisionVolumeID(std::string &name) { return -1; }
182
183 void setAnimationData(std::string name, void *data);
184
185 void *getAnimationData(std::string name);
186
187 void removeAnimationData(std::string name);
188
189 void addVisualParam(LLVisualParam *param);
190 void addSharedVisualParam(LLVisualParam *param);
191
192 BOOL setVisualParamWeight(LLVisualParam *which_param, F32 weight, BOOL set_by_user = FALSE );
193 BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL set_by_user = FALSE );
194 BOOL setVisualParamWeight(S32 index, F32 weight, BOOL set_by_user = FALSE );
195
196 // get visual param weight by param or name
197 F32 getVisualParamWeight(LLVisualParam *distortion);
198 F32 getVisualParamWeight(const char* param_name);
199 F32 getVisualParamWeight(S32 index);
200
201 // set all morph weights to 0
202 void clearVisualParamWeights();
203
204 // visual parameter accessors
205 LLVisualParam* getFirstVisualParam()
206 {
207 mCurIterator = mVisualParamIndexMap.begin();
208 return getNextVisualParam();
209 }
210 LLVisualParam* getNextVisualParam()
211 {
212 if (mCurIterator == mVisualParamIndexMap.end())
213 return 0;
214 return (mCurIterator++)->second;
215 }
216
217 LLVisualParam* getVisualParam(S32 id)
218 {
219 VisualParamIndexMap_t::iterator iter = mVisualParamIndexMap.find(id);
220 return (iter == mVisualParamIndexMap.end()) ? 0 : iter->second;
221 }
222 S32 getVisualParamID(LLVisualParam *id)
223 {
224 VisualParamIndexMap_t::iterator iter;
225 for (iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); iter++)
226 {
227 if (iter->second == id)
228 return iter->first;
229 }
230 return 0;
231 }
232 S32 getVisualParamCount() { return (S32)mVisualParamIndexMap.size(); }
233 LLVisualParam* getVisualParam(const char *name);
234
235
236 ESex getSex() { return mSex; }
237 void setSex( ESex sex ) { mSex = sex; }
238
239 U32 getAppearanceSerialNum() const { return mAppearanceSerialNum; }
240 void setAppearanceSerialNum( U32 num ) { mAppearanceSerialNum = num; }
241
242 U32 getSkeletonSerialNum() const { return mSkeletonSerialNum; }
243 void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
244
245 static LLLinkedList< LLCharacter > sInstances;
246
247protected:
248 LLMotionController mMotionController;
249
250 LLAssocList<std::string, void *> mAnimationData;
251
252 F32 mPreferredPelvisHeight;
253 ESex mSex;
254 U32 mAppearanceSerialNum;
255 U32 mSkeletonSerialNum;
256 LLAnimPauseRequest mPauseRequest;
257
258
259private:
260 // visual parameter stuff
261 typedef std::map<S32, LLVisualParam *> VisualParamIndexMap_t;
262 VisualParamIndexMap_t mVisualParamIndexMap;
263 VisualParamIndexMap_t::iterator mCurIterator;
264 typedef std::map<char *, LLVisualParam *> VisualParamNameMap_t;
265 VisualParamNameMap_t mVisualParamNameMap;
266
267 static LLStringTable sVisualParamNames;
268};
269
270#endif // LL_LLCHARACTER_H
271
diff --git a/linden/indra/llcharacter/llcharacter.vcproj b/linden/indra/llcharacter/llcharacter.vcproj
new file mode 100644
index 0000000..c8a9bc4
--- /dev/null
+++ b/linden/indra/llcharacter/llcharacter.vcproj
@@ -0,0 +1,294 @@
1<?xml version="1.0" encoding="Windows-1252"?>
2<VisualStudioProject
3 ProjectType="Visual C++"
4 Version="7.10"
5 Name="llcharacter"
6 ProjectGUID="{5EA5DDF0-C7E1-4F49-BEF5-9246A4656B2E}"
7 Keyword="Win32Proj">
8 <Platforms>
9 <Platform
10 Name="Win32"/>
11 </Platforms>
12 <Configurations>
13 <Configuration
14 Name="Debug|Win32"
15 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
16 IntermediateDirectory="Debug"
17 ConfigurationType="4"
18 CharacterSet="1">
19 <Tool
20 Name="VCCLCompilerTool"
21 Optimization="0"
22 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llvfs;..\llmessage;..\llxml;..\..\libraries\i686-win32\include;..\..\libraries\include\"
23 PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG"
24 MinimalRebuild="TRUE"
25 BasicRuntimeChecks="3"
26 RuntimeLibrary="1"
27 StructMemberAlignment="4"
28 ForceConformanceInForLoopScope="TRUE"
29 UsePrecompiledHeader="0"
30 WarningLevel="3"
31 WarnAsError="TRUE"
32 Detect64BitPortabilityProblems="FALSE"
33 DebugInformationFormat="4"/>
34 <Tool
35 Name="VCCustomBuildTool"/>
36 <Tool
37 Name="VCLibrarianTool"
38 OutputFile="$(OutDir)/llcharacter.lib"/>
39 <Tool
40 Name="VCMIDLTool"/>
41 <Tool
42 Name="VCPostBuildEventTool"/>
43 <Tool
44 Name="VCPreBuildEventTool"/>
45 <Tool
46 Name="VCPreLinkEventTool"/>
47 <Tool
48 Name="VCResourceCompilerTool"/>
49 <Tool
50 Name="VCWebServiceProxyGeneratorTool"/>
51 <Tool
52 Name="VCXMLDataGeneratorTool"/>
53 <Tool
54 Name="VCManagedWrapperGeneratorTool"/>
55 <Tool
56 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
57 </Configuration>
58 <Configuration
59 Name="Release|Win32"
60 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
61 IntermediateDirectory="Release"
62 ConfigurationType="4"
63 CharacterSet="1">
64 <Tool
65 Name="VCCLCompilerTool"
66 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llvfs;..\llmessage;..\llxml;..\..\libraries\i686-win32\include;..\..\libraries\include\"
67 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
68 RuntimeLibrary="0"
69 StructMemberAlignment="0"
70 ForceConformanceInForLoopScope="TRUE"
71 UsePrecompiledHeader="0"
72 WarningLevel="3"
73 WarnAsError="TRUE"
74 Detect64BitPortabilityProblems="FALSE"
75 DebugInformationFormat="3"/>
76 <Tool
77 Name="VCCustomBuildTool"/>
78 <Tool
79 Name="VCLibrarianTool"
80 OutputFile="$(OutDir)/llcharacter.lib"/>
81 <Tool
82 Name="VCMIDLTool"/>
83 <Tool
84 Name="VCPostBuildEventTool"/>
85 <Tool
86 Name="VCPreBuildEventTool"/>
87 <Tool
88 Name="VCPreLinkEventTool"/>
89 <Tool
90 Name="VCResourceCompilerTool"/>
91 <Tool
92 Name="VCWebServiceProxyGeneratorTool"/>
93 <Tool
94 Name="VCXMLDataGeneratorTool"/>
95 <Tool
96 Name="VCManagedWrapperGeneratorTool"/>
97 <Tool
98 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
99 </Configuration>
100 <Configuration
101 Name="ReleaseNoOpt|Win32"
102 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
103 IntermediateDirectory="$(ConfigurationName)"
104 ConfigurationType="4"
105 CharacterSet="1">
106 <Tool
107 Name="VCCLCompilerTool"
108 Optimization="0"
109 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llvfs;..\llmessage;..\llxml;..\..\libraries\i686-win32\include;..\..\libraries\include\"
110 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
111 RuntimeLibrary="0"
112 StructMemberAlignment="0"
113 ForceConformanceInForLoopScope="TRUE"
114 UsePrecompiledHeader="0"
115 WarningLevel="3"
116 WarnAsError="TRUE"
117 Detect64BitPortabilityProblems="FALSE"
118 DebugInformationFormat="3"/>
119 <Tool
120 Name="VCCustomBuildTool"/>
121 <Tool
122 Name="VCLibrarianTool"
123 OutputFile="$(OutDir)/llcharacter.lib"/>
124 <Tool
125 Name="VCMIDLTool"/>
126 <Tool
127 Name="VCPostBuildEventTool"/>
128 <Tool
129 Name="VCPreBuildEventTool"/>
130 <Tool
131 Name="VCPreLinkEventTool"/>
132 <Tool
133 Name="VCResourceCompilerTool"/>
134 <Tool
135 Name="VCWebServiceProxyGeneratorTool"/>
136 <Tool
137 Name="VCXMLDataGeneratorTool"/>
138 <Tool
139 Name="VCManagedWrapperGeneratorTool"/>
140 <Tool
141 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
142 </Configuration>
143 </Configurations>
144 <References>
145 </References>
146 <Files>
147 <Filter
148 Name="Source Files"
149 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
150 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
151 <File
152 RelativePath=".\llanimationstates.cpp">
153 </File>
154 <File
155 RelativePath=".\llbvhloader.cpp">
156 </File>
157 <File
158 RelativePath=".\llcharacter.cpp">
159 </File>
160 <File
161 RelativePath=".\lleditingmotion.cpp">
162 </File>
163 <File
164 RelativePath=".\llgesture.cpp">
165 </File>
166 <File
167 RelativePath=".\llhandmotion.cpp">
168 </File>
169 <File
170 RelativePath=".\llheadrotmotion.cpp">
171 </File>
172 <File
173 RelativePath=".\lljoint.cpp">
174 </File>
175 <File
176 RelativePath=".\lljointsolverrp3.cpp">
177 </File>
178 <File
179 RelativePath=".\llkeyframefallmotion.cpp">
180 </File>
181 <File
182 RelativePath=".\llkeyframemotion.cpp">
183 </File>
184 <File
185 RelativePath=".\llkeyframemotionparam.cpp">
186 </File>
187 <File
188 RelativePath=".\llkeyframestandmotion.cpp">
189 </File>
190 <File
191 RelativePath=".\llkeyframewalkmotion.cpp">
192 </File>
193 <File
194 RelativePath=".\llmotion.cpp">
195 </File>
196 <File
197 RelativePath=".\llmotioncontroller.cpp">
198 </File>
199 <File
200 RelativePath=".\llmultigesture.cpp">
201 </File>
202 <File
203 RelativePath=".\llpose.cpp">
204 </File>
205 <File
206 RelativePath=".\llstatemachine.cpp">
207 </File>
208 <File
209 RelativePath=".\lltargetingmotion.cpp">
210 </File>
211 <File
212 RelativePath=".\llvisualparam.cpp">
213 </File>
214 </Filter>
215 <Filter
216 Name="Header Files"
217 Filter="h;hpp;hxx;hm;inl;inc;xsd"
218 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
219 <File
220 RelativePath=".\llanimationstates.h">
221 </File>
222 <File
223 RelativePath=".\llbvhloader.h">
224 </File>
225 <File
226 RelativePath=".\llcharacter.h">
227 </File>
228 <File
229 RelativePath=".\lleditingmotion.h">
230 </File>
231 <File
232 RelativePath=".\llgesture.h">
233 </File>
234 <File
235 RelativePath=".\llhandmotion.h">
236 </File>
237 <File
238 RelativePath=".\llheadrotmotion.h">
239 </File>
240 <File
241 RelativePath=".\lljoint.h">
242 </File>
243 <File
244 RelativePath=".\lljointsolverrp3.h">
245 </File>
246 <File
247 RelativePath=".\lljointstate.h">
248 </File>
249 <File
250 RelativePath=".\llkeyframefallmotion.h">
251 </File>
252 <File
253 RelativePath=".\llkeyframemotion.h">
254 </File>
255 <File
256 RelativePath=".\llkeyframemotionparam.h">
257 </File>
258 <File
259 RelativePath=".\llkeyframestandmotion.h">
260 </File>
261 <File
262 RelativePath=".\llkeyframewalkmotion.h">
263 </File>
264 <File
265 RelativePath=".\llmotion.h">
266 </File>
267 <File
268 RelativePath=".\llmotioncontroller.h">
269 </File>
270 <File
271 RelativePath=".\llmultigesture.h">
272 </File>
273 <File
274 RelativePath=".\llpose.h">
275 </File>
276 <File
277 RelativePath=".\llstatemachine.h">
278 </File>
279 <File
280 RelativePath=".\lltargetingmotion.h">
281 </File>
282 <File
283 RelativePath=".\llvisualparam.h">
284 </File>
285 </Filter>
286 <Filter
287 Name="Resource Files"
288 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
289 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
290 </Filter>
291 </Files>
292 <Globals>
293 </Globals>
294</VisualStudioProject>
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//-----------------------------------------------------------------------------
41const LLQuaternion EDIT_MOTION_WRIST_ROTATION(F_PI_BY_TWO * 0.7f, LLVector3(1.0f, 0.0f, 0.0f));
42const F32 TARGET_LAG_HALF_LIFE = 0.1f; // half-life of IK targeting
43const F32 TORSO_LAG_HALF_LIFE = 0.2f;
44const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
45
46S32 LLEditingMotion::sHandPose = LLHandMotion::HAND_POSE_RELAXED_R;
47S32 LLEditingMotion::sHandPosePriority = 3;
48
49//-----------------------------------------------------------------------------
50// LLEditingMotion()
51// Class Constructor
52//-----------------------------------------------------------------------------
53LLEditingMotion::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//-----------------------------------------------------------------------------
70LLEditingMotion::~LLEditingMotion()
71{
72}
73
74//-----------------------------------------------------------------------------
75// LLEditingMotion::onInitialize(LLCharacter *character)
76//-----------------------------------------------------------------------------
77LLMotion::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//-----------------------------------------------------------------------------
140BOOL 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//-----------------------------------------------------------------------------
159BOOL 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//-----------------------------------------------------------------------------
248void LLEditingMotion::onDeactivate()
249{
250}
251
252
253// End
diff --git a/linden/indra/llcharacter/lleditingmotion.h b/linden/indra/llcharacter/lleditingmotion.h
new file mode 100644
index 0000000..37df991
--- /dev/null
+++ b/linden/indra/llcharacter/lleditingmotion.h
@@ -0,0 +1,134 @@
1/**
2 * @file lleditingmotion.h
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#ifndef LL_LLEDITINGMOTION_H
29#define LL_LLEDITINGMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llmotion.h"
35#include "lljointsolverrp3.h"
36#include "v3dmath.h"
37
38#define EDITING_EASEIN_DURATION 0.0f
39#define EDITING_EASEOUT_DURATION 0.5f
40#define EDITING_PRIORITY LLJoint::HIGH_PRIORITY
41#define MIN_REQUIRED_PIXEL_AREA_EDITING 500.f
42
43//-----------------------------------------------------------------------------
44// class LLEditingMotion
45//-----------------------------------------------------------------------------
46class LLEditingMotion :
47 public LLMotion
48{
49public:
50 // Constructor
51 LLEditingMotion(const LLUUID &id);
52
53 // Destructor
54 virtual ~LLEditingMotion();
55
56public:
57 //-------------------------------------------------------------------------
58 // functions to support MotionController and MotionRegistry
59 //-------------------------------------------------------------------------
60
61 // static constructor
62 // all subclasses must implement such a function and register it
63 static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); }
64
65public:
66 //-------------------------------------------------------------------------
67 // animation callbacks to be implemented by subclasses
68 //-------------------------------------------------------------------------
69
70 // motions must specify whether or not they loop
71 virtual BOOL getLoop() { return TRUE; }
72
73 // motions must report their total duration
74 virtual F32 getDuration() { return 0.0; }
75
76 // motions must report their "ease in" duration
77 virtual F32 getEaseInDuration() { return EDITING_EASEIN_DURATION; }
78
79 // motions must report their "ease out" duration.
80 virtual F32 getEaseOutDuration() { return EDITING_EASEOUT_DURATION; }
81
82 // motions must report their priority
83 virtual LLJoint::JointPriority getPriority() { return EDITING_PRIORITY; }
84
85 virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
86
87 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
88 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_EDITING; }
89
90 // run-time (post constructor) initialization,
91 // called after parameters have been set
92 // must return true to indicate success and be available for activation
93 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
94
95 // called when a motion is activated
96 // must return TRUE to indicate success, or else
97 // it will be deactivated
98 virtual BOOL onActivate();
99
100 // called per time step
101 // must return TRUE while it is active, and
102 // must return FALSE when the motion is completed.
103 virtual BOOL onUpdate(F32 time, U8* joint_mask);
104
105 // called when a motion is deactivated
106 virtual void onDeactivate();
107
108public:
109 //-------------------------------------------------------------------------
110 // joint states to be animated
111 //-------------------------------------------------------------------------
112 LLCharacter *mCharacter;
113 LLVector3 mWristOffset;
114
115 LLJointState mParentState;
116 LLJointState mShoulderState;
117 LLJointState mElbowState;
118 LLJointState mWristState;
119 LLJointState mTorsoState;
120
121 LLJoint mParentJoint;
122 LLJoint mShoulderJoint;
123 LLJoint mElbowJoint;
124 LLJoint mWristJoint;
125 LLJoint mTarget;
126 LLJointSolverRP3 mIKSolver;
127
128 static S32 sHandPose;
129 static S32 sHandPosePriority;
130 LLVector3 mLastSelectPt;
131};
132
133#endif // LL_LLKEYFRAMEMOTION_H
134
diff --git a/linden/indra/llcharacter/llgesture.cpp b/linden/indra/llcharacter/llgesture.cpp
new file mode 100644
index 0000000..944df78
--- /dev/null
+++ b/linden/indra/llcharacter/llgesture.cpp
@@ -0,0 +1,375 @@
1/**
2 * @file llgesture.cpp
3 *
4 * Copyright (c) 2002-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "indra_constants.h"
30
31#include "llgesture.h"
32#include "llendianswizzle.h"
33#include "message.h"
34#include <boost/tokenizer.hpp>
35
36// for allocating serialization buffers - these need to be updated when members change
37const S32 LLGestureList::SERIAL_HEADER_SIZE = sizeof(S32);
38const S32 LLGesture::MAX_SERIAL_SIZE = sizeof(KEY) + sizeof(MASK) + 16 + 26 + 41 + 41;
39
40LLGesture::LLGesture()
41: mKey(KEY_NONE),
42 mMask(MASK_NONE),
43 mTrigger(),
44 mTriggerLower(),
45 mSoundItemID(),
46 mAnimation(),
47 mOutputString()
48{ }
49
50LLGesture::LLGesture(KEY key, MASK mask, const std::string &trigger,
51 const LLUUID &sound_item_id,
52 const std::string &animation,
53 const std::string &output_string)
54:
55 mKey(key),
56 mMask(mask),
57 mTrigger(trigger),
58 mTriggerLower(trigger),
59 mSoundItemID(sound_item_id),
60 mAnimation(animation),
61 mOutputString(output_string)
62{
63 mTriggerLower = utf8str_tolower(mTriggerLower);
64}
65
66LLGesture::LLGesture(U8 **buffer, S32 max_size)
67{
68 *buffer = deserialize(*buffer, max_size);
69}
70
71LLGesture::LLGesture(const LLGesture &rhs)
72{
73 mKey = rhs.mKey;
74 mMask = rhs.mMask;
75 mTrigger = rhs.mTrigger;
76 mTriggerLower = rhs.mTriggerLower;
77 mSoundItemID = rhs.mSoundItemID;
78 mAnimation = rhs.mAnimation;
79 mOutputString = rhs.mOutputString;
80}
81
82const LLGesture &LLGesture::operator =(const LLGesture &rhs)
83{
84 mKey = rhs.mKey;
85 mMask = rhs.mMask;
86 mTrigger = rhs.mTrigger;
87 mTriggerLower = rhs.mTriggerLower;
88 mSoundItemID = rhs.mSoundItemID;
89 mAnimation = rhs.mAnimation;
90 mOutputString = rhs.mOutputString;
91 return (*this);
92}
93
94
95BOOL LLGesture::trigger(KEY key, MASK mask)
96{
97 llwarns << "Parent class trigger called: you probably didn't mean this." << llendl;
98 return FALSE;
99}
100
101
102BOOL LLGesture::trigger(const LLString &trigger_string)
103{
104 llwarns << "Parent class trigger called: you probably didn't mean this." << llendl;
105 return FALSE;
106}
107
108// NOT endian-neutral
109U8 *LLGesture::serialize(U8 *buffer) const
110{
111 htonmemcpy(buffer, &mKey, MVT_S8, 1);
112 buffer += sizeof(mKey);
113 htonmemcpy(buffer, &mMask, MVT_U32, 4);
114 buffer += sizeof(mMask);
115 htonmemcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16);
116 buffer += 16;
117
118 memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1); /* Flawfinder: ignore */
119 buffer += mTrigger.length() + 1;
120 memcpy(buffer, mAnimation.c_str(), mAnimation.length() + 1); /* Flawfinder: ignore */
121 buffer += mAnimation.length() + 1;
122 memcpy(buffer, mOutputString.c_str(), mOutputString.length() + 1); /* Flawfinder: ignore */
123 buffer += mOutputString.length() + 1;
124
125 return buffer;
126}
127
128U8 *LLGesture::deserialize(U8 *buffer, S32 max_size)
129{
130 U8 *tmp = buffer;
131
132 if (tmp + sizeof(mKey) + sizeof(mMask) + 16 > buffer + max_size)
133 {
134 llwarns << "Attempt to read past end of buffer, bad data!!!!" << llendl;
135 return buffer;
136 }
137
138 htonmemcpy(&mKey, tmp, MVT_S8, 1);
139 tmp += sizeof(mKey);
140 htonmemcpy(&mMask, tmp, MVT_U32, 4);
141 tmp += sizeof(mMask);
142 htonmemcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16);
143 tmp += 16;
144
145 mTrigger.assign((char *)tmp);
146 mTriggerLower = mTrigger;
147 mTriggerLower = utf8str_tolower(mTriggerLower);
148 tmp += mTrigger.length() + 1;
149 mAnimation.assign((char *)tmp);
150 //RN: force animation names to lower case
151 // must do this for backwards compatibility
152 mAnimation = utf8str_tolower(mAnimation);
153 tmp += mAnimation.length() + 1;
154 mOutputString.assign((char *)tmp);
155 tmp += mOutputString.length() + 1;
156
157 if (tmp > buffer + max_size)
158 {
159 llwarns << "Read past end of buffer, bad data!!!!" << llendl;
160 return tmp;
161 }
162
163 return tmp;
164}
165
166S32 LLGesture::getMaxSerialSize()
167{
168 return MAX_SERIAL_SIZE;
169}
170
171//---------------------------------------------------------------------
172// LLGestureList
173//---------------------------------------------------------------------
174
175LLGestureList::LLGestureList()
176: mList(0)
177{
178 // add some gestures for debugging
179// LLGesture *gesture = NULL;
180/*
181 gesture = new LLGesture(KEY_F2, MASK_NONE, ":-)",
182 SND_CHIRP, "dance2", ":-)" );
183 mList.put(gesture);
184
185 gesture = new LLGesture(KEY_F3, MASK_NONE, "/dance",
186 SND_OBJECT_CREATE, "dance3", "(dances)" );
187 mList.put(gesture);
188
189 gesture = new LLGesture(KEY_F4, MASK_NONE, "/boogie",
190 LLUUID::null, "dance4", LLString::null );
191 mList.put(gesture);
192
193 gesture = new LLGesture(KEY_F5, MASK_SHIFT, "/tongue",
194 LLUUID::null, "Express_Tongue_Out", LLString::null );
195 mList.put(gesture);
196 */
197}
198
199LLGestureList::~LLGestureList()
200{
201 deleteAll();
202}
203
204
205void LLGestureList::deleteAll()
206{
207 S32 count = mList.count();
208 for (S32 i = 0; i < count; i++)
209 {
210 delete mList.get(i);
211 }
212 mList.reset();
213}
214
215// Iterates through space delimited tokens in string, triggering any gestures found.
216// Generates a revised string that has the found tokens replaced by their replacement strings
217// and (as a minor side effect) has multiple spaces in a row replaced by single spaces.
218BOOL LLGestureList::triggerAndReviseString(const LLString &string, LLString* revised_string)
219{
220 LLString tokenized = string;
221
222 BOOL found_gestures = FALSE;
223 BOOL first_token = TRUE;
224
225 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
226 boost::char_separator<char> sep(" ");
227 tokenizer tokens(string, sep);
228 tokenizer::iterator token_iter;
229
230 for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
231 {
232 LLGesture* gesture = NULL;
233
234 if( !found_gestures ) // Only pay attention to the first gesture in the string.
235 {
236 LLString cur_token_lower = *token_iter;
237 LLString::toLower(cur_token_lower);
238
239 for (S32 i = 0; i < mList.count(); i++)
240 {
241 gesture = mList.get(i);
242 if (gesture->trigger(cur_token_lower))
243 {
244 if( !gesture->getOutputString().empty() )
245 {
246 if( !first_token )
247 {
248 revised_string->append( " " );
249 }
250
251 // Don't muck with the user's capitalization if we don't have to.
252 const std::string& output = gesture->getOutputString();
253 LLString output_lower = LLString(output.c_str());
254 LLString::toLower(output_lower);
255 if( cur_token_lower == output_lower )
256 {
257 revised_string->append(*token_iter);
258 }
259 else
260 {
261 revised_string->append(output.c_str());
262 }
263
264 }
265 found_gestures = TRUE;
266 break;
267 }
268 gesture = NULL;
269 }
270 }
271
272 if( !gesture )
273 {
274 if( !first_token )
275 {
276 revised_string->append( " " );
277 }
278 revised_string->append( *token_iter );
279 }
280
281 first_token = FALSE;
282 }
283 return found_gestures;
284}
285
286
287
288BOOL LLGestureList::trigger(KEY key, MASK mask)
289{
290 for (S32 i = 0; i < mList.count(); i++)
291 {
292 LLGesture* gesture = mList.get(i);
293 if( gesture )
294 {
295 if (gesture->trigger(key, mask))
296 {
297 return TRUE;
298 }
299 }
300 else
301 {
302 llwarns << "NULL gesture in gesture list (" << i << ")" << llendl
303 }
304 }
305 return FALSE;
306}
307
308// NOT endian-neutral
309U8 *LLGestureList::serialize(U8 *buffer) const
310{
311 // a single S32 serves as the header that tells us how many to read
312 S32 count = mList.count();
313 htonmemcpy(buffer, &count, MVT_S32, 4);
314 buffer += sizeof(count);
315
316 for (S32 i = 0; i < count; i++)
317 {
318 buffer = mList[i]->serialize(buffer);
319 }
320
321 return buffer;
322}
323
324const S32 MAX_GESTURES = 4096;
325
326U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size)
327{
328 deleteAll();
329
330 S32 count;
331 U8 *tmp = buffer;
332
333 if (tmp + sizeof(count) > buffer + max_size)
334 {
335 llwarns << "Invalid max_size" << llendl;
336 return buffer;
337 }
338
339 htonmemcpy(&count, tmp, MVT_S32, 4);
340
341 if (count > MAX_GESTURES)
342 {
343 llwarns << "Unreasonably large gesture list count in deserialize: " << count << llendl;
344 return tmp;
345 }
346
347 tmp += sizeof(count);
348
349 mList.reserve_block(count);
350
351 for (S32 i = 0; i < count; i++)
352 {
353 mList[i] = create_gesture(&tmp, max_size - (S32)(tmp - buffer));
354 if (tmp - buffer > max_size)
355 {
356 llwarns << "Deserialization read past end of buffer, bad data!!!!" << llendl;
357 return tmp;
358 }
359 }
360
361 return tmp;
362}
363
364// this is a helper for deserialize
365// it gets overridden by LLViewerGestureList to create LLViewerGestures
366// overridden by child class to use local LLGesture implementation
367LLGesture *LLGestureList::create_gesture(U8 **buffer, S32 max_size)
368{
369 return new LLGesture(buffer, max_size);
370}
371
372S32 LLGestureList::getMaxSerialSize()
373{
374 return SERIAL_HEADER_SIZE + (count() * LLGesture::getMaxSerialSize());
375}
diff --git a/linden/indra/llcharacter/llgesture.h b/linden/indra/llcharacter/llgesture.h
new file mode 100644
index 0000000..5180be0
--- /dev/null
+++ b/linden/indra/llcharacter/llgesture.h
@@ -0,0 +1,115 @@
1/**
2 * @file llgesture.h
3 * @brief A gesture is a combination of a triggering chat phrase or
4 * key, a sound, an animation, and a chat string.
5 *
6 * Copyright (c) 2002-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#ifndef LL_LLGESTURE_H
30#define LL_LLGESTURE_H
31
32#include "llanimationstates.h"
33#include "lluuid.h"
34#include "llstring.h"
35#include "lldarray.h"
36
37class LLGesture
38{
39public:
40 LLGesture();
41 LLGesture(KEY key, MASK mask, const std::string &trigger,
42 const LLUUID &sound_item_id, const std::string &animation,
43 const std::string &output_string);
44
45 LLGesture(U8 **buffer, S32 max_size); // deserializes, advances buffer
46 LLGesture(const LLGesture &gesture);
47 const LLGesture &operator=(const LLGesture &rhs);
48
49 virtual ~LLGesture() {};
50
51 // Accessors
52 KEY getKey() const { return mKey; }
53 MASK getMask() const { return mMask; }
54 const std::string& getTrigger() const { return mTrigger; }
55 const LLUUID& getSound() const { return mSoundItemID; }
56 const std::string& getAnimation() const { return mAnimation; }
57 const std::string& getOutputString() const { return mOutputString; }
58
59 // Triggers if a key/mask matches it
60 virtual BOOL trigger(KEY key, MASK mask);
61
62 // Triggers if case-insensitive substring matches (assumes string is lowercase)
63 virtual BOOL trigger(const LLString &string);
64
65 // non-endian-neutral serialization
66 U8 *serialize(U8 *buffer) const;
67 U8 *deserialize(U8 *buffer, S32 max_size);
68 static S32 getMaxSerialSize();
69
70protected:
71 KEY mKey; // usually a function key
72 MASK mMask; // usually MASK_NONE, or MASK_SHIFT
73 std::string mTrigger; // string, no whitespace allowed
74 std::string mTriggerLower; // lowercase version of mTrigger
75 LLUUID mSoundItemID; // ItemID of sound to play, LLUUID::null if none
76 std::string mAnimation; // canonical name of animation or face animation
77 std::string mOutputString; // string to say
78
79 static const S32 MAX_SERIAL_SIZE;
80};
81
82class LLGestureList
83{
84public:
85 LLGestureList();
86 virtual ~LLGestureList();
87
88 // Triggers if a key/mask matches one in the list
89 BOOL trigger(KEY key, MASK mask);
90
91 // Triggers if substring matches and generates revised string.
92 BOOL triggerAndReviseString(const LLString &string, LLString* revised_string);
93
94 // Used for construction from UI
95 S32 count() const { return mList.count(); }
96 virtual LLGesture* get(S32 i) const { return mList.get(i); }
97 virtual void put(LLGesture* gesture) { mList.put( gesture ); }
98 void deleteAll();
99
100 // non-endian-neutral serialization
101 U8 *serialize(U8 *buffer) const;
102 U8 *deserialize(U8 *buffer, S32 max_size);
103 S32 getMaxSerialSize();
104
105protected:
106 // overridden by child class to use local LLGesture implementation
107 virtual LLGesture *create_gesture(U8 **buffer, S32 max_size);
108
109protected:
110 LLDynamicArray<LLGesture*> mList;
111
112 static const S32 SERIAL_HEADER_SIZE;
113};
114
115#endif
diff --git a/linden/indra/llcharacter/llhandmotion.cpp b/linden/indra/llcharacter/llhandmotion.cpp
new file mode 100644
index 0000000..12ef070
--- /dev/null
+++ b/linden/indra/llcharacter/llhandmotion.cpp
@@ -0,0 +1,221 @@
1/**
2 * @file llhandmotion.cpp
3 * @brief Implementation of LLHandMotion 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 "llhandmotion.h"
34#include "llcharacter.h"
35#include "m3math.h"
36
37//-----------------------------------------------------------------------------
38// Constants
39//-----------------------------------------------------------------------------
40
41const char *gHandPoseNames[LLHandMotion::NUM_HAND_POSES] = /* Flawfinder: ignore */
42{
43 "",
44 "Hands_Relaxed",
45 "Hands_Point",
46 "Hands_Fist",
47 "Hands_Relaxed_L",
48 "Hands_Point_L",
49 "Hands_Fist_L",
50 "Hands_Relaxed_R",
51 "Hands_Point_R",
52 "Hands_Fist_R",
53 "Hands_Salute_R",
54 "Hands_Typing",
55 "Hands_Peace_R",
56 "Hands_Spread_R"
57};
58
59const F32 HAND_MORPH_BLEND_TIME = 0.2f;
60
61//-----------------------------------------------------------------------------
62// LLHandMotion()
63// Class Constructor
64//-----------------------------------------------------------------------------
65LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id)
66{
67 mCharacter = NULL;
68 mLastTime = 0.f;
69 mCurrentPose = HAND_POSE_RELAXED;
70 mNewPose = HAND_POSE_RELAXED;
71 mName = "hand_motion";
72
73 //RN: flag hand joint as highest priority for now, until we implement a proper animation track
74 mJointSignature[0][LL_HAND_JOINT_NUM] = 0xff;
75 mJointSignature[1][LL_HAND_JOINT_NUM] = 0xff;
76 mJointSignature[2][LL_HAND_JOINT_NUM] = 0xff;
77}
78
79
80//-----------------------------------------------------------------------------
81// ~LLHandMotion()
82// Class Destructor
83//-----------------------------------------------------------------------------
84LLHandMotion::~LLHandMotion()
85{
86}
87
88//-----------------------------------------------------------------------------
89// LLHandMotion::onInitialize(LLCharacter *character)
90//-----------------------------------------------------------------------------
91LLMotion::LLMotionInitStatus LLHandMotion::onInitialize(LLCharacter *character)
92{
93 mCharacter = character;
94
95 return STATUS_SUCCESS;
96}
97
98
99//-----------------------------------------------------------------------------
100// LLHandMotion::onActivate()
101//-----------------------------------------------------------------------------
102BOOL LLHandMotion::onActivate()
103{
104 LLPolyMesh *upperBodyMesh = mCharacter->getUpperBodyMesh();
105
106 if (upperBodyMesh)
107 {
108 // Note: 0 is the default
109 for (S32 i = 1; i < LLHandMotion::NUM_HAND_POSES; i++)
110 {
111 mCharacter->setVisualParamWeight(gHandPoseNames[i], 0.f);
112 }
113 mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
114 mCharacter->updateVisualParams();
115 }
116 return TRUE;
117}
118
119
120//-----------------------------------------------------------------------------
121// LLHandMotion::onUpdate()
122//-----------------------------------------------------------------------------
123BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
124{
125 eHandPose *requestedHandPose;
126
127 F32 timeDelta = time - mLastTime;
128 mLastTime = time;
129
130 requestedHandPose = (eHandPose *)mCharacter->getAnimationData("Hand Pose");
131 // check to see if requested pose has changed
132 if (!requestedHandPose)
133 {
134 if (mNewPose != HAND_POSE_RELAXED && mNewPose != mCurrentPose)
135 {
136 mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
137 }
138 mNewPose = HAND_POSE_RELAXED;
139 }
140 else
141 {
142 // this is a new morph we didn't know about before
143 if (*requestedHandPose != mNewPose && mNewPose != mCurrentPose && mNewPose != HAND_POSE_SPREAD)
144 {
145 mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
146 }
147 mNewPose = *requestedHandPose;
148 }
149
150 mCharacter->removeAnimationData("Hand Pose");
151 mCharacter->removeAnimationData("Hand Pose Priority");
152
153// if (requestedHandPose)
154// llinfos << "Hand Pose " << *requestedHandPose << llendl;
155
156 // if we are still blending...
157 if (mCurrentPose != mNewPose)
158 {
159 F32 incomingWeight = 1.f;
160 F32 outgoingWeight = 0.f;
161
162 if (mNewPose != HAND_POSE_SPREAD)
163 {
164 incomingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mNewPose]);
165 incomingWeight += (timeDelta / HAND_MORPH_BLEND_TIME);
166 incomingWeight = llclamp(incomingWeight, 0.f, 1.f);
167 mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], incomingWeight);
168 }
169
170 if (mCurrentPose != HAND_POSE_SPREAD)
171 {
172 outgoingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mCurrentPose]);
173 outgoingWeight -= (timeDelta / HAND_MORPH_BLEND_TIME);
174 outgoingWeight = llclamp(outgoingWeight, 0.f, 1.f);
175 mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], outgoingWeight);
176 }
177
178 mCharacter->updateVisualParams();
179
180 if (incomingWeight == 1.f && outgoingWeight == 0.f)
181 {
182 mCurrentPose = mNewPose;
183 }
184 }
185
186 return TRUE;
187}
188
189
190//-----------------------------------------------------------------------------
191// LLHandMotion::onDeactivate()
192//-----------------------------------------------------------------------------
193void LLHandMotion::onDeactivate()
194{
195}
196
197//-----------------------------------------------------------------------------
198// LLHandMotion::getHandPoseName()
199//-----------------------------------------------------------------------------
200LLString LLHandMotion::getHandPoseName(eHandPose pose)
201{
202 if ((S32)pose < LLHandMotion::NUM_HAND_POSES && (S32)pose >= 0)
203 {
204 return gHandPoseNames[pose];
205 }
206 return "";
207}
208
209LLHandMotion::eHandPose LLHandMotion::getHandPose(LLString posename)
210{
211 for (S32 pose = 0; pose < LLHandMotion::NUM_HAND_POSES; ++pose)
212 {
213 if (gHandPoseNames[pose] == posename)
214 {
215 return (eHandPose)pose;
216 }
217 }
218 return (eHandPose)0;
219}
220
221// End
diff --git a/linden/indra/llcharacter/llhandmotion.h b/linden/indra/llcharacter/llhandmotion.h
new file mode 100644
index 0000000..3f3dac6
--- /dev/null
+++ b/linden/indra/llcharacter/llhandmotion.h
@@ -0,0 +1,138 @@
1/**
2 * @file llhandmotion.h
3 * @brief Implementation of LLHandMotion 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#ifndef LL_LLHANDMOTION_H
29#define LL_LLHANDMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llmotion.h"
35#include "lltimer.h"
36
37#define MIN_REQUIRED_PIXEL_AREA_HAND 10000.f;
38
39//-----------------------------------------------------------------------------
40// class LLHandMotion
41//-----------------------------------------------------------------------------
42class LLHandMotion :
43 public LLMotion
44{
45public:
46 typedef enum e_hand_pose
47 {
48 HAND_POSE_SPREAD,
49 HAND_POSE_RELAXED,
50 HAND_POSE_POINT,
51 HAND_POSE_FIST,
52 HAND_POSE_RELAXED_L,
53 HAND_POSE_POINT_L,
54 HAND_POSE_FIST_L,
55 HAND_POSE_RELAXED_R,
56 HAND_POSE_POINT_R,
57 HAND_POSE_FIST_R,
58 HAND_POSE_SALUTE_R,
59 HAND_POSE_TYPING,
60 HAND_POSE_PEACE_R,
61 HAND_POSE_PALM_R,
62 NUM_HAND_POSES
63 } eHandPose;
64
65 // Constructor
66 LLHandMotion(const LLUUID &id);
67
68 // Destructor
69 virtual ~LLHandMotion();
70
71public:
72 //-------------------------------------------------------------------------
73 // functions to support MotionController and MotionRegistry
74 //-------------------------------------------------------------------------
75
76 // static constructor
77 // all subclasses must implement such a function and register it
78 static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); }
79
80public:
81 //-------------------------------------------------------------------------
82 // animation callbacks to be implemented by subclasses
83 //-------------------------------------------------------------------------
84
85 // motions must specify whether or not they loop
86 virtual BOOL getLoop() { return TRUE; }
87
88 // motions must report their total duration
89 virtual F32 getDuration() { return 0.0; }
90
91 // motions must report their "ease in" duration
92 virtual F32 getEaseInDuration() { return 0.0; }
93
94 // motions must report their "ease out" duration.
95 virtual F32 getEaseOutDuration() { return 0.0; }
96
97 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
98 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_HAND; }
99
100 // motions must report their priority
101 virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
102
103 virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
104
105 // run-time (post constructor) initialization,
106 // called after parameters have been set
107 // must return true to indicate success and be available for activation
108 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
109
110 // called when a motion is activated
111 // must return TRUE to indicate success, or else
112 // it will be deactivated
113 virtual BOOL onActivate();
114
115 // called per time step
116 // must return TRUE while it is active, and
117 // must return FALSE when the motion is completed.
118 virtual BOOL onUpdate(F32 time, U8* joint_mask);
119
120 // called when a motion is deactivated
121 virtual void onDeactivate();
122
123 static LLString getHandPoseName(eHandPose pose);
124 static eHandPose getHandPose(LLString posename);
125
126public:
127 //-------------------------------------------------------------------------
128 // joint states to be animated
129 //-------------------------------------------------------------------------
130
131 LLCharacter *mCharacter;
132
133 F32 mLastTime;
134 eHandPose mCurrentPose;
135 eHandPose mNewPose;
136};
137#endif // LL_LLHANDMOTION_H
138
diff --git a/linden/indra/llcharacter/llheadrotmotion.cpp b/linden/indra/llcharacter/llheadrotmotion.cpp
new file mode 100644
index 0000000..3bf7be0
--- /dev/null
+++ b/linden/indra/llcharacter/llheadrotmotion.cpp
@@ -0,0 +1,524 @@
1/**
2 * @file llheadrotmotion.cpp
3 * @brief Implementation of LLHeadRotMotion 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 "llheadrotmotion.h"
34#include "llcharacter.h"
35#include "llrand.h"
36#include "m3math.h"
37#include "v3dmath.h"
38#include "llcriticaldamp.h"
39
40//-----------------------------------------------------------------------------
41// Constants
42//-----------------------------------------------------------------------------
43const F32 TORSO_LAG = 0.35f; // torso rotation factor
44const F32 NECK_LAG = 0.5f; // neck rotation factor
45const F32 HEAD_LOOKAT_LAG_HALF_LIFE = 0.15f; // half-life of lookat targeting for head
46const F32 TORSO_LOOKAT_LAG_HALF_LIFE = 0.27f; // half-life of lookat targeting for torso
47const F32 EYE_LOOKAT_LAG_HALF_LIFE = 0.06f; // half-life of lookat targeting for eye
48const F32 HEAD_ROTATION_CONSTRAINT = F_PI_BY_TWO * 0.8f; // limit angle for head rotation
49
50const F32 MIN_HEAD_LOOKAT_DISTANCE = 0.3f; // minimum distance from head before we turn to look at it
51const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
52const F32 EYE_JITTER_MIN_TIME = 0.3f; // min amount of time between eye "jitter" motions
53const F32 EYE_JITTER_MAX_TIME = 2.5f; // max amount of time between eye "jitter" motions
54const F32 EYE_JITTER_MAX_YAW = 0.08f; // max yaw of eye jitter motion
55const F32 EYE_JITTER_MAX_PITCH = 0.015f; // max pitch of eye jitter motion
56const F32 EYE_LOOK_AWAY_MIN_TIME = 5.f; // min amount of time between eye "look away" motions
57const F32 EYE_LOOK_AWAY_MAX_TIME = 15.f; // max amount of time between eye "look away" motions
58const F32 EYE_LOOK_BACK_MIN_TIME = 1.f; // min amount of time before looking back after looking away
59const F32 EYE_LOOK_BACK_MAX_TIME = 5.f; // max amount of time before looking back after looking away
60const F32 EYE_LOOK_AWAY_MAX_YAW = 0.15f; // max yaw of eye look away motion
61const F32 EYE_LOOK_AWAY_MAX_PITCH = 0.12f; // max pitch of look away motion
62const F32 EYE_ROT_LIMIT_ANGLE = F_PI_BY_TWO * 0.3f; //max angle in radians for eye rotation
63
64const F32 EYE_BLINK_MIN_TIME = 0.5f; // minimum amount of time between blinks
65const F32 EYE_BLINK_MAX_TIME = 8.f; // maximum amount of time between blinks
66const F32 EYE_BLINK_CLOSE_TIME = 0.03f; // how long the eye stays closed in a blink
67const F32 EYE_BLINK_SPEED = 0.015f; // seconds it takes for a eye open/close movement
68const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blink and the other following
69
70//-----------------------------------------------------------------------------
71// LLHeadRotMotion()
72// Class Constructor
73//-----------------------------------------------------------------------------
74LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) :
75 LLMotion(id),
76 mCharacter(NULL),
77 mTorsoJoint(NULL),
78 mHeadJoint(NULL)
79{
80 mName = "head_rot";
81}
82
83
84//-----------------------------------------------------------------------------
85// ~LLHeadRotMotion()
86// Class Destructor
87//-----------------------------------------------------------------------------
88LLHeadRotMotion::~LLHeadRotMotion()
89{
90}
91
92//-----------------------------------------------------------------------------
93// LLHeadRotMotion::onInitialize(LLCharacter *character)
94//-----------------------------------------------------------------------------
95LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character)
96{
97 if (!character)
98 return STATUS_FAILURE;
99 mCharacter = character;
100
101 mPelvisJoint = character->getJoint("mPelvis");
102 if ( ! mPelvisJoint )
103 {
104 llinfos << getName() << ": Can't get pelvis joint." << llendl;
105 return STATUS_FAILURE;
106 }
107
108 mRootJoint = character->getJoint("mRoot");
109 if ( ! mRootJoint )
110 {
111 llinfos << getName() << ": Can't get root joint." << llendl;
112 return STATUS_FAILURE;
113 }
114
115 mTorsoJoint = character->getJoint("mTorso");
116 if ( ! mTorsoJoint )
117 {
118 llinfos << getName() << ": Can't get torso joint." << llendl;
119 return STATUS_FAILURE;
120 }
121
122 mHeadJoint = character->getJoint("mHead");
123 if ( ! mHeadJoint )
124 {
125 llinfos << getName() << ": Can't get head joint." << llendl;
126 return STATUS_FAILURE;
127 }
128
129 mTorsoState.setJoint( character->getJoint("mTorso") );
130 if ( ! mTorsoState.getJoint() )
131 {
132 llinfos << getName() << ": Can't get torso joint." << llendl;
133 return STATUS_FAILURE;
134 }
135
136 mNeckState.setJoint( character->getJoint("mNeck") );
137 if ( ! mNeckState.getJoint() )
138 {
139 llinfos << getName() << ": Can't get neck joint." << llendl;
140 return STATUS_FAILURE;
141 }
142
143 mHeadState.setJoint( character->getJoint("mHead") );
144 if ( ! mHeadState.getJoint() )
145 {
146 llinfos << getName() << ": Can't get head joint." << llendl;
147 return STATUS_FAILURE;
148 }
149
150 mTorsoState.setUsage(LLJointState::ROT);
151 mNeckState.setUsage(LLJointState::ROT);
152 mHeadState.setUsage(LLJointState::ROT);
153
154 addJointState( &mTorsoState );
155 addJointState( &mNeckState );
156 addJointState( &mHeadState );
157
158 mLastHeadRot.loadIdentity();
159
160 return STATUS_SUCCESS;
161}
162
163
164//-----------------------------------------------------------------------------
165// LLHeadRotMotion::onActivate()
166//-----------------------------------------------------------------------------
167BOOL LLHeadRotMotion::onActivate()
168{
169 return TRUE;
170}
171
172
173//-----------------------------------------------------------------------------
174// LLHeadRotMotion::onUpdate()
175//-----------------------------------------------------------------------------
176BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
177{
178 LLQuaternion targetHeadRotWorld;
179 LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation();
180 LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld;
181
182 F32 head_slerp_amt = LLCriticalDamp::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE);
183 F32 torso_slerp_amt = LLCriticalDamp::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE);
184
185 LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
186
187 if (targetPos)
188 {
189 LLVector3 headLookAt = *targetPos;
190
191// llinfos << "Look At: " << headLookAt + mHeadJoint->getWorldPosition() << llendl;
192
193 F32 lookatDistance = headLookAt.normVec();
194
195 if (lookatDistance < MIN_HEAD_LOOKAT_DISTANCE)
196 {
197 targetHeadRotWorld = mPelvisJoint->getWorldRotation();
198 }
199 else
200 {
201 LLVector3 root_up = LLVector3(0.f, 0.f, 1.f) * currentRootRotWorld;
202 LLVector3 left(root_up % headLookAt);
203 // if look_at has zero length, fail
204 // if look_at and skyward are parallel, fail
205 //
206 // Test both of these conditions with a cross product.
207
208 if (left.magVecSquared() < 0.15f)
209 {
210 LLVector3 root_at = LLVector3(1.f, 0.f, 0.f) * currentRootRotWorld;
211 root_at.mV[VZ] = 0.f;
212 root_at.normVec();
213
214 headLookAt = lerp(headLookAt, root_at, 0.4f);
215 headLookAt.normVec();
216
217 left = root_up % headLookAt;
218 }
219
220 // Make sure look_at and skyward and not parallel
221 // and neither are zero length
222 LLVector3 up(headLookAt % left);
223
224 targetHeadRotWorld = LLQuaternion(headLookAt, left, up);
225 }
226 }
227 else
228 {
229 targetHeadRotWorld = currentRootRotWorld;
230 }
231
232 LLQuaternion head_rot_local = targetHeadRotWorld * currentInvRootRotWorld;
233 head_rot_local.constrain(HEAD_ROTATION_CONSTRAINT);
234
235 // set final torso rotation
236 // Set torso target rotation such that it lags behind the head rotation
237 // by a fixed amount.
238 LLQuaternion torso_rot_local = nlerp(TORSO_LAG, LLQuaternion::DEFAULT, head_rot_local );
239 mTorsoState.setRotation( nlerp(torso_slerp_amt, mTorsoState.getRotation(), torso_rot_local) );
240
241 head_rot_local = nlerp(head_slerp_amt, mLastHeadRot, head_rot_local);
242 mLastHeadRot = head_rot_local;
243
244 // Set the head rotation.
245 LLQuaternion torsoRotLocal = mNeckState.getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
246 head_rot_local = head_rot_local * ~torsoRotLocal;
247 mNeckState.setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
248 mHeadState.setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local));
249
250 return TRUE;
251}
252
253
254//-----------------------------------------------------------------------------
255// LLHeadRotMotion::onDeactivate()
256//-----------------------------------------------------------------------------
257void LLHeadRotMotion::onDeactivate()
258{
259}
260
261
262//-----------------------------------------------------------------------------
263// LLEyeMotion()
264// Class Constructor
265//-----------------------------------------------------------------------------
266LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id)
267{
268 mCharacter = NULL;
269 mEyeJitterTime = 0.f;
270 mEyeJitterYaw = 0.f;
271 mEyeJitterPitch = 0.f;
272
273 mEyeLookAwayTime = 0.f;
274 mEyeLookAwayYaw = 0.f;
275 mEyeLookAwayPitch = 0.f;
276
277 mEyeBlinkTime = 0.f;
278 mEyesClosed = FALSE;
279
280 mHeadJoint = NULL;
281
282 mName = "eye_rot";
283}
284
285
286//-----------------------------------------------------------------------------
287// ~LLEyeMotion()
288// Class Destructor
289//-----------------------------------------------------------------------------
290LLEyeMotion::~LLEyeMotion()
291{
292}
293
294//-----------------------------------------------------------------------------
295// LLEyeMotion::onInitialize(LLCharacter *character)
296//-----------------------------------------------------------------------------
297LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character)
298{
299 mCharacter = character;
300
301 mHeadJoint = character->getJoint("mHead");
302 if ( ! mHeadJoint )
303 {
304 llinfos << getName() << ": Can't get head joint." << llendl;
305 return STATUS_FAILURE;
306 }
307
308 mLeftEyeState.setJoint( character->getJoint("mEyeLeft") );
309 if ( ! mLeftEyeState.getJoint() )
310 {
311 llinfos << getName() << ": Can't get left eyeball joint." << llendl;
312 return STATUS_FAILURE;
313 }
314
315 mRightEyeState.setJoint( character->getJoint("mEyeRight") );
316 if ( ! mRightEyeState.getJoint() )
317 {
318 llinfos << getName() << ": Can't get Right eyeball joint." << llendl;
319 return STATUS_FAILURE;
320 }
321
322 mLeftEyeState.setUsage(LLJointState::ROT);
323 mRightEyeState.setUsage(LLJointState::ROT);
324
325 addJointState( &mLeftEyeState );
326 addJointState( &mRightEyeState );
327
328 return STATUS_SUCCESS;
329}
330
331
332//-----------------------------------------------------------------------------
333// LLEyeMotion::onActivate()
334//-----------------------------------------------------------------------------
335BOOL LLEyeMotion::onActivate()
336{
337 return TRUE;
338}
339
340
341//-----------------------------------------------------------------------------
342// LLEyeMotion::onUpdate()
343//-----------------------------------------------------------------------------
344BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
345{
346 // Compute eye rotation.
347 LLQuaternion target_eye_rot;
348 LLVector3 eye_look_at;
349 F32 vergence;
350
351 //calculate jitter
352 if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
353 {
354 mEyeJitterTime = EYE_JITTER_MIN_TIME + frand(EYE_JITTER_MAX_TIME - EYE_JITTER_MIN_TIME);
355 mEyeJitterYaw = (frand(2.f) - 1.f) * EYE_JITTER_MAX_YAW;
356 mEyeJitterPitch = (frand(2.f) - 1.f) * EYE_JITTER_MAX_PITCH;
357 // make sure lookaway time count gets updated, because we're resetting the timer
358 mEyeLookAwayTime -= llmax(0.f, mEyeJitterTimer.getElapsedTimeF32());
359 mEyeJitterTimer.reset();
360 }
361 else if (mEyeJitterTimer.getElapsedTimeF32() > mEyeLookAwayTime)
362 {
363 if (frand(1.f) > 0.1f)
364 {
365 // blink while moving eyes some percentage of the time
366 mEyeBlinkTime = mEyeBlinkTimer.getElapsedTimeF32();
367 }
368 if (mEyeLookAwayYaw == 0.f && mEyeLookAwayPitch == 0.f)
369 {
370 mEyeLookAwayYaw = (frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_YAW;
371 mEyeLookAwayPitch = (frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_PITCH;
372 mEyeLookAwayTime = EYE_LOOK_BACK_MIN_TIME + frand(EYE_LOOK_BACK_MAX_TIME - EYE_LOOK_BACK_MIN_TIME);
373 }
374 else
375 {
376 mEyeLookAwayYaw = 0.f;
377 mEyeLookAwayPitch = 0.f;
378 mEyeLookAwayTime = EYE_LOOK_AWAY_MIN_TIME + frand(EYE_LOOK_AWAY_MAX_TIME - EYE_LOOK_AWAY_MIN_TIME);
379 }
380 }
381
382 // do blinking
383 if (!mEyesClosed && mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime)
384 {
385 F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime;
386 F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA;
387
388 leftEyeBlinkMorph = llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
389 rightEyeBlinkMorph = llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
390 mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph);
391 mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph);
392 mCharacter->updateVisualParams();
393
394 if (rightEyeBlinkMorph == 1.f)
395 {
396 mEyesClosed = TRUE;
397 mEyeBlinkTime = EYE_BLINK_CLOSE_TIME;
398 mEyeBlinkTimer.reset();
399 }
400 }
401 else if (mEyesClosed)
402 {
403 if (mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime)
404 {
405 F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime;
406 F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA;
407
408 leftEyeBlinkMorph = 1.f - llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
409 rightEyeBlinkMorph = 1.f - llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
410 mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph);
411 mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph);
412 mCharacter->updateVisualParams();
413
414 if (rightEyeBlinkMorph == 0.f)
415 {
416 mEyesClosed = FALSE;
417 mEyeBlinkTime = EYE_BLINK_MIN_TIME + frand(EYE_BLINK_MAX_TIME - EYE_BLINK_MIN_TIME);
418 mEyeBlinkTimer.reset();
419 }
420 }
421 }
422
423 BOOL has_eye_target = FALSE;
424 LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
425
426 if (targetPos)
427 {
428 LLVector3 skyward(0.f, 0.f, 1.f);
429 LLVector3 left;
430 LLVector3 up;
431
432 eye_look_at = *targetPos;
433 F32 lookAtDistance = eye_look_at.normVec();
434
435 left.setVec(skyward % eye_look_at);
436 up.setVec(eye_look_at % left);
437
438 target_eye_rot = LLQuaternion(eye_look_at, left, up);
439
440 // calculate vergence
441 F32 interocular_dist = (mLeftEyeState.getJoint()->getWorldPosition() - mRightEyeState.getJoint()->getWorldPosition()).magVec();
442 vergence = -atan2((interocular_dist / 2.f), lookAtDistance);
443 llclamp(vergence, -F_PI_BY_TWO, 0.f);
444 }
445 else
446 {
447 target_eye_rot = mHeadJoint->getWorldRotation();
448 vergence = 0.f;
449 }
450
451 //RN: subtract 4 degrees to account for foveal angular offset relative to pupil
452 vergence += 4.f * DEG_TO_RAD;
453
454 // calculate eye jitter
455 LLQuaternion eye_jitter_rot;
456
457 // vergence not too high...
458 if (vergence > -0.05f)
459 {
460 //...go ahead and jitter
461 eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw);
462 }
463 else
464 {
465 //...or don't
466 eye_jitter_rot.loadIdentity();
467 }
468
469 // calculate vergence of eyes as an object gets closer to the avatar's head
470 LLQuaternion vergence_quat;
471
472 if (has_eye_target)
473 {
474 vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f));
475 }
476 else
477 {
478 vergence_quat.loadIdentity();
479 }
480
481 // calculate eye rotations
482 LLQuaternion left_eye_rot = target_eye_rot;
483 left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot;
484
485 LLQuaternion right_eye_rot = target_eye_rot;
486 vergence_quat.transQuat();
487 right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot;
488
489 //set final eye rotations
490 // start with left
491 LLQuaternion tQw = mLeftEyeState.getJoint()->getParent()->getWorldRotation();
492 LLQuaternion tQh = left_eye_rot * ~tQw;
493 tQh.constrain(EYE_ROT_LIMIT_ANGLE);
494 mLeftEyeState.setRotation( tQh );
495
496 // now do right eye
497 tQw = mRightEyeState.getJoint()->getParent()->getWorldRotation();
498 tQh = right_eye_rot * ~tQw;
499 tQh.constrain(EYE_ROT_LIMIT_ANGLE);
500 mRightEyeState.setRotation( tQh );
501
502 return TRUE;
503}
504
505
506//-----------------------------------------------------------------------------
507// LLEyeMotion::onDeactivate()
508//-----------------------------------------------------------------------------
509void LLEyeMotion::onDeactivate()
510{
511 LLJoint* joint = mLeftEyeState.getJoint();
512 if (joint)
513 {
514 joint->setRotation(LLQuaternion::DEFAULT);
515 }
516
517 joint = mRightEyeState.getJoint();
518 if (joint)
519 {
520 joint->setRotation(LLQuaternion::DEFAULT);
521 }
522}
523
524// End
diff --git a/linden/indra/llcharacter/llheadrotmotion.h b/linden/indra/llcharacter/llheadrotmotion.h
new file mode 100644
index 0000000..1412354
--- /dev/null
+++ b/linden/indra/llcharacter/llheadrotmotion.h
@@ -0,0 +1,213 @@
1/**
2 * @file llheadrotmotion.h
3 * @brief Implementation of LLHeadRotMotion 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#ifndef LL_LLHEADROTMOTION_H
29#define LL_LLHEADROTMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llmotion.h"
35#include "llframetimer.h"
36
37#define MIN_REQUIRED_PIXEL_AREA_HEAD_ROT 500.f;
38#define MIN_REQUIRED_PIXEL_AREA_EYE 25000.f;
39
40//-----------------------------------------------------------------------------
41// class LLHeadRotMotion
42//-----------------------------------------------------------------------------
43class LLHeadRotMotion :
44 public LLMotion
45{
46public:
47 // Constructor
48 LLHeadRotMotion(const LLUUID &id);
49
50 // Destructor
51 virtual ~LLHeadRotMotion();
52
53public:
54 //-------------------------------------------------------------------------
55 // functions to support MotionController and MotionRegistry
56 //-------------------------------------------------------------------------
57
58 // static constructor
59 // all subclasses must implement such a function and register it
60 static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); }
61
62public:
63 //-------------------------------------------------------------------------
64 // animation callbacks to be implemented by subclasses
65 //-------------------------------------------------------------------------
66
67 // motions must specify whether or not they loop
68 virtual BOOL getLoop() { return TRUE; }
69
70 // motions must report their total duration
71 virtual F32 getDuration() { return 0.0; }
72
73 // motions must report their "ease in" duration
74 virtual F32 getEaseInDuration() { return 1.f; }
75
76 // motions must report their "ease out" duration.
77 virtual F32 getEaseOutDuration() { return 1.f; }
78
79 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
80 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_HEAD_ROT; }
81
82 // motions must report their priority
83 virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
84
85 virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
86
87 // run-time (post constructor) initialization,
88 // called after parameters have been set
89 // must return true to indicate success and be available for activation
90 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
91
92 // called when a motion is activated
93 // must return TRUE to indicate success, or else
94 // it will be deactivated
95 virtual BOOL onActivate();
96
97 // called per time step
98 // must return TRUE while it is active, and
99 // must return FALSE when the motion is completed.
100 virtual BOOL onUpdate(F32 time, U8* joint_mask);
101
102 // called when a motion is deactivated
103 virtual void onDeactivate();
104
105public:
106 //-------------------------------------------------------------------------
107 // joint states to be animated
108 //-------------------------------------------------------------------------
109 LLCharacter *mCharacter;
110
111 LLJoint *mTorsoJoint;
112 LLJoint *mHeadJoint;
113 LLJoint *mRootJoint;
114 LLJoint *mPelvisJoint;
115
116 LLJointState mTorsoState;
117 LLJointState mNeckState;
118 LLJointState mHeadState;
119
120 LLQuaternion mLastHeadRot;
121};
122
123//-----------------------------------------------------------------------------
124// class LLEyeMotion
125//-----------------------------------------------------------------------------
126class LLEyeMotion :
127 public LLMotion
128{
129public:
130 // Constructor
131 LLEyeMotion(const LLUUID &id);
132
133 // Destructor
134 virtual ~LLEyeMotion();
135
136public:
137 //-------------------------------------------------------------------------
138 // functions to support MotionController and MotionRegistry
139 //-------------------------------------------------------------------------
140
141 // static constructor
142 // all subclasses must implement such a function and register it
143 static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); }
144
145public:
146 //-------------------------------------------------------------------------
147 // animation callbacks to be implemented by subclasses
148 //-------------------------------------------------------------------------
149
150 // motions must specify whether or not they loop
151 virtual BOOL getLoop() { return TRUE; }
152
153 // motions must report their total duration
154 virtual F32 getDuration() { return 0.0; }
155
156 // motions must report their "ease in" duration
157 virtual F32 getEaseInDuration() { return 0.5f; }
158
159 // motions must report their "ease out" duration.
160 virtual F32 getEaseOutDuration() { return 0.5f; }
161
162 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
163 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_EYE; }
164
165 // motions must report their priority
166 virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
167
168 virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
169
170 // run-time (post constructor) initialization,
171 // called after parameters have been set
172 // must return true to indicate success and be available for activation
173 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
174
175 // called when a motion is activated
176 // must return TRUE to indicate success, or else
177 // it will be deactivated
178 virtual BOOL onActivate();
179
180 // called per time step
181 // must return TRUE while it is active, and
182 // must return FALSE when the motion is completed.
183 virtual BOOL onUpdate(F32 time, U8* joint_mask);
184
185 // called when a motion is deactivated
186 virtual void onDeactivate();
187
188public:
189 //-------------------------------------------------------------------------
190 // joint states to be animated
191 //-------------------------------------------------------------------------
192 LLCharacter *mCharacter;
193
194 LLJoint *mHeadJoint;
195 LLJointState mLeftEyeState;
196 LLJointState mRightEyeState;
197
198 LLFrameTimer mEyeJitterTimer;
199 F32 mEyeJitterTime;
200 F32 mEyeJitterYaw;
201 F32 mEyeJitterPitch;
202 F32 mEyeLookAwayTime;
203 F32 mEyeLookAwayYaw;
204 F32 mEyeLookAwayPitch;
205
206 // eye blinking
207 LLFrameTimer mEyeBlinkTimer;
208 F32 mEyeBlinkTime;
209 BOOL mEyesClosed;
210};
211
212#endif // LL_LLHEADROTMOTION_H
213
diff --git a/linden/indra/llcharacter/lljoint.cpp b/linden/indra/llcharacter/lljoint.cpp
new file mode 100644
index 0000000..4ef9835
--- /dev/null
+++ b/linden/indra/llcharacter/lljoint.cpp
@@ -0,0 +1,523 @@
1/**
2 * @file lljoint.cpp
3 * @brief Implementation of LLJoint 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 "lljoint.h"
34
35#include "llmath.h"
36
37S32 LLJoint::sNumUpdates = 0;
38S32 LLJoint::sNumTouches = 0;
39
40//-----------------------------------------------------------------------------
41// LLJoint()
42// Class Constructor
43//-----------------------------------------------------------------------------
44LLJoint::LLJoint()
45{
46 mName = "unnamed";
47 mParent = NULL;
48 mXform.setScaleChildOffset(TRUE);
49 mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
50 mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;
51 mUpdateXform = TRUE;
52 mJointNum = -1;
53 touch();
54}
55
56
57//-----------------------------------------------------------------------------
58// LLJoint()
59// Class Constructor
60//-----------------------------------------------------------------------------
61LLJoint::LLJoint(const std::string &name, LLJoint *parent)
62{
63 mName = "unnamed";
64 mParent = NULL;
65 mXform.setScaleChildOffset(TRUE);
66 mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
67 mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;
68 mJointNum = 0;
69
70 setName(name);
71 if (parent)
72 parent->addChild( this );
73
74 touch();
75}
76
77//-----------------------------------------------------------------------------
78// ~LLJoint()
79// Class Destructor
80//-----------------------------------------------------------------------------
81LLJoint::~LLJoint()
82{
83 removeAllChildren();
84}
85
86
87//-----------------------------------------------------------------------------
88// setup()
89//-----------------------------------------------------------------------------
90void LLJoint::setup(const std::string &name, LLJoint *parent)
91{
92 setName(name);
93 if (parent)
94 parent->addChild( this );
95}
96
97//-----------------------------------------------------------------------------
98// touch()
99// Sets all dirty flags for all children, recursively.
100//-----------------------------------------------------------------------------
101void LLJoint::touch(U32 flags)
102{
103 if ((flags | mDirtyFlags) != mDirtyFlags)
104 {
105 sNumTouches++;
106 mDirtyFlags |= flags;
107 U32 child_flags = flags;
108 if (flags & ROTATION_DIRTY)
109 {
110 child_flags |= POSITION_DIRTY;
111 }
112
113 for ( LLJoint *joint = mChildren.getFirstData();
114 joint != NULL;
115 joint = mChildren.getNextData() )
116 {
117 joint->touch(child_flags);
118 }
119 }
120}
121
122//-----------------------------------------------------------------------------
123// getRoot()
124//-----------------------------------------------------------------------------
125LLJoint *LLJoint::getRoot()
126{
127 if ( getParent() == NULL )
128 {
129 return this;
130 }
131 return getParent()->getRoot();
132}
133
134
135//-----------------------------------------------------------------------------
136// findJoint()
137//-----------------------------------------------------------------------------
138LLJoint *LLJoint::findJoint( const std::string &name )
139{
140 if (name == getName())
141 return this;
142
143 for ( LLJoint *j = mChildren.getFirstData();
144 j != NULL;
145 j = mChildren.getNextData() )
146 {
147 LLJoint *found = j->findJoint(name);
148 if (found)
149 return found;
150 }
151
152 return NULL;
153}
154
155
156//--------------------------------------------------------------------
157// addChild()
158//--------------------------------------------------------------------
159void LLJoint::addChild(LLJoint *joint)
160{
161 if (joint->mParent)
162 joint->mParent->removeChild(joint);
163
164 mChildren.addDataAtEnd(joint);
165 joint->mXform.setParent(&mXform);
166 joint->mParent = this;
167 joint->touch();
168}
169
170
171//--------------------------------------------------------------------
172// removeChild()
173//--------------------------------------------------------------------
174void LLJoint::removeChild(LLJoint *joint)
175{
176 this->mChildren.removeData(joint);
177 joint->mXform.setParent(NULL);
178 joint->mParent = NULL;
179 joint->touch();
180}
181
182
183//--------------------------------------------------------------------
184// removeAllChildren()
185//--------------------------------------------------------------------
186void LLJoint::removeAllChildren()
187{
188 for ( LLJoint *joint = mChildren.getFirstData();
189 joint != NULL;
190 joint = mChildren.getNextData() )
191 {
192 removeChild(joint);
193 }
194}
195
196
197//--------------------------------------------------------------------
198// getPosition()
199//--------------------------------------------------------------------
200const LLVector3& LLJoint::getPosition()
201{
202 return mXform.getPosition();
203}
204
205
206//--------------------------------------------------------------------
207// setPosition()
208//--------------------------------------------------------------------
209void LLJoint::setPosition( const LLVector3& pos )
210{
211 mXform.setPosition(pos);
212 touch(MATRIX_DIRTY | POSITION_DIRTY);
213}
214
215
216//--------------------------------------------------------------------
217// getWorldPosition()
218//--------------------------------------------------------------------
219LLVector3 LLJoint::getWorldPosition()
220{
221 updateWorldPRSParent();
222 return mXform.getWorldPosition();
223}
224
225//-----------------------------------------------------------------------------
226// getLastWorldPosition()
227//-----------------------------------------------------------------------------
228LLVector3 LLJoint::getLastWorldPosition()
229{
230 return mXform.getWorldPosition();
231}
232
233
234//--------------------------------------------------------------------
235// setWorldPosition()
236//--------------------------------------------------------------------
237void LLJoint::setWorldPosition( const LLVector3& pos )
238{
239 if (mParent == NULL)
240 {
241 this->setPosition( pos );
242 return;
243 }
244
245 LLMatrix4 temp_matrix = getWorldMatrix();
246 temp_matrix.mMatrix[VW][VX] = pos.mV[VX];
247 temp_matrix.mMatrix[VW][VY] = pos.mV[VY];
248 temp_matrix.mMatrix[VW][VZ] = pos.mV[VZ];
249
250 LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix();
251 LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert();
252
253 temp_matrix *= invParentWorldMatrix;
254
255 LLVector3 localPos( temp_matrix.mMatrix[VW][VX],
256 temp_matrix.mMatrix[VW][VY],
257 temp_matrix.mMatrix[VW][VZ] );
258
259 setPosition( localPos );
260}
261
262
263//--------------------------------------------------------------------
264// mXform.getRotation()
265//--------------------------------------------------------------------
266const LLQuaternion& LLJoint::getRotation()
267{
268 return mXform.getRotation();
269}
270
271
272//--------------------------------------------------------------------
273// setRotation()
274//--------------------------------------------------------------------
275void LLJoint::setRotation( const LLQuaternion& rot )
276{
277 if (rot.isFinite())
278 {
279 mXform.setRotation(rot);
280 touch(MATRIX_DIRTY | ROTATION_DIRTY);
281 }
282}
283
284
285//--------------------------------------------------------------------
286// getWorldRotation()
287//--------------------------------------------------------------------
288LLQuaternion LLJoint::getWorldRotation()
289{
290 updateWorldPRSParent();
291
292 return mXform.getWorldRotation();
293}
294
295//-----------------------------------------------------------------------------
296// getLastWorldRotation()
297//-----------------------------------------------------------------------------
298LLQuaternion LLJoint::getLastWorldRotation()
299{
300 return mXform.getWorldRotation();
301}
302
303//--------------------------------------------------------------------
304// setWorldRotation()
305//--------------------------------------------------------------------
306void LLJoint::setWorldRotation( const LLQuaternion& rot )
307{
308 if (mParent == NULL)
309 {
310 this->setRotation( rot );
311 return;
312 }
313
314 LLMatrix4 temp_mat(rot);
315
316 LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix();
317 parentWorldMatrix.mMatrix[VW][VX] = 0;
318 parentWorldMatrix.mMatrix[VW][VY] = 0;
319 parentWorldMatrix.mMatrix[VW][VZ] = 0;
320
321 LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert();
322
323 temp_mat *= invParentWorldMatrix;
324
325 setRotation(LLQuaternion(temp_mat));
326}
327
328
329//--------------------------------------------------------------------
330// getScale()
331//--------------------------------------------------------------------
332const LLVector3& LLJoint::getScale()
333{
334 return mXform.getScale();
335}
336
337//--------------------------------------------------------------------
338// setScale()
339//--------------------------------------------------------------------
340void LLJoint::setScale( const LLVector3& scale )
341{
342 mXform.setScale(scale);
343 touch();
344}
345
346
347
348//--------------------------------------------------------------------
349// getWorldMatrix()
350//--------------------------------------------------------------------
351const LLMatrix4 &LLJoint::getWorldMatrix()
352{
353 updateWorldMatrixParent();
354
355 return mXform.getWorldMatrix();
356}
357
358
359//--------------------------------------------------------------------
360// setWorldMatrix()
361//--------------------------------------------------------------------
362void LLJoint::setWorldMatrix( const LLMatrix4& mat )
363{
364llinfos << "WARNING: LLJoint::setWorldMatrix() not correctly implemented yet" << llendl;
365 // extract global translation
366 LLVector3 trans( mat.mMatrix[VW][VX],
367 mat.mMatrix[VW][VY],
368 mat.mMatrix[VW][VZ] );
369
370 // extract global rotation
371 LLQuaternion rot( mat );
372
373 setWorldPosition( trans );
374 setWorldRotation( rot );
375}
376
377//-----------------------------------------------------------------------------
378// updateWorldMatrixParent()
379//-----------------------------------------------------------------------------
380void LLJoint::updateWorldMatrixParent()
381{
382 if (mDirtyFlags & MATRIX_DIRTY)
383 {
384 LLJoint *parent = getParent();
385 if (parent)
386 {
387 parent->updateWorldMatrixParent();
388 }
389 updateWorldMatrix();
390 }
391}
392
393//-----------------------------------------------------------------------------
394// updateWorldPRSParent()
395//-----------------------------------------------------------------------------
396void LLJoint::updateWorldPRSParent()
397{
398 if (mDirtyFlags & (ROTATION_DIRTY | POSITION_DIRTY))
399 {
400 LLJoint *parent = getParent();
401 if (parent)
402 {
403 parent->updateWorldPRSParent();
404 }
405
406 mXform.update();
407 mDirtyFlags &= ~(ROTATION_DIRTY | POSITION_DIRTY);
408 }
409}
410
411//-----------------------------------------------------------------------------
412// updateWorldMatrixChildren()
413//-----------------------------------------------------------------------------
414void LLJoint::updateWorldMatrixChildren()
415{
416 if (mDirtyFlags & MATRIX_DIRTY)
417 {
418 updateWorldMatrix();
419 }
420 for (LLJoint *child = mChildren.getFirstData(); child; child = mChildren.getNextData())
421 {
422 child->updateWorldMatrixChildren();
423 }
424}
425
426//-----------------------------------------------------------------------------
427// updateWorldMatrix()
428//-----------------------------------------------------------------------------
429void LLJoint::updateWorldMatrix()
430{
431 if (mDirtyFlags & MATRIX_DIRTY)
432 {
433 sNumUpdates++;
434 mXform.updateMatrix(FALSE);
435 mDirtyFlags = 0x0;
436 }
437}
438
439//--------------------------------------------------------------------
440// getSkinOffset()
441//--------------------------------------------------------------------
442const LLVector3 &LLJoint::getSkinOffset()
443{
444 return mSkinOffset;
445}
446
447
448//--------------------------------------------------------------------
449// setSkinOffset()
450//--------------------------------------------------------------------
451void LLJoint::setSkinOffset( const LLVector3& offset )
452{
453 mSkinOffset = offset;
454}
455
456//-----------------------------------------------------------------------------
457// setConstraintSilhouette()
458//-----------------------------------------------------------------------------
459void LLJoint::setConstraintSilhouette(LLDynamicArray<LLVector3>& silhouette)
460{
461 S32 i;
462
463 mConstraintSilhouette.reset();
464 for (i = 0; i < silhouette.count(); i++)
465 {
466 if (i % 2 == 1)
467 {
468 // skip normals
469 continue;
470 }
471 mConstraintSilhouette[i / 2] = silhouette[i];
472 }
473 LLQuaternion inv_parent_rotation = LLQuaternion::DEFAULT;
474
475 if (getParent())
476 {
477 inv_parent_rotation = ~getParent()->getWorldRotation();
478 }
479
480 for (i = 0; i < mConstraintSilhouette.count(); i++)
481 {
482 LLVector3 vert = mConstraintSilhouette[i];
483
484 vert -= getWorldPosition();
485 vert.normVec();
486 vert = vert * inv_parent_rotation;
487 }
488}
489
490//-----------------------------------------------------------------------------
491// clampRotation()
492//-----------------------------------------------------------------------------
493void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot)
494{
495 LLVector3 main_axis(1.f, 0.f, 0.f);
496
497 for (LLJoint* joint = mChildren.getFirstData(); joint; joint = mChildren.getNextData())
498 {
499 if (joint->isAnimatable())
500 {
501 main_axis = joint->getPosition();
502 main_axis.normVec();
503 // only care about first animatable child
504 break;
505 }
506 }
507
508 // 2003.03.26 - This code was just using up cpu cycles. AB
509
510// LLVector3 old_axis = main_axis * old_rot;
511// LLVector3 new_axis = main_axis * new_rot;
512
513// for (S32 i = 0; i < mConstraintSilhouette.count() - 1; i++)
514// {
515// LLVector3 vert1 = mConstraintSilhouette[i];
516// LLVector3 vert2 = mConstraintSilhouette[i + 1];
517
518 // figure out how to clamp rotation to line on 3-sphere
519
520// }
521}
522
523// End
diff --git a/linden/indra/llcharacter/lljoint.h b/linden/indra/llcharacter/lljoint.h
new file mode 100644
index 0000000..15b82c2
--- /dev/null
+++ b/linden/indra/llcharacter/lljoint.h
@@ -0,0 +1,182 @@
1/**
2 * @file lljoint.h
3 * @brief Implementation of LLJoint 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#ifndef LL_LLJOINT_H
29#define LL_LLJOINT_H
30
31//-----------------------------------------------------------------------------
32// Header Files
33//-----------------------------------------------------------------------------
34#include <string>
35
36#include "linked_lists.h"
37#include "v3math.h"
38#include "v4math.h"
39#include "m4math.h"
40#include "llquaternion.h"
41#include "xform.h"
42#include "lldarray.h"
43
44const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15;
45const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4!
46const U32 LL_HAND_JOINT_NUM = 31;
47const U32 LL_FACE_JOINT_NUM = 30;
48const S32 LL_CHARACTER_MAX_PRIORITY = 7;
49const F32 LL_MAX_PELVIS_OFFSET = 5.f;
50
51//-----------------------------------------------------------------------------
52// class LLJoint
53//-----------------------------------------------------------------------------
54class LLJoint
55{
56public:
57 // priority levels, from highest to lowest
58 enum JointPriority
59 {
60 USE_MOTION_PRIORITY = -1,
61 LOW_PRIORITY = 0,
62 MEDIUM_PRIORITY,
63 HIGH_PRIORITY,
64 HIGHER_PRIORITY,
65 HIGHEST_PRIORITY,
66 ADDITIVE_PRIORITY = LL_CHARACTER_MAX_PRIORITY
67 };
68
69 enum DirtyFlags
70 {
71 MATRIX_DIRTY = 0x1 << 0,
72 ROTATION_DIRTY = 0x1 << 1,
73 POSITION_DIRTY = 0x1 << 2,
74 ALL_DIRTY = 0x7
75 };
76protected:
77 std::string mName;
78
79 // parent joint
80 LLJoint *mParent;
81
82 // explicit transformation members
83 LLXformMatrix mXform;
84
85public:
86 U32 mDirtyFlags;
87 BOOL mWorldRotationDirty;
88 BOOL mUpdateXform;
89
90 // describes the skin binding pose
91 LLVector3 mSkinOffset;
92
93 S32 mJointNum;
94
95 LLDynamicArray<LLVector3> mConstraintSilhouette;
96
97 // child joints
98 LLLinkedList<LLJoint> mChildren;
99
100 // debug statics
101 static S32 sNumTouches;
102 static S32 sNumUpdates;
103
104public:
105 LLJoint();
106 LLJoint( const std::string &name, LLJoint *parent=NULL );
107
108 virtual ~LLJoint();
109
110 // set name and parent
111 void setup( const std::string &name, LLJoint *parent=NULL );
112
113 void touch(U32 flags = ALL_DIRTY);
114
115 // get/set name
116 const std::string &getName() { return mName; }
117 void setName( const std::string &name ) { mName = name; }
118
119 // getParent
120 LLJoint *getParent() { return mParent; }
121
122 // getRoot
123 LLJoint *getRoot();
124
125 // search for child joints by name
126 LLJoint *findJoint( const std::string &name );
127
128 // add/remove children
129 void addChild( LLJoint *joint );
130 void removeChild( LLJoint *joint );
131 void removeAllChildren();
132
133 // get/set local position
134 const LLVector3& getPosition();
135 void setPosition( const LLVector3& pos );
136
137 // get/set world position
138 LLVector3 getWorldPosition();
139 LLVector3 getLastWorldPosition();
140 void setWorldPosition( const LLVector3& pos );
141
142 // get/set local rotation
143 const LLQuaternion& getRotation();
144 void setRotation( const LLQuaternion& rot );
145
146 // get/set world rotation
147 LLQuaternion getWorldRotation();
148 LLQuaternion getLastWorldRotation();
149 void setWorldRotation( const LLQuaternion& rot );
150
151 // get/set local scale
152 const LLVector3& getScale();
153 void setScale( const LLVector3& scale );
154
155 // get/set world matrix
156 const LLMatrix4 &getWorldMatrix();
157 void setWorldMatrix( const LLMatrix4& mat );
158
159 void updateWorldMatrixChildren();
160 void updateWorldMatrixParent();
161
162 void updateWorldPRSParent();
163
164 void updateWorldMatrix();
165
166 // get/set skin offset
167 const LLVector3 &getSkinOffset();
168 void setSkinOffset( const LLVector3 &offset);
169
170 LLXformMatrix *getXform() { return &mXform; }
171
172 void setConstraintSilhouette(LLDynamicArray<LLVector3>& silhouette);
173
174 void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot);
175
176 virtual BOOL isAnimatable() { return TRUE; }
177
178 S32 getJointNum() { return mJointNum; }
179 void setJointNum(S32 joint_num) { mJointNum = joint_num; }
180};
181#endif // LL_LLJOINT_H
182
diff --git a/linden/indra/llcharacter/lljointsolverrp3.cpp b/linden/indra/llcharacter/lljointsolverrp3.cpp
new file mode 100644
index 0000000..2221a53
--- /dev/null
+++ b/linden/indra/llcharacter/lljointsolverrp3.cpp
@@ -0,0 +1,385 @@
1/**
2 * @file lljointsolverrp3.cpp
3 * @brief Implementation of LLJointSolverRP3 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 "lljointsolverrp3.h"
34
35#include <math.h>
36
37#include "llmath.h"
38
39#define F_EPSILON 0.00001f
40
41
42//-----------------------------------------------------------------------------
43// Constructor
44//-----------------------------------------------------------------------------
45LLJointSolverRP3::LLJointSolverRP3()
46{
47 mJointA = NULL;
48 mJointB = NULL;
49 mJointC = NULL;
50 mJointGoal = NULL;
51 mLengthAB = 1.0f;
52 mLengthBC = 1.0f;
53 mPoleVector.setVec( 1.0f, 0.0f, 0.0f );
54 mbUseBAxis = FALSE;
55 mTwist = 0.0f;
56 mFirstTime = TRUE;
57}
58
59
60//-----------------------------------------------------------------------------
61// Destructor
62//-----------------------------------------------------------------------------
63/*virtual*/ LLJointSolverRP3::~LLJointSolverRP3()
64{
65}
66
67
68//-----------------------------------------------------------------------------
69// setupJoints()
70//-----------------------------------------------------------------------------
71void LLJointSolverRP3::setupJoints( LLJoint* jointA,
72 LLJoint* jointB,
73 LLJoint* jointC,
74 LLJoint* jointGoal )
75{
76 mJointA = jointA;
77 mJointB = jointB;
78 mJointC = jointC;
79 mJointGoal = jointGoal;
80
81 mLengthAB = mJointB->getPosition().magVec();
82 mLengthBC = mJointC->getPosition().magVec();
83
84 mJointABaseRotation = jointA->getRotation();
85 mJointBBaseRotation = jointB->getRotation();
86}
87
88
89//-----------------------------------------------------------------------------
90// getPoleVector()
91//-----------------------------------------------------------------------------
92const LLVector3& LLJointSolverRP3::getPoleVector()
93{
94 return mPoleVector;
95}
96
97
98//-----------------------------------------------------------------------------
99// setPoleVector()
100//-----------------------------------------------------------------------------
101void LLJointSolverRP3::setPoleVector( const LLVector3& poleVector )
102{
103 mPoleVector = poleVector;
104 mPoleVector.normVec();
105}
106
107
108//-----------------------------------------------------------------------------
109// setPoleVector()
110//-----------------------------------------------------------------------------
111void LLJointSolverRP3::setBAxis( const LLVector3& bAxis )
112{
113 mBAxis = bAxis;
114 mBAxis.normVec();
115 mbUseBAxis = TRUE;
116}
117
118//-----------------------------------------------------------------------------
119// getTwist()
120//-----------------------------------------------------------------------------
121F32 LLJointSolverRP3::getTwist()
122{
123 return mTwist;
124}
125
126
127//-----------------------------------------------------------------------------
128// setTwist()
129//-----------------------------------------------------------------------------
130void LLJointSolverRP3::setTwist( F32 twist )
131{
132 mTwist = twist;
133}
134
135
136//-----------------------------------------------------------------------------
137// solve()
138//-----------------------------------------------------------------------------
139void LLJointSolverRP3::solve()
140{
141// llinfos << llendl;
142// llinfos << "LLJointSolverRP3::solve()" << llendl;
143
144 //-------------------------------------------------------------------------
145 // setup joints in their base rotations
146 //-------------------------------------------------------------------------
147 mJointA->setRotation( mJointABaseRotation );
148 mJointB->setRotation( mJointBBaseRotation );
149
150 //-------------------------------------------------------------------------
151 // get joint positions in world space
152 //-------------------------------------------------------------------------
153 LLVector3 aPos = mJointA->getWorldPosition();
154 LLVector3 bPos = mJointB->getWorldPosition();
155 LLVector3 cPos = mJointC->getWorldPosition();
156 LLVector3 gPos = mJointGoal->getWorldPosition();
157
158// llinfos << "bPosLocal = " << mJointB->getPosition() << llendl;
159// llinfos << "cPosLocal = " << mJointC->getPosition() << llendl;
160// llinfos << "bRotLocal = " << mJointB->getRotation() << llendl;
161// llinfos << "cRotLocal = " << mJointC->getRotation() << llendl;
162
163// llinfos << "aPos : " << aPos << llendl;
164// llinfos << "bPos : " << bPos << llendl;
165// llinfos << "cPos : " << cPos << llendl;
166// llinfos << "gPos : " << gPos << llendl;
167
168 //-------------------------------------------------------------------------
169 // get the poleVector in world space
170 //-------------------------------------------------------------------------
171 LLMatrix4 worldJointAParentMat;
172 if ( mJointA->getParent() )
173 {
174 worldJointAParentMat = mJointA->getParent()->getWorldMatrix();
175 }
176 LLVector3 poleVec = rotate_vector( mPoleVector, worldJointAParentMat );
177
178 //-------------------------------------------------------------------------
179 // compute the following:
180 // vector from A to B
181 // vector from B to C
182 // vector from A to C
183 // vector from A to G (goal)
184 //-------------------------------------------------------------------------
185 LLVector3 abVec = bPos - aPos;
186 LLVector3 bcVec = cPos - bPos;
187 LLVector3 acVec = cPos - aPos;
188 LLVector3 agVec = gPos - aPos;
189
190// llinfos << "abVec : " << abVec << llendl;
191// llinfos << "bcVec : " << bcVec << llendl;
192// llinfos << "acVec : " << acVec << llendl;
193// llinfos << "agVec : " << agVec << llendl;
194
195 //-------------------------------------------------------------------------
196 // compute needed lengths of those vectors
197 //-------------------------------------------------------------------------
198 F32 abLen = abVec.magVec();
199 F32 bcLen = bcVec.magVec();
200 F32 agLen = agVec.magVec();
201
202// llinfos << "abLen : " << abLen << llendl;
203// llinfos << "bcLen : " << bcLen << llendl;
204// llinfos << "agLen : " << agLen << llendl;
205
206 //-------------------------------------------------------------------------
207 // compute component vector of (A->B) orthogonal to (A->C)
208 //-------------------------------------------------------------------------
209 LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
210
211// llinfos << "abacCompOrthoVec : " << abacCompOrthoVec << llendl
212
213 //-------------------------------------------------------------------------
214 // compute the normal of the original ABC plane (and store for later)
215 //-------------------------------------------------------------------------
216 LLVector3 abcNorm;
217 if (!mbUseBAxis)
218 {
219 if( are_parallel(abVec, bcVec, 0.001f) )
220 {
221 // the current solution is maxed out, so we use the axis that is
222 // orthogonal to both poleVec and A->B
223 if ( are_parallel(poleVec, abVec, 0.001f) )
224 {
225 // ACK! the problem is singular
226 if ( are_parallel(poleVec, agVec, 0.001f) )
227 {
228 // the solutions is also singular
229 return;
230 }
231 else
232 {
233 abcNorm = poleVec % agVec;
234 }
235 }
236 else
237 {
238 abcNorm = poleVec % abVec;
239 }
240 }
241 else
242 {
243 abcNorm = abVec % bcVec;
244 }
245 }
246 else
247 {
248 abcNorm = mBAxis * mJointB->getWorldRotation();
249 }
250
251 //-------------------------------------------------------------------------
252 // compute rotation of B
253 //-------------------------------------------------------------------------
254 // angle between A->B and B->C
255 F32 abbcAng = angle_between(abVec, bcVec);
256
257 // vector orthogonal to A->B and B->C
258 LLVector3 abbcOrthoVec = abVec % bcVec;
259 if (abbcOrthoVec.magVecSquared() < 0.001f)
260 {
261 abbcOrthoVec = poleVec % abVec;
262 abacCompOrthoVec = poleVec;
263 }
264 abbcOrthoVec.normVec();
265
266 F32 agLenSq = agLen * agLen;
267
268 // angle arm for extension
269 F32 cosTheta = (agLenSq - abLen*abLen - bcLen*bcLen) / (2.0f * abLen * bcLen);
270 if (cosTheta > 1.0f)
271 cosTheta = 1.0f;
272 else if (cosTheta < -1.0f)
273 cosTheta = -1.0f;
274
275 F32 theta = acos(cosTheta);
276
277 LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
278
279// llinfos << "abbcAng : " << abbcAng << llendl;
280// llinfos << "abbcOrthoVec : " << abbcOrthoVec << llendl;
281// llinfos << "agLenSq : " << agLenSq << llendl;
282// llinfos << "cosTheta : " << cosTheta << llendl;
283// llinfos << "theta : " << theta << llendl;
284// llinfos << "bRot : " << bRot << llendl;
285// llinfos << "theta abbcAng theta-abbcAng: " << theta*180.0/F_PI << " " << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << llendl;
286
287 //-------------------------------------------------------------------------
288 // compute rotation that rotates new A->C to A->G
289 //-------------------------------------------------------------------------
290 // rotate B->C by bRot
291 bcVec = bcVec * bRot;
292
293 // update A->C
294 acVec = abVec + bcVec;
295
296 LLQuaternion cgRot;
297 cgRot.shortestArc( acVec, agVec );
298
299// llinfos << "bcVec : " << bcVec << llendl;
300// llinfos << "acVec : " << acVec << llendl;
301// llinfos << "cgRot : " << cgRot << llendl;
302
303 // update A->B and B->C with rotation from C to G
304 abVec = abVec * cgRot;
305 bcVec = bcVec * cgRot;
306 abcNorm = abcNorm * cgRot;
307 acVec = abVec + bcVec;
308
309 //-------------------------------------------------------------------------
310 // compute the normal of the APG plane
311 //-------------------------------------------------------------------------
312 if (are_parallel(agVec, poleVec, 0.001f))
313 {
314 // the solution plane is undefined ==> we're done
315 return;
316 }
317 LLVector3 apgNorm = poleVec % agVec;
318 apgNorm.normVec();
319
320 if (!mbUseBAxis)
321 {
322 //---------------------------------------------------------------------
323 // compute the normal of the new ABC plane
324 // (only necessary if we're NOT using mBAxis)
325 //---------------------------------------------------------------------
326 if( are_parallel(abVec, bcVec, 0.001f) )
327 {
328 // G is either too close or too far away
329 // we'll use the old ABCnormal
330 }
331 else
332 {
333 abcNorm = abVec % bcVec;
334 }
335 abcNorm.normVec();
336 }
337
338 //-------------------------------------------------------------------------
339 // calcuate plane rotation
340 //-------------------------------------------------------------------------
341 LLQuaternion pRot;
342 if ( are_parallel( abcNorm, apgNorm, 0.001f) )
343 {
344 if (abcNorm * apgNorm < 0.0f)
345 {
346 // we must be PI radians off ==> rotate by PI around agVec
347 pRot.setQuat(F_PI, agVec);
348 }
349 else
350 {
351 // we're done
352 }
353 }
354 else
355 {
356 pRot.shortestArc( abcNorm, apgNorm );
357 }
358
359// llinfos << "abcNorm = " << abcNorm << llendl;
360// llinfos << "apgNorm = " << apgNorm << llendl;
361// llinfos << "pRot = " << pRot << llendl;
362
363 //-------------------------------------------------------------------------
364 // compute twist rotation
365 //-------------------------------------------------------------------------
366 LLQuaternion twistRot( mTwist, agVec );
367
368// llinfos << "twist : " << mTwist*180.0/F_PI << llendl;
369// llinfos << "agNormVec: " << agNormVec << llendl;
370// llinfos << "twistRot : " << twistRot << llendl;
371
372 //-------------------------------------------------------------------------
373 // compute rotation of A
374 //-------------------------------------------------------------------------
375 LLQuaternion aRot = cgRot * pRot * twistRot;
376
377 //-------------------------------------------------------------------------
378 // apply the rotations
379 //-------------------------------------------------------------------------
380 mJointB->setWorldRotation( mJointB->getWorldRotation() * bRot );
381 mJointA->setWorldRotation( mJointA->getWorldRotation() * aRot );
382}
383
384
385// End
diff --git a/linden/indra/llcharacter/lljointsolverrp3.h b/linden/indra/llcharacter/lljointsolverrp3.h
new file mode 100644
index 0000000..7dd35eb
--- /dev/null
+++ b/linden/indra/llcharacter/lljointsolverrp3.h
@@ -0,0 +1,177 @@
1/**
2 * @file lljointsolverrp3.h
3 * @brief Implementation of LLJointSolverRP3 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#ifndef LL_LLJOINTSOLVERRP3_H
29#define LL_LLJOINTSOLVERRP3_H
30
31//-----------------------------------------------------------------------------
32// Header Files
33//-----------------------------------------------------------------------------
34#include "lljoint.h"
35
36/* -some compilers don't like line continuation chars-
37//-----------------------------------------------------------------------------
38// class LLJointSolverRP3
39//
40// This class is a "poor man's" IK for simple 3 joint kinematic chains.
41// It is modeled after the 'ikRPSolver' in Maya.
42// This class takes 4 LLJoints:
43// jointA
44// jointB
45// jointC
46// jointGoal
47//
48// Such that jointA is the parent of jointB, jointB is the parent of jointC.
49// When invoked, this class modifies the rotations of jointA and jointB such
50// that the position of the jointC attempts to reach the position of jointGoal.
51//
52// At object initialization time, the distances between jointA - jointB and
53// jointB - jointC are cached. During evaluation these bone lengths are
54// preserved.
55//
56// A A
57// | |
58// | |
59// B B---CG A---B---C...G
60// \
61// \
62// CG
63//
64//
65// In addition a "poleVector" is specified that does two things:
66//
67// a) defines the plane in which the solution occurs, thus
68// reducing an infinite number of solutions, down to 2.
69//
70// b) disambiguates the resulting two solutions as follows:
71//
72// A A A--->poleVector
73// | \ \
74// | \ \
75// B vs. B ==> B
76// \ | |
77// \ | |
78// CG CG CG
79//
80// A "twist" setting allows the solution plane to be rotated about the
81// line between A and C. A handy animation feature.
82//
83// For "smarter" results for non-coplanar limbs, specify the joints axis
84// of bend in the B's local frame (see setBAxis())
85//-----------------------------------------------------------------------------
86*/
87
88class LLJointSolverRP3
89{
90protected:
91 LLJoint *mJointA;
92 LLJoint *mJointB;
93 LLJoint *mJointC;
94 LLJoint *mJointGoal;
95
96 F32 mLengthAB;
97 F32 mLengthBC;
98
99 LLVector3 mPoleVector;
100 LLVector3 mBAxis;
101 BOOL mbUseBAxis;
102
103 F32 mTwist;
104
105 BOOL mFirstTime;
106 LLMatrix4 mSavedJointAMat;
107 LLMatrix4 mSavedInvPlaneMat;
108
109 LLQuaternion mJointABaseRotation;
110 LLQuaternion mJointBBaseRotation;
111
112public:
113 //-------------------------------------------------------------------------
114 // Constructor/Destructor
115 //-------------------------------------------------------------------------
116 LLJointSolverRP3();
117 virtual ~LLJointSolverRP3();
118
119 //-------------------------------------------------------------------------
120 // setupJoints()
121 // This must be called one time to setup the solver.
122 // This must be called AFTER the skeleton has been created, all parent/child
123 // relationships are established, and after the joints are placed in
124 // a valid configuration (as distances between them will be cached).
125 //-------------------------------------------------------------------------
126 void setupJoints( LLJoint* jointA,
127 LLJoint* jointB,
128 LLJoint* jointC,
129 LLJoint* jointGoal );
130
131 //-------------------------------------------------------------------------
132 // getPoleVector()
133 // Returns the current pole vector.
134 //-------------------------------------------------------------------------
135 const LLVector3& getPoleVector();
136
137 //-------------------------------------------------------------------------
138 // setPoleVector()
139 // Sets the pole vector.
140 // The pole vector is defined relative to (in the space of) jointA's parent.
141 // The default pole vector is (1,0,0), and this is used if this function
142 // is never called.
143 // This vector is normalized when set.
144 //-------------------------------------------------------------------------
145 void setPoleVector( const LLVector3& poleVector );
146
147 //-------------------------------------------------------------------------
148 // setBAxis()
149 // Sets the joint's axis in B's local frame, and enable "smarter" solve().
150 // This allows for smarter IK when for twisted limbs.
151 //-------------------------------------------------------------------------
152 void setBAxis( const LLVector3& bAxis );
153
154 //-------------------------------------------------------------------------
155 // getTwist()
156 // Returns the current twist in radians.
157 //-------------------------------------------------------------------------
158 F32 getTwist();
159
160 //-------------------------------------------------------------------------
161 // setTwist()
162 // Sets the twist value.
163 // The default is 0.0.
164 //-------------------------------------------------------------------------
165 void setTwist( F32 twist );
166
167 //-------------------------------------------------------------------------
168 // solve()
169 // This is the "work" function.
170 // When called, the rotations of jointA and jointB will be modified
171 // such that jointC attempts to reach jointGoal.
172 //-------------------------------------------------------------------------
173 void solve();
174};
175
176#endif // LL_LLJOINTSOLVERRP3_H
177
diff --git a/linden/indra/llcharacter/lljointstate.h b/linden/indra/llcharacter/lljointstate.h
new file mode 100644
index 0000000..7fef28a
--- /dev/null
+++ b/linden/indra/llcharacter/lljointstate.h
@@ -0,0 +1,125 @@
1/**
2 * @file lljointstate.h
3 * @brief Implementation of LLJointState 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#ifndef LL_LLJOINTSTATE_H
29#define LL_LLJOINTSTATE_H
30
31//-----------------------------------------------------------------------------
32// Header Files
33//-----------------------------------------------------------------------------
34#include "lljoint.h"
35
36//-----------------------------------------------------------------------------
37// class LLJointState
38//-----------------------------------------------------------------------------
39class LLJointState
40{
41public:
42 enum BlendPhase
43 {
44 INACTIVE,
45 EASE_IN,
46 ACTIVE,
47 EASE_OUT
48 };
49protected:
50 // associated joint
51 LLJoint *mJoint;
52
53 // indicates which members are used
54 U32 mUsage;
55
56 // indicates weighted effect of this joint
57 F32 mWeight;
58
59 // transformation members
60 LLVector3 mPosition; // position relative to parent joint
61 LLQuaternion mRotation; // joint rotation relative to parent joint
62 LLVector3 mScale; // scale relative to rotated frame
63 LLJoint::JointPriority mPriority; // how important this joint state is relative to others
64public:
65 // Constructor
66 LLJointState()
67 {
68 mUsage = 0;
69 mJoint = NULL;
70 mUsage = 0;
71 mWeight = 0.f;
72 mPriority = LLJoint::USE_MOTION_PRIORITY;
73 }
74
75 LLJointState(LLJoint* joint)
76 {
77 mUsage = 0;
78 mJoint = joint;
79 mUsage = 0;
80 mWeight = 0.f;
81 mPriority = LLJoint::USE_MOTION_PRIORITY;
82 }
83
84 // Destructor
85 virtual ~LLJointState()
86 {
87 }
88
89 // joint that this state is applied to
90 LLJoint *getJoint() { return mJoint; }
91 BOOL setJoint( LLJoint *joint ) { mJoint = joint; return mJoint != NULL; }
92
93 // transform type (bitwise flags can be combined)
94 // Note that these are set automatically when various
95 // member setPos/setRot/setScale functions are called.
96 enum Usage
97 {
98 POS = 1,
99 ROT = 2,
100 SCALE = 4,
101 };
102 U32 getUsage() { return mUsage; }
103 void setUsage( U32 usage ) { mUsage = usage; }
104 F32 getWeight() { return mWeight; }
105 void setWeight( F32 weight ) { mWeight = weight; }
106
107 // get/set position
108 const LLVector3& getPosition() { return mPosition; }
109 void setPosition( const LLVector3& pos ) { llassert(mUsage & POS); mPosition = pos; }
110
111 // get/set rotation
112 const LLQuaternion& getRotation() { return mRotation; }
113 void setRotation( const LLQuaternion& rot ) { llassert(mUsage & ROT); mRotation = rot; }
114
115 // get/set scale
116 const LLVector3& getScale() { return mScale; }
117 void setScale( const LLVector3& scale ) { llassert(mUsage & SCALE); mScale = scale; }
118
119 // get/set priority
120 const LLJoint::JointPriority getPriority() { return mPriority; }
121 void setPriority( const LLJoint::JointPriority priority ) { mPriority = priority; }
122};
123
124#endif // LL_LLJOINTSTATE_H
125
diff --git a/linden/indra/llcharacter/llkeyframefallmotion.cpp b/linden/indra/llcharacter/llkeyframefallmotion.cpp
new file mode 100644
index 0000000..2fca225
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframefallmotion.cpp
@@ -0,0 +1,142 @@
1/**
2 * @file llkeyframefallmotion.cpp
3 * @brief Implementation of LLKeyframeFallMotion 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 "llkeyframefallmotion.h"
34#include "llcharacter.h"
35#include "m3math.h"
36
37//-----------------------------------------------------------------------------
38// Macros
39//-----------------------------------------------------------------------------
40#define GO_TO_KEY_POSE 1
41#define MIN_TRACK_SPEED 0.01f
42
43//-----------------------------------------------------------------------------
44// LLKeyframeFallMotion()
45// Class Constructor
46//-----------------------------------------------------------------------------
47LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id)
48{
49 mVelocityZ = 0.f;
50 mCharacter = NULL;
51}
52
53
54//-----------------------------------------------------------------------------
55// ~LLKeyframeFallMotion()
56// Class Destructor
57//-----------------------------------------------------------------------------
58LLKeyframeFallMotion::~LLKeyframeFallMotion()
59{
60}
61
62
63//-----------------------------------------------------------------------------
64// LLKeyframeFallMotion::onInitialize()
65//-----------------------------------------------------------------------------
66LLMotion::LLMotionInitStatus LLKeyframeFallMotion::onInitialize(LLCharacter *character)
67{
68 // save character pointer for later use
69 mCharacter = character;
70
71 // load keyframe data, setup pose and joint states
72 LLMotion::LLMotionInitStatus result = LLKeyframeMotion::onInitialize(character);
73
74 for (U32 jm=0; jm<mJointMotionList->mNumJointMotions; jm++)
75 {
76 if (!mJointStates[jm].getJoint())
77 continue;
78 if (mJointStates[jm].getJoint()->getName() == std::string("mPelvis"))
79 {
80 mPelvisStatep = &mJointStates[jm];
81 }
82 }
83
84 return result;
85}
86
87//-----------------------------------------------------------------------------
88// LLKeyframeFallMotion::onActivate()
89//-----------------------------------------------------------------------------
90BOOL LLKeyframeFallMotion::onActivate()
91{
92 LLVector3 ground_pos;
93 LLVector3 ground_normal;
94 LLQuaternion inverse_pelvis_rot;
95 LLVector3 fwd_axis(1.f, 0.f, 0.f);
96
97 mVelocityZ = -mCharacter->getCharacterVelocity().mV[VZ];
98 mCharacter->getGround( mCharacter->getCharacterPosition(), ground_pos, ground_normal);
99 ground_normal.normVec();
100
101 inverse_pelvis_rot = mCharacter->getCharacterRotation();
102 inverse_pelvis_rot.transQuat();
103
104 // find ground normal in pelvis space
105 ground_normal = ground_normal * inverse_pelvis_rot;
106
107 // calculate new foward axis
108 fwd_axis = fwd_axis - (ground_normal * (ground_normal * fwd_axis));
109 fwd_axis.normVec();
110 mRotationToGroundNormal = LLQuaternion(fwd_axis, ground_normal % fwd_axis, ground_normal);
111
112 return LLKeyframeMotion::onActivate();
113}
114
115//-----------------------------------------------------------------------------
116// LLKeyframeFallMotion::onUpdate()
117//-----------------------------------------------------------------------------
118BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
119{
120 BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
121 F32 slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
122
123 mPelvisStatep->setRotation(mPelvisStatep->getRotation() * slerp(slerp_amt, mRotationToGroundNormal, LLQuaternion()));
124
125 return result;
126}
127
128//-----------------------------------------------------------------------------
129// LLKeyframeFallMotion::getEaseInDuration()
130//-----------------------------------------------------------------------------
131F32 LLKeyframeFallMotion::getEaseInDuration()
132{
133 if (mVelocityZ == 0.f)
134 {
135 // we've already hit the ground
136 return 0.4f;
137 }
138
139 return mCharacter->getPreferredPelvisHeight() / mVelocityZ;
140}
141
142// End
diff --git a/linden/indra/llcharacter/llkeyframefallmotion.h b/linden/indra/llcharacter/llkeyframefallmotion.h
new file mode 100644
index 0000000..ddf4c45
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframefallmotion.h
@@ -0,0 +1,79 @@
1/**
2 * @file llkeyframefallmotion.h
3 * @brief Implementation of LLKeframeWalkMotion 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#ifndef LL_LLKeyframeFallMotion_H
29#define LL_LLKeyframeFallMotion_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llkeyframemotion.h"
35#include "llcharacter.h"
36
37//-----------------------------------------------------------------------------
38// class LLKeyframeFallMotion
39//-----------------------------------------------------------------------------
40class LLKeyframeFallMotion :
41 public LLKeyframeMotion
42{
43public:
44 // Constructor
45 LLKeyframeFallMotion(const LLUUID &id);
46
47 // Destructor
48 virtual ~LLKeyframeFallMotion();
49
50public:
51 //-------------------------------------------------------------------------
52 // functions to support MotionController and MotionRegistry
53 //-------------------------------------------------------------------------
54
55 // static constructor
56 // all subclasses must implement such a function and register it
57 static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); }
58
59public:
60 //-------------------------------------------------------------------------
61 // animation callbacks to be implemented by subclasses
62 //-------------------------------------------------------------------------
63 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
64 virtual BOOL onActivate();
65 virtual F32 getEaseInDuration();
66 virtual BOOL onUpdate(F32 activeTime, U8* joint_mask);
67
68protected:
69 //-------------------------------------------------------------------------
70 // Member Data
71 //-------------------------------------------------------------------------
72 LLCharacter* mCharacter;
73 F32 mVelocityZ;
74 LLJointState* mPelvisStatep;
75 LLQuaternion mRotationToGroundNormal;
76};
77
78#endif // LL_LLKeyframeFallMotion_H
79
diff --git a/linden/indra/llcharacter/llkeyframemotion.cpp b/linden/indra/llcharacter/llkeyframemotion.cpp
new file mode 100644
index 0000000..e5b0d99
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframemotion.cpp
@@ -0,0 +1,2138 @@
1/**
2 * @file llkeyframemotion.cpp
3 * @brief Implementation of LLKeyframeMotion 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 "llmath.h"
34#include "llanimationstates.h"
35#include "llassetstorage.h"
36#include "lldatapacker.h"
37#include "llcharacter.h"
38#include "llcriticaldamp.h"
39#include "lldir.h"
40#include "llendianswizzle.h"
41#include "llkeyframemotion.h"
42#include "llquantize.h"
43#include "llvfile.h"
44#include "m3math.h"
45#include "message.h"
46
47//-----------------------------------------------------------------------------
48// Static Definitions
49//-----------------------------------------------------------------------------
50LLVFS* LLKeyframeMotion::sVFS = NULL;
51LLKeyframeDataCache::LLKeyframeDataMap LLKeyframeDataCache::sKeyframeDataMap;
52
53//-----------------------------------------------------------------------------
54// Globals
55//-----------------------------------------------------------------------------
56static F32 JOINT_LENGTH_K = 0.7f;
57static S32 MAX_ITERATIONS = 20;
58static S32 MIN_ITERATIONS = 1;
59static S32 MIN_ITERATION_COUNT = 2;
60static F32 MAX_PIXEL_AREA_CONSTRAINTS = 80000.f;
61static F32 MIN_PIXEL_AREA_CONSTRAINTS = 1000.f;
62static F32 MIN_ACCELERATION_SQUARED = 0.0005f * 0.0005f;
63
64static F32 MAX_CONSTRAINTS = 10;
65
66//-----------------------------------------------------------------------------
67// JointMotionList::dumpDiagInfo()
68//-----------------------------------------------------------------------------
69U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo()
70{
71 S32 total_size = sizeof(JointMotionList);
72
73 for (U32 i = 0; i < mNumJointMotions; i++)
74 {
75 LLKeyframeMotion::JointMotion* joint_motion_p = &mJointMotionArray[i];
76
77 llinfos << "\tJoint " << joint_motion_p->mJointName << llendl;
78 if (joint_motion_p->mUsage & LLJointState::SCALE)
79 {
80 llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
81 << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl;
82
83 total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey);
84 }
85 if (joint_motion_p->mUsage & LLJointState::ROT)
86 {
87 llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
88 << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl;
89
90 total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey);
91 }
92 if (joint_motion_p->mUsage & LLJointState::POS)
93 {
94 llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
95 << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl;
96
97 total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey);
98 }
99 }
100 llinfos << "Size: " << total_size << " bytes" << llendl;
101
102 return total_size;
103}
104
105//-----------------------------------------------------------------------------
106//-----------------------------------------------------------------------------
107// ****Curve classes
108//-----------------------------------------------------------------------------
109//-----------------------------------------------------------------------------
110
111//-----------------------------------------------------------------------------
112// ScaleCurve::ScaleCurve()
113//-----------------------------------------------------------------------------
114LLKeyframeMotion::ScaleCurve::ScaleCurve()
115{
116 mInterpolationType = LLKeyframeMotion::IT_LINEAR;
117 mNumKeys = 0;
118}
119
120//-----------------------------------------------------------------------------
121// ScaleCurve::~ScaleCurve()
122//-----------------------------------------------------------------------------
123LLKeyframeMotion::ScaleCurve::~ScaleCurve()
124{
125 mKeys.deleteAllData();
126 mNumKeys = 0;
127}
128
129//-----------------------------------------------------------------------------
130// getValue()
131//-----------------------------------------------------------------------------
132LLVector3 LLKeyframeMotion::ScaleCurve::getValue(F32 time, F32 duration)
133{
134 LLVector3 value;
135 F32 index_before, index_after;
136 ScaleKey* scale_before;
137 ScaleKey* scale_after;
138
139 mKeys.getInterval(time, index_before, index_after, scale_before, scale_after);
140 if (scale_before)
141 {
142 if (!scale_after)
143 {
144 scale_after = &mLoopInKey;
145 index_after = duration;
146 }
147
148 if (index_after == index_before)
149 {
150 value = scale_after->mScale;
151 }
152 else
153 {
154 F32 u = (time - index_before) / (index_after - index_before);
155 value = interp(u, *scale_before, *scale_after);
156 }
157 }
158 else
159 {
160 // before first key
161 if (scale_after)
162 {
163 value = scale_after->mScale;
164 }
165 // no keys?
166 else
167 {
168 value.clearVec();
169 }
170 }
171
172 return value;
173}
174
175//-----------------------------------------------------------------------------
176// interp()
177//-----------------------------------------------------------------------------
178LLVector3 LLKeyframeMotion::ScaleCurve::interp(F32 u, ScaleKey& before, ScaleKey& after)
179{
180 switch (mInterpolationType)
181 {
182 case IT_STEP:
183 return before.mScale;
184
185 default:
186 case IT_LINEAR:
187 case IT_SPLINE:
188 return lerp(before.mScale, after.mScale, u);
189 }
190}
191
192//-----------------------------------------------------------------------------
193// RotationCurve::RotationCurve()
194//-----------------------------------------------------------------------------
195LLKeyframeMotion::RotationCurve::RotationCurve()
196{
197 mInterpolationType = LLKeyframeMotion::IT_LINEAR;
198 mNumKeys = 0;
199}
200
201//-----------------------------------------------------------------------------
202// RotationCurve::~RotationCurve()
203//-----------------------------------------------------------------------------
204LLKeyframeMotion::RotationCurve::~RotationCurve()
205{
206 mKeys.deleteAllData();
207 mNumKeys = 0;
208}
209
210//-----------------------------------------------------------------------------
211// RotationCurve::getValue()
212//-----------------------------------------------------------------------------
213LLQuaternion LLKeyframeMotion::RotationCurve::getValue(F32 time, F32 duration)
214{
215 LLQuaternion value;
216 F32 index_before, index_after;
217 RotationKey* rot_before;
218 RotationKey* rot_after;
219
220 mKeys.getInterval(time, index_before, index_after, rot_before, rot_after);
221
222 if (rot_before)
223 {
224 if (!rot_after)
225 {
226 rot_after = &mLoopInKey;
227 index_after = duration;
228 }
229
230 if (index_after == index_before)
231 {
232 value = rot_after->mRotation;
233 }
234 else
235 {
236 F32 u = (time - index_before) / (index_after - index_before);
237 value = interp(u, *rot_before, *rot_after);
238 }
239 }
240 else
241 {
242 // before first key
243 if (rot_after)
244 {
245 value = rot_after->mRotation;
246 }
247 // no keys?
248 else
249 {
250 value = LLQuaternion::DEFAULT;
251 }
252 }
253
254 return value;
255}
256
257//-----------------------------------------------------------------------------
258// interp()
259//-----------------------------------------------------------------------------
260LLQuaternion LLKeyframeMotion::RotationCurve::interp(F32 u, RotationKey& before, RotationKey& after)
261{
262 switch (mInterpolationType)
263 {
264 case IT_STEP:
265 return before.mRotation;
266
267 default:
268 case IT_LINEAR:
269 case IT_SPLINE:
270 return nlerp(u, before.mRotation, after.mRotation);
271 }
272}
273
274
275//-----------------------------------------------------------------------------
276// PositionCurve::PositionCurve()
277//-----------------------------------------------------------------------------
278LLKeyframeMotion::PositionCurve::PositionCurve()
279{
280 mInterpolationType = LLKeyframeMotion::IT_LINEAR;
281 mNumKeys = 0;
282}
283
284//-----------------------------------------------------------------------------
285// PositionCurve::~PositionCurve()
286//-----------------------------------------------------------------------------
287LLKeyframeMotion::PositionCurve::~PositionCurve()
288{
289 mKeys.deleteAllData();
290 mNumKeys = 0;
291}
292
293//-----------------------------------------------------------------------------
294// PositionCurve::getValue()
295//-----------------------------------------------------------------------------
296LLVector3 LLKeyframeMotion::PositionCurve::getValue(F32 time, F32 duration)
297{
298 LLVector3 value;
299 F32 index_before, index_after;
300 PositionKey* pos_before;
301 PositionKey* pos_after;
302
303 mKeys.getInterval(time, index_before, index_after, pos_before, pos_after);
304
305 if (pos_before)
306 {
307 if (!pos_after)
308 {
309 pos_after = &mLoopInKey;
310 index_after = duration;
311 }
312
313 if (index_after == index_before)
314 {
315 value = pos_after->mPosition;
316 }
317 else
318 {
319 F32 u = (time - index_before) / (index_after - index_before);
320 value = interp(u, *pos_before, *pos_after);
321 }
322 }
323 else
324 {
325 // before first key
326 if (pos_after)
327 {
328 value = pos_after->mPosition;
329 }
330 // no keys?
331 else
332 {
333 value.clearVec();
334 }
335 }
336
337 llassert(value.isFinite());
338
339 return value;
340}
341
342//-----------------------------------------------------------------------------
343// interp()
344//-----------------------------------------------------------------------------
345LLVector3 LLKeyframeMotion::PositionCurve::interp(F32 u, PositionKey& before, PositionKey& after)
346{
347 switch (mInterpolationType)
348 {
349 case IT_STEP:
350 return before.mPosition;
351 default:
352 case IT_LINEAR:
353 case IT_SPLINE:
354 return lerp(before.mPosition, after.mPosition, u);
355 }
356}
357
358
359//-----------------------------------------------------------------------------
360//-----------------------------------------------------------------------------
361// JointMotion class
362//-----------------------------------------------------------------------------
363//-----------------------------------------------------------------------------
364
365//-----------------------------------------------------------------------------
366// JointMotion::update()
367//-----------------------------------------------------------------------------
368void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, F32 duration)
369{
370 // this value being 0 is the cause of https://jira.lindenlab.com/browse/SL-22678 but I haven't
371 // managed to get a stack to see how it got here. Testing for 0 here will stop the crash.
372 if ( joint_state == 0 )
373 {
374 return;
375 };
376
377 U32 usage = joint_state->getUsage();
378
379 //-------------------------------------------------------------------------
380 // update scale component of joint state
381 //-------------------------------------------------------------------------
382 if ((usage & LLJointState::SCALE) && mScaleCurve.mNumKeys)
383 {
384 joint_state->setScale( mScaleCurve.getValue( time, duration ) );
385 }
386
387 //-------------------------------------------------------------------------
388 // update rotation component of joint state
389 //-------------------------------------------------------------------------
390 if ((usage & LLJointState::ROT) && mRotationCurve.mNumKeys)
391 {
392 joint_state->setRotation( mRotationCurve.getValue( time, duration ) );
393 }
394
395 //-------------------------------------------------------------------------
396 // update position component of joint state
397 //-------------------------------------------------------------------------
398 if ((usage & LLJointState::POS) && mPositionCurve.mNumKeys)
399 {
400 joint_state->setPosition( mPositionCurve.getValue( time, duration ) );
401 }
402}
403
404
405//-----------------------------------------------------------------------------
406//-----------------------------------------------------------------------------
407// LLKeyframeMotion class
408//-----------------------------------------------------------------------------
409//-----------------------------------------------------------------------------
410
411//-----------------------------------------------------------------------------
412// LLKeyframeMotion()
413// Class Constructor
414//-----------------------------------------------------------------------------
415LLKeyframeMotion::LLKeyframeMotion( const LLUUID &id) : LLMotion(id)
416{
417 mJointMotionList = NULL;
418 mJointStates = NULL;
419 mLastSkeletonSerialNum = 0;
420 mLastLoopedTime = 0.f;
421 mLastUpdateTime = 0.f;
422 mAssetStatus = ASSET_UNDEFINED;
423 mPelvisp = NULL;
424}
425
426
427//-----------------------------------------------------------------------------
428// ~LLKeyframeMotion()
429// Class Destructor
430//-----------------------------------------------------------------------------
431LLKeyframeMotion::~LLKeyframeMotion()
432{
433 if (mJointStates)
434 {
435 delete [] mJointStates;
436 }
437 mConstraints.deleteAllData();
438}
439
440//-----------------------------------------------------------------------------
441// create()
442//-----------------------------------------------------------------------------
443LLMotion *LLKeyframeMotion::create(const LLUUID &id)
444{
445 return new LLKeyframeMotion(id);
446}
447
448//-----------------------------------------------------------------------------
449// LLKeyframeMotion::onInitialize(LLCharacter *character)
450//-----------------------------------------------------------------------------
451LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *character)
452{
453 mCharacter = character;
454
455 LLUUID* character_id;
456
457 // asset already loaded?
458 switch(mAssetStatus)
459 {
460 case ASSET_NEEDS_FETCH:
461 // request asset
462 mAssetStatus = ASSET_FETCHED;
463
464 character_id = new LLUUID(mCharacter->getID());
465 gAssetStorage->getAssetData(mID,
466 LLAssetType::AT_ANIMATION,
467 onLoadComplete,
468 (void *)character_id,
469 FALSE);
470
471 return STATUS_HOLD;
472 case ASSET_FETCHED:
473 return STATUS_HOLD;
474 case ASSET_FETCH_FAILED:
475 return STATUS_FAILURE;
476 case ASSET_LOADED:
477 return STATUS_SUCCESS;
478 default:
479 // we don't know what state the asset is in yet, so keep going
480 // check keyframe cache first then static vfs then asset request
481 break;
482 }
483
484 LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
485
486 if(joint_motion_list)
487 {
488 // motion already existed in cache, so grab it
489 mJointMotionList = joint_motion_list;
490
491 // don't forget to allocate joint states
492 mJointStates = new LLJointState[mJointMotionList->mNumJointMotions];
493
494 // set up joint states to point to character joints
495 for(U32 i = 0; i < mJointMotionList->mNumJointMotions; i++)
496 {
497 if (LLJoint *jointp = mCharacter->getJoint(mJointMotionList->mJointMotionArray[i].mJointName))
498 {
499 mJointStates[i].setJoint(jointp);
500 mJointStates[i].setUsage(mJointMotionList->mJointMotionArray[i].mUsage);
501 mJointStates[i].setPriority(joint_motion_list->mJointMotionArray[i].mPriority);
502 }
503 }
504 mAssetStatus = ASSET_LOADED;
505 setupPose();
506 return STATUS_SUCCESS;
507 }
508
509 //-------------------------------------------------------------------------
510 // Load named file by concatenating the character prefix with the motion name.
511 // Load data into a buffer to be parsed.
512 //-------------------------------------------------------------------------
513 U8 *anim_data;
514 S32 anim_file_size;
515
516 if (!sVFS)
517 {
518 llerrs << "Must call LLKeyframeMotion::setVFS() first before loading a keyframe file!" << llendl;
519 }
520
521 BOOL success = FALSE;
522 LLVFile* anim_file = new LLVFile(sVFS, mID, LLAssetType::AT_ANIMATION);
523 if (!anim_file || !anim_file->getSize())
524 {
525 delete anim_file;
526 anim_file = NULL;
527
528 // request asset over network on next call to load
529 mAssetStatus = ASSET_NEEDS_FETCH;
530
531 return STATUS_HOLD;
532 }
533 else
534 {
535 anim_file_size = anim_file->getSize();
536 anim_data = new U8[anim_file_size];
537 success = anim_file->read(anim_data, anim_file_size); /*Flawfinder: ignore*/
538 delete anim_file;
539 anim_file = NULL;
540 }
541
542 if (!success)
543 {
544 llwarns << "Can't open animation file " << mID << llendl;
545 mAssetStatus = ASSET_FETCH_FAILED;
546 return STATUS_FAILURE;
547 }
548
549 lldebugs << "Loading keyframe data for: " << getName() << ":" << getID() << " (" << anim_file_size << " bytes)" << llendl;
550
551 LLDataPackerBinaryBuffer dp(anim_data, anim_file_size);
552
553 if (!deserialize(dp))
554 {
555 llwarns << "Failed to decode asset for animation " << getName() << ":" << getID() << llendl;
556 mAssetStatus = ASSET_FETCH_FAILED;
557 return STATUS_FAILURE;
558 }
559
560 delete []anim_data;
561
562 mAssetStatus = ASSET_LOADED;
563 return STATUS_SUCCESS;
564}
565
566//-----------------------------------------------------------------------------
567// setupPose()
568//-----------------------------------------------------------------------------
569BOOL LLKeyframeMotion::setupPose()
570{
571 // add all valid joint states to the pose
572 U32 jm;
573 for (jm=0; jm<mJointMotionList->mNumJointMotions; jm++)
574 {
575 if ( mJointStates[jm].getJoint() )
576 {
577 addJointState( &mJointStates[jm] );
578 }
579 }
580
581 // initialize joint constraints
582 for (JointConstraintSharedData* shared_constraintp = mJointMotionList->mConstraints.getFirstData();
583 shared_constraintp;
584 shared_constraintp = mJointMotionList->mConstraints.getNextData())
585 {
586 JointConstraint* constraintp = new JointConstraint(shared_constraintp);
587 initializeConstraint(constraintp);
588 mConstraints.addData(constraintp);
589 }
590
591 if (mJointMotionList->mConstraints.getLength())
592 {
593 mPelvisp = mCharacter->getJoint("mPelvis");
594 if (!mPelvisp)
595 {
596 return FALSE;
597 }
598 }
599
600 // setup loop keys
601 setLoopIn(mJointMotionList->mLoopInPoint);
602 setLoopOut(mJointMotionList->mLoopOutPoint);
603
604 return TRUE;
605}
606
607//-----------------------------------------------------------------------------
608// LLKeyframeMotion::onActivate()
609//-----------------------------------------------------------------------------
610BOOL LLKeyframeMotion::onActivate()
611{
612 // If the keyframe anim has an associated emote, trigger it.
613 if( mEmoteName.length() > 0 )
614 {
615 mCharacter->startMotion( gAnimLibrary.stringToAnimState(mEmoteName.c_str()) );
616 }
617
618 mLastLoopedTime = 0.f;
619
620 return TRUE;
621}
622
623//-----------------------------------------------------------------------------
624// LLKeyframeMotion::onUpdate()
625//-----------------------------------------------------------------------------
626BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
627{
628 llassert(time >= 0.f);
629
630 if (mJointMotionList->mLoop)
631 {
632 if (mJointMotionList->mDuration == 0.0f)
633 {
634 time = 0.f;
635 mLastLoopedTime = 0.0f;
636 }
637 else if (mStopped)
638 {
639 mLastLoopedTime = llmin(mJointMotionList->mDuration, mLastLoopedTime + time - mLastUpdateTime);
640 }
641 else if (time > mJointMotionList->mLoopOutPoint)
642 {
643 if ((mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint) == 0.f)
644 {
645 mLastLoopedTime = mJointMotionList->mLoopOutPoint;
646 }
647 else
648 {
649 mLastLoopedTime = mJointMotionList->mLoopInPoint +
650 fmod(time - mJointMotionList->mLoopOutPoint,
651 mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
652 }
653 }
654 else
655 {
656 mLastLoopedTime = time;
657 }
658 }
659 else
660 {
661 mLastLoopedTime = time;
662 }
663
664 applyKeyframes(mLastLoopedTime);
665
666 applyConstraints(mLastLoopedTime, joint_mask);
667
668 mLastUpdateTime = time;
669
670 return mLastLoopedTime <= mJointMotionList->mDuration;
671}
672
673//-----------------------------------------------------------------------------
674// applyKeyframes()
675//-----------------------------------------------------------------------------
676void LLKeyframeMotion::applyKeyframes(F32 time)
677{
678 U32 i;
679 for (i=0; i<mJointMotionList->mNumJointMotions; i++)
680 {
681 mJointMotionList->mJointMotionArray[i].update(
682 &mJointStates[i],
683 time,
684 mJointMotionList->mDuration );
685 }
686
687 LLJoint::JointPriority* pose_priority = (LLJoint::JointPriority* )mCharacter->getAnimationData("Hand Pose Priority");
688 if (pose_priority)
689 {
690 if (mJointMotionList->mMaxPriority >= *pose_priority)
691 {
692 mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose);
693 mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority);
694 }
695 }
696 else
697 {
698 mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose);
699 mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority);
700 }
701}
702
703//-----------------------------------------------------------------------------
704// applyConstraints()
705//-----------------------------------------------------------------------------
706void LLKeyframeMotion::applyConstraints(F32 time, U8* joint_mask)
707{
708 //TODO: investigate replacing spring simulation with critically damped motion
709
710 // re-init constraints if skeleton has changed
711 if (mCharacter->getSkeletonSerialNum() != mLastSkeletonSerialNum)
712 {
713 mLastSkeletonSerialNum = mCharacter->getSkeletonSerialNum();
714 for (JointConstraint* constraintp = mConstraints.getFirstData();
715 constraintp;
716 constraintp = mConstraints.getNextData())
717 {
718 initializeConstraint(constraintp);
719 }
720 }
721
722 // apply constraints
723 for (JointConstraint* constraintp = mConstraints.getFirstData();
724 constraintp;
725 constraintp = mConstraints.getNextData())
726 {
727 applyConstraint(constraintp, time, joint_mask);
728 }
729}
730
731//-----------------------------------------------------------------------------
732// LLKeyframeMotion::onDeactivate()
733//-----------------------------------------------------------------------------
734void LLKeyframeMotion::onDeactivate()
735{
736 for (JointConstraint* constraintp = mConstraints.getFirstData();
737 constraintp;
738 constraintp = mConstraints.getNextData())
739 {
740 deactivateConstraint(constraintp);
741 }
742}
743
744//-----------------------------------------------------------------------------
745// setStopTime()
746//-----------------------------------------------------------------------------
747// time is in seconds since character creation
748void LLKeyframeMotion::setStopTime(F32 time)
749{
750 LLMotion::setStopTime(time);
751
752 if (mJointMotionList->mLoop && mJointMotionList->mLoopOutPoint != mJointMotionList->mDuration)
753 {
754 F32 start_loop_time = mActivationTimestamp + mJointMotionList->mLoopInPoint;
755 F32 loop_fraction_time;
756 if (mJointMotionList->mLoopOutPoint == mJointMotionList->mLoopInPoint)
757 {
758 loop_fraction_time = 0.f;
759 }
760 else
761 {
762 loop_fraction_time = fmod(time - start_loop_time,
763 mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
764 }
765 mStopTimestamp = llmax(time,
766 (time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration());
767 }
768}
769
770//-----------------------------------------------------------------------------
771// initializeConstraint()
772//-----------------------------------------------------------------------------
773void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
774{
775 JointConstraintSharedData *shared_data = constraint->mSharedData;
776
777 S32 joint_num;
778 LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
779 LLJoint* cur_joint = mJointStates[shared_data->mJointStateIndices[0]].getJoint();
780
781 F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
782
783 constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
784
785 // grab joint lengths
786 for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
787 {
788 cur_joint = mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint();
789 if (!cur_joint)
790 {
791 return;
792 }
793 constraint->mJointLengths[joint_num] = dist_vec(cur_joint->getWorldPosition(), cur_joint->getParent()->getWorldPosition());
794 constraint->mTotalLength += constraint->mJointLengths[joint_num];
795 }
796
797 // store fraction of total chain length so we know how to shear the entire chain towards the goal position
798 for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
799 {
800 constraint->mJointLengthFractions[joint_num] = constraint->mJointLengths[joint_num] / constraint->mTotalLength;
801 }
802
803 // add last step in chain, from final joint to constraint position
804 constraint->mTotalLength += source_pos_offset;
805
806 constraint->mSourceVolume = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume);
807 constraint->mTargetVolume = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume);
808}
809
810//-----------------------------------------------------------------------------
811// activateConstraint()
812//-----------------------------------------------------------------------------
813void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
814{
815 JointConstraintSharedData *shared_data = constraint->mSharedData;
816 constraint->mActive = TRUE;
817 S32 joint_num;
818
819 // grab ground position if we need to
820 if (shared_data->mConstraintTargetType == TYPE_GROUND)
821 {
822 LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
823 LLVector3 ground_pos_agent;
824 mCharacter->getGround(source_pos, ground_pos_agent, constraint->mGroundNorm);
825 constraint->mGroundPos = mCharacter->getPosGlobalFromAgent(ground_pos_agent + shared_data->mTargetConstraintOffset);
826 }
827
828 for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
829 {
830 LLJoint* cur_joint = mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint();
831 constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
832 }
833
834 constraint->mWeight = 1.f;
835}
836
837//-----------------------------------------------------------------------------
838// deactivateConstraint()
839//-----------------------------------------------------------------------------
840void LLKeyframeMotion::deactivateConstraint(JointConstraint *constraintp)
841{
842 if (constraintp->mSourceVolume)
843 {
844 constraintp->mSourceVolume->mUpdateXform = FALSE;
845 }
846
847 if (!constraintp->mSharedData->mConstraintTargetType == TYPE_GROUND)
848 {
849 if (constraintp->mTargetVolume)
850 {
851 constraintp->mTargetVolume->mUpdateXform = FALSE;
852 }
853 }
854 constraintp->mActive = FALSE;
855}
856
857//-----------------------------------------------------------------------------
858// applyConstraint()
859//-----------------------------------------------------------------------------
860void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8* joint_mask)
861{
862 JointConstraintSharedData *shared_data = constraint->mSharedData;
863 if (!shared_data) return;
864
865 LLVector3 positions[MAX_CHAIN_LENGTH];
866 const F32* joint_lengths = constraint->mJointLengths;
867 LLVector3 velocities[MAX_CHAIN_LENGTH - 1];
868 LLQuaternion old_rots[MAX_CHAIN_LENGTH];
869 S32 joint_num;
870 LLJoint* cur_joint;
871
872 if (time < shared_data->mEaseInStartTime)
873 {
874 return;
875 }
876
877 if (time > shared_data->mEaseOutStopTime)
878 {
879 if (constraint->mActive)
880 {
881 deactivateConstraint(constraint);
882 }
883 return;
884 }
885
886 if (!constraint->mActive || time < shared_data->mEaseInStopTime)
887 {
888 activateConstraint(constraint);
889 }
890
891 LLJoint* root_joint = mJointStates[shared_data->mJointStateIndices[shared_data->mChainLength]].getJoint();
892 LLVector3 root_pos = root_joint->getWorldPosition();
893// LLQuaternion root_rot =
894 root_joint->getParent()->getWorldRotation();
895// LLQuaternion inv_root_rot = ~root_rot;
896
897// LLVector3 current_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
898
899 //apply underlying keyframe animation to get nominal "kinematic" joint positions
900 for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
901 {
902 cur_joint = mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint();
903 if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
904 {
905 // skip constraint
906 return;
907 }
908 old_rots[joint_num] = cur_joint->getRotation();
909 cur_joint->setRotation(mJointStates[shared_data->mJointStateIndices[joint_num]].getRotation());
910 }
911
912
913 LLVector3 keyframe_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
914 LLVector3 target_pos;
915
916 switch(shared_data->mConstraintTargetType)
917 {
918 case TYPE_GROUND:
919 target_pos = mCharacter->getPosAgentFromGlobal(constraint->mGroundPos);
920// llinfos << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl;
921 break;
922 case TYPE_BODY:
923 target_pos = mCharacter->getVolumePos(shared_data->mTargetConstraintVolume, shared_data->mTargetConstraintOffset);
924 break;
925 default:
926 break;
927 }
928
929 LLVector3 norm;
930 LLJoint *source_jointp = NULL;
931 LLJoint *target_jointp = NULL;
932
933 if (shared_data->mConstraintType == TYPE_PLANE)
934 {
935 switch(shared_data->mConstraintTargetType)
936 {
937 case TYPE_GROUND:
938 norm = constraint->mGroundNorm;
939 break;
940 case TYPE_BODY:
941 target_jointp = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume);
942 if (target_jointp)
943 {
944 // *FIX: do proper normal calculation for stretched
945 // spheres (inverse transpose)
946 norm = target_pos - target_jointp->getWorldPosition();
947 }
948
949 if (norm.isExactlyZero())
950 {
951 source_jointp = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume);
952 norm = -1.f * shared_data->mSourceConstraintOffset;
953 if (source_jointp)
954 {
955 norm = norm * source_jointp->getWorldRotation();
956 }
957 }
958 norm.normVec();
959 break;
960 default:
961 norm.clearVec();
962 break;
963 }
964
965 target_pos = keyframe_source_pos + (norm * ((target_pos - keyframe_source_pos) * norm));
966 }
967
968 if (constraint->mSharedData->mChainLength != 0 &&
969 dist_vec_squared(root_pos, target_pos) * 0.95f > constraint->mTotalLength * constraint->mTotalLength)
970 {
971 constraint->mWeight = lerp(constraint->mWeight, 0.f, LLCriticalDamp::getInterpolant(0.1f));
972 }
973 else
974 {
975 constraint->mWeight = lerp(constraint->mWeight, 1.f, LLCriticalDamp::getInterpolant(0.3f));
976 }
977
978 F32 weight = constraint->mWeight * ((shared_data->mEaseOutStopTime == 0.f) ? 1.f :
979 llmin(clamp_rescale(time, shared_data->mEaseInStartTime, shared_data->mEaseInStopTime, 0.f, 1.f),
980 clamp_rescale(time, shared_data->mEaseOutStartTime, shared_data->mEaseOutStopTime, 1.f, 0.f)));
981
982 LLVector3 source_to_target = target_pos - keyframe_source_pos;
983
984 S32 max_iteration_count = llround(clamp_rescale(
985 mCharacter->getPixelArea(),
986 MAX_PIXEL_AREA_CONSTRAINTS,
987 MIN_PIXEL_AREA_CONSTRAINTS,
988 (F32)MAX_ITERATIONS,
989 (F32)MIN_ITERATIONS));
990
991 if (shared_data->mChainLength)
992 {
993 LLQuaternion end_rot = mJointStates[shared_data->mJointStateIndices[0]].getJoint()->getWorldRotation();
994
995 // slam start and end of chain to the proper positions (rest of chain stays put)
996 positions[0] = lerp(keyframe_source_pos, target_pos, weight);
997 positions[shared_data->mChainLength] = root_pos;
998
999 // grab keyframe-specified positions of joints
1000 for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
1001 {
1002 LLVector3 kinematic_position = mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint()->getWorldPosition() +
1003 (source_to_target * constraint->mJointLengthFractions[joint_num]);
1004
1005 // convert intermediate joint positions to world coordinates
1006 positions[joint_num] = ( constraint->mPositions[joint_num] * mPelvisp->getWorldRotation()) + mPelvisp->getWorldPosition();
1007 F32 time_constant = 1.f / clamp_rescale(constraint->mFixupDistanceRMS, 0.f, 0.5f, 0.2f, 8.f);
1008// llinfos << "Interpolant " << LLCriticalDamp::getInterpolant(time_constant, FALSE) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl;
1009 positions[joint_num] = lerp(positions[joint_num], kinematic_position,
1010 LLCriticalDamp::getInterpolant(time_constant, FALSE));
1011 }
1012
1013 S32 iteration_count;
1014 for (iteration_count = 0; iteration_count < max_iteration_count; iteration_count++)
1015 {
1016 S32 num_joints_finished = 0;
1017 for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
1018 {
1019 // constraint to child
1020 LLVector3 acceleration = (positions[joint_num - 1] - positions[joint_num]) *
1021 (dist_vec(positions[joint_num], positions[joint_num - 1]) - joint_lengths[joint_num - 1]) * JOINT_LENGTH_K;
1022 // constraint to parent
1023 acceleration += (positions[joint_num + 1] - positions[joint_num]) *
1024 (dist_vec(positions[joint_num + 1], positions[joint_num]) - joint_lengths[joint_num]) * JOINT_LENGTH_K;
1025
1026 if (acceleration.magVecSquared() < MIN_ACCELERATION_SQUARED)
1027 {
1028 num_joints_finished++;
1029 }
1030
1031 velocities[joint_num - 1] = velocities[joint_num - 1] * 0.7f;
1032 positions[joint_num] += velocities[joint_num - 1] + (acceleration * 0.5f);
1033 velocities[joint_num - 1] += acceleration;
1034 }
1035
1036 if ((iteration_count >= MIN_ITERATION_COUNT) &&
1037 (num_joints_finished == shared_data->mChainLength - 1))
1038 {
1039// llinfos << iteration_count << " iterations on " <<
1040// mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl;
1041 break;
1042 }
1043 }
1044
1045 for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
1046 {
1047 LLQuaternion parent_rot = mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint()->getParent()->getWorldRotation();
1048 cur_joint = mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint();
1049 LLJoint* child_joint = mJointStates[shared_data->mJointStateIndices[joint_num - 1]].getJoint();
1050
1051 LLQuaternion cur_rot = cur_joint->getWorldRotation();
1052 LLQuaternion fixup_rot;
1053
1054 LLVector3 target_at = positions[joint_num - 1] - positions[joint_num];
1055 LLVector3 current_at;
1056
1057 // at bottom of chain, use point on collision volume, not joint position
1058 if (joint_num == 1)
1059 {
1060 current_at = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset) -
1061 cur_joint->getWorldPosition();
1062 }
1063 else
1064 {
1065 current_at = child_joint->getPosition() * cur_rot;
1066 }
1067 fixup_rot.shortestArc(current_at, target_at);
1068
1069 LLQuaternion target_rot = cur_rot * fixup_rot;
1070 target_rot = target_rot * ~parent_rot;
1071
1072 if (weight != 1.f)
1073 {
1074 LLQuaternion cur_rot = mJointStates[shared_data->mJointStateIndices[joint_num]].getRotation();
1075 target_rot = nlerp(weight, cur_rot, target_rot);
1076 }
1077
1078 mJointStates[shared_data->mJointStateIndices[joint_num]].setRotation(target_rot);
1079 cur_joint->setRotation(target_rot);
1080 }
1081
1082 LLJoint* end_joint = mJointStates[shared_data->mJointStateIndices[0]].getJoint();
1083 LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
1084
1085 if (weight == 1.f)
1086 {
1087 mJointStates[shared_data->mJointStateIndices[0]].setRotation(end_local_rot);
1088 }
1089 else
1090 {
1091 LLQuaternion cur_rot = mJointStates[shared_data->mJointStateIndices[0]].getRotation();
1092 mJointStates[shared_data->mJointStateIndices[0]].setRotation(nlerp(weight, cur_rot, end_local_rot));
1093 }
1094
1095 // save simulated positions in pelvis-space and calculate total fixup distance
1096 constraint->mFixupDistanceRMS = 0.f;
1097 F32 delta_time = llmax(0.02f, llabs(time - mLastUpdateTime));
1098 for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
1099 {
1100 LLVector3 new_pos = (positions[joint_num] - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
1101 constraint->mFixupDistanceRMS += dist_vec_squared(new_pos, constraint->mPositions[joint_num]) / delta_time;
1102 constraint->mPositions[joint_num] = new_pos;
1103 }
1104 constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
1105 constraint->mFixupDistanceRMS = fsqrtf(constraint->mFixupDistanceRMS);
1106
1107 //reset old joint rots
1108 for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
1109 {
1110 mJointStates[shared_data->mJointStateIndices[joint_num]].getJoint()->setRotation(old_rots[joint_num]);
1111 }
1112 }
1113 // simple positional constraint (pelvis only)
1114 else if (mJointStates[shared_data->mJointStateIndices[0]].getUsage() & LLJointState::POS)
1115 {
1116 LLVector3 delta = source_to_target * weight;
1117 LLJointState* current_joint_statep = &mJointStates[shared_data->mJointStateIndices[0]];
1118 LLQuaternion parent_rot = current_joint_statep->getJoint()->getParent()->getWorldRotation();
1119 delta = delta * ~parent_rot;
1120 current_joint_statep->setPosition(current_joint_statep->getJoint()->getPosition() + delta);
1121 }
1122}
1123
1124//-----------------------------------------------------------------------------
1125// deserialize()
1126//-----------------------------------------------------------------------------
1127BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
1128{
1129 BOOL old_version = FALSE;
1130 mJointMotionList = new LLKeyframeMotion::JointMotionList;
1131 mJointMotionList->mNumJointMotions = 0;
1132
1133 //-------------------------------------------------------------------------
1134 // get base priority
1135 //-------------------------------------------------------------------------
1136 S32 temp_priority;
1137 U16 version;
1138 U16 sub_version;
1139
1140 if (!dp.unpackU16(version, "version"))
1141 {
1142 llwarns << "can't read version number" << llendl;
1143 return FALSE;
1144 }
1145
1146 if (!dp.unpackU16(sub_version, "sub_version"))
1147 {
1148 llwarns << "can't read sub version number" << llendl;
1149 return FALSE;
1150 }
1151
1152 if (version == 0 && sub_version == 1)
1153 {
1154 old_version = TRUE;
1155 }
1156 else if (version != KEYFRAME_MOTION_VERSION || sub_version != KEYFRAME_MOTION_SUBVERSION)
1157 {
1158#if LL_RELEASE
1159 llwarns << "Bad animation version " << version << "." << sub_version << llendl;
1160 return FALSE;
1161#else
1162 llerrs << "Bad animation version " << version << "." << sub_version << llendl;
1163#endif
1164 }
1165
1166 if (!dp.unpackS32(temp_priority, "base_priority"))
1167 {
1168 llwarns << "can't read priority" << llendl;
1169 return FALSE;
1170 }
1171 mJointMotionList->mBasePriority = (LLJoint::JointPriority) temp_priority;
1172
1173 if (mJointMotionList->mBasePriority >= LLJoint::ADDITIVE_PRIORITY)
1174 {
1175 mJointMotionList->mBasePriority = (LLJoint::JointPriority)((int)LLJoint::ADDITIVE_PRIORITY-1);
1176 mJointMotionList->mMaxPriority = mJointMotionList->mBasePriority;
1177 }
1178
1179 //-------------------------------------------------------------------------
1180 // get duration
1181 //-------------------------------------------------------------------------
1182 if (!dp.unpackF32(mJointMotionList->mDuration, "duration"))
1183 {
1184 llwarns << "can't read duration" << llendl;
1185 return FALSE;
1186 }
1187
1188 //-------------------------------------------------------------------------
1189 // get emote (optional)
1190 //-------------------------------------------------------------------------
1191 if (!dp.unpackString(mEmoteName, "emote_name"))
1192 {
1193 llwarns << "can't read optional_emote_animation" << llendl;
1194 return FALSE;
1195 }
1196
1197 //-------------------------------------------------------------------------
1198 // get loop
1199 //-------------------------------------------------------------------------
1200 if (!dp.unpackF32(mJointMotionList->mLoopInPoint, "loop_in_point"))
1201 {
1202 llwarns << "can't read loop point" << llendl;
1203 return FALSE;
1204 }
1205
1206 if (!dp.unpackF32(mJointMotionList->mLoopOutPoint, "loop_out_point"))
1207 {
1208 llwarns << "can't read loop point" << llendl;
1209 return FALSE;
1210 }
1211
1212 if (!dp.unpackS32(mJointMotionList->mLoop, "loop"))
1213 {
1214 llwarns << "can't read loop" << llendl;
1215 return FALSE;
1216 }
1217
1218 //-------------------------------------------------------------------------
1219 // get easeIn and easeOut
1220 //-------------------------------------------------------------------------
1221 if (!dp.unpackF32(mJointMotionList->mEaseInDuration, "ease_in_duration"))
1222 {
1223 llwarns << "can't read easeIn" << llendl;
1224 return FALSE;
1225 }
1226
1227 if (!dp.unpackF32(mJointMotionList->mEaseOutDuration, "ease_out_duration"))
1228 {
1229 llwarns << "can't read easeOut" << llendl;
1230 return FALSE;
1231 }
1232
1233 //-------------------------------------------------------------------------
1234 // get hand pose
1235 //-------------------------------------------------------------------------
1236 U32 word;
1237 if (!dp.unpackU32(word, "hand_pose"))
1238 {
1239 llwarns << "can't read hand pose" << llendl;
1240 return FALSE;
1241 }
1242 mJointMotionList->mHandPose = (LLHandMotion::eHandPose)word;
1243
1244 //-------------------------------------------------------------------------
1245 // get number of joint motions
1246 //-------------------------------------------------------------------------
1247 if (!dp.unpackU32(mJointMotionList->mNumJointMotions, "num_joints"))
1248 {
1249 llwarns << "can't read number of joints" << llendl;
1250 return FALSE;
1251 }
1252
1253 if (mJointMotionList->mNumJointMotions == 0)
1254 {
1255 llwarns << "no joints in animation" << llendl;
1256 return FALSE;
1257 }
1258 else if (mJointMotionList->mNumJointMotions > LL_CHARACTER_MAX_JOINTS)
1259 {
1260 llwarns << "too many joints in animation" << llendl;
1261 return FALSE;
1262 }
1263
1264 mJointMotionList->mJointMotionArray = new JointMotion[mJointMotionList->mNumJointMotions];
1265 mJointStates = new LLJointState[mJointMotionList->mNumJointMotions];
1266
1267 if (!mJointMotionList->mJointMotionArray)
1268 {
1269 mJointMotionList->mDuration = 0.0f;
1270 mJointMotionList->mEaseInDuration = 0.0f;
1271 mJointMotionList->mEaseOutDuration = 0.0f;
1272 return FALSE;
1273 }
1274
1275 //-------------------------------------------------------------------------
1276 // initialize joint motions
1277 //-------------------------------------------------------------------------
1278 S32 k;
1279 for(U32 i=0; i<mJointMotionList->mNumJointMotions; ++i)
1280 {
1281 std::string joint_name;
1282 if (!dp.unpackString(joint_name, "joint_name"))
1283 {
1284 llwarns << "can't read joint name" << llendl;
1285 return FALSE;
1286 }
1287
1288 //---------------------------------------------------------------------
1289 // find the corresponding joint
1290 //---------------------------------------------------------------------
1291 LLJoint *joint = mCharacter->getJoint( joint_name );
1292 if (joint)
1293 {
1294// llinfos << " joint: " << joint_name << llendl;
1295 }
1296 else
1297 {
1298 llwarns << "joint not found: " << joint_name << llendl;
1299 //return FALSE;
1300 }
1301
1302 mJointMotionList->mJointMotionArray[i].mJointName = joint_name;
1303 mJointStates[i].setJoint( joint );
1304 mJointStates[i].setUsage( 0 );
1305
1306 //---------------------------------------------------------------------
1307 // get joint priority
1308 //---------------------------------------------------------------------
1309 S32 joint_priority;
1310 if (!dp.unpackS32(joint_priority, "joint_priority"))
1311 {
1312 llwarns << "can't read joint priority." << llendl;
1313 return FALSE;
1314 }
1315
1316 mJointMotionList->mJointMotionArray[i].mPriority = (LLJoint::JointPriority)joint_priority;
1317 if (joint_priority != LLJoint::USE_MOTION_PRIORITY &&
1318 joint_priority > mJointMotionList->mMaxPriority)
1319 {
1320 mJointMotionList->mMaxPriority = (LLJoint::JointPriority)joint_priority;
1321 }
1322
1323 mJointStates[i].setPriority((LLJoint::JointPriority)joint_priority);
1324
1325 //---------------------------------------------------------------------
1326 // scan rotation curve header
1327 //---------------------------------------------------------------------
1328 if (!dp.unpackS32(mJointMotionList->mJointMotionArray[i].mRotationCurve.mNumKeys, "num_rot_keys"))
1329 {
1330 llwarns << "can't read number of rotation keys" << llendl;
1331 return FALSE;
1332 }
1333
1334 mJointMotionList->mJointMotionArray[i].mRotationCurve.mInterpolationType = IT_LINEAR;
1335 if (mJointMotionList->mJointMotionArray[i].mRotationCurve.mNumKeys != 0)
1336 {
1337 mJointStates[i].setUsage(mJointStates[i].getUsage() | LLJointState::ROT );
1338 }
1339
1340 //---------------------------------------------------------------------
1341 // scan rotation curve keys
1342 //---------------------------------------------------------------------
1343 RotationCurve *rCurve = &mJointMotionList->mJointMotionArray[i].mRotationCurve;
1344
1345 for (k = 0; k < mJointMotionList->mJointMotionArray[i].mRotationCurve.mNumKeys; k++)
1346 {
1347 F32 time;
1348 U16 time_short;
1349
1350 if (old_version)
1351 {
1352 if (!dp.unpackF32(time, "time"))
1353 {
1354 llwarns << "can't read rotation key (" << k << ")" << llendl;
1355 return FALSE;
1356 }
1357
1358 }
1359 else
1360 {
1361 if (!dp.unpackU16(time_short, "time"))
1362 {
1363 llwarns << "can't read rotation key (" << k << ")" << llendl;
1364 return FALSE;
1365 }
1366
1367 time = U16_to_F32(time_short, 0.f, mJointMotionList->mDuration);
1368 }
1369
1370 RotationKey *rot_key = new RotationKey;
1371 rot_key->mTime = time;
1372 LLVector3 rot_angles;
1373 U16 x, y, z;
1374
1375 BOOL success = TRUE;
1376
1377 if (old_version)
1378 {
1379 success = dp.unpackVector3(rot_angles, "rot_angles");
1380
1381 LLQuaternion::Order ro = StringToOrder("ZYX");
1382 rot_key->mRotation = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro);
1383 }
1384 else
1385 {
1386 success &= dp.unpackU16(x, "rot_angle_x");
1387 success &= dp.unpackU16(y, "rot_angle_y");
1388 success &= dp.unpackU16(z, "rot_angle_z");
1389
1390 LLVector3 rot_vec;
1391 rot_vec.mV[VX] = U16_to_F32(x, -1.f, 1.f);
1392 rot_vec.mV[VY] = U16_to_F32(y, -1.f, 1.f);
1393 rot_vec.mV[VZ] = U16_to_F32(z, -1.f, 1.f);
1394 rot_key->mRotation.unpackFromVector3(rot_vec);
1395 }
1396
1397 if (!success)
1398 {
1399 llwarns << "can't read rotation key (" << k << ")" << llendl;
1400 return FALSE;
1401 }
1402
1403 rCurve->mKeys[time] = rot_key;
1404 }
1405
1406 //---------------------------------------------------------------------
1407 // scan position curve header
1408 //---------------------------------------------------------------------
1409 if (!dp.unpackS32(mJointMotionList->mJointMotionArray[i].mPositionCurve.mNumKeys, "num_pos_keys"))
1410 {
1411 llwarns << "can't read number of position keys" << llendl;
1412 return FALSE;
1413 }
1414
1415 mJointMotionList->mJointMotionArray[i].mPositionCurve.mInterpolationType = IT_LINEAR;
1416 if (mJointMotionList->mJointMotionArray[i].mPositionCurve.mNumKeys != 0)
1417 {
1418 mJointStates[i].setUsage(mJointStates[i].getUsage() | LLJointState::POS );
1419 }
1420
1421 //---------------------------------------------------------------------
1422 // scan position curve keys
1423 //---------------------------------------------------------------------
1424 PositionCurve *pCurve = &mJointMotionList->mJointMotionArray[i].mPositionCurve;
1425 BOOL is_pelvis = mJointMotionList->mJointMotionArray[i].mJointName == "mPelvis";
1426 for (k = 0; k < mJointMotionList->mJointMotionArray[i].mPositionCurve.mNumKeys; k++)
1427 {
1428 U16 time_short;
1429 PositionKey* pos_key = new PositionKey;
1430
1431 if (old_version)
1432 {
1433 if (!dp.unpackF32(pos_key->mTime, "time"))
1434 {
1435 llwarns << "can't read position key (" << k << ")" << llendl;
1436 delete pos_key;
1437 return FALSE;
1438 }
1439 }
1440 else
1441 {
1442 if (!dp.unpackU16(time_short, "time"))
1443 {
1444 llwarns << "can't read position key (" << k << ")" << llendl;
1445 delete pos_key;
1446 return FALSE;
1447 }
1448
1449 pos_key->mTime = U16_to_F32(time_short, 0.f, mJointMotionList->mDuration);
1450 }
1451
1452 BOOL success = TRUE;
1453
1454 if (old_version)
1455 {
1456 success = dp.unpackVector3(pos_key->mPosition, "pos");
1457 }
1458 else
1459 {
1460 U16 x, y, z;
1461
1462 success &= dp.unpackU16(x, "pos_x");
1463 success &= dp.unpackU16(y, "pos_y");
1464 success &= dp.unpackU16(z, "pos_z");
1465
1466 pos_key->mPosition.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1467 pos_key->mPosition.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1468 pos_key->mPosition.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1469 }
1470
1471 if (!success)
1472 {
1473 llwarns << "can't read position key (" << k << ")" << llendl;
1474 delete pos_key;
1475 return FALSE;
1476 }
1477
1478 pCurve->mKeys[pos_key->mTime] = pos_key;
1479
1480 if (is_pelvis)
1481 {
1482 mJointMotionList->mPelvisBBox.addPoint(pos_key->mPosition);
1483 }
1484 }
1485
1486 mJointMotionList->mJointMotionArray[i].mUsage = mJointStates[i].getUsage();
1487 }
1488
1489 //-------------------------------------------------------------------------
1490 // get number of constraints
1491 //-------------------------------------------------------------------------
1492 S32 num_constraints = 0;
1493 if (!dp.unpackS32(num_constraints, "num_constraints"))
1494 {
1495 llwarns << "can't read number of constraints" << llendl;
1496 return FALSE;
1497 }
1498
1499 if (num_constraints > MAX_CONSTRAINTS)
1500 {
1501 llwarns << "Too many constraints...ignoring" << llendl;
1502 }
1503 else
1504 {
1505 //-------------------------------------------------------------------------
1506 // get constraints
1507 //-------------------------------------------------------------------------
1508 std::string str;
1509 for(S32 i = 0; i < num_constraints; ++i)
1510 {
1511 // read in constraint data
1512 JointConstraintSharedData* constraintp = new JointConstraintSharedData;
1513 U8 byte = 0;
1514
1515 if (!dp.unpackU8(byte, "chain_length"))
1516 {
1517 llwarns << "can't read constraint chain length" << llendl;
1518 return FALSE;
1519 }
1520 constraintp->mChainLength = (S32) byte;
1521
1522 if (!dp.unpackU8(byte, "constraint_type"))
1523 {
1524 llwarns << "can't read constraint type" << llendl;
1525 return FALSE;
1526 }
1527 constraintp->mConstraintType = (EConstraintType)byte;
1528
1529 const S32 BIN_DATA_LENGTH = 16;
1530 U8 bin_data[BIN_DATA_LENGTH];
1531 if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "source_volume"))
1532 {
1533 llwarns << "can't read source volume name" << llendl;
1534 return FALSE;
1535 }
1536
1537 bin_data[BIN_DATA_LENGTH-1] = 0; // Ensure null termination
1538 str = (char*)bin_data;
1539 constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str);
1540
1541 if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset"))
1542 {
1543 llwarns << "can't read constraint source offset" << llendl;
1544 return FALSE;
1545 }
1546
1547 if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "target_volume"))
1548 {
1549 llwarns << "can't read target volume name" << llendl;
1550 return FALSE;
1551 }
1552
1553 bin_data[BIN_DATA_LENGTH-1] = 0; // Ensure null termination
1554 str = (char*)bin_data;
1555 if (str == "GROUND")
1556 {
1557 // constrain to ground
1558 constraintp->mConstraintTargetType = TYPE_GROUND;
1559 }
1560 else
1561 {
1562 constraintp->mConstraintTargetType = TYPE_BODY;
1563 constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str);
1564 }
1565
1566 if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset"))
1567 {
1568 llwarns << "can't read constraint target offset" << llendl;
1569 return FALSE;
1570 }
1571
1572 if (!dp.unpackVector3(constraintp->mTargetConstraintDir, "target_dir"))
1573 {
1574 llwarns << "can't read constraint target direction" << llendl;
1575 return FALSE;
1576 }
1577
1578 if (!constraintp->mTargetConstraintDir.isExactlyZero())
1579 {
1580 constraintp->mUseTargetOffset = TRUE;
1581 // constraintp->mTargetConstraintDir *= constraintp->mSourceConstraintOffset.magVec();
1582 }
1583
1584 if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start"))
1585 {
1586 llwarns << "can't read constraint ease in start time" << llendl;
1587 return FALSE;
1588 }
1589
1590 if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop"))
1591 {
1592 llwarns << "can't read constraint ease in stop time" << llendl;
1593 return FALSE;
1594 }
1595
1596 if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start"))
1597 {
1598 llwarns << "can't read constraint ease out start time" << llendl;
1599 return FALSE;
1600 }
1601
1602 if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop"))
1603 {
1604 llwarns << "can't read constraint ease out stop time" << llendl;
1605 return FALSE;
1606 }
1607
1608 mJointMotionList->mConstraints.addData(constraintp);
1609
1610 constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1];
1611
1612 LLJoint* joint = mCharacter->findCollisionVolume(constraintp->mSourceConstraintVolume);
1613 // get joint to which this collision volume is attached
1614 if (!joint)
1615 {
1616 return FALSE;
1617 }
1618 for (S32 i = 0; i < constraintp->mChainLength + 1; i++)
1619 {
1620 LLJoint* parent = joint->getParent();
1621 if (!parent)
1622 {
1623 llwarns << "Joint with no parent: " << joint->getName()
1624 << " Emote: " << mEmoteName << llendl;
1625 return FALSE;
1626 }
1627 joint = parent;
1628 constraintp->mJointStateIndices[i] = -1;
1629 for (U32 j = 0; j < mJointMotionList->mNumJointMotions; j++)
1630 {
1631 if(mJointStates[j].getJoint() == joint)
1632 {
1633 constraintp->mJointStateIndices[i] = (S32)j;
1634 break;
1635 }
1636 }
1637 }
1638
1639 }
1640 }
1641
1642 // *FIX: support cleanup of old keyframe data
1643 LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList);
1644 mAssetStatus = ASSET_LOADED;
1645
1646 setupPose();
1647
1648 return TRUE;
1649}
1650
1651//-----------------------------------------------------------------------------
1652// serialize()
1653//-----------------------------------------------------------------------------
1654BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
1655{
1656 BOOL success = TRUE;
1657
1658 success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version");
1659 success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
1660 success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority");
1661 success &= dp.packF32(mJointMotionList->mDuration, "duration");
1662 success &= dp.packString(mEmoteName.c_str(), "emote_name");
1663 success &= dp.packF32(mJointMotionList->mLoopInPoint, "loop_in_point");
1664 success &= dp.packF32(mJointMotionList->mLoopOutPoint, "loop_out_point");
1665 success &= dp.packS32(mJointMotionList->mLoop, "loop");
1666 success &= dp.packF32(mJointMotionList->mEaseInDuration, "ease_in_duration");
1667 success &= dp.packF32(mJointMotionList->mEaseOutDuration, "ease_out_duration");
1668 success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose");
1669 success &= dp.packU32(mJointMotionList->mNumJointMotions, "num_joints");
1670
1671 for (U32 i = 0; i < mJointMotionList->mNumJointMotions; i++)
1672 {
1673 JointMotion* joint_motionp = &mJointMotionList->mJointMotionArray[i];
1674 success &= dp.packString(joint_motionp->mJointName.c_str(), "joint_name");
1675 success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
1676 success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys");
1677
1678 for (RotationKey* rot_keyp = joint_motionp->mRotationCurve.mKeys.getFirstData();
1679 rot_keyp;
1680 rot_keyp = joint_motionp->mRotationCurve.mKeys.getNextData())
1681 {
1682 U16 time_short = F32_to_U16(rot_keyp->mTime, 0.f, mJointMotionList->mDuration);
1683 success &= dp.packU16(time_short, "time");
1684
1685 LLVector3 rot_angles = rot_keyp->mRotation.packToVector3();
1686
1687 U16 x, y, z;
1688 rot_angles.quantize16(-1.f, 1.f, -1.f, 1.f);
1689 x = F32_to_U16(rot_angles.mV[VX], -1.f, 1.f);
1690 y = F32_to_U16(rot_angles.mV[VY], -1.f, 1.f);
1691 z = F32_to_U16(rot_angles.mV[VZ], -1.f, 1.f);
1692 success &= dp.packU16(x, "rot_angle_x");
1693 success &= dp.packU16(y, "rot_angle_y");
1694 success &= dp.packU16(z, "rot_angle_z");
1695 }
1696
1697 success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
1698 for (PositionKey* pos_keyp = joint_motionp->mPositionCurve.mKeys.getFirstData();
1699 pos_keyp;
1700 pos_keyp = joint_motionp->mPositionCurve.mKeys.getNextData())
1701 {
1702 U16 time_short = F32_to_U16(pos_keyp->mTime, 0.f, mJointMotionList->mDuration);
1703 success &= dp.packU16(time_short, "time");
1704
1705 U16 x, y, z;
1706 pos_keyp->mPosition.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1707 x = F32_to_U16(pos_keyp->mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1708 y = F32_to_U16(pos_keyp->mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1709 z = F32_to_U16(pos_keyp->mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
1710 success &= dp.packU16(x, "pos_x");
1711 success &= dp.packU16(y, "pos_y");
1712 success &= dp.packU16(z, "pos_z");
1713 }
1714 }
1715
1716 success &= dp.packS32(mJointMotionList->mConstraints.getLength(), "num_constraints");
1717 for (JointConstraintSharedData* shared_constraintp = mJointMotionList->mConstraints.getFirstData();
1718 shared_constraintp;
1719 shared_constraintp = mJointMotionList->mConstraints.getNextData())
1720 {
1721 success &= dp.packU8(shared_constraintp->mChainLength, "chain_length");
1722 success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type");
1723 char volume_name[16];
1724 snprintf(volume_name, sizeof(volume_name), "%s",
1725 mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str()); /* Flawfinder: ignore */
1726 success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "source_volume");
1727 success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset");
1728 if (shared_constraintp->mConstraintTargetType == TYPE_GROUND)
1729 {
1730 snprintf(volume_name,sizeof(volume_name), "%s", "GROUND"); /* Flawfinder: ignore */
1731 }
1732 else
1733 {
1734 snprintf(volume_name, sizeof(volume_name),"%s",
1735 mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str()); /* Flawfinder: ignore */
1736 }
1737 success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "target_volume");
1738 success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset");
1739 success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir");
1740 success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start");
1741 success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop");
1742 success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start");
1743 success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop");
1744 }
1745
1746 return success;
1747}
1748
1749//-----------------------------------------------------------------------------
1750// getFileSize()
1751//-----------------------------------------------------------------------------
1752U32 LLKeyframeMotion::getFileSize()
1753{
1754 // serialize into a dummy buffer to calculate required size
1755 LLDataPackerBinaryBuffer dp;
1756 serialize(dp);
1757
1758 return dp.getCurrentSize();
1759}
1760
1761//-----------------------------------------------------------------------------
1762// getPelvisBBox()
1763//-----------------------------------------------------------------------------
1764const LLBBoxLocal &LLKeyframeMotion::getPelvisBBox()
1765{
1766 return mJointMotionList->mPelvisBBox;
1767}
1768
1769//-----------------------------------------------------------------------------
1770// setPriority()
1771//-----------------------------------------------------------------------------
1772void LLKeyframeMotion::setPriority(S32 priority)
1773{
1774 if (mJointMotionList)
1775 {
1776 S32 priority_delta = priority - mJointMotionList->mBasePriority;
1777 mJointMotionList->mBasePriority = (LLJoint::JointPriority)priority;
1778 mJointMotionList->mMaxPriority = mJointMotionList->mBasePriority;
1779
1780 for (U32 i = 0; i < mJointMotionList->mNumJointMotions; i++)
1781 {
1782 mJointMotionList->mJointMotionArray[i].mPriority = (LLJoint::JointPriority)llclamp(
1783 (S32)mJointMotionList->mJointMotionArray[i].mPriority + priority_delta,
1784 (S32)LLJoint::LOW_PRIORITY,
1785 (S32)LLJoint::HIGHEST_PRIORITY);
1786 mJointStates[i].setPriority(mJointMotionList->mJointMotionArray[i].mPriority);
1787 }
1788 }
1789}
1790
1791//-----------------------------------------------------------------------------
1792// setEmote()
1793//-----------------------------------------------------------------------------
1794void LLKeyframeMotion::setEmote(const LLUUID& emote_id)
1795{
1796 const char* emote_name = gAnimLibrary.animStateToString(emote_id);
1797 if (emote_name)
1798 {
1799 mEmoteName = emote_name;
1800 }
1801 else
1802 {
1803 mEmoteName = "";
1804 }
1805}
1806
1807//-----------------------------------------------------------------------------
1808// setEaseIn()
1809//-----------------------------------------------------------------------------
1810void LLKeyframeMotion::setEaseIn(F32 ease_in)
1811{
1812 if (mJointMotionList)
1813 {
1814 mJointMotionList->mEaseInDuration = llmax(ease_in, 0.f);
1815 }
1816}
1817
1818//-----------------------------------------------------------------------------
1819// setEaseOut()
1820//-----------------------------------------------------------------------------
1821void LLKeyframeMotion::setEaseOut(F32 ease_in)
1822{
1823 if (mJointMotionList)
1824 {
1825 mJointMotionList->mEaseOutDuration = llmax(ease_in, 0.f);
1826 }
1827}
1828
1829
1830//-----------------------------------------------------------------------------
1831// flushKeyframeCache()
1832//-----------------------------------------------------------------------------
1833void LLKeyframeMotion::flushKeyframeCache()
1834{
1835 LLKeyframeDataCache::clear();
1836}
1837
1838//-----------------------------------------------------------------------------
1839// setLoop()
1840//-----------------------------------------------------------------------------
1841void LLKeyframeMotion::setLoop(BOOL loop)
1842{
1843 if (mJointMotionList)
1844 {
1845 mJointMotionList->mLoop = loop;
1846 mSendStopTimestamp = F32_MAX;
1847 }
1848}
1849
1850
1851//-----------------------------------------------------------------------------
1852// setLoopIn()
1853//-----------------------------------------------------------------------------
1854void LLKeyframeMotion::setLoopIn(F32 in_point)
1855{
1856 if (mJointMotionList)
1857 {
1858 mJointMotionList->mLoopInPoint = in_point;
1859
1860 // set up loop keys
1861 for (U32 i = 0; i < mJointMotionList->mNumJointMotions; i++)
1862 {
1863 PositionCurve* pos_curve = &mJointMotionList->mJointMotionArray[i].mPositionCurve;
1864 RotationCurve* rot_curve = &mJointMotionList->mJointMotionArray[i].mRotationCurve;
1865 ScaleCurve* scale_curve = &mJointMotionList->mJointMotionArray[i].mScaleCurve;
1866
1867 pos_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
1868 rot_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
1869 scale_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
1870
1871 pos_curve->mLoopInKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
1872 rot_curve->mLoopInKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
1873 scale_curve->mLoopInKey.mScale = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
1874 }
1875 }
1876}
1877
1878//-----------------------------------------------------------------------------
1879// setLoopOut()
1880//-----------------------------------------------------------------------------
1881void LLKeyframeMotion::setLoopOut(F32 out_point)
1882{
1883 if (mJointMotionList)
1884 {
1885 mJointMotionList->mLoopOutPoint = out_point;
1886
1887 // set up loop keys
1888 for (U32 i = 0; i < mJointMotionList->mNumJointMotions; i++)
1889 {
1890 PositionCurve* pos_curve = &mJointMotionList->mJointMotionArray[i].mPositionCurve;
1891 RotationCurve* rot_curve = &mJointMotionList->mJointMotionArray[i].mRotationCurve;
1892 ScaleCurve* scale_curve = &mJointMotionList->mJointMotionArray[i].mScaleCurve;
1893
1894 pos_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
1895 rot_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
1896 scale_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
1897
1898 pos_curve->mLoopOutKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
1899 rot_curve->mLoopOutKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
1900 scale_curve->mLoopOutKey.mScale = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
1901 }
1902 }
1903}
1904
1905//-----------------------------------------------------------------------------
1906// onLoadComplete()
1907//-----------------------------------------------------------------------------
1908void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
1909 const LLUUID& asset_uuid,
1910 LLAssetType::EType type,
1911 void* user_data, S32 status)
1912{
1913 LLUUID* id = (LLUUID*)user_data;
1914
1915 LLCharacter* character = NULL;
1916
1917 for(character = LLCharacter::sInstances.getFirstData();
1918 character;
1919 character = LLCharacter::sInstances.getNextData())
1920 {
1921 if (character->getID() == *id)
1922 {
1923 break;
1924 }
1925 }
1926
1927 delete id;
1928
1929 if (!character)
1930 {
1931 return;
1932 }
1933
1934 // create an instance of this motion (it may or may not already exist)
1935 LLKeyframeMotion* motionp = (LLKeyframeMotion*)character->createMotion(asset_uuid);
1936
1937 if (0 == status && motionp)
1938 {
1939 if (motionp->mAssetStatus == ASSET_LOADED)
1940 {
1941 // asset already loaded
1942 return;
1943 }
1944 LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
1945 S32 size = file.getSize();
1946
1947 U8* buffer = new U8[size];
1948 file.read((U8*)buffer, size); /*Flawfinder: ignore*/
1949
1950 lldebugs << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << llendl;
1951
1952 LLDataPackerBinaryBuffer dp(buffer, size);
1953 if (motionp->deserialize(dp))
1954 {
1955 motionp->mAssetStatus = ASSET_LOADED;
1956 }
1957 else
1958 {
1959 llwarns << "Failed to decode asset for animation " << motionp->getName() << ":" << motionp->getID() << llendl;
1960 motionp->mAssetStatus = ASSET_FETCH_FAILED;
1961 }
1962
1963 delete []buffer;
1964
1965 }
1966 else
1967 {
1968 llwarns << "Failed to load asset for animation " << motionp->getName() << ":" << motionp->getID() << llendl;
1969 motionp->mAssetStatus = ASSET_FETCH_FAILED;
1970 }
1971}
1972
1973
1974//-----------------------------------------------------------------------------
1975// writeCAL3D()
1976//-----------------------------------------------------------------------------
1977void LLKeyframeMotion::writeCAL3D(apr_file_t* fp)
1978{
1979// <ANIMATION VERSION="1000" DURATION="1.03333" NUMTRACKS="58">
1980// <TRACK BONEID="0" NUMKEYFRAMES="31">
1981// <KEYFRAME TIME="0">
1982// <TRANSLATION>0 0 48.8332</TRANSLATION>
1983// <ROTATION>0.0512905 0.05657 0.66973 0.738668</ROTATION>
1984// </KEYFRAME>
1985// </TRACK>
1986// </ANIMATION>
1987
1988 apr_file_printf(fp, "<ANIMATION VERSION=\"1000\" DURATION=\"%.5f\" NUMTRACKS=\"%d\">\n", getDuration(), mJointMotionList->mNumJointMotions);
1989 for (U32 joint_index = 0; joint_index < mJointMotionList->mNumJointMotions; joint_index++)
1990 {
1991 JointMotion* joint_motionp = &mJointMotionList->mJointMotionArray[joint_index];
1992 LLJoint* animated_joint = mCharacter->getJoint(joint_motionp->mJointName);
1993 S32 joint_num = animated_joint->mJointNum + 1;
1994
1995 apr_file_printf(fp, " <TRACK BONEID=\"%d\" NUMKEYFRAMES=\"%d\">\n", joint_num, joint_motionp->mRotationCurve.mNumKeys );
1996 PositionKey* pos_keyp = joint_motionp->mPositionCurve.mKeys.getFirstData();
1997 for (RotationKey* rot_keyp = joint_motionp->mRotationCurve.mKeys.getFirstData();
1998 rot_keyp;
1999 rot_keyp = joint_motionp->mRotationCurve.mKeys.getNextData())
2000 {
2001 apr_file_printf(fp, " <KEYFRAME TIME=\"%0.3f\">\n", rot_keyp->mTime);
2002 LLVector3 nominal_pos = animated_joint->getPosition();
2003 if (animated_joint->getParent())
2004 {
2005 nominal_pos.scaleVec(animated_joint->getParent()->getScale());
2006 }
2007 nominal_pos = nominal_pos * 100.f;
2008
2009 if (joint_motionp->mUsage & LLJointState::POS && pos_keyp)
2010 {
2011 LLVector3 pos_val = pos_keyp->mPosition;
2012 pos_val = pos_val * 100.f;
2013 pos_val += nominal_pos;
2014 apr_file_printf(fp, " <TRANSLATION>%0.4f %0.4f %0.4f</TRANSLATION>\n", pos_val.mV[VX], pos_val.mV[VY], pos_val.mV[VZ]);
2015 pos_keyp = joint_motionp->mPositionCurve.mKeys.getNextData();
2016 }
2017 else
2018 {
2019 apr_file_printf(fp, " <TRANSLATION>%0.4f %0.4f %0.4f</TRANSLATION>\n", nominal_pos.mV[VX], nominal_pos.mV[VY], nominal_pos.mV[VZ]);
2020 }
2021
2022 LLQuaternion rot_val = ~rot_keyp->mRotation;
2023 apr_file_printf(fp, " <ROTATION>%0.4f %0.4f %0.4f %0.4f</ROTATION>\n", rot_val.mQ[VX], rot_val.mQ[VY], rot_val.mQ[VZ], rot_val.mQ[VW]);
2024 apr_file_printf(fp, " </KEYFRAME>\n");
2025 }
2026 apr_file_printf(fp, " </TRACK>\n");
2027 }
2028 apr_file_printf(fp, "</ANIMATION>\n");
2029}
2030
2031//--------------------------------------------------------------------
2032// LLKeyframeDataCache::dumpDiagInfo()
2033//--------------------------------------------------------------------
2034void LLKeyframeDataCache::dumpDiagInfo()
2035{
2036 // keep track of totals
2037 U32 total_size = 0;
2038
2039 char buf[1024]; /* Flawfinder: ignore */
2040
2041 llinfos << "-----------------------------------------------------" << llendl;
2042 llinfos << " Global Motion Table (DEBUG only)" << llendl;
2043 llinfos << "-----------------------------------------------------" << llendl;
2044
2045 // print each loaded mesh, and it's memory usage
2046 LLKeyframeDataMap::iterator map_it;
2047 for (map_it = sKeyframeDataMap.begin(); map_it != sKeyframeDataMap.end(); ++map_it)
2048 {
2049 U32 joint_motion_kb;
2050
2051 LLKeyframeMotion::JointMotionList *motion_list_p = map_it->second;
2052
2053 llinfos << "Motion: " << map_it->first << llendl;
2054
2055 joint_motion_kb = motion_list_p->dumpDiagInfo();
2056
2057 total_size += joint_motion_kb;
2058 }
2059
2060 llinfos << "-----------------------------------------------------" << llendl;
2061 llinfos << "Motions\tTotal Size" << llendl;
2062 snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */
2063 llinfos << buf << llendl;
2064 llinfos << "-----------------------------------------------------" << llendl;
2065}
2066
2067
2068//--------------------------------------------------------------------
2069// LLKeyframeDataCache::addKeyframeData()
2070//--------------------------------------------------------------------
2071void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp)
2072{
2073 sKeyframeDataMap[id] = joint_motion_listp;
2074}
2075
2076//--------------------------------------------------------------------
2077// LLKeyframeDataCache::removeKeyframeData()
2078//--------------------------------------------------------------------
2079void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id)
2080{
2081 LLKeyframeMotion::JointMotionList* joint_motion_listp = getKeyframeData(id);
2082 if (joint_motion_listp)
2083 {
2084 delete joint_motion_listp;
2085 }
2086 sKeyframeDataMap.erase(id);
2087}
2088
2089//--------------------------------------------------------------------
2090// LLKeyframeDataCache::getKeyframeData()
2091//--------------------------------------------------------------------
2092LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id)
2093{
2094 LLKeyframeDataMap::iterator found_data = sKeyframeDataMap.find(id);
2095 if (found_data == sKeyframeDataMap.end())
2096 {
2097 return NULL;
2098 }
2099 return found_data->second;
2100}
2101
2102//--------------------------------------------------------------------
2103// ~LLKeyframeDataCache::LLKeyframeDataCache()
2104//--------------------------------------------------------------------
2105LLKeyframeDataCache::~LLKeyframeDataCache()
2106{
2107 clear();
2108}
2109
2110//-----------------------------------------------------------------------------
2111// clear()
2112//-----------------------------------------------------------------------------
2113void LLKeyframeDataCache::clear()
2114{
2115 for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer());
2116 sKeyframeDataMap.clear();
2117}
2118
2119//-----------------------------------------------------------------------------
2120// JointConstraint()
2121//-----------------------------------------------------------------------------
2122LLKeyframeMotion::JointConstraint::JointConstraint(JointConstraintSharedData* shared_data) : mSharedData(shared_data)
2123{
2124 mTotalLength = 0.f;
2125 mActive = FALSE;
2126 mSourceVolume = NULL;
2127 mTargetVolume = NULL;
2128 mFixupDistanceRMS = 0.f;
2129}
2130
2131//-----------------------------------------------------------------------------
2132// ~JointConstraint()
2133//-----------------------------------------------------------------------------
2134LLKeyframeMotion::JointConstraint::~JointConstraint()
2135{
2136}
2137
2138// End
diff --git a/linden/indra/llcharacter/llkeyframemotion.h b/linden/indra/llcharacter/llkeyframemotion.h
new file mode 100644
index 0000000..c33df80
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframemotion.h
@@ -0,0 +1,456 @@
1/**
2 * @file llkeyframemotion.h
3 * @brief Implementation of LLKeframeMotion 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#ifndef LL_LLKEYFRAMEMOTION_H
29#define LL_LLKEYFRAMEMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34
35#include <string>
36
37#include "llassetstorage.h"
38#include "llassoclist.h"
39#include "llbboxlocal.h"
40#include "llhandmotion.h"
41#include "lljointstate.h"
42#include "llmotion.h"
43#include "llptrskipmap.h"
44#include "llquaternion.h"
45#include "v3dmath.h"
46#include "v3math.h"
47#include "llapr.h"
48
49class LLKeyframeDataCache;
50class LLVFS;
51class LLDataPacker;
52
53#define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f)
54#define MAX_CHAIN_LENGTH (4)
55
56const S32 KEYFRAME_MOTION_VERSION = 1;
57const S32 KEYFRAME_MOTION_SUBVERSION = 0;
58
59//-----------------------------------------------------------------------------
60// class LLKeyframeMotion
61//-----------------------------------------------------------------------------
62class LLKeyframeMotion :
63 public LLMotion
64{
65 friend class LLKeyframeDataCache;
66public:
67 // Constructor
68 LLKeyframeMotion(const LLUUID &id);
69
70 // Destructor
71 virtual ~LLKeyframeMotion();
72
73public:
74 //-------------------------------------------------------------------------
75 // functions to support MotionController and MotionRegistry
76 //-------------------------------------------------------------------------
77
78 // static constructor
79 // all subclasses must implement such a function and register it
80 static LLMotion *create(const LLUUID& id);
81
82public:
83 //-------------------------------------------------------------------------
84 // animation callbacks to be implemented by subclasses
85 //-------------------------------------------------------------------------
86
87 // motions must specify whether or not they loop
88 virtual BOOL getLoop() {
89 if (mJointMotionList) return mJointMotionList->mLoop;
90 else return FALSE;
91 }
92
93 // motions must report their total duration
94 virtual F32 getDuration() {
95 if (mJointMotionList) return mJointMotionList->mDuration;
96 else return 0.f;
97 }
98
99 // motions must report their "ease in" duration
100 virtual F32 getEaseInDuration() {
101 if (mJointMotionList) return mJointMotionList->mEaseInDuration;
102 else return 0.f;
103 }
104
105 // motions must report their "ease out" duration.
106 virtual F32 getEaseOutDuration() {
107 if (mJointMotionList) return mJointMotionList->mEaseOutDuration;
108 else return 0.f;
109 }
110
111 // motions must report their priority
112 virtual LLJoint::JointPriority getPriority() {
113 if (mJointMotionList) return mJointMotionList->mBasePriority;
114 else return LLJoint::LOW_PRIORITY;
115 }
116
117 virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
118
119 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
120 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
121
122 // run-time (post constructor) initialization,
123 // called after parameters have been set
124 // must return true to indicate success and be available for activation
125 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
126
127 // called when a motion is activated
128 // must return TRUE to indicate success, or else
129 // it will be deactivated
130 virtual BOOL onActivate();
131
132 // called per time step
133 // must return TRUE while it is active, and
134 // must return FALSE when the motion is completed.
135 virtual BOOL onUpdate(F32 time, U8* joint_mask);
136
137 // called when a motion is deactivated
138 virtual void onDeactivate();
139
140 virtual void setStopTime(F32 time);
141
142 static void setVFS(LLVFS* vfs) { sVFS = vfs; }
143
144 static void onLoadComplete(LLVFS *vfs,
145 const LLUUID& asset_uuid,
146 LLAssetType::EType type,
147 void* user_data, S32 status);
148
149public:
150 U32 getFileSize();
151 BOOL serialize(LLDataPacker& dp) const;
152 BOOL deserialize(LLDataPacker& dp);
153 void writeCAL3D(apr_file_t* fp);
154 BOOL isLoaded() { return mJointMotionList != NULL; }
155
156
157 // setters for modifying a keyframe animation
158 void setLoop(BOOL loop);
159
160 F32 getLoopIn() {
161 return (mJointMotionList) ? mJointMotionList->mLoopInPoint : 0.f;
162 }
163
164 F32 getLoopOut() {
165 return (mJointMotionList) ? mJointMotionList->mLoopOutPoint : 0.f;
166 }
167
168 void setLoopIn(F32 in_point);
169
170 void setLoopOut(F32 out_point);
171
172 void setHandPose(LLHandMotion::eHandPose pose) {
173 if (mJointMotionList) mJointMotionList->mHandPose = pose;
174 }
175
176 LLHandMotion::eHandPose getHandPose() {
177 return (mJointMotionList) ? mJointMotionList->mHandPose : LLHandMotion::HAND_POSE_RELAXED;
178 }
179
180 void setPriority(S32 priority);
181
182 void setEmote(const LLUUID& emote_id);
183
184 void setEaseIn(F32 ease_in);
185
186 void setEaseOut(F32 ease_in);
187
188 F32 getLastUpdateTime() { return mLastLoopedTime; }
189
190 const LLBBoxLocal& getPelvisBBox();
191
192 static void flushKeyframeCache();
193
194 typedef enum e_constraint_type
195 {
196 TYPE_POINT,
197 TYPE_PLANE
198 } EConstraintType;
199
200 typedef enum e_constraint_target_type
201 {
202 TYPE_BODY,
203 TYPE_GROUND
204 } EConstraintTargetType;
205
206protected:
207 //-------------------------------------------------------------------------
208 // JointConstraintSharedData
209 //-------------------------------------------------------------------------
210 class JointConstraintSharedData
211 {
212 public:
213 JointConstraintSharedData() :
214 mChainLength(0),
215 mEaseInStartTime(0.f),
216 mEaseInStopTime(0.f),
217 mEaseOutStartTime(0.f),
218 mEaseOutStopTime(0.f),
219 mUseTargetOffset(FALSE),
220 mConstraintType(TYPE_POINT),
221 mConstraintTargetType(TYPE_BODY) {};
222 ~JointConstraintSharedData() { delete [] mJointStateIndices; }
223
224 S32 mSourceConstraintVolume;
225 LLVector3 mSourceConstraintOffset;
226 S32 mTargetConstraintVolume;
227 LLVector3 mTargetConstraintOffset;
228 LLVector3 mTargetConstraintDir;
229 S32 mChainLength;
230 S32* mJointStateIndices;
231 F32 mEaseInStartTime;
232 F32 mEaseInStopTime;
233 F32 mEaseOutStartTime;
234 F32 mEaseOutStopTime;
235 BOOL mUseTargetOffset;
236 EConstraintType mConstraintType;
237 EConstraintTargetType mConstraintTargetType;
238 };
239
240 //-----------------------------------------------------------------------------
241 // JointConstraint()
242 //-----------------------------------------------------------------------------
243 class JointConstraint
244 {
245 public:
246 JointConstraint(JointConstraintSharedData* shared_data);
247 ~JointConstraint();
248
249 JointConstraintSharedData* mSharedData;
250 F32 mWeight;
251 F32 mTotalLength;
252 LLVector3 mPositions[MAX_CHAIN_LENGTH];
253 F32 mJointLengths[MAX_CHAIN_LENGTH];
254 F32 mJointLengthFractions[MAX_CHAIN_LENGTH];
255 BOOL mActive;
256 LLVector3d mGroundPos;
257 LLVector3 mGroundNorm;
258 LLJoint* mSourceVolume;
259 LLJoint* mTargetVolume;
260 F32 mFixupDistanceRMS;
261 };
262
263 void applyKeyframes(F32 time);
264
265 void applyConstraints(F32 time, U8* joint_mask);
266
267 void activateConstraint(JointConstraint* constraintp);
268
269 void initializeConstraint(JointConstraint* constraint);
270
271 void deactivateConstraint(JointConstraint *constraintp);
272
273 void applyConstraint(JointConstraint* constraintp, F32 time, U8* joint_mask);
274
275 BOOL setupPose();
276
277public:
278 enum AssetStatus { ASSET_LOADED, ASSET_FETCHED, ASSET_NEEDS_FETCH, ASSET_FETCH_FAILED, ASSET_UNDEFINED };
279
280 enum InterpolationType { IT_STEP, IT_LINEAR, IT_SPLINE };
281
282 //-------------------------------------------------------------------------
283 // ScaleKey
284 //-------------------------------------------------------------------------
285 class ScaleKey
286 {
287 public:
288 ScaleKey() { mTime = 0.0f; }
289 ScaleKey(F32 time, const LLVector3 &scale) { mTime = time; mScale = scale; }
290
291 F32 mTime;
292 LLVector3 mScale;
293 };
294
295 //-------------------------------------------------------------------------
296 // RotationKey
297 //-------------------------------------------------------------------------
298 class RotationKey
299 {
300 public:
301 RotationKey() { mTime = 0.0f; }
302 RotationKey(F32 time, const LLQuaternion &rotation) { mTime = time; mRotation = rotation; }
303
304 F32 mTime;
305 LLQuaternion mRotation;
306 };
307
308 //-------------------------------------------------------------------------
309 // PositionKey
310 //-------------------------------------------------------------------------
311 class PositionKey
312 {
313 public:
314 PositionKey() { mTime = 0.0f; }
315 PositionKey(F32 time, const LLVector3 &position) { mTime = time; mPosition = position; }
316
317 F32 mTime;
318 LLVector3 mPosition;
319 };
320
321 //-------------------------------------------------------------------------
322 // ScaleCurve
323 //-------------------------------------------------------------------------
324 class ScaleCurve
325 {
326 public:
327 ScaleCurve();
328 ~ScaleCurve();
329 LLVector3 getValue(F32 time, F32 duration);
330 LLVector3 interp(F32 u, ScaleKey& before, ScaleKey& after);
331
332 InterpolationType mInterpolationType;
333 S32 mNumKeys;
334 LLPtrSkipMap<F32, ScaleKey*> mKeys;
335 ScaleKey mLoopInKey;
336 ScaleKey mLoopOutKey;
337 };
338
339 //-------------------------------------------------------------------------
340 // RotationCurve
341 //-------------------------------------------------------------------------
342 class RotationCurve
343 {
344 public:
345 RotationCurve();
346 ~RotationCurve();
347 LLQuaternion getValue(F32 time, F32 duration);
348 LLQuaternion interp(F32 u, RotationKey& before, RotationKey& after);
349
350 InterpolationType mInterpolationType;
351 S32 mNumKeys;
352 LLPtrSkipMap<F32, RotationKey*> mKeys;
353 RotationKey mLoopInKey;
354 RotationKey mLoopOutKey;
355 };
356
357 //-------------------------------------------------------------------------
358 // PositionCurve
359 //-------------------------------------------------------------------------
360 class PositionCurve
361 {
362 public:
363 PositionCurve();
364 ~PositionCurve();
365 LLVector3 getValue(F32 time, F32 duration);
366 LLVector3 interp(F32 u, PositionKey& before, PositionKey& after);
367
368 InterpolationType mInterpolationType;
369 S32 mNumKeys;
370 LLPtrSkipMap<F32, PositionKey*> mKeys;
371 PositionKey mLoopInKey;
372 PositionKey mLoopOutKey;
373 };
374
375 //-------------------------------------------------------------------------
376 // JointMotion
377 //-------------------------------------------------------------------------
378 class JointMotion
379 {
380 public:
381 PositionCurve mPositionCurve;
382 RotationCurve mRotationCurve;
383 ScaleCurve mScaleCurve;
384 std::string mJointName;
385 U32 mUsage;
386 LLJoint::JointPriority mPriority;
387
388 void update(LLJointState *joint_state, F32 time, F32 duration);
389 };
390
391 //-------------------------------------------------------------------------
392 // JointMotionList
393 //-------------------------------------------------------------------------
394 class JointMotionList
395 {
396 public:
397 U32 mNumJointMotions;
398 JointMotion* mJointMotionArray;
399 F32 mDuration;
400 BOOL mLoop;
401 F32 mLoopInPoint;
402 F32 mLoopOutPoint;
403 F32 mEaseInDuration;
404 F32 mEaseOutDuration;
405 LLJoint::JointPriority mBasePriority;
406 LLHandMotion::eHandPose mHandPose;
407 LLJoint::JointPriority mMaxPriority;
408 LLLinkedList<JointConstraintSharedData> mConstraints;
409 LLBBoxLocal mPelvisBBox;
410 public:
411 JointMotionList() : mNumJointMotions(0), mJointMotionArray(NULL) {};
412 ~JointMotionList() { mConstraints.deleteAllData(); delete [] mJointMotionArray; }
413 U32 dumpDiagInfo();
414 };
415
416
417protected:
418 static LLVFS* sVFS;
419
420 //-------------------------------------------------------------------------
421 // Member Data
422 //-------------------------------------------------------------------------
423 JointMotionList* mJointMotionList;
424 LLJointState* mJointStates;
425 LLJoint* mPelvisp;
426 LLCharacter* mCharacter;
427 std::string mEmoteName;
428 LLLinkedList<JointConstraint> mConstraints;
429 U32 mLastSkeletonSerialNum;
430 F32 mLastUpdateTime;
431 F32 mLastLoopedTime;
432 AssetStatus mAssetStatus;
433};
434
435class LLKeyframeDataCache
436{
437public:
438 // *FIX: implement this as an actual singleton member of LLKeyframeMotion
439 LLKeyframeDataCache(){};
440 ~LLKeyframeDataCache();
441
442 typedef std::map<LLUUID, class LLKeyframeMotion::JointMotionList*> LLKeyframeDataMap;
443 static LLKeyframeDataMap sKeyframeDataMap;
444
445 static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*);
446 static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id);
447
448 static void removeKeyframeData(const LLUUID& id);
449
450 //print out diagnostic info
451 static void dumpDiagInfo();
452 static void clear();
453};
454
455#endif // LL_LLKEYFRAMEMOTION_H
456
diff --git a/linden/indra/llcharacter/llkeyframemotionparam.cpp b/linden/indra/llcharacter/llkeyframemotionparam.cpp
new file mode 100644
index 0000000..0bdc723
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframemotionparam.cpp
@@ -0,0 +1,461 @@
1/**
2 * @file llkeyframemotionparam.cpp
3 * @brief Implementation of LLKeyframeMotion 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 "llkeyframemotionparam.h"
34#include "llcharacter.h"
35#include "llmath.h"
36#include "m3math.h"
37#include "lldir.h"
38#include "llanimationstates.h"
39
40//-----------------------------------------------------------------------------
41//-----------------------------------------------------------------------------
42// LLKeyframeMotionParam class
43//-----------------------------------------------------------------------------
44//-----------------------------------------------------------------------------
45
46//-----------------------------------------------------------------------------
47// sortFunc()
48//-----------------------------------------------------------------------------
49BOOL LLKeyframeMotionParam::sortFunc(ParameterizedMotion *new_motion, ParameterizedMotion *tested_motion)
50{
51 return (new_motion->second < tested_motion->second);
52}
53
54//-----------------------------------------------------------------------------
55// LLKeyframeMotionParam()
56// Class Constructor
57//-----------------------------------------------------------------------------
58LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id)
59{
60 mJointStates = NULL;
61 mDefaultKeyframeMotion = NULL;
62 mCharacter = NULL;
63
64 mEaseInDuration = 0.f;
65 mEaseOutDuration = 0.f;
66 mDuration = 0.f;
67 mPriority = LLJoint::LOW_PRIORITY;
68}
69
70
71//-----------------------------------------------------------------------------
72// ~LLKeyframeMotionParam()
73// Class Destructor
74//-----------------------------------------------------------------------------
75LLKeyframeMotionParam::~LLKeyframeMotionParam()
76{
77 for (U32 i = 0; i < mParameterizedMotions.length(); i++)
78 {
79 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
80 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
81 {
82 delete paramMotion->first;
83 }
84 delete motionList;
85 }
86
87 mParameterizedMotions.removeAll();
88}
89
90//-----------------------------------------------------------------------------
91// LLKeyframeMotionParam::onInitialize(LLCharacter *character)
92//-----------------------------------------------------------------------------
93LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character)
94{
95 mCharacter = character;
96
97 if (!loadMotions())
98 {
99 return STATUS_FAILURE;
100 }
101
102 for (U32 i = 0; i < mParameterizedMotions.length(); i++)
103 {
104 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
105 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
106 {
107 paramMotion->first->onInitialize(character);
108
109 if (paramMotion->first->getDuration() > mEaseInDuration)
110 {
111 mEaseInDuration = paramMotion->first->getEaseInDuration();
112 }
113
114 if (paramMotion->first->getEaseOutDuration() > mEaseOutDuration)
115 {
116 mEaseOutDuration = paramMotion->first->getEaseOutDuration();
117 }
118
119 if (paramMotion->first->getDuration() > mDuration)
120 {
121 mDuration = paramMotion->first->getDuration();
122 }
123
124 if (paramMotion->first->getPriority() > mPriority)
125 {
126 mPriority = paramMotion->first->getPriority();
127 }
128
129 LLPose *pose = paramMotion->first->getPose();
130
131 mPoseBlender.addMotion(paramMotion->first);
132 for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
133 {
134 LLPose *blendedPose = mPoseBlender.getBlendedPose();
135 blendedPose->addJointState(jsp);
136 }
137 }
138 }
139
140 return STATUS_SUCCESS;
141}
142
143//-----------------------------------------------------------------------------
144// LLKeyframeMotionParam::onActivate()
145//-----------------------------------------------------------------------------
146BOOL LLKeyframeMotionParam::onActivate()
147{
148 for (U32 i = 0; i < mParameterizedMotions.length(); i++)
149 {
150 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
151 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
152 {
153 paramMotion->first->activate();
154 }
155 }
156 return TRUE;
157}
158
159
160//-----------------------------------------------------------------------------
161// LLKeyframeMotionParam::onUpdate()
162//-----------------------------------------------------------------------------
163BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
164{
165 F32 weightFactor = 1.f / (F32)mParameterizedMotions.length();
166 U32 i;
167
168 // zero out all pose weights
169 for (i = 0; i < mParameterizedMotions.length(); i++)
170 {
171 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
172
173 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
174 {
175// llinfos << "Weight for pose " << paramMotion->first->getName() << " is " << paramMotion->first->getPose()->getWeight() << llendl;
176 paramMotion->first->getPose()->setWeight(0.f);
177 }
178 }
179
180
181 for (i = 0; i < mParameterizedMotions.length(); i++)
182 {
183 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
184 std::string *paramName = mParameterizedMotions.getIndexAt(i);
185 F32* paramValue = (F32 *)mCharacter->getAnimationData(*paramName);
186 ParameterizedMotion* firstMotion = NULL;
187 ParameterizedMotion* secondMotion = NULL;
188
189 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
190 {
191 paramMotion->first->onUpdate(time, joint_mask);
192
193 F32 distToParam = paramMotion->second - *paramValue;
194
195 if ( distToParam <= 0.f)
196 {
197 // keep track of the motion closest to the parameter value
198 firstMotion = paramMotion;
199 }
200 else
201 {
202 // we've passed the parameter value
203 // so store the first motion we find as the second one we want to blend...
204 if (firstMotion && !secondMotion )
205 {
206 secondMotion = paramMotion;
207 }
208 //...or, if we've seen no other motion so far, make sure we blend to this only
209 else if (!firstMotion)
210 {
211 firstMotion = paramMotion;
212 secondMotion = paramMotion;
213 }
214 }
215 }
216
217 LLPose *firstPose;
218 LLPose *secondPose;
219
220 if (firstMotion)
221 firstPose = firstMotion->first->getPose();
222 else
223 firstPose = NULL;
224
225 if (secondMotion)
226 secondPose = secondMotion->first->getPose();
227 else
228 secondPose = NULL;
229
230 // now modify weight of the subanim (only if we are blending between two motions)
231 if (firstMotion && secondMotion)
232 {
233 if (firstMotion == secondMotion)
234 {
235 firstPose->setWeight(weightFactor);
236 }
237 else if (firstMotion->second == secondMotion->second)
238 {
239 firstPose->setWeight(0.5f * weightFactor);
240 secondPose->setWeight(0.5f * weightFactor);
241 }
242 else
243 {
244 F32 first_weight = 1.f -
245 ((llclamp(*paramValue - firstMotion->second, 0.f, (secondMotion->second - firstMotion->second))) /
246 (secondMotion->second - firstMotion->second));
247 first_weight = llclamp(first_weight, 0.f, 1.f);
248
249 F32 second_weight = 1.f - first_weight;
250
251 firstPose->setWeight(first_weight * weightFactor);
252 secondPose->setWeight(second_weight * weightFactor);
253
254// llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl;
255// llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl;
256 }
257 }
258 else if (firstMotion && !secondMotion)
259 {
260 firstPose->setWeight(weightFactor);
261 }
262 }
263
264 // blend poses
265 mPoseBlender.blendAndApply();
266
267 llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl;
268
269 return TRUE;
270}
271
272//-----------------------------------------------------------------------------
273// LLKeyframeMotionParam::onDeactivate()
274//-----------------------------------------------------------------------------
275void LLKeyframeMotionParam::onDeactivate()
276{
277 for (U32 i = 0; i < mParameterizedMotions.length(); i++)
278 {
279 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
280 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
281 {
282 paramMotion->first->onDeactivate();
283 }
284 }
285}
286
287//-----------------------------------------------------------------------------
288// LLKeyframeMotionParam::addKeyframeMotion()
289//-----------------------------------------------------------------------------
290BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value)
291{
292 LLMotion *newMotion = mCharacter->createMotion( id );
293
294 if (!newMotion)
295 {
296 return FALSE;
297 }
298
299 newMotion->setName(name);
300
301 // make sure a list of motions exists for this parameter
302 LLLinkedList< ParameterizedMotion > *motionList;
303 if (mParameterizedMotions.getValue(param))
304 {
305 motionList = *mParameterizedMotions.getValue(param);
306 }
307 else
308 {
309 motionList = new LLLinkedList< ParameterizedMotion >;
310 motionList->setInsertBefore(sortFunc);
311 mParameterizedMotions.addToHead(param, motionList);
312 }
313
314 // now add motion to this list
315 ParameterizedMotion *parameterizedMotion = new ParameterizedMotion(newMotion, value);
316
317 motionList->addDataSorted(parameterizedMotion);
318
319 return TRUE;
320}
321
322
323//-----------------------------------------------------------------------------
324// LLKeyframeMotionParam::setDefaultKeyframeMotion()
325//-----------------------------------------------------------------------------
326void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name)
327{
328 for (U32 i = 0; i < mParameterizedMotions.length(); i++)
329 {
330 LLLinkedList< ParameterizedMotion > *motionList = *mParameterizedMotions.getValueAt(i);
331 for (ParameterizedMotion* paramMotion = motionList->getFirstData(); paramMotion; paramMotion = motionList->getNextData())
332 {
333 if (paramMotion->first->getName() == name)
334 {
335 mDefaultKeyframeMotion = paramMotion->first;
336 }
337 }
338 }
339}
340
341//-----------------------------------------------------------------------------
342// loadMotions()
343//-----------------------------------------------------------------------------
344BOOL LLKeyframeMotionParam::loadMotions()
345{
346 //-------------------------------------------------------------------------
347 // Load named file by concatenating the character prefix with the motion name.
348 // Load data into a buffer to be parsed.
349 //-------------------------------------------------------------------------
350 char path[LL_MAX_PATH]; /* Flawfinder: ignore */
351 snprintf( path, sizeof(path), "%s_%s.llp",
352 gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()).c_str(),
353 getName().c_str() ); /* Flawfinder: ignore */
354
355 //-------------------------------------------------------------------------
356 // open the file
357 //-------------------------------------------------------------------------
358 S32 fileSize = 0;
359 apr_file_t* fp = ll_apr_file_open(path, LL_APR_R, &fileSize);
360 if (!fp || fileSize == 0)
361 {
362 llinfos << "ERROR: can't open: " << path << llendl;
363 return FALSE;
364 }
365
366 // allocate a text buffer
367 char *text = new char[ fileSize+1 ];
368 if ( !text )
369 {
370 llinfos << "ERROR: can't allocated keyframe text buffer." << llendl;
371 apr_file_close(fp);
372 return FALSE;
373 }
374
375 //-------------------------------------------------------------------------
376 // load data from file into buffer
377 //-------------------------------------------------------------------------
378 bool error = false;
379 char *p = text;
380 while ( 1 )
381 {
382 if (apr_file_eof(fp) == APR_EOF)
383 {
384 break;
385 }
386 if (apr_file_gets(p, 1024, fp) != APR_SUCCESS)
387 {
388 error = true;
389 break;
390 }
391 while ( *(++p) )
392 ;
393 }
394
395 //-------------------------------------------------------------------------
396 // close the file
397 //-------------------------------------------------------------------------
398 apr_file_close( fp );
399
400 //-------------------------------------------------------------------------
401 // check for error
402 //-------------------------------------------------------------------------
403 llassert( p <= (text+fileSize) );
404
405 if ( error )
406 {
407 llinfos << "ERROR: error while reading from " << path << llendl;
408 delete [] text;
409 return FALSE;
410 }
411
412 llinfos << "Loading parametric keyframe data for: " << getName() << llendl;
413
414 //-------------------------------------------------------------------------
415 // parse the text and build keyframe data structures
416 //-------------------------------------------------------------------------
417 p = text;
418 S32 num;
419 char strA[80]; /* Flawfinder: ignore */
420 char strB[80]; /* Flawfinder: ignore */
421 F32 floatA = 0.0f;
422
423
424 //-------------------------------------------------------------------------
425 // get priority
426 //-------------------------------------------------------------------------
427 BOOL isFirstMotion = TRUE;
428 num = sscanf(p, "%79s %79s %f", strA, strB, &floatA);
429
430 while(1)
431 {
432 if (num == 0 || num == EOF) break;
433 if ((num != 3))
434 {
435 llinfos << "WARNING: can't read parametric motion" << llendl;
436 delete [] text;
437 return FALSE;
438 }
439
440 addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(strA), strB, floatA);
441 if (isFirstMotion)
442 {
443 isFirstMotion = FALSE;
444 setDefaultKeyframeMotion(strA);
445 }
446
447 p = strstr(p, "\n");
448 if (!p)
449 {
450 break;
451 }
452
453 p++;
454 num = sscanf(p, "%79s %79s %f", strA, strB, &floatA);
455 }
456
457 delete [] text;
458 return TRUE;
459}
460
461// End
diff --git a/linden/indra/llcharacter/llkeyframemotionparam.h b/linden/indra/llcharacter/llkeyframemotionparam.h
new file mode 100644
index 0000000..33dd094
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframemotionparam.h
@@ -0,0 +1,157 @@
1/**
2 * @file llkeyframemotionparam.h
3 * @brief Implementation of LLKeframeMotionParam class.
4 *
5 * Copyright (c) 2002-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#ifndef LL_LLKEYFRAMEMOTIONPARAM_H
29#define LL_LLKEYFRAMEMOTIONPARAM_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34
35#include <string>
36
37#include "llmotion.h"
38#include "lljointstate.h"
39#include "v3math.h"
40#include "llquaternion.h"
41#include "linked_lists.h"
42#include "llkeyframemotion.h"
43
44//-----------------------------------------------------------------------------
45// class LLKeyframeMotionParam
46//-----------------------------------------------------------------------------
47class LLKeyframeMotionParam :
48 public LLMotion
49{
50public:
51 // Constructor
52 LLKeyframeMotionParam(const LLUUID &id);
53
54 // Destructor
55 virtual ~LLKeyframeMotionParam();
56
57public:
58 //-------------------------------------------------------------------------
59 // functions to support MotionController and MotionRegistry
60 //-------------------------------------------------------------------------
61
62 // static constructor
63 // all subclasses must implement such a function and register it
64 static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); }
65
66public:
67 //-------------------------------------------------------------------------
68 // animation callbacks to be implemented by subclasses
69 //-------------------------------------------------------------------------
70
71 // motions must specify whether or not they loop
72 virtual BOOL getLoop() {
73 return TRUE;
74 }
75
76 // motions must report their total duration
77 virtual F32 getDuration() {
78 return mDuration;
79 }
80
81 // motions must report their "ease in" duration
82 virtual F32 getEaseInDuration() {
83 return mEaseInDuration;
84 }
85
86 // motions must report their "ease out" duration.
87 virtual F32 getEaseOutDuration() {
88 return mEaseOutDuration;
89 }
90
91 // motions must report their priority
92 virtual LLJoint::JointPriority getPriority() {
93 return mPriority;
94 }
95
96 virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
97
98 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
99 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
100
101 // run-time (post constructor) initialization,
102 // called after parameters have been set
103 // must return true to indicate success and be available for activation
104 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
105
106 // called when a motion is activated
107 // must return TRUE to indicate success, or else
108 // it will be deactivated
109 virtual BOOL onActivate();
110
111 // called per time step
112 // must return TRUE while it is active, and
113 // must return FALSE when the motion is completed.
114 virtual BOOL onUpdate(F32 time, U8* joint_mask);
115
116 // called when a motion is deactivated
117 virtual void onDeactivate();
118
119 virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();}
120
121protected:
122 //-------------------------------------------------------------------------
123 // new functions defined by this subclass
124 //-------------------------------------------------------------------------
125 typedef std::pair<LLMotion*, F32> ParameterizedMotion;
126
127 // add a motion and associated parameter triplet
128 BOOL addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value);
129
130 // set default motion for LOD and retrieving blend constants
131 void setDefaultKeyframeMotion(char *);
132
133 static BOOL sortFunc(ParameterizedMotion *new_motion, ParameterizedMotion *tested_motion);
134
135 BOOL loadMotions();
136
137protected:
138 //-------------------------------------------------------------------------
139 // Member Data
140 //-------------------------------------------------------------------------
141
142 typedef LLLinkedList < ParameterizedMotion > motion_list_t;
143 LLAssocList <std::string, motion_list_t* > mParameterizedMotions;
144 LLJointState* mJointStates;
145 LLMotion* mDefaultKeyframeMotion;
146 LLCharacter* mCharacter;
147 LLPoseBlender mPoseBlender;
148
149 F32 mEaseInDuration;
150 F32 mEaseOutDuration;
151 F32 mDuration;
152 LLJoint::JointPriority mPriority;
153
154 LLUUID mTransactionID;
155};
156
157#endif // LL_LLKEYFRAMEMOTIONPARAM_H
diff --git a/linden/indra/llcharacter/llkeyframestandmotion.cpp b/linden/indra/llcharacter/llkeyframestandmotion.cpp
new file mode 100644
index 0000000..4fcb76c
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframestandmotion.cpp
@@ -0,0 +1,339 @@
1/**
2 * @file llkeyframestandmotion.cpp
3 * @brief Implementation of LLKeyframeStandMotion 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 "llkeyframestandmotion.h"
34#include "llcharacter.h"
35
36//-----------------------------------------------------------------------------
37// Macros and consts
38//-----------------------------------------------------------------------------
39#define GO_TO_KEY_POSE 1
40#define MIN_TRACK_SPEED 0.01f
41const F32 ROTATION_THRESHOLD = 0.6f;
42const F32 POSITION_THRESHOLD = 0.1f;
43
44//-----------------------------------------------------------------------------
45// LLKeyframeStandMotion()
46// Class Constructor
47//-----------------------------------------------------------------------------
48LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id)
49{
50 mFlipFeet = FALSE;
51 mCharacter = NULL;
52
53 // create kinematic hierarchy
54 mPelvisJoint.addChild( &mHipLeftJoint );
55 mHipLeftJoint.addChild( &mKneeLeftJoint );
56 mKneeLeftJoint.addChild( &mAnkleLeftJoint );
57 mPelvisJoint.addChild( &mHipRightJoint );
58 mHipRightJoint.addChild( &mKneeRightJoint );
59 mKneeRightJoint.addChild( &mAnkleRightJoint );
60
61 mPelvisState = NULL;
62
63 mHipLeftState = NULL;
64 mKneeLeftState = NULL;
65 mAnkleLeftState = NULL;
66
67 mHipRightState = NULL;
68 mKneeRightState = NULL;
69 mAnkleRightState = NULL;
70
71 mTrackAnkles = TRUE;
72
73 mFrameNum = 0;
74}
75
76
77//-----------------------------------------------------------------------------
78// ~LLKeyframeStandMotion()
79// Class Destructor
80//-----------------------------------------------------------------------------
81LLKeyframeStandMotion::~LLKeyframeStandMotion()
82{
83}
84
85
86//-----------------------------------------------------------------------------
87// LLKeyframeStandMotion::onInitialize()
88//-----------------------------------------------------------------------------
89LLMotion::LLMotionInitStatus LLKeyframeStandMotion::onInitialize(LLCharacter *character)
90{
91 // save character pointer for later use
92 mCharacter = character;
93
94 mFlipFeet = FALSE;
95
96 // load keyframe data, setup pose and joint states
97 LLMotion::LLMotionInitStatus status = LLKeyframeMotion::onInitialize(character);
98 if ( status == STATUS_FAILURE )
99 {
100 return status;
101 }
102
103 // find the necessary joint states
104 LLPose *pose = getPose();
105 mPelvisState = pose->findJointState("mPelvis");
106
107 mHipLeftState = pose->findJointState("mHipLeft");
108 mKneeLeftState = pose->findJointState("mKneeLeft");
109 mAnkleLeftState = pose->findJointState("mAnkleLeft");
110
111 mHipRightState = pose->findJointState("mHipRight");
112 mKneeRightState = pose->findJointState("mKneeRight");
113 mAnkleRightState = pose->findJointState("mAnkleRight");
114
115 if ( !mPelvisState ||
116 !mHipLeftState ||
117 !mKneeLeftState ||
118 !mAnkleLeftState ||
119 !mHipRightState ||
120 !mKneeRightState ||
121 !mAnkleRightState )
122 {
123 llinfos << getName() << ": Can't find necessary joint states" << llendl;
124 return STATUS_FAILURE;
125 }
126
127 return STATUS_SUCCESS;
128}
129
130//-----------------------------------------------------------------------------
131// LLKeyframeStandMotion::onActivate()
132//-----------------------------------------------------------------------------
133BOOL LLKeyframeStandMotion::onActivate()
134{
135 //-------------------------------------------------------------------------
136 // setup the IK solvers
137 //-------------------------------------------------------------------------
138 mIKLeft.setPoleVector( LLVector3(1.0f, 0.0f, 0.0f));
139 mIKRight.setPoleVector( LLVector3(1.0f, 0.0f, 0.0f));
140 mIKLeft.setBAxis( LLVector3(0.05f, 1.0f, 0.0f));
141 mIKRight.setBAxis( LLVector3(-0.05f, 1.0f, 0.0f));
142
143 mLastGoodPelvisRotation.loadIdentity();
144 mLastGoodPosition.clearVec();
145
146 mFrameNum = 0;
147
148 return LLKeyframeMotion::onActivate();
149}
150
151//-----------------------------------------------------------------------------
152// LLKeyframeStandMotion::onDeactivate()
153//-----------------------------------------------------------------------------
154void LLKeyframeStandMotion::onDeactivate()
155{
156 LLKeyframeMotion::onDeactivate();
157}
158
159//-----------------------------------------------------------------------------
160// LLKeyframeStandMotion::onUpdate()
161//-----------------------------------------------------------------------------
162BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
163{
164 //-------------------------------------------------------------------------
165 // let the base class update the cycle
166 //-------------------------------------------------------------------------
167 BOOL status = LLKeyframeMotion::onUpdate(time, joint_mask);
168 if (!status)
169 {
170 return FALSE;
171 }
172
173 LLVector3 root_world_pos = mPelvisState->getJoint()->getParent()->getWorldPosition();
174
175 // have we received a valid world position for this avatar?
176 if (root_world_pos.isExactlyZero())
177 {
178 return TRUE;
179 }
180
181 //-------------------------------------------------------------------------
182 // Stop tracking (start locking) ankles once ease in is done.
183 // Setting this here ensures we track until we get valid foot position.
184 //-------------------------------------------------------------------------
185 if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD)
186 {
187 mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation();
188 mLastGoodPelvisRotation.normQuat();
189 mTrackAnkles = TRUE;
190 }
191 else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD)
192 {
193 mLastGoodPosition = mCharacter->getCharacterPosition();
194 mTrackAnkles = TRUE;
195 }
196 else if (mPose.getWeight() < 1.f)
197 {
198 mTrackAnkles = TRUE;
199 }
200
201
202 //-------------------------------------------------------------------------
203 // propagate joint positions to internal versions
204 //-------------------------------------------------------------------------
205 mPelvisJoint.setPosition(
206 root_world_pos +
207 mPelvisState->getPosition() );
208
209 mHipLeftJoint.setPosition( mHipLeftState->getJoint()->getPosition() );
210 mKneeLeftJoint.setPosition( mKneeLeftState->getJoint()->getPosition() );
211 mAnkleLeftJoint.setPosition( mAnkleLeftState->getJoint()->getPosition() );
212
213 mHipLeftJoint.setScale( mHipLeftState->getJoint()->getScale() );
214 mKneeLeftJoint.setScale( mKneeLeftState->getJoint()->getScale() );
215 mAnkleLeftJoint.setScale( mAnkleLeftState->getJoint()->getScale() );
216
217 mHipRightJoint.setPosition( mHipRightState->getJoint()->getPosition() );
218 mKneeRightJoint.setPosition( mKneeRightState->getJoint()->getPosition() );
219 mAnkleRightJoint.setPosition( mAnkleRightState->getJoint()->getPosition() );
220
221 mHipRightJoint.setScale( mHipRightState->getJoint()->getScale() );
222 mKneeRightJoint.setScale( mKneeRightState->getJoint()->getScale() );
223 mAnkleRightJoint.setScale( mAnkleRightState->getJoint()->getScale() );
224 //-------------------------------------------------------------------------
225 // propagate joint rotations to internal versions
226 //-------------------------------------------------------------------------
227 mPelvisJoint.setRotation( mPelvisState->getJoint()->getWorldRotation() );
228
229#if GO_TO_KEY_POSE
230 mHipLeftJoint.setRotation( mHipLeftState->getRotation() );
231 mKneeLeftJoint.setRotation( mKneeLeftState->getRotation() );
232 mAnkleLeftJoint.setRotation( mAnkleLeftState->getRotation() );
233
234 mHipRightJoint.setRotation( mHipRightState->getRotation() );
235 mKneeRightJoint.setRotation( mKneeRightState->getRotation() );
236 mAnkleRightJoint.setRotation( mAnkleRightState->getRotation() );
237#else
238 mHipLeftJoint.setRotation( mHipLeftState->getJoint()->getRotation() );
239 mKneeLeftJoint.setRotation( mKneeLeftState->getJoint()->getRotation() );
240 mAnkleLeftJoint.setRotation( mAnkleLeftState->getJoint()->getRotation() );
241
242 mHipRightJoint.setRotation( mHipRightState->getJoint()->getRotation() );
243 mKneeRightJoint.setRotation( mKneeRightState->getJoint()->getRotation() );
244 mAnkleRightJoint.setRotation( mAnkleRightState->getJoint()->getRotation() );
245#endif
246
247 // need to wait for underlying keyframe motion to affect the skeleton
248 if (mFrameNum == 2)
249 {
250 mIKLeft.setupJoints( &mHipLeftJoint, &mKneeLeftJoint, &mAnkleLeftJoint, &mTargetLeft );
251 mIKRight.setupJoints( &mHipRightJoint, &mKneeRightJoint, &mAnkleRightJoint, &mTargetRight );
252 }
253 else if (mFrameNum < 2)
254 {
255 mFrameNum++;
256 return TRUE;
257 }
258
259 mFrameNum++;
260
261 //-------------------------------------------------------------------------
262 // compute target position by projecting ankles to the ground
263 //-------------------------------------------------------------------------
264 if ( mTrackAnkles )
265 {
266 mCharacter->getGround( mAnkleLeftJoint.getWorldPosition(), mPositionLeft, mNormalLeft);
267 mCharacter->getGround( mAnkleRightJoint.getWorldPosition(), mPositionRight, mNormalRight);
268
269 mTargetLeft.setPosition( mPositionLeft );
270 mTargetRight.setPosition( mPositionRight );
271 }
272
273 //-------------------------------------------------------------------------
274 // update solvers
275 //-------------------------------------------------------------------------
276 mIKLeft.solve();
277 mIKRight.solve();
278
279 //-------------------------------------------------------------------------
280 // make ankle rotation conform to the ground
281 //-------------------------------------------------------------------------
282 if ( mTrackAnkles )
283 {
284 LLVector4 dirLeft4 = mAnkleLeftJoint.getWorldMatrix().getFwdRow4();
285 LLVector4 dirRight4 = mAnkleRightJoint.getWorldMatrix().getFwdRow4();
286 LLVector3 dirLeft = vec4to3( dirLeft4 );
287 LLVector3 dirRight = vec4to3( dirRight4 );
288
289 LLVector3 up;
290 LLVector3 dir;
291 LLVector3 left;
292
293 up = mNormalLeft;
294 up.normVec();
295 if (mFlipFeet)
296 {
297 up *= -1.0f;
298 }
299 dir = dirLeft;
300 dir.normVec();
301 left = up % dir;
302 left.normVec();
303 dir = left % up;
304 mRotationLeft = LLQuaternion( dir, left, up );
305
306 up = mNormalRight;
307 up.normVec();
308 if (mFlipFeet)
309 {
310 up *= -1.0f;
311 }
312 dir = dirRight;
313 dir.normVec();
314 left = up % dir;
315 left.normVec();
316 dir = left % up;
317 mRotationRight = LLQuaternion( dir, left, up );
318 }
319 mAnkleLeftJoint.setWorldRotation( mRotationLeft );
320 mAnkleRightJoint.setWorldRotation( mRotationRight );
321
322 //-------------------------------------------------------------------------
323 // propagate joint rotations to joint states
324 //-------------------------------------------------------------------------
325 mHipLeftState->setRotation( mHipLeftJoint.getRotation() );
326 mKneeLeftState->setRotation( mKneeLeftJoint.getRotation() );
327 mAnkleLeftState->setRotation( mAnkleLeftJoint.getRotation() );
328
329 mHipRightState->setRotation( mHipRightJoint.getRotation() );
330 mKneeRightState->setRotation( mKneeRightJoint.getRotation() );
331 mAnkleRightState->setRotation( mAnkleRightJoint.getRotation() );
332
333 //llinfos << "Stand drift amount " << (mCharacter->getCharacterPosition() - mLastGoodPosition).magVec() << llendl;
334
335// llinfos << "DEBUG: " << speed << " : " << mTrackAnkles << llendl;
336 return TRUE;
337}
338
339// End
diff --git a/linden/indra/llcharacter/llkeyframestandmotion.h b/linden/indra/llcharacter/llkeyframestandmotion.h
new file mode 100644
index 0000000..f569498
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframestandmotion.h
@@ -0,0 +1,117 @@
1/**
2 * @file llkeyframestandmotion.h
3 * @brief Implementation of LLKeyframeStandMotion 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#ifndef LL_LLKEYFRAMESTANDMOTION_H
29#define LL_LLKEYFRAMESTANDMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llkeyframemotion.h"
35#include "lljointsolverrp3.h"
36
37
38//-----------------------------------------------------------------------------
39// class LLKeyframeStandMotion
40//-----------------------------------------------------------------------------
41class LLKeyframeStandMotion :
42 public LLKeyframeMotion
43{
44public:
45 // Constructor
46 LLKeyframeStandMotion(const LLUUID &id);
47
48 // Destructor
49 virtual ~LLKeyframeStandMotion();
50
51public:
52 //-------------------------------------------------------------------------
53 // functions to support MotionController and MotionRegistry
54 //-------------------------------------------------------------------------
55
56 // static constructor
57 // all subclasses must implement such a function and register it
58 static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); }
59
60public:
61 //-------------------------------------------------------------------------
62 // animation callbacks to be implemented by subclasses
63 //-------------------------------------------------------------------------
64 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
65 virtual BOOL onActivate();
66 void onDeactivate();
67 virtual BOOL onUpdate(F32 time, U8* joint_mask);
68
69public:
70 //-------------------------------------------------------------------------
71 // Member Data
72 //-------------------------------------------------------------------------
73 LLCharacter *mCharacter;
74
75 BOOL mFlipFeet;
76
77 LLJointState *mPelvisState;
78
79 LLJointState *mHipLeftState;
80 LLJointState *mKneeLeftState;
81 LLJointState *mAnkleLeftState;
82
83 LLJointState *mHipRightState;
84 LLJointState *mKneeRightState;
85 LLJointState *mAnkleRightState;
86
87 LLJoint mPelvisJoint;
88
89 LLJoint mHipLeftJoint;
90 LLJoint mKneeLeftJoint;
91 LLJoint mAnkleLeftJoint;
92 LLJoint mTargetLeft;
93
94 LLJoint mHipRightJoint;
95 LLJoint mKneeRightJoint;
96 LLJoint mAnkleRightJoint;
97 LLJoint mTargetRight;
98
99 LLJointSolverRP3 mIKLeft;
100 LLJointSolverRP3 mIKRight;
101
102 LLVector3 mPositionLeft;
103 LLVector3 mPositionRight;
104 LLVector3 mNormalLeft;
105 LLVector3 mNormalRight;
106 LLQuaternion mRotationLeft;
107 LLQuaternion mRotationRight;
108
109 LLQuaternion mLastGoodPelvisRotation;
110 LLVector3 mLastGoodPosition;
111 BOOL mTrackAnkles;
112
113 S32 mFrameNum;
114};
115
116#endif // LL_LLKEYFRAMESTANDMOTION_H
117
diff --git a/linden/indra/llcharacter/llkeyframewalkmotion.cpp b/linden/indra/llcharacter/llkeyframewalkmotion.cpp
new file mode 100644
index 0000000..b1838d8
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -0,0 +1,398 @@
1/**
2 * @file llkeyframewalkmotion.cpp
3 * @brief Implementation of LLKeyframeWalkMotion 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 "llkeyframewalkmotion.h"
34#include "llcharacter.h"
35#include "llmath.h"
36#include "m3math.h"
37#include "llcriticaldamp.h"
38
39//-----------------------------------------------------------------------------
40// Macros
41//-----------------------------------------------------------------------------
42const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed
43
44const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection
45const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
46const F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed
47const F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second
48const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction
49const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out
50const F32 MAX_ROLL = 0.6f;
51
52//-----------------------------------------------------------------------------
53// LLKeyframeWalkMotion()
54// Class Constructor
55//-----------------------------------------------------------------------------
56LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id) : LLKeyframeMotion(id)
57{
58 mRealTimeLast = 0.0f;
59 mAdjTimeLast = 0.0f;
60 mCharacter = NULL;
61}
62
63
64//-----------------------------------------------------------------------------
65// ~LLKeyframeWalkMotion()
66// Class Destructor
67//-----------------------------------------------------------------------------
68LLKeyframeWalkMotion::~LLKeyframeWalkMotion()
69{
70}
71
72
73//-----------------------------------------------------------------------------
74// LLKeyframeWalkMotion::onInitialize()
75//-----------------------------------------------------------------------------
76LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character)
77{
78 mCharacter = character;
79
80 return LLKeyframeMotion::onInitialize(character);
81}
82
83//-----------------------------------------------------------------------------
84// LLKeyframeWalkMotion::onActivate()
85//-----------------------------------------------------------------------------
86BOOL LLKeyframeWalkMotion::onActivate()
87{
88 mRealTimeLast = 0.0f;
89 mAdjTimeLast = 0.0f;
90
91 return LLKeyframeMotion::onActivate();
92}
93
94//-----------------------------------------------------------------------------
95// LLKeyframeWalkMotion::onDeactivate()
96//-----------------------------------------------------------------------------
97void LLKeyframeWalkMotion::onDeactivate()
98{
99 mCharacter->removeAnimationData("Down Foot");
100 LLKeyframeMotion::onDeactivate();
101}
102
103//-----------------------------------------------------------------------------
104// LLKeyframeWalkMotion::onUpdate()
105//-----------------------------------------------------------------------------
106BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
107{
108 // compute time since last update
109 F32 deltaTime = time - mRealTimeLast;
110
111 void* speed_ptr = mCharacter->getAnimationData("Walk Speed");
112 F32 speed = (speed_ptr) ? *((F32 *)speed_ptr) : 1.f;
113
114 // adjust the passage of time accordingly
115 F32 adjusted_time = mAdjTimeLast + (deltaTime * speed);
116
117 // save time for next update
118 mRealTimeLast = time;
119 mAdjTimeLast = adjusted_time;
120
121 // handle wrap around
122 if (adjusted_time < 0.0f)
123 {
124 adjusted_time = getDuration() + fmod(adjusted_time, getDuration());
125 }
126
127 // let the base class update the cycle
128 return LLKeyframeMotion::onUpdate( adjusted_time, joint_mask );
129}
130
131// End
132
133
134//-----------------------------------------------------------------------------
135// LLWalkAdjustMotion()
136// Class Constructor
137//-----------------------------------------------------------------------------
138LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : LLMotion(id)
139{
140 mLastTime = 0.f;
141 mName = "walk_adjust";
142}
143
144//-----------------------------------------------------------------------------
145// LLWalkAdjustMotion::onInitialize()
146//-----------------------------------------------------------------------------
147LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *character)
148{
149 mCharacter = character;
150 mLeftAnkleJoint = mCharacter->getJoint("mAnkleLeft");
151 mRightAnkleJoint = mCharacter->getJoint("mAnkleRight");
152
153 mPelvisJoint = mCharacter->getJoint("mPelvis");
154 mPelvisState.setJoint( mPelvisJoint );
155 if ( !mPelvisJoint )
156 {
157 llwarns << getName() << ": Can't get pelvis joint." << llendl;
158 return STATUS_FAILURE;
159 }
160
161 mPelvisState.setUsage(LLJointState::POS);
162 addJointState( &mPelvisState );
163
164 return STATUS_SUCCESS;
165}
166
167//-----------------------------------------------------------------------------
168// LLWalkAdjustMotion::onActivate()
169//-----------------------------------------------------------------------------
170BOOL LLWalkAdjustMotion::onActivate()
171{
172 mAvgCorrection = 0.f;
173 mSpeedAdjust = 0.f;
174 mAnimSpeed = 0.f;
175 mAvgSpeed = 0.f;
176 mRelativeDir = 1.f;
177 mPelvisState.setPosition(LLVector3::zero);
178 // store ankle positions for next frame
179 mLastLeftAnklePos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
180 mLastRightAnklePos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
181
182 F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
183 F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
184 mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
185
186 return TRUE;
187}
188
189//-----------------------------------------------------------------------------
190// LLWalkAdjustMotion::onUpdate()
191//-----------------------------------------------------------------------------
192BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
193{
194 LLVector3 footCorrection;
195 LLVector3 vel = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
196 F32 deltaTime = llclamp(time - mLastTime, 0.f, MAX_TIME_DELTA);
197 mLastTime = time;
198
199 LLQuaternion inv_rotation = ~mPelvisJoint->getWorldRotation();
200
201 // get speed and normalize velocity vector
202 LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
203 F32 speed = llmin(vel.normVec(), MAX_WALK_PLAYBACK_SPEED);
204 mAvgSpeed = lerp(mAvgSpeed, speed, LLCriticalDamp::getInterpolant(0.2f));
205
206 // calculate facing vector in pelvis-local space
207 // (either straight forward or back, depending on velocity)
208 LLVector3 localVel = vel * inv_rotation;
209 if (localVel.mV[VX] > 0.f)
210 {
211 mRelativeDir = 1.f;
212 }
213 else if (localVel.mV[VX] < 0.f)
214 {
215 mRelativeDir = -1.f;
216 }
217
218 // calculate world-space foot drift
219 LLVector3 leftFootDelta;
220 LLVector3 leftFootWorldPosition = mLeftAnkleJoint->getWorldPosition();
221 LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(leftFootWorldPosition);
222 leftFootDelta.setVec(mLastLeftAnklePos - leftFootGlobalPosition);
223 mLastLeftAnklePos = leftFootGlobalPosition;
224
225 LLVector3 rightFootDelta;
226 LLVector3 rightFootWorldPosition = mRightAnkleJoint->getWorldPosition();
227 LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(rightFootWorldPosition);
228 rightFootDelta.setVec(mLastRightAnklePos - rightFootGlobalPosition);
229 mLastRightAnklePos = rightFootGlobalPosition;
230
231 // find foot drift along velocity vector
232 if (mAvgSpeed > 0.1)
233 {
234 // walking/running
235 F32 leftFootDriftAmt = leftFootDelta * vel;
236 F32 rightFootDriftAmt = rightFootDelta * vel;
237
238 if (rightFootDriftAmt > leftFootDriftAmt)
239 {
240 footCorrection = rightFootDelta;
241 } else
242 {
243 footCorrection = leftFootDelta;
244 }
245 }
246 else
247 {
248 mAvgSpeed = ang_vel.magVec() * mAnkleOffset;
249 mRelativeDir = 1.f;
250
251 // standing/turning
252 // find the lower foot
253 if (leftFootWorldPosition.mV[VZ] < rightFootWorldPosition.mV[VZ])
254 {
255 // pivot on left foot
256 footCorrection = leftFootDelta;
257 }
258 else
259 {
260 // pivot on right foot
261 footCorrection = rightFootDelta;
262 }
263 }
264
265 // rotate into avatar coordinates
266 footCorrection = footCorrection * inv_rotation;
267
268 // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
269 // the amount of foot slippage this frame + the offset applied last frame
270 mPelvisOffset = mPelvisState.getPosition() + lerp(LLVector3::zero, footCorrection, LLCriticalDamp::getInterpolant(0.2f));
271
272 // pelvis drift (along walk direction)
273 mAvgCorrection = lerp(mAvgCorrection, footCorrection.mV[VX] * mRelativeDir, LLCriticalDamp::getInterpolant(0.1f));
274
275 // calculate average velocity of foot slippage
276 F32 footSlipVelocity = (deltaTime != 0.f) ? (-mAvgCorrection / deltaTime) : 0.f;
277
278 F32 newSpeedAdjust = 0.f;
279
280 // modulate speed by dot products of facing and velocity
281 // so that if we are moving sideways, we slow down the animation
282 // and if we're moving backward, we walk backward
283
284 F32 directional_factor = localVel.mV[VX] * mRelativeDir;
285 if (speed > 0.1f)
286 {
287 // calculate ratio of desired foot velocity to detected foot velocity
288 newSpeedAdjust = llclamp(footSlipVelocity - mAvgSpeed * (1.f - directional_factor),
289 -SPEED_ADJUST_MAX, SPEED_ADJUST_MAX);
290 newSpeedAdjust = lerp(mSpeedAdjust, newSpeedAdjust, LLCriticalDamp::getInterpolant(0.2f));
291
292 F32 speedDelta = newSpeedAdjust - mSpeedAdjust;
293 speedDelta = llclamp(speedDelta, -SPEED_ADJUST_MAX_SEC * deltaTime, SPEED_ADJUST_MAX_SEC * deltaTime);
294
295 mSpeedAdjust = mSpeedAdjust + speedDelta;
296 }
297 else
298 {
299 mSpeedAdjust = lerp(mSpeedAdjust, 0.f, LLCriticalDamp::getInterpolant(0.2f));
300 }
301
302 mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir;
303// char debug_text[64];
304// sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
305// mCharacter->addDebugText(debug_text);
306// sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
307// mCharacter->addDebugText(debug_text);
308// sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
309// mCharacter->addDebugText(debug_text);
310// sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
311// mCharacter->addDebugText(debug_text);
312 mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
313
314 // clamp pelvis offset to a 90 degree arc behind the nominal position
315 F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED;
316 drift_comp_max *= DRIFT_COMP_MAX_TOTAL;
317
318 LLVector3 currentPelvisPos = mPelvisState.getJoint()->getPosition();
319
320 // NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
321 // must clamp with absolute position of pelvis in mind
322 mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max - currentPelvisPos.mV[VX], drift_comp_max - currentPelvisPos.mV[VX] );
323 mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max - currentPelvisPos.mV[VY], drift_comp_max - currentPelvisPos.mV[VY]);
324 mPelvisOffset.mV[VZ] = 0.f;
325
326 // set position
327 mPelvisState.setPosition(mPelvisOffset);
328
329 mCharacter->setAnimationData("Pelvis Offset", &mPelvisOffset);
330
331 return TRUE;
332}
333
334//-----------------------------------------------------------------------------
335// LLWalkAdjustMotion::onDeactivate()
336//-----------------------------------------------------------------------------
337void LLWalkAdjustMotion::onDeactivate()
338{
339 mCharacter->removeAnimationData("Walk Speed");
340}
341
342//-----------------------------------------------------------------------------
343// LLFlyAdjustMotion::onInitialize()
344//-----------------------------------------------------------------------------
345LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *character)
346{
347 mCharacter = character;
348
349 LLJoint* pelvisJoint = mCharacter->getJoint("mPelvis");
350 mPelvisState.setJoint( pelvisJoint );
351 if ( !pelvisJoint )
352 {
353 llwarns << getName() << ": Can't get pelvis joint." << llendl;
354 return STATUS_FAILURE;
355 }
356
357 mPelvisState.setUsage(LLJointState::POS | LLJointState::ROT);
358 addJointState( &mPelvisState );
359
360 return STATUS_SUCCESS;
361}
362
363//-----------------------------------------------------------------------------
364// LLFlyAdjustMotion::onActivate()
365//-----------------------------------------------------------------------------
366BOOL LLFlyAdjustMotion::onActivate()
367{
368 mPelvisState.setPosition(LLVector3::zero);
369 mPelvisState.setRotation(LLQuaternion::DEFAULT);
370 mRoll = 0.f;
371 return TRUE;
372}
373
374//-----------------------------------------------------------------------------
375// LLFlyAdjustMotion::onUpdate()
376//-----------------------------------------------------------------------------
377BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
378{
379 LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
380 F32 speed = mCharacter->getCharacterVelocity().magVec();
381
382 F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL);
383 F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
384
385 // roll is critically damped interpolation between current roll and angular velocity-derived target roll
386 mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
387
388// llinfos << mRoll << llendl;
389
390 LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
391 mPelvisState.setRotation(roll);
392
393// F32 lerp_amt = LLCriticalDamp::getInterpolant(0.2f);
394//
395// LLVector3 pelvis_correction = mPelvisState.getPosition() - lerp(LLVector3::zero, mPelvisState.getJoint()->getPosition() + mPelvisState.getPosition(), lerp_amt);
396// mPelvisState.setPosition(pelvis_correction);
397 return TRUE;
398}
diff --git a/linden/indra/llcharacter/llkeyframewalkmotion.h b/linden/indra/llcharacter/llkeyframewalkmotion.h
new file mode 100644
index 0000000..3367b64
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframewalkmotion.h
@@ -0,0 +1,177 @@
1/**
2 * @file llkeyframewalkmotion.h
3 * @brief Implementation of LLKeframeWalkMotion 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#ifndef LL_LLKEYFRAMEWALKMOTION_H
29#define LL_LLKEYFRAMEWALKMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llkeyframemotion.h"
35#include "llcharacter.h"
36#include "v3dmath.h"
37
38#define MIN_REQUIRED_PIXEL_AREA_WALK_ADJUST (20.f)
39#define MIN_REQUIRED_PIXEL_AREA_FLY_ADJUST (20.f)
40
41//-----------------------------------------------------------------------------
42// class LLKeyframeWalkMotion
43//-----------------------------------------------------------------------------
44class LLKeyframeWalkMotion :
45 public LLKeyframeMotion
46{
47 friend class LLWalkAdjustMotion;
48public:
49 // Constructor
50 LLKeyframeWalkMotion(const LLUUID &id);
51
52 // Destructor
53 virtual ~LLKeyframeWalkMotion();
54
55public:
56 //-------------------------------------------------------------------------
57 // functions to support MotionController and MotionRegistry
58 //-------------------------------------------------------------------------
59
60 // static constructor
61 // all subclasses must implement such a function and register it
62 static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); }
63
64public:
65 //-------------------------------------------------------------------------
66 // animation callbacks to be implemented by subclasses
67 //-------------------------------------------------------------------------
68 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
69 virtual BOOL onActivate();
70 virtual void onDeactivate();
71 virtual BOOL onUpdate(F32 time, U8* joint_mask);
72
73public:
74 //-------------------------------------------------------------------------
75 // Member Data
76 //-------------------------------------------------------------------------
77 LLCharacter *mCharacter;
78 F32 mCyclePhase;
79 F32 mRealTimeLast;
80 F32 mAdjTimeLast;
81 S32 mDownFoot;
82};
83
84class LLWalkAdjustMotion : public LLMotion
85{
86public:
87 // Constructor
88 LLWalkAdjustMotion(const LLUUID &id);
89
90public:
91 //-------------------------------------------------------------------------
92 // functions to support MotionController and MotionRegistry
93 //-------------------------------------------------------------------------
94
95 // static constructor
96 // all subclasses must implement such a function and register it
97 static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); }
98
99public:
100 //-------------------------------------------------------------------------
101 // animation callbacks to be implemented by subclasses
102 //-------------------------------------------------------------------------
103 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
104 virtual BOOL onActivate();
105 virtual void onDeactivate();
106 virtual BOOL onUpdate(F32 time, U8* joint_mask);
107 virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGH_PRIORITY;}
108 virtual BOOL getLoop() { return TRUE; }
109 virtual F32 getDuration() { return 0.f; }
110 virtual F32 getEaseInDuration() { return 0.f; }
111 virtual F32 getEaseOutDuration() { return 0.f; }
112 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_WALK_ADJUST; }
113 virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
114
115public:
116 //-------------------------------------------------------------------------
117 // Member Data
118 //-------------------------------------------------------------------------
119 LLCharacter *mCharacter;
120 LLJoint* mLeftAnkleJoint;
121 LLJoint* mRightAnkleJoint;
122 LLJointState mPelvisState;
123 LLJoint* mPelvisJoint;
124 LLVector3d mLastLeftAnklePos;
125 LLVector3d mLastRightAnklePos;
126 F32 mLastTime;
127 F32 mAvgCorrection;
128 F32 mSpeedAdjust;
129 F32 mAnimSpeed;
130 F32 mAvgSpeed;
131 F32 mRelativeDir;
132 LLVector3 mPelvisOffset;
133 F32 mAnkleOffset;
134};
135
136class LLFlyAdjustMotion : public LLMotion
137{
138public:
139 // Constructor
140 LLFlyAdjustMotion(const LLUUID &id) : LLMotion(id) {mName = "fly_adjust";}
141
142public:
143 //-------------------------------------------------------------------------
144 // functions to support MotionController and MotionRegistry
145 //-------------------------------------------------------------------------
146
147 // static constructor
148 // all subclasses must implement such a function and register it
149 static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); }
150
151public:
152 //-------------------------------------------------------------------------
153 // animation callbacks to be implemented by subclasses
154 //-------------------------------------------------------------------------
155 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
156 virtual BOOL onActivate();
157 virtual void onDeactivate() {};
158 virtual BOOL onUpdate(F32 time, U8* joint_mask);
159 virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;}
160 virtual BOOL getLoop() { return TRUE; }
161 virtual F32 getDuration() { return 0.f; }
162 virtual F32 getEaseInDuration() { return 0.f; }
163 virtual F32 getEaseOutDuration() { return 0.f; }
164 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_FLY_ADJUST; }
165 virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
166
167protected:
168 //-------------------------------------------------------------------------
169 // Member Data
170 //-------------------------------------------------------------------------
171 LLCharacter *mCharacter;
172 LLJointState mPelvisState;
173 F32 mRoll;
174};
175
176#endif // LL_LLKeyframeWalkMotion_H
177
diff --git a/linden/indra/llcharacter/llmotion.cpp b/linden/indra/llcharacter/llmotion.cpp
new file mode 100644
index 0000000..d2343ab
--- /dev/null
+++ b/linden/indra/llcharacter/llmotion.cpp
@@ -0,0 +1,150 @@
1/**
2 * @file llmotion.cpp
3 * @brief Implementation of LLMotion 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 "llmotion.h"
34#include "llcriticaldamp.h"
35
36//-----------------------------------------------------------------------------
37//-----------------------------------------------------------------------------
38// LLMotion class
39//-----------------------------------------------------------------------------
40//-----------------------------------------------------------------------------
41
42//-----------------------------------------------------------------------------
43// LLMotion()
44// Class Constructor
45//-----------------------------------------------------------------------------
46LLMotion::LLMotion( const LLUUID &id )
47{
48 mActivationTimestamp = 0.f;
49 mStopTimestamp = 0.f;
50 mSendStopTimestamp = F32_MAX;
51 mResidualWeight = 0.f;
52 mFadeWeight = 1.f;
53 mStopped = TRUE;
54 mActive = FALSE;
55 mDeactivateCallback = NULL;
56
57 memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
58 memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
59 memset(&mJointSignature[2][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
60
61 mID = id;
62}
63
64//-----------------------------------------------------------------------------
65// ~LLMotion()
66// Class Destructor
67//-----------------------------------------------------------------------------
68LLMotion::~LLMotion()
69{
70}
71
72//-----------------------------------------------------------------------------
73// fadeOut()
74//-----------------------------------------------------------------------------
75void LLMotion::fadeOut()
76{
77 if (mFadeWeight > 0.01f)
78 {
79 mFadeWeight = lerp(mFadeWeight, 0.f, LLCriticalDamp::getInterpolant(0.15f));
80 }
81 else
82 {
83 mFadeWeight = 0.f;
84 }
85}
86
87//-----------------------------------------------------------------------------
88// fadeIn()
89//-----------------------------------------------------------------------------
90void LLMotion::fadeIn()
91{
92 if (mFadeWeight < 0.99f)
93 {
94 mFadeWeight = lerp(mFadeWeight, 1.f, LLCriticalDamp::getInterpolant(0.15f));
95 }
96 else
97 {
98 mFadeWeight = 1.f;
99 }
100}
101
102//-----------------------------------------------------------------------------
103// addJointState()
104//-----------------------------------------------------------------------------
105void LLMotion::addJointState(LLJointState* jointState)
106{
107 mPose.addJointState(jointState);
108 S32 priority = jointState->getPriority();
109 if (priority == LLJoint::USE_MOTION_PRIORITY)
110 {
111 priority = getPriority();
112 }
113
114 U32 usage = jointState->getUsage();
115
116 // for now, usage is everything
117 mJointSignature[0][jointState->getJoint()->getJointNum()] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0;
118 mJointSignature[1][jointState->getJoint()->getJointNum()] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0;
119 mJointSignature[2][jointState->getJoint()->getJointNum()] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0;
120}
121
122void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata )
123{
124 mDeactivateCallback = cb;
125 mDeactivateCallbackUserData = userdata;
126}
127
128//-----------------------------------------------------------------------------
129// activate()
130//-----------------------------------------------------------------------------
131void LLMotion::activate()
132{
133 mStopped = FALSE;
134 mActive = TRUE;
135 onActivate();
136}
137
138//-----------------------------------------------------------------------------
139// deactivate()
140//-----------------------------------------------------------------------------
141void LLMotion::deactivate()
142{
143 mActive = FALSE;
144
145 if (mDeactivateCallback) (*mDeactivateCallback)(mDeactivateCallbackUserData);
146
147 onDeactivate();
148}
149
150// End
diff --git a/linden/indra/llcharacter/llmotion.h b/linden/indra/llcharacter/llmotion.h
new file mode 100644
index 0000000..2e302cf
--- /dev/null
+++ b/linden/indra/llcharacter/llmotion.h
@@ -0,0 +1,256 @@
1/**
2 * @file llmotion.h
3 * @brief Implementation of LLMotion 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#ifndef LL_LLMOTION_H
29#define LL_LLMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include <string>
35
36#include "llerror.h"
37#include "llpose.h"
38#include "lluuid.h"
39
40class LLCharacter;
41
42//-----------------------------------------------------------------------------
43// class LLMotion
44//-----------------------------------------------------------------------------
45class LLMotion
46{
47public:
48 enum LLMotionBlendType
49 {
50 NORMAL_BLEND,
51 ADDITIVE_BLEND
52 };
53
54 enum LLMotionInitStatus
55 {
56 STATUS_FAILURE,
57 STATUS_SUCCESS,
58 STATUS_HOLD
59 };
60
61 // Constructor
62 LLMotion(const LLUUID &id);
63
64 // Destructor
65 virtual ~LLMotion();
66
67public:
68 //-------------------------------------------------------------------------
69 // functions to support MotionController and MotionRegistry
70 //-------------------------------------------------------------------------
71
72 // static constructor
73 // all subclasses must implement such a function and register it
74 static LLMotion *create(const LLUUID &id) { return NULL; }
75
76 // get the name of this instance
77 const std::string &getName() const { return mName; }
78
79 // set the name of this instance
80 void setName(const std::string &name) { mName = name; }
81
82 const LLUUID& getID() const { return mID; }
83
84 // returns the pose associated with the current state of this motion
85 virtual LLPose* getPose() { return &mPose;}
86
87 void fadeOut();
88
89 void fadeIn();
90
91 F32 getFadeWeight() const { return mFadeWeight; }
92
93 F32 getStopTime() const { return mStopTimestamp; }
94
95 virtual void setStopTime(F32 time) { mStopTimestamp = time; mStopped = TRUE; }
96
97 BOOL isStopped() const { return mStopped; }
98
99 void setStopped(BOOL stopped) { mStopped = stopped; }
100
101 void activate();
102
103 void deactivate();
104
105 BOOL isActive() { return mActive; }
106
107
108public:
109 //-------------------------------------------------------------------------
110 // animation callbacks to be implemented by subclasses
111 //-------------------------------------------------------------------------
112
113 // motions must specify whether or not they loop
114 virtual BOOL getLoop() = 0;
115
116 // motions must report their total duration
117 virtual F32 getDuration() = 0;
118
119 // motions must report their "ease in" duration
120 virtual F32 getEaseInDuration() = 0;
121
122 // motions must report their "ease out" duration.
123 virtual F32 getEaseOutDuration() = 0;
124
125 // motions must report their priority level
126 virtual LLJoint::JointPriority getPriority() = 0;
127
128 // motions must report their blend type
129 virtual LLMotionBlendType getBlendType() = 0;
130
131 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
132 virtual F32 getMinPixelArea() = 0;
133
134 // run-time (post constructor) initialization,
135 // called after parameters have been set
136 // must return true to indicate success and be available for activation
137 virtual LLMotionInitStatus onInitialize(LLCharacter *character) = 0;
138
139 // called per time step
140 // must return TRUE while it is active, and
141 // must return FALSE when the motion is completed.
142 virtual BOOL onUpdate(F32 activeTime, U8* joint_mask) = 0;
143
144 // called when a motion is deactivated
145 virtual void onDeactivate() = 0;
146
147 // optional callback routine called when animation deactivated.
148 void setDeactivateCallback( void (*cb)(void *), void* userdata );
149
150protected:
151 // called when a motion is activated
152 // must return TRUE to indicate success, or else
153 // it will be deactivated
154 virtual BOOL onActivate() = 0;
155
156 void addJointState(LLJointState* jointState);
157
158protected:
159 LLPose mPose;
160 BOOL mStopped; // motion has been stopped;
161 BOOL mActive; // motion is on active list (can be stopped or not stopped)
162
163public:
164 //-------------------------------------------------------------------------
165 // these are set implicitly by the motion controller and
166 // may be referenced (read only) in the above handlers.
167 //-------------------------------------------------------------------------
168 std::string mName; // instance name assigned by motion controller
169 LLUUID mID;
170
171 F32 mActivationTimestamp; // time when motion was activated
172 F32 mStopTimestamp; // time when motion was told to stop
173 F32 mSendStopTimestamp; // time when simulator should be told to stop this motion
174 F32 mResidualWeight; // blend weight at beginning of stop motion phase
175 F32 mFadeWeight; // for fading in and out based on LOD
176 U8 mJointSignature[3][LL_CHARACTER_MAX_JOINTS]; // signature of which joints are animated at what priority
177 void (*mDeactivateCallback)(void* data);
178 void* mDeactivateCallbackUserData;
179};
180
181
182//-----------------------------------------------------------------------------
183// LLTestMotion
184//-----------------------------------------------------------------------------
185class LLTestMotion : public LLMotion
186{
187public:
188 LLTestMotion(const LLUUID &id) : LLMotion(id){}
189 ~LLTestMotion() {}
190 static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); }
191 BOOL getLoop() { return FALSE; }
192 F32 getDuration() { return 0.0f; }
193 F32 getEaseInDuration() { return 0.0f; }
194 F32 getEaseOutDuration() { return 0.0f; }
195 LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; }
196 LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
197 F32 getMinPixelArea() { return 0.f; }
198
199 LLMotionInitStatus onInitialize(LLCharacter*) { llinfos << "LLTestMotion::onInitialize()" << llendl; return STATUS_SUCCESS; }
200 BOOL onActivate() { llinfos << "LLTestMotion::onActivate()" << llendl; return TRUE; }
201 BOOL onUpdate(F32 time, U8* joint_mask) { llinfos << "LLTestMotion::onUpdate(" << time << ")" << llendl; return TRUE; }
202 void onDeactivate() { llinfos << "LLTestMotion::onDeactivate()" << llendl; }
203};
204
205
206//-----------------------------------------------------------------------------
207// LLNullMotion
208//-----------------------------------------------------------------------------
209class LLNullMotion : public LLMotion
210{
211public:
212 LLNullMotion(const LLUUID &id) : LLMotion(id) {}
213 ~LLNullMotion() {}
214 static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); }
215
216 // motions must specify whether or not they loop
217 /*virtual*/ BOOL getLoop() { return TRUE; }
218
219 // motions must report their total duration
220 /*virtual*/ F32 getDuration() { return 1.f; }
221
222 // motions must report their "ease in" duration
223 /*virtual*/ F32 getEaseInDuration() { return 0.f; }
224
225 // motions must report their "ease out" duration.
226 /*virtual*/ F32 getEaseOutDuration() { return 0.f; }
227
228 // motions must report their priority level
229 /*virtual*/ LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; }
230
231 // motions must report their blend type
232 /*virtual*/ LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
233
234 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
235 /*virtual*/ F32 getMinPixelArea() { return 0.f; }
236
237 // run-time (post constructor) initialization,
238 // called after parameters have been set
239 // must return true to indicate success and be available for activation
240 /*virtual*/ LLMotionInitStatus onInitialize(LLCharacter *character) { return STATUS_SUCCESS; }
241
242 // called when a motion is activated
243 // must return TRUE to indicate success, or else
244 // it will be deactivated
245 /*virtual*/ BOOL onActivate() { return TRUE; }
246
247 // called per time step
248 // must return TRUE while it is active, and
249 // must return FALSE when the motion is completed.
250 /*virtual*/ BOOL onUpdate(F32 activeTime, U8* joint_mask) { return TRUE; }
251
252 // called when a motion is deactivated
253 /*virtual*/ void onDeactivate() {}
254};
255#endif // LL_LLMOTION_H
256
diff --git a/linden/indra/llcharacter/llmotioncontroller.cpp b/linden/indra/llcharacter/llmotioncontroller.cpp
new file mode 100644
index 0000000..3e1456b
--- /dev/null
+++ b/linden/indra/llcharacter/llmotioncontroller.cpp
@@ -0,0 +1,946 @@
1/**
2 * @file llmotioncontroller.cpp
3 * @brief Implementation of LLMotionController 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 "llmotioncontroller.h"
34#include "llkeyframemotion.h"
35#include "llmath.h"
36#include "lltimer.h"
37#include "llanimationstates.h"
38#include "llstl.h"
39
40const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4;
41const U32 MAX_MOTION_INSTANCES = 32;
42
43//-----------------------------------------------------------------------------
44// Constants and statics
45//-----------------------------------------------------------------------------
46LLMotionRegistry LLMotionController::sRegistry;
47
48//-----------------------------------------------------------------------------
49// LLMotionTableEntry()
50//-----------------------------------------------------------------------------
51LLMotionTableEntry::LLMotionTableEntry()
52{
53 mConstructor = NULL;
54 mID.setNull();
55}
56
57LLMotionTableEntry::LLMotionTableEntry(LLMotionConstructor constructor, const LLUUID& id)
58 : mConstructor(constructor), mID(id)
59{
60
61}
62
63//-----------------------------------------------------------------------------
64// create()
65//-----------------------------------------------------------------------------
66LLMotion* LLMotionTableEntry::create(const LLUUID &id)
67{
68 LLMotion* motionp = mConstructor(id);
69
70 return motionp;
71}
72
73
74//-----------------------------------------------------------------------------
75//-----------------------------------------------------------------------------
76// LLMotionRegistry class
77//-----------------------------------------------------------------------------
78//-----------------------------------------------------------------------------
79
80//-----------------------------------------------------------------------------
81// LLMotionRegistry()
82// Class Constructor
83//-----------------------------------------------------------------------------
84LLMotionRegistry::LLMotionRegistry() : mMotionTable(LLMotionTableEntry::uuidEq, LLMotionTableEntry())
85{
86
87}
88
89
90//-----------------------------------------------------------------------------
91// ~LLMotionRegistry()
92// Class Destructor
93//-----------------------------------------------------------------------------
94LLMotionRegistry::~LLMotionRegistry()
95{
96 mMotionTable.removeAll();
97}
98
99
100//-----------------------------------------------------------------------------
101// addMotion()
102//-----------------------------------------------------------------------------
103BOOL LLMotionRegistry::addMotion( const LLUUID& id, LLMotionConstructor constructor )
104{
105// llinfos << "Registering motion: " << name << llendl;
106 if (!mMotionTable.check(id))
107 {
108 mMotionTable.set(id, LLMotionTableEntry(constructor, id));
109 return TRUE;
110 }
111
112 return FALSE;
113}
114
115//-----------------------------------------------------------------------------
116// markBad()
117//-----------------------------------------------------------------------------
118void LLMotionRegistry::markBad( const LLUUID& id )
119{
120 mMotionTable.set(id, LLMotionTableEntry());
121}
122
123//-----------------------------------------------------------------------------
124// createMotion()
125//-----------------------------------------------------------------------------
126LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
127{
128 LLMotionTableEntry motion_entry = mMotionTable.get(id);
129 LLMotion* motion = NULL;
130
131 if ( motion_entry.getID().isNull() )
132 {
133 // *FIX: need to replace with a better default scheme. RN
134 motion = LLKeyframeMotion::create(id);
135 }
136 else
137 {
138 motion = motion_entry.create(id);
139 }
140
141 return motion;
142}
143
144//-----------------------------------------------------------------------------
145//-----------------------------------------------------------------------------
146// LLMotionController class
147//-----------------------------------------------------------------------------
148//-----------------------------------------------------------------------------
149
150//-----------------------------------------------------------------------------
151// LLMotionController()
152// Class Constructor
153//-----------------------------------------------------------------------------
154LLMotionController::LLMotionController( )
155{
156 mTime = 0.f;
157 mTimeOffset = 0.f;
158 mLastTime = 0.0f;
159 mHasRunOnce = FALSE;
160 mPaused = FALSE;
161 mPauseTime = 0.f;
162 mTimeStep = 0.f;
163 mTimeStepCount = 0;
164 mLastInterp = 0.f;
165 mTimeFactor = 1.f;
166}
167
168
169//-----------------------------------------------------------------------------
170// ~LLMotionController()
171// Class Destructor
172//-----------------------------------------------------------------------------
173LLMotionController::~LLMotionController()
174{
175 deleteAllMotions();
176}
177
178//-----------------------------------------------------------------------------
179// deleteAllMotions()
180//-----------------------------------------------------------------------------
181void LLMotionController::deleteAllMotions()
182{
183 mLoadingMotions.removeAllNodes();
184 mLoadedMotions.clear();
185 mActiveMotions.removeAllNodes();
186
187 for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
188 mAllMotions.clear();
189}
190
191//-----------------------------------------------------------------------------
192// addLoadedMotion()
193//-----------------------------------------------------------------------------
194void LLMotionController::addLoadedMotion(LLMotion* motionp)
195{
196 if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
197 {
198 // too many motions active this frame, kill all blenders
199 mPoseBlender.clearBlenders();
200
201 for (U32 i = 0; i < mLoadedMotions.size(); i++)
202 {
203 LLMotion* cur_motionp = mLoadedMotions.front();
204 mLoadedMotions.pop_front();
205
206 // motion isn't playing, delete it
207 if (!isMotionActive(cur_motionp))
208 {
209 mCharacter->requestStopMotion(cur_motionp);
210 mAllMotions.erase(cur_motionp->getID());
211 delete cur_motionp;
212 if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES)
213 {
214 break;
215 }
216 }
217 else
218 {
219 // put active motion on back
220 mLoadedMotions.push_back(cur_motionp);
221 }
222 }
223 }
224 mLoadedMotions.push_back(motionp);
225}
226
227//-----------------------------------------------------------------------------
228// setTimeStep()
229//-----------------------------------------------------------------------------
230void LLMotionController::setTimeStep(F32 step)
231{
232 mTimeStep = step;
233
234 if (step != 0.f)
235 {
236 // make sure timestamps conform to new quantum
237 for( LLMotion* motionp = mActiveMotions.getFirstData();
238 motionp != NULL;
239 motionp = mActiveMotions.getNextData() )
240 {
241 motionp->mActivationTimestamp = (F32)llfloor(motionp->mActivationTimestamp / step) * step;
242 BOOL stopped = motionp->isStopped();
243 motionp->setStopTime((F32)llfloor(motionp->getStopTime() / step) * step);
244 motionp->setStopped(stopped);
245 motionp->mSendStopTimestamp = (F32)llfloor(motionp->mSendStopTimestamp / step) * step;
246 }
247 }
248}
249
250//-----------------------------------------------------------------------------
251// setTimeFactor()
252//-----------------------------------------------------------------------------
253void LLMotionController::setTimeFactor(F32 time_factor)
254{
255 mTimeOffset += mTimer.getElapsedTimeAndResetF32() * mTimeFactor;
256 mTimeFactor = time_factor;
257}
258
259//-----------------------------------------------------------------------------
260// getFirstActiveMotion()
261//-----------------------------------------------------------------------------
262LLMotion* LLMotionController::getFirstActiveMotion()
263{
264 return mActiveMotions.getFirstData();
265}
266
267//-----------------------------------------------------------------------------
268// getNextActiveMotion()
269//-----------------------------------------------------------------------------
270LLMotion* LLMotionController::getNextActiveMotion()
271{
272 return mActiveMotions.getNextData();
273}
274
275
276//-----------------------------------------------------------------------------
277// setCharacter()
278//-----------------------------------------------------------------------------
279void LLMotionController::setCharacter(LLCharacter *character)
280{
281 mCharacter = character;
282}
283
284
285//-----------------------------------------------------------------------------
286// addMotion()
287//-----------------------------------------------------------------------------
288BOOL LLMotionController::addMotion( const LLUUID& id, LLMotionConstructor constructor )
289{
290 return sRegistry.addMotion(id, constructor);
291}
292
293//-----------------------------------------------------------------------------
294// removeMotion()
295//-----------------------------------------------------------------------------
296void LLMotionController::removeMotion( const LLUUID& id)
297{
298 LLMotion* motionp = findMotion(id);
299 if (motionp)
300 {
301 stopMotionLocally(id, TRUE);
302
303 mLoadingMotions.deleteData(motionp);
304 std::deque<LLMotion*>::iterator motion_it;
305 for (motion_it = mLoadedMotions.begin(); motion_it != mLoadedMotions.end(); ++motion_it)
306 {
307 if(*motion_it == motionp)
308 {
309 mLoadedMotions.erase(motion_it);
310 break;
311 }
312 }
313 mActiveMotions.deleteData(motionp);
314 mAllMotions.erase(id);
315 delete motionp;
316 }
317}
318
319//-----------------------------------------------------------------------------
320// createMotion()
321//-----------------------------------------------------------------------------
322LLMotion* LLMotionController::createMotion( const LLUUID &id )
323{
324 // do we have an instance of this motion for this character?
325 LLMotion *motion = findMotion(id);
326
327 // if not, we need to create one
328 if (!motion)
329 {
330 // look up constructor and create it
331 motion = sRegistry.createMotion(id);
332 if (!motion)
333 {
334 return NULL;
335 }
336
337 // look up name for default motions
338 const char* motion_name = gAnimLibrary.animStateToString(id);
339 if (motion_name)
340 {
341 motion->setName(motion_name);
342 }
343
344 // initialize the new instance
345 LLMotion::LLMotionInitStatus stat = motion->onInitialize(mCharacter);
346 switch(stat)
347 {
348 case LLMotion::STATUS_FAILURE:
349 llinfos << "Motion " << id << " init failed." << llendl;
350 sRegistry.markBad(id);
351 delete motion;
352 return NULL;
353 case LLMotion::STATUS_HOLD:
354 mLoadingMotions.addData(motion);
355 break;
356 case LLMotion::STATUS_SUCCESS:
357 // add motion to our list
358 addLoadedMotion(motion);
359 break;
360 default:
361 llerrs << "Invalid initialization status" << llendl;
362 break;
363 }
364
365 mAllMotions[id] = motion;
366 }
367 return motion;
368}
369
370//-----------------------------------------------------------------------------
371// startMotion()
372//-----------------------------------------------------------------------------
373BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
374{
375 // look for motion in our list of created motions
376 LLMotion *motion = createMotion(id);
377
378 if (!motion)
379 {
380 return FALSE;
381 }
382 //if the motion is already active, then we're done
383 else if (isMotionActive(motion)) // motion is playing and...
384 {
385 if (motion->isStopped()) // motion has been stopped
386 {
387 deactivateMotion(motion);
388 }
389 else if (mTime < motion->mSendStopTimestamp) // motion is still active
390 {
391 return TRUE;
392 }
393 }
394
395// llinfos << "Starting motion " << name << llendl;
396 return activateMotion(motion, mTime - start_offset);
397}
398
399
400//-----------------------------------------------------------------------------
401// stopMotionLocally()
402//-----------------------------------------------------------------------------
403BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate)
404{
405 // if already inactive, return false
406 LLMotion *motion = findMotion(id);
407 if (!motion)
408 {
409 return FALSE;
410 }
411
412 // If on active list, stop it
413 if (isMotionActive(motion) && !motion->isStopped())
414 {
415 // when using timesteps, set stop time to last frame's time, otherwise grab current timer value
416 // *FIX: should investigate this inconsistency...hints of obscure bugs
417
418 F32 stop_time = (mTimeStep != 0.f || mPaused) ? (mTime) : mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor);
419 motion->setStopTime(stop_time);
420
421 if (stop_immediate)
422 {
423 deactivateMotion(motion);
424 }
425 return TRUE;
426 }
427 else if (isMotionLoading(motion))
428 {
429 motion->setStopped(TRUE);
430 return TRUE;
431 }
432
433 return FALSE;
434}
435
436
437//-----------------------------------------------------------------------------
438// updateRegularMotions()
439//-----------------------------------------------------------------------------
440void LLMotionController::updateRegularMotions()
441{
442 updateMotionsByType(LLMotion::NORMAL_BLEND);
443}
444
445//-----------------------------------------------------------------------------
446// updateAdditiveMotions()
447//-----------------------------------------------------------------------------
448void LLMotionController::updateAdditiveMotions()
449{
450 updateMotionsByType(LLMotion::ADDITIVE_BLEND);
451}
452
453//-----------------------------------------------------------------------------
454// resetJointSignatures()
455//-----------------------------------------------------------------------------
456void LLMotionController::resetJointSignatures()
457{
458 memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
459 memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
460}
461
462//-----------------------------------------------------------------------------
463// updateMotionsByType()
464//-----------------------------------------------------------------------------
465void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
466{
467 BOOL update_result = TRUE;
468 U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS];
469
470 memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
471
472 // iterate through active motions in chronological order
473 for(LLMotion* motionp = mActiveMotions.getFirstData();
474 motionp != NULL;
475 motionp = mActiveMotions.getNextData())
476 {
477 if (motionp->getBlendType() != anim_type)
478 {
479 continue;
480 }
481
482 BOOL update_motion = FALSE;
483
484 if (motionp->getPose()->getWeight() < 1.f)
485 {
486 update_motion = TRUE;
487 }
488 else
489 {
490 S32 i;
491 // NUM_JOINT_SIGNATURE_STRIDES should be multiple of 4
492 for (i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++)
493 {
494 U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]);
495 U32 test_signature = *(U32*)&(motionp->mJointSignature[0][i * 4]);
496
497 if ((*current_signature | test_signature) > (*current_signature))
498 {
499 *current_signature |= test_signature;
500 update_motion = TRUE;
501 }
502
503 *((U32*)&last_joint_signature[i * 4]) = *(U32*)&(mJointSignature[1][i * 4]);
504 current_signature = (U32*)&(mJointSignature[1][i * 4]);
505 test_signature = *(U32*)&(motionp->mJointSignature[1][i * 4]);
506
507 if ((*current_signature | test_signature) > (*current_signature))
508 {
509 *current_signature |= test_signature;
510 update_motion = TRUE;
511 }
512 }
513 }
514
515 if (!update_motion)
516 {
517 if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
518 {
519 deactivateMotion(motionp);
520 }
521 else if (motionp->isStopped() && mTime > motionp->getStopTime())
522 {
523 // is this the first iteration in the ease out phase?
524 if (mLastTime <= motionp->getStopTime())
525 {
526 // store residual weight for this motion
527 motionp->mResidualWeight = motionp->getPose()->getWeight();
528 }
529 }
530 else if (mTime > motionp->mSendStopTimestamp)
531 {
532 // notify character of timed stop event on first iteration past sendstoptimestamp
533 // this will only be called when an animation stops itself (runs out of time)
534 if (mLastTime <= motionp->mSendStopTimestamp)
535 {
536 mCharacter->requestStopMotion( motionp );
537 stopMotionLocally(motionp->getID(), FALSE);
538 }
539 }
540 else if (mTime >= motionp->mActivationTimestamp)
541 {
542 if (mLastTime < motionp->mActivationTimestamp)
543 {
544 motionp->mResidualWeight = motionp->getPose()->getWeight();
545 }
546 }
547 continue;
548 }
549
550 LLPose *posep = motionp->getPose();
551
552 // only filter by LOD after running every animation at least once (to prime the avatar state)
553 if (mHasRunOnce && motionp->getMinPixelArea() > mCharacter->getPixelArea())
554 {
555 motionp->fadeOut();
556
557 //should we notify the simulator that this motion should be stopped (check even if skipped by LOD logic)
558 if (mTime > motionp->mSendStopTimestamp)
559 {
560 // notify character of timed stop event on first iteration past sendstoptimestamp
561 // this will only be called when an animation stops itself (runs out of time)
562 if (mLastTime <= motionp->mSendStopTimestamp)
563 {
564 mCharacter->requestStopMotion( motionp );
565 stopMotionLocally(motionp->getID(), FALSE);
566 }
567 }
568
569 if (motionp->getFadeWeight() < 0.01f)
570 {
571 if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
572 {
573 posep->setWeight(0.f);
574 deactivateMotion(motionp);
575 }
576 continue;
577 }
578 }
579 else
580 {
581 motionp->fadeIn();
582 }
583
584 //**********************
585 // MOTION INACTIVE
586 //**********************
587 if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
588 {
589 // this motion has gone on too long, deactivate it
590 // did we have a chance to stop it?
591 if (mLastTime <= motionp->getStopTime())
592 {
593 // if not, let's stop it this time through and deactivate it the next
594
595 posep->setWeight(motionp->getFadeWeight());
596 motionp->onUpdate(motionp->getStopTime() - motionp->mActivationTimestamp, last_joint_signature);
597 }
598 else
599 {
600 posep->setWeight(0.f);
601 deactivateMotion(motionp);
602 continue;
603 }
604 }
605
606 //**********************
607 // MOTION EASE OUT
608 //**********************
609 else if (motionp->isStopped() && mTime > motionp->getStopTime())
610 {
611 // is this the first iteration in the ease out phase?
612 if (mLastTime <= motionp->getStopTime())
613 {
614 // store residual weight for this motion
615 motionp->mResidualWeight = motionp->getPose()->getWeight();
616 }
617
618 if (motionp->getEaseOutDuration() == 0.f)
619 {
620 posep->setWeight(0.f);
621 }
622 else
623 {
624 posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight * cubic_step(1.f - ((mTime - motionp->getStopTime()) / motionp->getEaseOutDuration())));
625 }
626
627 // perform motion update
628 update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature);
629 }
630
631 //**********************
632 // MOTION ACTIVE
633 //**********************
634 else if (mTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
635 {
636 posep->setWeight(motionp->getFadeWeight());
637
638 //should we notify the simulator that this motion should be stopped?
639 if (mTime > motionp->mSendStopTimestamp)
640 {
641 // notify character of timed stop event on first iteration past sendstoptimestamp
642 // this will only be called when an animation stops itself (runs out of time)
643 if (mLastTime <= motionp->mSendStopTimestamp)
644 {
645 mCharacter->requestStopMotion( motionp );
646 stopMotionLocally(motionp->getID(), FALSE);
647 }
648 }
649
650 // perform motion update
651 update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature);
652 }
653
654 //**********************
655 // MOTION EASE IN
656 //**********************
657 else if (mTime >= motionp->mActivationTimestamp)
658 {
659 if (mLastTime < motionp->mActivationTimestamp)
660 {
661 motionp->mResidualWeight = motionp->getPose()->getWeight();
662 }
663 if (motionp->getEaseInDuration() == 0.f)
664 {
665 posep->setWeight(motionp->getFadeWeight());
666 }
667 else
668 {
669 // perform motion update
670 posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight + (1.f - motionp->mResidualWeight) * cubic_step((mTime - motionp->mActivationTimestamp) / motionp->getEaseInDuration()));
671 }
672 // perform motion update
673 update_result = motionp->onUpdate(mTime - motionp->mActivationTimestamp, last_joint_signature);
674 }
675 else
676 {
677 posep->setWeight(0.f);
678 update_result = motionp->onUpdate(0.f, last_joint_signature);
679 }
680
681 // allow motions to deactivate themselves
682 if (!update_result)
683 {
684 if (!motionp->isStopped() || motionp->getStopTime() > mTime)
685 {
686 // animation has stopped itself due to internal logic
687 // propagate this to the network
688 // as not all viewers are guaranteed to have access to the same logic
689 mCharacter->requestStopMotion( motionp );
690 stopMotionLocally(motionp->getID(), FALSE);
691 }
692
693 }
694
695 // even if onupdate returns FALSE, add this motion in to the blend one last time
696 mPoseBlender.addMotion(motionp);
697 }
698}
699
700
701//-----------------------------------------------------------------------------
702// updateMotion()
703//-----------------------------------------------------------------------------
704void LLMotionController::updateMotion()
705{
706 BOOL use_quantum = (mTimeStep != 0.f);
707
708 // Update timing info for this time step.
709 if (!mPaused)
710 {
711 F32 update_time = mTimeOffset + (mTimer.getElapsedTimeF32() * mTimeFactor);
712 if (use_quantum)
713 {
714 F32 time_interval = fmodf(update_time, mTimeStep);
715
716 // always animate *ahead* of actual time
717 S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1;
718 if (quantum_count == mTimeStepCount)
719 {
720 // we're still in same time quantum as before, so just interpolate and exit
721 if (!mPaused)
722 {
723 F32 interp = time_interval / mTimeStep;
724 mPoseBlender.interpolate(interp - mLastInterp);
725 mLastInterp = interp;
726 }
727
728 return;
729 }
730
731 // is calculating a new keyframe pose, make sure the last one gets applied
732 mPoseBlender.interpolate(1.f);
733 mPoseBlender.clearBlenders();
734
735 mTimeStepCount = quantum_count;
736 mLastTime = mTime;
737 mTime = (F32)quantum_count * mTimeStep;
738 mLastInterp = 0.f;
739 }
740 else
741 {
742 mLastTime = mTime;
743 mTime = update_time;
744 }
745 }
746
747 // query pending motions for completion
748 LLMotion* motionp;
749
750 for ( motionp = mLoadingMotions.getFirstData();
751 motionp != NULL;
752 motionp = mLoadingMotions.getNextData() )
753 {
754 LLMotion::LLMotionInitStatus status = motionp->onInitialize(mCharacter);
755 if (status == LLMotion::STATUS_SUCCESS)
756 {
757 mLoadingMotions.removeCurrentData();
758 // add motion to our loaded motion list
759 addLoadedMotion(motionp);
760 // this motion should be playing
761 if (!motionp->isStopped())
762 {
763 activateMotion(motionp, mTime);
764 }
765 }
766 else if (status == LLMotion::STATUS_FAILURE)
767 {
768 llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
769 sRegistry.markBad(motionp->getID());
770 mLoadingMotions.removeCurrentData();
771 mAllMotions.erase(motionp->getID());
772 delete motionp;
773 }
774 }
775
776 resetJointSignatures();
777
778 if (!mPaused)
779 {
780 // update additive motions
781 updateAdditiveMotions();
782 resetJointSignatures();
783
784 // update all regular motions
785 updateRegularMotions();
786
787 if (use_quantum)
788 {
789 mPoseBlender.blendAndCache(TRUE);
790 }
791 else
792 {
793 mPoseBlender.blendAndApply();
794 }
795 }
796
797 mHasRunOnce = TRUE;
798// llinfos << "Motion controller time " << motionTimer.getElapsedTimeF32() << llendl;
799}
800
801
802//-----------------------------------------------------------------------------
803// activateMotion()
804//-----------------------------------------------------------------------------
805BOOL LLMotionController::activateMotion(LLMotion *motion, F32 time)
806{
807 if (mLoadingMotions.checkData(motion))
808 {
809 // we want to start this motion, but we can't yet, so flag it as started
810 motion->setStopped(FALSE);
811 // report pending animations as activated
812 return TRUE;
813 }
814
815 motion->mResidualWeight = motion->getPose()->getWeight();
816 motion->mActivationTimestamp = time;
817
818 // set stop time based on given duration and ease out time
819 if (motion->getDuration() != 0.f && !motion->getLoop())
820 {
821 F32 ease_out_time;
822 F32 motion_duration;
823
824 // should we stop at the end of motion duration, or a bit earlier
825 // to allow it to ease out while moving?
826 ease_out_time = motion->getEaseOutDuration();
827
828 // is the clock running when the motion is easing in?
829 // if not (POSTURE_EASE) then we need to wait that much longer before triggering the stop
830 motion_duration = llmax(motion->getDuration() - ease_out_time, 0.f);
831 motion->mSendStopTimestamp = time + motion_duration;
832 }
833 else
834 {
835 motion->mSendStopTimestamp = F32_MAX;
836 }
837
838 mActiveMotions.addData(motion);
839
840 motion->activate();
841 motion->onUpdate(0.f, mJointSignature[1]);
842
843 return TRUE;
844}
845
846//-----------------------------------------------------------------------------
847// deactivateMotion()
848//-----------------------------------------------------------------------------
849BOOL LLMotionController::deactivateMotion(LLMotion *motion)
850{
851 motion->deactivate();
852 mActiveMotions.removeData(motion);
853
854 return TRUE;
855}
856
857//-----------------------------------------------------------------------------
858// isMotionActive()
859//-----------------------------------------------------------------------------
860BOOL LLMotionController::isMotionActive(LLMotion *motion)
861{
862 if (motion && motion->isActive())
863 {
864 return TRUE;
865 }
866
867 return FALSE;
868}
869
870//-----------------------------------------------------------------------------
871// isMotionLoading()
872//-----------------------------------------------------------------------------
873BOOL LLMotionController::isMotionLoading(LLMotion* motion)
874{
875 return mLoadingMotions.checkData(motion);
876}
877
878
879//-----------------------------------------------------------------------------
880// findMotion()
881//-----------------------------------------------------------------------------
882LLMotion *LLMotionController::findMotion(const LLUUID& id)
883{
884 return mAllMotions[id];
885}
886
887
888//-----------------------------------------------------------------------------
889// flushAllMotions()
890//-----------------------------------------------------------------------------
891void LLMotionController::flushAllMotions()
892{
893 LLDynamicArray<LLUUID> active_motions;
894 LLDynamicArray<F32> active_motion_times;
895
896 for (LLMotion* motionp = mActiveMotions.getFirstData();
897 motionp;
898 motionp = mActiveMotions.getNextData())
899 {
900 active_motions.put(motionp->getID());
901 active_motion_times.put(mTime - motionp->mActivationTimestamp);
902 motionp->deactivate();
903 }
904
905 // delete all motion instances
906 deleteAllMotions();
907
908 // kill current hand pose that was previously called out by
909 // keyframe motion
910 mCharacter->removeAnimationData("Hand Pose");
911
912 // restart motions
913 for (S32 i = 0; i < active_motions.count(); i++)
914 {
915 startMotion(active_motions[i], active_motion_times[i]);
916 }
917}
918
919//-----------------------------------------------------------------------------
920// pause()
921//-----------------------------------------------------------------------------
922void LLMotionController::pause()
923{
924 if (!mPaused)
925 {
926 //llinfos << "Pausing animations..." << llendl;
927 mPauseTime = mTimer.getElapsedTimeF32();
928 mPaused = TRUE;
929 }
930
931}
932
933//-----------------------------------------------------------------------------
934// unpause()
935//-----------------------------------------------------------------------------
936void LLMotionController::unpause()
937{
938 if (mPaused)
939 {
940 //llinfos << "Unpausing animations..." << llendl;
941 mTimer.reset();
942 mTimer.setAge(mPauseTime);
943 mPaused = FALSE;
944 }
945}
946// End
diff --git a/linden/indra/llcharacter/llmotioncontroller.h b/linden/indra/llcharacter/llmotioncontroller.h
new file mode 100644
index 0000000..c9ee7c4
--- /dev/null
+++ b/linden/indra/llcharacter/llmotioncontroller.h
@@ -0,0 +1,226 @@
1/**
2 * @file llmotioncontroller.h
3 * @brief Implementation of LLMotionController 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#ifndef LL_LLMOTIONCONTROLLER_H
29#define LL_LLMOTIONCONTROLLER_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include <string>
35#include <map>
36#include <deque>
37
38#include "linked_lists.h"
39#include "lluuidhashmap.h"
40#include "llmotion.h"
41#include "llpose.h"
42#include "llframetimer.h"
43#include "llstatemachine.h"
44#include "llstring.h"
45
46//-----------------------------------------------------------------------------
47// Class predeclaration
48// This is necessary because llcharacter.h includes this file.
49//-----------------------------------------------------------------------------
50class LLCharacter;
51
52//-----------------------------------------------------------------------------
53// LLMotionRegistry
54//-----------------------------------------------------------------------------
55typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id);
56
57class LLMotionTableEntry
58{
59public:
60 LLMotionTableEntry();
61 LLMotionTableEntry(LLMotionConstructor constructor, const LLUUID& id);
62 ~LLMotionTableEntry(){};
63
64 LLMotion* create(const LLUUID& id);
65 static BOOL uuidEq(const LLUUID &uuid, const LLMotionTableEntry &id_pair)
66 {
67 if (uuid == id_pair.mID)
68 {
69 return TRUE;
70 }
71 return FALSE;
72 }
73
74 const LLUUID& getID() { return mID; }
75
76protected:
77 LLMotionConstructor mConstructor;
78 LLUUID mID;
79};
80
81class LLMotionRegistry
82{
83public:
84 // Constructor
85 LLMotionRegistry();
86
87 // Destructor
88 ~LLMotionRegistry();
89
90 // adds motion classes to the registry
91 // returns true if successfull
92 BOOL addMotion( const LLUUID& id, LLMotionConstructor create);
93
94 // creates a new instance of a named motion
95 // returns NULL motion is not registered
96 LLMotion *createMotion( const LLUUID &id );
97
98 // initialization of motion failed, don't try to create this motion again
99 void markBad( const LLUUID& id );
100
101
102protected:
103 LLUUIDHashMap<LLMotionTableEntry, 32> mMotionTable;
104};
105
106//-----------------------------------------------------------------------------
107// class LLMotionController
108//-----------------------------------------------------------------------------
109class LLMotionController
110{
111public:
112 // Constructor
113 LLMotionController();
114
115 // Destructor
116 virtual ~LLMotionController();
117
118 // set associated character
119 // this must be called exactly once by the containing character class.
120 // this is generally done in the Character constructor
121 void setCharacter( LLCharacter *character );
122
123 // registers a motion with the controller
124 // (actually just forwards call to motion registry)
125 // returns true if successfull
126 BOOL addMotion( const LLUUID& id, LLMotionConstructor create );
127
128 // creates a motion from the registry
129 LLMotion *createMotion( const LLUUID &id );
130
131 // unregisters a motion with the controller
132 // (actually just forwards call to motion registry)
133 // returns true if successfull
134 void removeMotion( const LLUUID& id );
135
136 // start motion
137 // begins playing the specified motion
138 // returns true if successful
139 BOOL startMotion( const LLUUID &id, F32 start_offset );
140
141 // stop motion
142 // stops a playing motion
143 // in reality, it begins the ease out transition phase
144 // returns true if successful
145 BOOL stopMotionLocally( const LLUUID &id, BOOL stop_immediate );
146
147 // update motions
148 // invokes the update handlers for each active motion
149 // activates sequenced motions
150 // deactivates terminated motions`
151 void updateMotion();
152
153 // flush motions
154 // releases all motion instances
155 void flushAllMotions();
156
157 // pause and continue all motions
158 void pause();
159 void unpause();
160 BOOL isPaused() { return mPaused; }
161
162 void setTimeStep(F32 step);
163
164 void setTimeFactor(F32 time_factor);
165 F32 getTimeFactor() { return mTimeFactor; }
166
167 LLMotion* getFirstActiveMotion();
168 LLMotion* getNextActiveMotion();
169
170//protected:
171 BOOL isMotionActive( LLMotion *motion );
172 BOOL isMotionLoading( LLMotion *motion );
173 LLMotion *findMotion( const LLUUID& id );
174
175protected:
176 void deleteAllMotions();
177 void addLoadedMotion(LLMotion *motion);
178 BOOL activateMotion(LLMotion *motion, F32 time);
179 BOOL deactivateMotion(LLMotion *motion);
180 void updateRegularMotions();
181 void updateAdditiveMotions();
182 void resetJointSignatures();
183 void updateMotionsByType(LLMotion::LLMotionBlendType motion_type);
184protected:
185
186 F32 mTimeFactor;
187 static LLMotionRegistry sRegistry;
188 LLPoseBlender mPoseBlender;
189
190 LLCharacter *mCharacter;
191
192// Life cycle of an animation:
193//
194// Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime.
195// If the animations depend on any asset data, the appropriate data is fetched from the data server,
196// and the animation is put on the mLoadingMotions list.
197// Once an animations is loaded, it will be initialized and put on the mLoadedMotions deque.
198// Any animation that is currently playing also sits in the mActiveMotions list.
199
200 std::map<LLUUID, LLMotion*> mAllMotions;
201
202 LLLinkedList<LLMotion> mLoadingMotions;
203 std::deque<LLMotion*> mLoadedMotions;
204 LLLinkedList<LLMotion> mActiveMotions;
205
206 LLFrameTimer mTimer;
207 F32 mTime;
208 F32 mTimeOffset;
209 F32 mLastTime;
210 BOOL mHasRunOnce;
211 BOOL mPaused;
212 F32 mTimeStep;
213 S32 mTimeStepCount;
214 F32 mLastInterp;
215 F32 mPauseTime;
216
217 U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS];
218};
219
220//-----------------------------------------------------------------------------
221// Class declaractions
222//-----------------------------------------------------------------------------
223#include "llcharacter.h"
224
225#endif // LL_LLMOTIONCONTROLLER_H
226
diff --git a/linden/indra/llcharacter/llmultigesture.cpp b/linden/indra/llcharacter/llmultigesture.cpp
new file mode 100644
index 0000000..80cbacb
--- /dev/null
+++ b/linden/indra/llcharacter/llmultigesture.cpp
@@ -0,0 +1,489 @@
1/**
2 * @file llmultigesture.cpp
3 * @brief Gestures that are asset-based and can have multiple steps.
4 *
5 * Copyright (c) 2004-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#include "linden_common.h"
29
30#include <algorithm>
31
32#include "stdio.h"
33
34#include "llmultigesture.h"
35
36#include "llerror.h"
37#include "lldatapacker.h"
38#include "llstl.h"
39
40const S32 GESTURE_VERSION = 2;
41
42//---------------------------------------------------------------------------
43// LLMultiGesture
44//---------------------------------------------------------------------------
45LLMultiGesture::LLMultiGesture()
46: mKey(),
47 mMask(),
48 mTrigger(),
49 mReplaceText(),
50 mSteps(),
51 mPlaying(FALSE),
52 mCurrentStep(0),
53 mDoneCallback(NULL),
54 mCallbackData(NULL)
55{
56 reset();
57}
58
59LLMultiGesture::~LLMultiGesture()
60{
61 std::for_each(mSteps.begin(), mSteps.end(), DeletePointer());
62}
63
64void LLMultiGesture::reset()
65{
66 mPlaying = FALSE;
67 mCurrentStep = 0;
68 mWaitTimer.reset();
69 mWaitingTimer = FALSE;
70 mWaitingAnimations = FALSE;
71 mWaitingAtEnd = FALSE;
72 mRequestedAnimIDs.clear();
73 mPlayingAnimIDs.clear();
74}
75
76S32 LLMultiGesture::getMaxSerialSize() const
77{
78 S32 max_size = 0;
79
80 // ascii format, being very conservative about possible
81 // label lengths.
82 max_size += 64; // version S32
83 max_size += 64; // key U8
84 max_size += 64; // mask U32
85 max_size += 256; // trigger string
86 max_size += 256; // replace string
87
88 max_size += 64; // step count S32
89
90 std::vector<LLGestureStep*>::const_iterator it;
91 for (it = mSteps.begin(); it != mSteps.end(); ++it)
92 {
93 LLGestureStep* step = *it;
94 max_size += 64; // type S32
95 max_size += step->getMaxSerialSize();
96 }
97
98 /* binary format
99 max_size += sizeof(S32); // version
100 max_size += sizeof(mKey);
101 max_size += sizeof(mMask);
102 max_size += mTrigger.length() + 1; // for null
103
104 max_size += sizeof(S32); // step count
105
106 std::vector<LLGestureStep*>::const_iterator it;
107 for (it = mSteps.begin(); it != mSteps.end(); ++it)
108 {
109 LLGestureStep* step = *it;
110 max_size += sizeof(S32); // type
111 max_size += step->getMaxSerialSize();
112 }
113 */
114
115 return max_size;
116}
117
118BOOL LLMultiGesture::serialize(LLDataPacker& dp) const
119{
120 dp.packS32(GESTURE_VERSION, "version");
121 dp.packU8(mKey, "key");
122 dp.packU32(mMask, "mask");
123 dp.packString(mTrigger.c_str(), "trigger");
124 dp.packString(mReplaceText.c_str(), "replace");
125
126 S32 count = (S32)mSteps.size();
127 dp.packS32(count, "step_count");
128 S32 i;
129 for (i = 0; i < count; ++i)
130 {
131 LLGestureStep* step = mSteps[i];
132
133 dp.packS32(step->getType(), "step_type");
134 BOOL ok = step->serialize(dp);
135 if (!ok)
136 {
137 return FALSE;
138 }
139 }
140 return TRUE;
141}
142
143BOOL LLMultiGesture::deserialize(LLDataPacker& dp)
144{
145 S32 version;
146 dp.unpackS32(version, "version");
147 if (version != GESTURE_VERSION)
148 {
149 llwarns << "Bad LLMultiGesture version " << version
150 << " should be " << GESTURE_VERSION
151 << llendl;
152 return FALSE;
153 }
154
155 dp.unpackU8(mKey, "key");
156 dp.unpackU32(mMask, "mask");
157
158
159 dp.unpackString(mTrigger, "trigger");
160
161 dp.unpackString(mReplaceText, "replace");
162
163 S32 count;
164 dp.unpackS32(count, "step_count");
165 if (count < 0)
166 {
167 llwarns << "Bad LLMultiGesture step count " << count << llendl;
168 return FALSE;
169 }
170
171 S32 i;
172 for (i = 0; i < count; ++i)
173 {
174 S32 type;
175 dp.unpackS32(type, "step_type");
176
177 EStepType step_type = (EStepType)type;
178 switch(step_type)
179 {
180 case STEP_ANIMATION:
181 {
182 LLGestureStepAnimation* step = new LLGestureStepAnimation();
183 BOOL ok = step->deserialize(dp);
184 if (!ok) return FALSE;
185 mSteps.push_back(step);
186 break;
187 }
188 case STEP_SOUND:
189 {
190 LLGestureStepSound* step = new LLGestureStepSound();
191 BOOL ok = step->deserialize(dp);
192 if (!ok) return FALSE;
193 mSteps.push_back(step);
194 break;
195 }
196 case STEP_CHAT:
197 {
198 LLGestureStepChat* step = new LLGestureStepChat();
199 BOOL ok = step->deserialize(dp);
200 if (!ok) return FALSE;
201 mSteps.push_back(step);
202 break;
203 }
204 case STEP_WAIT:
205 {
206 LLGestureStepWait* step = new LLGestureStepWait();
207 BOOL ok = step->deserialize(dp);
208 if (!ok) return FALSE;
209 mSteps.push_back(step);
210 break;
211 }
212 default:
213 {
214 llwarns << "Bad LLMultiGesture step type " << type << llendl;
215 return FALSE;
216 }
217 }
218 }
219 return TRUE;
220}
221
222void LLMultiGesture::dump()
223{
224 llinfos << "key " << S32(mKey) << " mask " << U32(mMask)
225 << " trigger " << mTrigger
226 << " replace " << mReplaceText
227 << llendl;
228 U32 i;
229 for (i = 0; i < mSteps.size(); ++i)
230 {
231 LLGestureStep* step = mSteps[i];
232 step->dump();
233 }
234}
235
236//---------------------------------------------------------------------------
237// LLGestureStepAnimation
238//---------------------------------------------------------------------------
239LLGestureStepAnimation::LLGestureStepAnimation()
240: LLGestureStep(),
241 mAnimName("None"),
242 mAnimAssetID(),
243 mFlags(0x0)
244{ }
245
246LLGestureStepAnimation::~LLGestureStepAnimation()
247{ }
248
249S32 LLGestureStepAnimation::getMaxSerialSize() const
250{
251 S32 max_size = 0;
252
253 // ascii
254 max_size += 256; // anim name
255 max_size += 64; // anim asset id
256 max_size += 64; // flags
257
258 /* binary
259 max_size += mAnimName.length() + 1;
260 max_size += sizeof(mAnimAssetID);
261 max_size += sizeof(mFlags);
262 */
263 return max_size;
264}
265
266BOOL LLGestureStepAnimation::serialize(LLDataPacker& dp) const
267{
268 dp.packString(mAnimName.c_str(), "anim_name");
269 dp.packUUID(mAnimAssetID, "asset_id");
270 dp.packU32(mFlags, "flags");
271 return TRUE;
272}
273
274BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp)
275{
276 dp.unpackString(mAnimName, "anim_name");
277
278 // Apparently an earlier version of the gesture code added \r to the end
279 // of the animation names. Get rid of it. JC
280 if (mAnimName[mAnimName.length() - 1] == '\r')
281 {
282 // chop the last character
283 mAnimName.resize(mAnimName.length() - 1);
284 }
285
286 dp.unpackUUID(mAnimAssetID, "asset_id");
287 dp.unpackU32(mFlags, "flags");
288 return TRUE;
289}
290
291std::string LLGestureStepAnimation::getLabel() const
292{
293 std::string label;
294 if (mFlags & ANIM_FLAG_STOP)
295 {
296 label = "Stop Animation: ";
297 }
298 else
299 {
300 label = "Start Animation: ";
301 }
302 label += mAnimName;
303 return label;
304}
305
306void LLGestureStepAnimation::dump()
307{
308 llinfos << "step animation " << mAnimName
309 << " id " << mAnimAssetID
310 << " flags " << mFlags
311 << llendl;
312}
313
314//---------------------------------------------------------------------------
315// LLGestureStepSound
316//---------------------------------------------------------------------------
317LLGestureStepSound::LLGestureStepSound()
318: LLGestureStep(),
319 mSoundName("None"),
320 mSoundAssetID(),
321 mFlags(0x0)
322{ }
323
324LLGestureStepSound::~LLGestureStepSound()
325{ }
326
327S32 LLGestureStepSound::getMaxSerialSize() const
328{
329 S32 max_size = 0;
330 max_size += 256; // sound name
331 max_size += 64; // sound asset id
332 max_size += 64; // flags
333 /* binary
334 max_size += mSoundName.length() + 1;
335 max_size += sizeof(mSoundAssetID);
336 max_size += sizeof(mFlags);
337 */
338 return max_size;
339}
340
341BOOL LLGestureStepSound::serialize(LLDataPacker& dp) const
342{
343 dp.packString(mSoundName.c_str(), "sound_name");
344 dp.packUUID(mSoundAssetID, "asset_id");
345 dp.packU32(mFlags, "flags");
346 return TRUE;
347}
348
349BOOL LLGestureStepSound::deserialize(LLDataPacker& dp)
350{
351 dp.unpackString(mSoundName, "sound_name");
352
353 dp.unpackUUID(mSoundAssetID, "asset_id");
354 dp.unpackU32(mFlags, "flags");
355 return TRUE;
356}
357
358std::string LLGestureStepSound::getLabel() const
359{
360 std::string label("Sound: ");
361 label += mSoundName;
362 return label;
363}
364
365void LLGestureStepSound::dump()
366{
367 llinfos << "step sound " << mSoundName
368 << " id " << mSoundAssetID
369 << " flags " << mFlags
370 << llendl;
371}
372
373
374//---------------------------------------------------------------------------
375// LLGestureStepChat
376//---------------------------------------------------------------------------
377LLGestureStepChat::LLGestureStepChat()
378: LLGestureStep(),
379 mChatText(),
380 mFlags(0x0)
381{ }
382
383LLGestureStepChat::~LLGestureStepChat()
384{ }
385
386S32 LLGestureStepChat::getMaxSerialSize() const
387{
388 S32 max_size = 0;
389 max_size += 256; // chat text
390 max_size += 64; // flags
391 /* binary
392 max_size += mChatText.length() + 1;
393 max_size += sizeof(mFlags);
394 */
395 return max_size;
396}
397
398BOOL LLGestureStepChat::serialize(LLDataPacker& dp) const
399{
400 dp.packString(mChatText.c_str(), "chat_text");
401 dp.packU32(mFlags, "flags");
402 return TRUE;
403}
404
405BOOL LLGestureStepChat::deserialize(LLDataPacker& dp)
406{
407 dp.unpackString(mChatText, "chat_text");
408
409 dp.unpackU32(mFlags, "flags");
410 return TRUE;
411}
412
413std::string LLGestureStepChat::getLabel() const
414{
415 std::string label("Chat: ");
416 label += mChatText;
417 return label;
418}
419
420void LLGestureStepChat::dump()
421{
422 llinfos << "step chat " << mChatText
423 << " flags " << mFlags
424 << llendl;
425}
426
427
428//---------------------------------------------------------------------------
429// LLGestureStepWait
430//---------------------------------------------------------------------------
431LLGestureStepWait::LLGestureStepWait()
432: LLGestureStep(),
433 mWaitSeconds(0.f),
434 mFlags(0x0)
435{ }
436
437LLGestureStepWait::~LLGestureStepWait()
438{ }
439
440S32 LLGestureStepWait::getMaxSerialSize() const
441{
442 S32 max_size = 0;
443 max_size += 64; // wait seconds
444 max_size += 64; // flags
445 /* binary
446 max_size += sizeof(mWaitSeconds);
447 max_size += sizeof(mFlags);
448 */
449 return max_size;
450}
451
452BOOL LLGestureStepWait::serialize(LLDataPacker& dp) const
453{
454 dp.packF32(mWaitSeconds, "wait_seconds");
455 dp.packU32(mFlags, "flags");
456 return TRUE;
457}
458
459BOOL LLGestureStepWait::deserialize(LLDataPacker& dp)
460{
461 dp.unpackF32(mWaitSeconds, "wait_seconds");
462 dp.unpackU32(mFlags, "flags");
463 return TRUE;
464}
465
466std::string LLGestureStepWait::getLabel() const
467{
468 std::string label("--- Wait: ");
469 if (mFlags & WAIT_FLAG_TIME)
470 {
471 char buffer[64]; /* Flawfinder: ignore */
472 snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */
473 label += buffer;
474 }
475 else if (mFlags & WAIT_FLAG_ALL_ANIM)
476 {
477 label += "until animations are done";
478 }
479
480 return label;
481}
482
483
484void LLGestureStepWait::dump()
485{
486 llinfos << "step wait " << mWaitSeconds
487 << " flags " << mFlags
488 << llendl;
489}
diff --git a/linden/indra/llcharacter/llmultigesture.h b/linden/indra/llcharacter/llmultigesture.h
new file mode 100644
index 0000000..aeb7c04
--- /dev/null
+++ b/linden/indra/llcharacter/llmultigesture.h
@@ -0,0 +1,232 @@
1/**
2 * @file llmultigesture.h
3 * @brief Gestures that are asset-based and can have multiple steps.
4 *
5 * Copyright (c) 2004-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#ifndef LL_LLMULTIGESTURE_H
29#define LL_LLMULTIGESTURE_H
30
31#include <set>
32#include <string>
33#include <vector>
34
35#include "lluuid.h"
36#include "llframetimer.h"
37
38class LLDataPacker;
39class LLGestureStep;
40
41class LLMultiGesture
42{
43public:
44 LLMultiGesture();
45 virtual ~LLMultiGesture();
46
47 // Maximum number of bytes this could hold once serialized.
48 S32 getMaxSerialSize() const;
49
50 BOOL serialize(LLDataPacker& dp) const;
51 BOOL deserialize(LLDataPacker& dp);
52
53 void dump();
54
55 void reset();
56
57 const std::string& getTrigger() const { return mTrigger; }
58protected:
59 LLMultiGesture(const LLMultiGesture& gest);
60 const LLMultiGesture& operator=(const LLMultiGesture& rhs);
61
62public:
63 // name is stored at asset level
64 // desc is stored at asset level
65 KEY mKey;
66 MASK mMask;
67
68 // String, like "/foo" or "hello" that makes it play
69 std::string mTrigger;
70
71 // Replaces the trigger substring with this text
72 std::string mReplaceText;
73
74 std::vector<LLGestureStep*> mSteps;
75
76 // Is the gesture currently playing?
77 BOOL mPlaying;
78
79 // "instruction pointer" for steps
80 S32 mCurrentStep;
81
82 // We're waiting for triggered animations to stop playing
83 BOOL mWaitingAnimations;
84
85 // We're waiting a fixed amount of time
86 BOOL mWaitingTimer;
87
88 // Waiting after the last step played for all animations to complete
89 BOOL mWaitingAtEnd;
90
91 // Timer for waiting
92 LLFrameTimer mWaitTimer;
93
94 void (*mDoneCallback)(LLMultiGesture* gesture, void* data);
95 void* mCallbackData;
96
97 // Animations that we requested to start
98 std::set<LLUUID> mRequestedAnimIDs;
99
100 // Once the animation starts playing (sim says to start playing)
101 // the ID is moved from mRequestedAnimIDs to here.
102 std::set<LLUUID> mPlayingAnimIDs;
103};
104
105
106enum EStepType
107{
108 STEP_ANIMATION = 0,
109 STEP_SOUND = 1,
110 STEP_CHAT = 2,
111 STEP_WAIT = 3,
112
113 STEP_EOF = 4
114};
115
116
117class LLGestureStep
118{
119public:
120 LLGestureStep() {}
121 virtual ~LLGestureStep() {}
122
123 virtual EStepType getType() = 0;
124
125 // Return a user-readable label for this step
126 virtual std::string getLabel() const = 0;
127
128 virtual S32 getMaxSerialSize() const = 0;
129 virtual BOOL serialize(LLDataPacker& dp) const = 0;
130 virtual BOOL deserialize(LLDataPacker& dp) = 0;
131
132 virtual void dump() = 0;
133};
134
135
136// By default, animation steps start animations.
137// If the least significant bit is 1, it will stop animations.
138const U32 ANIM_FLAG_STOP = 0x01;
139
140class LLGestureStepAnimation : public LLGestureStep
141{
142public:
143 LLGestureStepAnimation();
144 virtual ~LLGestureStepAnimation();
145
146 virtual EStepType getType() { return STEP_ANIMATION; }
147
148 virtual std::string getLabel() const;
149
150 virtual S32 getMaxSerialSize() const;
151 virtual BOOL serialize(LLDataPacker& dp) const;
152 virtual BOOL deserialize(LLDataPacker& dp);
153
154 virtual void dump();
155
156public:
157 std::string mAnimName;
158 LLUUID mAnimAssetID;
159 U32 mFlags;
160};
161
162
163class LLGestureStepSound : public LLGestureStep
164{
165public:
166 LLGestureStepSound();
167 virtual ~LLGestureStepSound();
168
169 virtual EStepType getType() { return STEP_SOUND; }
170
171 virtual std::string getLabel() const;
172
173 virtual S32 getMaxSerialSize() const;
174 virtual BOOL serialize(LLDataPacker& dp) const;
175 virtual BOOL deserialize(LLDataPacker& dp);
176
177 virtual void dump();
178
179public:
180 std::string mSoundName;
181 LLUUID mSoundAssetID;
182 U32 mFlags;
183};
184
185
186class LLGestureStepChat : public LLGestureStep
187{
188public:
189 LLGestureStepChat();
190 virtual ~LLGestureStepChat();
191
192 virtual EStepType getType() { return STEP_CHAT; }
193
194 virtual std::string getLabel() const;
195
196 virtual S32 getMaxSerialSize() const;
197 virtual BOOL serialize(LLDataPacker& dp) const;
198 virtual BOOL deserialize(LLDataPacker& dp);
199
200 virtual void dump();
201
202public:
203 std::string mChatText;
204 U32 mFlags;
205};
206
207
208const U32 WAIT_FLAG_TIME = 0x01;
209const U32 WAIT_FLAG_ALL_ANIM = 0x02;
210
211class LLGestureStepWait : public LLGestureStep
212{
213public:
214 LLGestureStepWait();
215 virtual ~LLGestureStepWait();
216
217 virtual EStepType getType() { return STEP_WAIT; }
218
219 virtual std::string getLabel() const;
220
221 virtual S32 getMaxSerialSize() const;
222 virtual BOOL serialize(LLDataPacker& dp) const;
223 virtual BOOL deserialize(LLDataPacker& dp);
224
225 virtual void dump();
226
227public:
228 F32 mWaitSeconds;
229 U32 mFlags;
230};
231
232#endif
diff --git a/linden/indra/llcharacter/llpose.cpp b/linden/indra/llcharacter/llpose.cpp
new file mode 100644
index 0000000..ebf6a67
--- /dev/null
+++ b/linden/indra/llcharacter/llpose.cpp
@@ -0,0 +1,563 @@
1/**
2 * @file llpose.cpp
3 * @brief Implementation of LLPose 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 "llpose.h"
34
35#include "llmotion.h"
36#include "llmath.h"
37
38//-----------------------------------------------------------------------------
39// Static
40//-----------------------------------------------------------------------------
41
42//-----------------------------------------------------------------------------
43// LLPose
44//-----------------------------------------------------------------------------
45LLPose::~LLPose()
46{
47}
48
49//-----------------------------------------------------------------------------
50// getFirstJointState()
51//-----------------------------------------------------------------------------
52LLJointState *LLPose::getFirstJointState()
53{
54 mListIter = mJointMap.begin();
55 if (mListIter == mJointMap.end())
56 {
57 return NULL;
58 }
59 else
60 {
61 return mListIter->second;
62 }
63}
64
65//-----------------------------------------------------------------------------
66// getNextJointState()
67//-----------------------------------------------------------------------------
68LLJointState *LLPose::getNextJointState()
69{
70 mListIter++;
71 if (mListIter == mJointMap.end())
72 {
73 return NULL;
74 }
75 else
76 {
77 return mListIter->second;
78 }
79}
80
81//-----------------------------------------------------------------------------
82// addJointState()
83//-----------------------------------------------------------------------------
84BOOL LLPose::addJointState(LLJointState *jointState)
85{
86 if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
87 {
88 mJointMap[jointState->getJoint()->getName()] = jointState;
89 }
90 return TRUE;
91}
92
93//-----------------------------------------------------------------------------
94// removeJointState()
95//-----------------------------------------------------------------------------
96BOOL LLPose::removeJointState(LLJointState *jointState)
97{
98 mJointMap.erase(jointState->getJoint()->getName());
99 return TRUE;
100}
101
102//-----------------------------------------------------------------------------
103// removeAllJointStates()
104//-----------------------------------------------------------------------------
105BOOL LLPose::removeAllJointStates()
106{
107 mJointMap.clear();
108 return TRUE;
109}
110
111//-----------------------------------------------------------------------------
112// findJointState()
113//-----------------------------------------------------------------------------
114LLJointState* LLPose::findJointState(LLJoint *joint)
115{
116 joint_map_iterator iter = mJointMap.find(joint->getName());
117
118 if (iter == mJointMap.end())
119 {
120 return NULL;
121 }
122 else
123 {
124 return iter->second;
125 }
126}
127
128//-----------------------------------------------------------------------------
129// findJointState()
130//-----------------------------------------------------------------------------
131LLJointState* LLPose::findJointState(const std::string &name)
132{
133 joint_map_iterator iter = mJointMap.find(name);
134
135 if (iter == mJointMap.end())
136 {
137 return NULL;
138 }
139 else
140 {
141 return iter->second;
142 }
143}
144
145//-----------------------------------------------------------------------------
146// setWeight()
147//-----------------------------------------------------------------------------
148void LLPose::setWeight(F32 weight)
149{
150 joint_map_iterator iter;
151 for(iter = mJointMap.begin();
152 iter != mJointMap.end();
153 ++iter)
154 {
155 iter->second->setWeight(weight);
156 }
157 mWeight = weight;
158}
159
160//-----------------------------------------------------------------------------
161// getWeight()
162//-----------------------------------------------------------------------------
163F32 LLPose::getWeight() const
164{
165 return mWeight;
166}
167
168//-----------------------------------------------------------------------------
169// getNumJointStates()
170//-----------------------------------------------------------------------------
171S32 LLPose::getNumJointStates() const
172{
173 return (S32)mJointMap.size();
174}
175
176//-----------------------------------------------------------------------------
177// LLJointStateBlender
178//-----------------------------------------------------------------------------
179
180LLJointStateBlender::LLJointStateBlender()
181{
182 for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
183 {
184 mJointStates[i] = NULL;
185 mPriorities[i] = S32_MIN;
186 }
187}
188
189LLJointStateBlender::~LLJointStateBlender()
190{
191
192}
193
194//-----------------------------------------------------------------------------
195// addJointState()
196//-----------------------------------------------------------------------------
197BOOL LLJointStateBlender::addJointState(LLJointState *joint_state, S32 priority, BOOL additive_blend)
198{
199 llassert(joint_state);
200
201 if (!joint_state->getJoint())
202 // this joint state doesn't point to an actual joint, so we don't care about applying it
203 return FALSE;
204
205 for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
206 {
207 if (NULL == mJointStates[i])
208 {
209 mJointStates[i] = joint_state;
210 mPriorities[i] = priority;
211 mAdditiveBlends[i] = additive_blend;
212 return TRUE;
213 }
214 else if (priority > mPriorities[i])
215 {
216 // we're at a higher priority than the current joint state in this slot
217 // so shift everyone over
218 // previous joint states (newer motions) with same priority should stay in place
219 for (S32 j = JSB_NUM_JOINT_STATES - 1; j > i; j--)
220 {
221 mJointStates[j] = mJointStates[j - 1];
222 mPriorities[j] = mPriorities[j - 1];
223 mAdditiveBlends[j] = mAdditiveBlends[j - 1];
224 }
225 // now store ourselves in this slot
226 mJointStates[i] = joint_state;
227 mPriorities[i] = priority;
228 mAdditiveBlends[i] = additive_blend;
229 return TRUE;
230 }
231 }
232
233 return FALSE;
234}
235
236//-----------------------------------------------------------------------------
237// blendJointStates()
238//-----------------------------------------------------------------------------
239void LLJointStateBlender::blendJointStates(BOOL apply_now)
240{
241 // we need at least one joint to blend
242 // if there is one, it will be in slot zero according to insertion logic
243 // instead of resetting joint state to default, just leave it unchanged from last frame
244 if (NULL == mJointStates[0])
245 {
246 return;
247 }
248
249 LLJoint* target_joint = apply_now ? mJointStates[0]->getJoint() : &mJointCache;
250
251 const S32 POS_WEIGHT = 0;
252 const S32 ROT_WEIGHT = 1;
253 const S32 SCALE_WEIGHT = 2;
254
255 F32 sum_weights[3];
256 U32 sum_usage = 0;
257
258 LLVector3 blended_pos = target_joint->getPosition();
259 LLQuaternion blended_rot = target_joint->getRotation();
260 LLVector3 blended_scale = target_joint->getScale();
261
262 LLVector3 added_pos;
263 LLQuaternion added_rot;
264 LLVector3 added_scale;
265
266 //S32 joint_state_index;
267
268 sum_weights[POS_WEIGHT] = 0.f;
269 sum_weights[ROT_WEIGHT] = 0.f;
270 sum_weights[SCALE_WEIGHT] = 0.f;
271
272 for(S32 joint_state_index = 0;
273 joint_state_index < JSB_NUM_JOINT_STATES && mJointStates[joint_state_index] != NULL;
274 joint_state_index++)
275 {
276 U32 current_usage = mJointStates[joint_state_index]->getUsage();
277 F32 current_weight = mJointStates[joint_state_index]->getWeight();
278 LLJointState* jsp = mJointStates[joint_state_index];
279
280 if (current_weight == 0.f)
281 {
282 continue;
283 }
284
285 if (mAdditiveBlends[joint_state_index])
286 {
287 if(current_usage & LLJointState::POS)
288 {
289 F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]);
290
291 // add in pos for this jointstate modulated by weight
292 added_pos += jsp->getPosition() * (new_weight_sum - sum_weights[POS_WEIGHT]);
293 //sum_weights[POS_WEIGHT] = new_weight_sum;
294 }
295
296 // now do scale
297 if(current_usage & LLJointState::SCALE)
298 {
299 F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]);
300
301 // add in scale for this jointstate modulated by weight
302 added_scale += jsp->getScale() * (new_weight_sum - sum_weights[SCALE_WEIGHT]);
303 //sum_weights[SCALE_WEIGHT] = new_weight_sum;
304 }
305
306 if (current_usage & LLJointState::ROT)
307 {
308 F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]);
309
310 // add in rotation for this jointstate modulated by weight
311 added_rot = nlerp((new_weight_sum - sum_weights[ROT_WEIGHT]), added_rot, jsp->getRotation()) * added_rot;
312 //sum_weights[ROT_WEIGHT] = new_weight_sum;
313 }
314 }
315 else
316 {
317 // blend two jointstates together
318
319 // blend position
320 if(current_usage & LLJointState::POS)
321 {
322 if(sum_usage & LLJointState::POS)
323 {
324 F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]);
325
326 // blend positions from both
327 blended_pos = lerp(mJointStates[joint_state_index]->getPosition(), blended_pos, sum_weights[POS_WEIGHT] / new_weight_sum);
328 sum_weights[POS_WEIGHT] = new_weight_sum;
329 }
330 else
331 {
332 // copy position from current
333 blended_pos = mJointStates[joint_state_index]->getPosition();
334 sum_weights[POS_WEIGHT] = current_weight;
335 }
336 }
337
338 // now do scale
339 if(current_usage & LLJointState::SCALE)
340 {
341 if(sum_usage & LLJointState::SCALE)
342 {
343 F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]);
344
345 // blend scales from both
346 blended_scale = lerp(mJointStates[joint_state_index]->getScale(), blended_scale, sum_weights[SCALE_WEIGHT] / new_weight_sum);
347 sum_weights[SCALE_WEIGHT] = new_weight_sum;
348 }
349 else
350 {
351 // copy scale from current
352 blended_scale = mJointStates[joint_state_index]->getScale();
353 sum_weights[SCALE_WEIGHT] = current_weight;
354 }
355 }
356
357 // rotation
358 if (current_usage & LLJointState::ROT)
359 {
360 if(sum_usage & LLJointState::ROT)
361 {
362 F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]);
363
364 // blend rotations from both
365 blended_rot = nlerp(sum_weights[ROT_WEIGHT] / new_weight_sum, mJointStates[joint_state_index]->getRotation(), blended_rot);
366 sum_weights[ROT_WEIGHT] = new_weight_sum;
367 }
368 else
369 {
370 // copy rotation from current
371 blended_rot = mJointStates[joint_state_index]->getRotation();
372 sum_weights[ROT_WEIGHT] = current_weight;
373 }
374 }
375
376 // update resulting usage mask
377 sum_usage = sum_usage | current_usage;
378 }
379 }
380
381 // apply blended transforms
382 target_joint->setPosition(blended_pos);
383 target_joint->setScale(blended_scale);
384 target_joint->setRotation(blended_rot);
385
386 // apply additive transforms
387 target_joint->setPosition(target_joint->getPosition() + added_pos);
388 target_joint->setScale(target_joint->getScale() + added_scale);
389 target_joint->setRotation(added_rot * target_joint->getRotation());
390
391 if (apply_now)
392 {
393 // now clear joint states
394 for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
395 {
396 mJointStates[i] = NULL;
397 }
398 }
399}
400
401//-----------------------------------------------------------------------------
402// interpolate()
403//-----------------------------------------------------------------------------
404void LLJointStateBlender::interpolate(F32 u)
405{
406 // only interpolate if we have a joint state
407 if (!mJointStates[0])
408 {
409 return;
410 }
411 LLJoint* target_joint = mJointStates[0]->getJoint();
412
413 if (!target_joint)
414 {
415 return;
416 }
417
418 target_joint->setPosition(lerp(target_joint->getPosition(), mJointCache.getPosition(), u));
419 target_joint->setScale(lerp(target_joint->getScale(), mJointCache.getScale(), u));
420 target_joint->setRotation(nlerp(u, target_joint->getRotation(), mJointCache.getRotation()));
421}
422
423//-----------------------------------------------------------------------------
424// clear()
425//-----------------------------------------------------------------------------
426void LLJointStateBlender::clear()
427{
428 // now clear joint states
429 for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
430 {
431 mJointStates[i] = NULL;
432 }
433}
434
435//-----------------------------------------------------------------------------
436// resetCachedJoint()
437//-----------------------------------------------------------------------------
438void LLJointStateBlender::resetCachedJoint()
439{
440 if (!mJointStates[0])
441 {
442 return;
443 }
444 LLJoint* source_joint = mJointStates[0]->getJoint();
445 mJointCache.setPosition(source_joint->getPosition());
446 mJointCache.setScale(source_joint->getScale());
447 mJointCache.setRotation(source_joint->getRotation());
448}
449
450//-----------------------------------------------------------------------------
451// LLPoseBlender
452//-----------------------------------------------------------------------------
453
454LLPoseBlender::LLPoseBlender()
455{
456}
457
458LLPoseBlender::~LLPoseBlender()
459{
460 mJointStateBlenderPool.deleteAllData();
461}
462
463//-----------------------------------------------------------------------------
464// addMotion()
465//-----------------------------------------------------------------------------
466BOOL LLPoseBlender::addMotion(LLMotion* motion)
467{
468 LLPose* pose = motion->getPose();
469
470 for(LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
471 {
472 LLJoint *jointp = jsp->getJoint();
473 LLJointStateBlender* joint_blender;
474 if (!mJointStateBlenderPool.checkData(jointp))
475 {
476 // this is the first time we are animating this joint
477 // so create new jointblender and add it to our pool
478 joint_blender = new LLJointStateBlender();
479 mJointStateBlenderPool.addData(jointp, joint_blender);
480 } else
481 {
482 joint_blender = mJointStateBlenderPool.getData(jointp);
483 }
484
485 if (jsp->getPriority() == LLJoint::USE_MOTION_PRIORITY)
486 {
487 joint_blender->addJointState(jsp, motion->getPriority(), motion->getBlendType() == LLMotion::ADDITIVE_BLEND);
488 }
489 else
490 {
491 joint_blender->addJointState(jsp, jsp->getPriority(), motion->getBlendType() == LLMotion::ADDITIVE_BLEND);
492 }
493
494 // add it to our list of active blenders
495 if(!mActiveBlenders.checkData(joint_blender))
496 {
497 mActiveBlenders.addData(joint_blender);
498 }
499 }
500 return TRUE;
501}
502
503//-----------------------------------------------------------------------------
504// blendAndApply()
505//-----------------------------------------------------------------------------
506void LLPoseBlender::blendAndApply()
507{
508 for (LLJointStateBlender* jsbp = mActiveBlenders.getFirstData();
509 jsbp;
510 jsbp = mActiveBlenders.getNextData())
511 {
512 jsbp->blendJointStates();
513 }
514
515 // we're done now so there are no more active blenders for this frame
516 mActiveBlenders.removeAllNodes();
517}
518
519//-----------------------------------------------------------------------------
520// blendAndCache()
521//-----------------------------------------------------------------------------
522void LLPoseBlender::blendAndCache(BOOL reset_cached_joints)
523{
524 for (LLJointStateBlender* jsbp = mActiveBlenders.getFirstData();
525 jsbp;
526 jsbp = mActiveBlenders.getNextData())
527 {
528 if (reset_cached_joints)
529 {
530 jsbp->resetCachedJoint();
531 }
532 jsbp->blendJointStates(FALSE);
533 }
534}
535
536//-----------------------------------------------------------------------------
537// interpolate()
538//-----------------------------------------------------------------------------
539void LLPoseBlender::interpolate(F32 u)
540{
541 for (LLJointStateBlender* jsbp = mActiveBlenders.getFirstData();
542 jsbp;
543 jsbp = mActiveBlenders.getNextData())
544 {
545 jsbp->interpolate(u);
546 }
547}
548
549//-----------------------------------------------------------------------------
550// clearBlenders()
551//-----------------------------------------------------------------------------
552void LLPoseBlender::clearBlenders()
553{
554 for (LLJointStateBlender* jsbp = mActiveBlenders.getFirstData();
555 jsbp;
556 jsbp = mActiveBlenders.getNextData())
557 {
558 jsbp->clear();
559 }
560
561 mActiveBlenders.removeAllNodes();
562}
563
diff --git a/linden/indra/llcharacter/llpose.h b/linden/indra/llcharacter/llpose.h
new file mode 100644
index 0000000..12d1640
--- /dev/null
+++ b/linden/indra/llcharacter/llpose.h
@@ -0,0 +1,139 @@
1/**
2 * @file llpose.h
3 * @brief Implementation of LLPose 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#ifndef LL_LLPOSE_H
29#define LL_LLPOSE_H
30
31//-----------------------------------------------------------------------------
32// Header Files
33//-----------------------------------------------------------------------------
34#include <string>
35
36#include "linked_lists.h"
37#include "llmap.h"
38#include "lljointstate.h"
39#include "llassoclist.h"
40#include "lljoint.h"
41#include <map>
42
43
44//-----------------------------------------------------------------------------
45// class LLPose
46//-----------------------------------------------------------------------------
47class LLPose
48{
49 friend class LLPoseBlender;
50protected:
51 typedef std::map<std::string, LLJointState*> joint_map;
52 typedef joint_map::iterator joint_map_iterator;
53 typedef joint_map::value_type joint_map_value_type;
54
55 joint_map mJointMap;
56 F32 mWeight;
57 joint_map_iterator mListIter;
58public:
59 // Iterate through jointStates
60 LLJointState *getFirstJointState();
61 LLJointState *getNextJointState();
62 LLJointState *findJointState(LLJoint *joint);
63 LLJointState *findJointState(const std::string &name);
64public:
65 // Constructor
66 LLPose() : mWeight(0.f) {}
67 // Destructor
68 ~LLPose();
69 // add a joint state in this pose
70 BOOL addJointState(LLJointState *jointState);
71 // remove a joint state from this pose
72 BOOL removeJointState(LLJointState *jointState);
73 // removes all joint states from this pose
74 BOOL removeAllJointStates();
75 // set weight for all joint states in this pose
76 void setWeight(F32 weight);
77 // get weight for this pose
78 F32 getWeight() const;
79 // returns number of joint states stored in this pose
80 S32 getNumJointStates() const;
81};
82
83const S32 JSB_NUM_JOINT_STATES = 4;
84
85class LLJointStateBlender
86{
87protected:
88 LLJointState* mJointStates[JSB_NUM_JOINT_STATES];
89 S32 mPriorities[JSB_NUM_JOINT_STATES];
90 BOOL mAdditiveBlends[JSB_NUM_JOINT_STATES];
91public:
92 LLJointStateBlender();
93 ~LLJointStateBlender();
94 void blendJointStates(BOOL apply_now = TRUE);
95 BOOL addJointState(LLJointState *joint_state, S32 priority, BOOL additive_blend);
96 void interpolate(F32 u);
97 void clear();
98 void resetCachedJoint();
99
100public:
101 LLJoint mJointCache;
102};
103
104class LLMotion;
105
106class LLPoseBlender
107{
108protected:
109 LLMap<LLJoint*,LLJointStateBlender*> mJointStateBlenderPool;
110 LLLinkedList<LLJointStateBlender> mActiveBlenders;
111
112 S32 mNextPoseSlot;
113 LLPose mBlendedPose;
114public:
115 // Constructor
116 LLPoseBlender();
117 // Destructor
118 ~LLPoseBlender();
119
120 // request motion joint states to be added to pose blender joint state records
121 BOOL addMotion(LLMotion* motion);
122
123 // blend all joint states and apply to skeleton
124 void blendAndApply();
125
126 // removes all joint state blenders from last time
127 void clearBlenders();
128
129 // blend all joint states and cache results
130 void blendAndCache(BOOL reset_cached_joints);
131
132 // interpolate all joints towards cached values
133 void interpolate(F32 u);
134
135 LLPose* getBlendedPose() { return &mBlendedPose; }
136};
137
138#endif // LL_LLPOSE_H
139
diff --git a/linden/indra/llcharacter/llstatemachine.cpp b/linden/indra/llcharacter/llstatemachine.cpp
new file mode 100644
index 0000000..6920bcf
--- /dev/null
+++ b/linden/indra/llcharacter/llstatemachine.cpp
@@ -0,0 +1,397 @@
1/**
2 * @file llstatemachine.cpp
3 * @brief LLStateMachine implementation file.
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#include "linden_common.h"
29
30#include "llstatemachine.h"
31#include "llapr.h"
32
33#define FSM_PRINT_STATE_TRANSITIONS (0)
34
35U32 LLUniqueID::sNextID = 0;
36
37bool operator==(const LLUniqueID &a, const LLUniqueID &b)
38{
39 return (a.mId == b.mId);
40}
41
42bool operator!=(const LLUniqueID &a, const LLUniqueID &b)
43{
44 return (a.mId != b.mId);
45}
46
47//-----------------------------------------------------------------------------
48// LLStateDiagram
49//-----------------------------------------------------------------------------
50LLStateDiagram::LLStateDiagram()
51{
52 mUseDefaultState = FALSE;
53}
54
55LLStateDiagram::~LLStateDiagram()
56{
57
58}
59
60// add a state to the state graph
61BOOL LLStateDiagram::addState(LLFSMState *state)
62{
63 mStates[state] = Transitions();
64 return TRUE;
65}
66
67// add a directed transition between 2 states
68BOOL LLStateDiagram::addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition)
69{
70 StateMap::iterator state_it;
71 state_it = mStates.find(&start_state);
72 Transitions* state_transitions = NULL;
73 if (state_it == mStates.end() )
74 {
75 addState(&start_state);
76 state_transitions = &mStates[&start_state];
77 }
78 else
79 {
80 state_transitions = &state_it->second;
81 }
82 state_it = mStates.find(&end_state);
83 if (state_it == mStates.end() )
84 {
85 addState(&end_state);
86 }
87
88 Transitions::iterator transition_it = state_transitions->find(&transition);
89 if (transition_it != state_transitions->end())
90 {
91 llerrs << "LLStateTable::addDirectedTransition() : transition already exists" << llendl;
92 return FALSE; // transition already exists
93 }
94
95 (*state_transitions)[&transition] = &end_state;
96 return TRUE;
97}
98
99// add an undirected transition between 2 states
100BOOL LLStateDiagram::addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition)
101{
102 BOOL result;
103 result = addTransition(start_state, end_state, transition);
104 if (result)
105 {
106 result = addTransition(end_state, start_state, transition);
107 }
108 return result;
109}
110
111// add a transition that exists for every state
112void LLStateDiagram::addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition)
113{
114 mDefaultTransitions[&transition] = &end_state;
115}
116
117// process a possible transition, and get the resulting state
118LLFSMState* LLStateDiagram::processTransition(LLFSMState& start_state, LLFSMTransition& transition)
119{
120 // look up transition
121 //LLFSMState** dest_state = (mStates.getValue(&start_state))->getValue(&transition);
122 LLFSMState* dest_state = NULL;
123 StateMap::iterator state_it = mStates.find(&start_state);
124 if (state_it == mStates.end())
125 {
126 return NULL;
127 }
128 Transitions::iterator transition_it = state_it->second.find(&transition);
129
130 // try default transitions if state-specific transition not found
131 if (transition_it == state_it->second.end())
132 {
133 dest_state = mDefaultTransitions[&transition];
134 }
135 else
136 {
137 dest_state = transition_it->second;
138 }
139
140 // if we have a destination state...
141 if (NULL != dest_state)
142 {
143 // ...return it...
144 return dest_state;
145 }
146 // ... otherwise ...
147 else
148 {
149 // ...look for default state...
150 if (mUseDefaultState)
151 {
152 // ...return it if we have it...
153 return mDefaultState;
154 }
155 else
156 {
157 // ...or else we're still in the same state.
158 return &start_state;
159 }
160 }
161}
162
163void LLStateDiagram::setDefaultState(LLFSMState& default_state)
164{
165 mUseDefaultState = TRUE;
166 mDefaultState = &default_state;
167}
168
169S32 LLStateDiagram::numDeadendStates()
170{
171 S32 numDeadends = 0;
172 StateMap::iterator state_it;
173 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
174 {
175 if (state_it->second.size() == 0)
176 {
177 numDeadends++;
178 }
179 }
180 return numDeadends;
181}
182
183BOOL LLStateDiagram::stateIsValid(LLFSMState& state)
184{
185 if (mStates.find(&state) != mStates.end())
186 {
187 return TRUE;
188 }
189 return FALSE;
190}
191
192LLFSMState* LLStateDiagram::getState(U32 state_id)
193{
194 StateMap::iterator state_it;
195 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
196 {
197 if (state_it->first->getID() == state_id)
198 {
199 return state_it->first;
200 }
201 }
202 return NULL;
203}
204
205BOOL LLStateDiagram::saveDotFile(const char* filename)
206{
207 apr_file_t* dot_file = ll_apr_file_open(filename, LL_APR_W);
208
209 if (!dot_file)
210 {
211 llwarns << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << llendl;
212 return FALSE;
213 }
214 apr_file_printf(dot_file, "digraph StateMachine {\n\tsize=\"100,100\";\n\tfontsize=40;\n\tlabel=\"Finite State Machine\";\n\torientation=landscape\n\tratio=.77\n");
215
216 StateMap::iterator state_it;
217 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
218 {
219 apr_file_printf(dot_file, "\t\"%s\" [fontsize=28,shape=box]\n", state_it->first->getName().c_str());
220 }
221 apr_file_printf(dot_file, "\t\"All States\" [fontsize=30,style=bold,shape=box]\n");
222
223 Transitions::iterator transitions_it;
224 for(transitions_it = mDefaultTransitions.begin(); transitions_it != mDefaultTransitions.end(); ++transitions_it)
225 {
226 apr_file_printf(dot_file, "\t\"All States\" -> \"%s\" [label = \"%s\",fontsize=24];\n", transitions_it->second->getName().c_str(),
227 transitions_it->second->getName().c_str());
228 }
229
230 if (mDefaultState)
231 {
232 apr_file_printf(dot_file, "\t\"All States\" -> \"%s\";\n", mDefaultState->getName().c_str());
233 }
234
235
236 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
237 {
238 LLFSMState *state = state_it->first;
239
240 Transitions::iterator transitions_it;
241 for(transitions_it = state_it->second.begin();
242 transitions_it != state_it->second.end();
243 ++transitions_it)
244 {
245 std::string state_name = state->getName();
246 std::string target_name = transitions_it->second->getName();
247 std::string transition_name = transitions_it->first->getName();
248 apr_file_printf(dot_file, "\t\"%s\" -> \"%s\" [label = \"%s\",fontsize=24];\n", state->getName().c_str(),
249 target_name.c_str(),
250 transition_name.c_str());
251 }
252 }
253
254 apr_file_printf(dot_file, "}\n");
255
256 apr_file_close(dot_file);
257
258 return TRUE;
259}
260
261std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM)
262{
263 if (FSM.mDefaultState)
264 {
265 s << "Default State: " << FSM.mDefaultState->getName() << "\n";
266 }
267
268 LLStateDiagram::Transitions::iterator transitions_it;
269 for(transitions_it = FSM.mDefaultTransitions.begin();
270 transitions_it != FSM.mDefaultTransitions.end();
271 ++transitions_it)
272 {
273 s << "Any State -- " << transitions_it->first->getName()
274 << " --> " << transitions_it->second->getName() << "\n";
275 }
276
277 LLStateDiagram::StateMap::iterator state_it;
278 for(state_it = FSM.mStates.begin(); state_it != FSM.mStates.end(); ++state_it)
279 {
280 LLStateDiagram::Transitions::iterator transitions_it;
281 for(transitions_it = state_it->second.begin();
282 transitions_it != state_it->second.end();
283 ++transitions_it)
284 {
285 s << state_it->first->getName() << " -- " << transitions_it->first->getName()
286 << " --> " << transitions_it->second->getName() << "\n";
287 }
288 s << "\n";
289 }
290
291 return s;
292}
293
294//-----------------------------------------------------------------------------
295// LLStateMachine
296//-----------------------------------------------------------------------------
297
298LLStateMachine::LLStateMachine()
299{
300 // we haven't received a starting state yet
301 mCurrentState = NULL;
302 mLastState = NULL;
303 mStateDiagram = NULL;
304}
305
306LLStateMachine::~LLStateMachine()
307{
308
309}
310
311// returns current state
312LLFSMState* LLStateMachine::getCurrentState() const
313{
314 return mCurrentState;
315}
316
317// executes current state
318void LLStateMachine::runCurrentState(void *data)
319{
320 mCurrentState->execute(data);
321}
322
323// set current state
324BOOL LLStateMachine::setCurrentState(LLFSMState *initial_state, void* user_data, BOOL skip_entry)
325{
326 llassert(mStateDiagram);
327
328 if (mStateDiagram->stateIsValid(*initial_state))
329 {
330 mLastState = mCurrentState = initial_state;
331 if (!skip_entry)
332 {
333 initial_state->onEntry(user_data);
334 }
335 return TRUE;
336 }
337
338 return FALSE;
339}
340
341BOOL LLStateMachine::setCurrentState(U32 state_id, void* user_data, BOOL skip_entry)
342{
343 llassert(mStateDiagram);
344
345 LLFSMState* state = mStateDiagram->getState(state_id);
346
347 if (state)
348 {
349 mLastState = mCurrentState = state;
350 if (!skip_entry)
351 {
352 state->onEntry(user_data);
353 }
354 return TRUE;
355 }
356
357 return FALSE;
358}
359
360void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_data)
361{
362 llassert(mStateDiagram);
363
364 LLFSMState* new_state = mStateDiagram->processTransition(*mCurrentState, transition);
365
366 mLastTransition = &transition;
367 mLastState = mCurrentState;
368
369 if (*mCurrentState != *new_state)
370 {
371 if (mCurrentState && new_state && *mCurrentState != *new_state)
372 {
373 mCurrentState->onExit(user_data);
374 }
375 if (new_state)
376 {
377 if (!mCurrentState || *mCurrentState != *new_state)
378 {
379 mCurrentState = new_state;
380 if (mCurrentState)
381 {
382 mCurrentState->onEntry(user_data);
383 }
384 }
385 }
386#if FSM_PRINT_STATE_TRANSITIONS
387 llinfos << "Entering state " << mCurrentState->getName() <<
388 " on transition " << transition.getName() << " from state " <<
389 mLastState->getName() << llendl;
390#endif
391 }
392}
393
394void LLStateMachine::setStateDiagram(LLStateDiagram* diagram)
395{
396 mStateDiagram = diagram;
397}
diff --git a/linden/indra/llcharacter/llstatemachine.h b/linden/indra/llcharacter/llstatemachine.h
new file mode 100644
index 0000000..0f986bd
--- /dev/null
+++ b/linden/indra/llcharacter/llstatemachine.h
@@ -0,0 +1,149 @@
1/**
2 * @file llstatemachine.h
3 * @brief LLStateMachine class header file.
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#ifndef LL_LLSTATEMACHINE_H
29#define LL_LLSTATEMACHINE_H
30
31#include <string>
32
33#include "llassoclist.h"
34#include "llerror.h"
35#include <map>
36
37class LLUniqueID
38{
39 friend bool operator==(const LLUniqueID &a, const LLUniqueID &b);
40 friend bool operator!=(const LLUniqueID &a, const LLUniqueID &b);
41protected:
42 static U32 sNextID;
43 U32 mId;
44public:
45 LLUniqueID(){mId = sNextID++;}
46 virtual ~LLUniqueID(){}
47 U32 getID() {return mId;}
48};
49
50class LLFSMTransition : public LLUniqueID
51{
52public:
53 LLFSMTransition() : LLUniqueID(){};
54 virtual std::string getName(){ return "unnamed"; }
55};
56
57class LLFSMState : public LLUniqueID
58{
59public:
60 LLFSMState() : LLUniqueID(){};
61 virtual void onEntry(void *){};
62 virtual void onExit(void *){};
63 virtual void execute(void *){};
64 virtual std::string getName(){ return "unnamed"; }
65};
66
67class LLStateDiagram
68{
69typedef std::map<LLFSMTransition*, LLFSMState*> Transitions;
70
71friend std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM);
72friend class LLStateMachine;
73
74protected:
75 typedef std::map<LLFSMState*, Transitions> StateMap;
76 StateMap mStates;
77 Transitions mDefaultTransitions;
78 LLFSMState* mDefaultState;
79 BOOL mUseDefaultState;
80
81public:
82 LLStateDiagram();
83 virtual ~LLStateDiagram();
84
85protected:
86 // add a state to the state graph, executed implicitly when adding transitions
87 BOOL addState(LLFSMState *state);
88
89 // add a directed transition between 2 states
90 BOOL addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition);
91
92 // add an undirected transition between 2 states
93 BOOL addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition);
94
95 // add a transition that is taken if none other exist
96 void addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition);
97
98 // process a possible transition, and get the resulting state
99 LLFSMState* processTransition(LLFSMState& start_state, LLFSMTransition& transition);
100
101 // add a transition that exists for every state
102 void setDefaultState(LLFSMState& default_state);
103
104 // return total number of states with no outgoing transitions
105 S32 numDeadendStates();
106
107 // does this state exist in the state diagram?
108 BOOL stateIsValid(LLFSMState& state);
109
110 // get a state pointer by ID
111 LLFSMState* getState(U32 state_id);
112
113public:
114 // save the graph in a DOT file for rendering and visualization
115 BOOL saveDotFile(const char* filename);
116};
117
118class LLStateMachine
119{
120protected:
121 LLFSMState* mCurrentState;
122 LLFSMState* mLastState;
123 LLFSMTransition* mLastTransition;
124 LLStateDiagram* mStateDiagram;
125
126public:
127 LLStateMachine();
128 virtual ~LLStateMachine();
129
130 // set state diagram
131 void setStateDiagram(LLStateDiagram* diagram);
132
133 // process this transition
134 void processTransition(LLFSMTransition &transition, void* user_data);
135
136 // returns current state
137 LLFSMState* getCurrentState() const;
138
139 // execute current state
140 void runCurrentState(void *data);
141
142 // set state by state pointer
143 BOOL setCurrentState(LLFSMState *initial_state, void* user_data, BOOL skip_entry = TRUE);
144
145 // set state by unique ID
146 BOOL setCurrentState(U32 state_id, void* user_data, BOOL skip_entry = TRUE);
147};
148
149#endif //_LL_LLSTATEMACHINE_H
diff --git a/linden/indra/llcharacter/lltargetingmotion.cpp b/linden/indra/llcharacter/lltargetingmotion.cpp
new file mode 100644
index 0000000..799e4d0
--- /dev/null
+++ b/linden/indra/llcharacter/lltargetingmotion.cpp
@@ -0,0 +1,170 @@
1/**
2 * @file lltargetingmotion.cpp
3 * @brief Implementation of LLTargetingMotion 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 "lltargetingmotion.h"
34#include "llcharacter.h"
35#include "v3dmath.h"
36#include "llcriticaldamp.h"
37
38//-----------------------------------------------------------------------------
39// Constants
40//-----------------------------------------------------------------------------
41const F32 TORSO_TARGET_HALF_LIFE = 0.25f;
42const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
43const F32 TARGET_PLANE_THRESHOLD_DOT = 0.6f;
44const F32 TORSO_ROT_FRACTION = 0.5f;
45
46//-----------------------------------------------------------------------------
47// LLTargetingMotion()
48// Class Constructor
49//-----------------------------------------------------------------------------
50LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id)
51{
52 mCharacter = NULL;
53 mName = "targeting";
54}
55
56
57//-----------------------------------------------------------------------------
58// ~LLTargetingMotion()
59// Class Destructor
60//-----------------------------------------------------------------------------
61LLTargetingMotion::~LLTargetingMotion()
62{
63}
64
65//-----------------------------------------------------------------------------
66// LLTargetingMotion::onInitialize(LLCharacter *character)
67//-----------------------------------------------------------------------------
68LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *character)
69{
70 // save character for future use
71 mCharacter = character;
72
73 mPelvisJoint = mCharacter->getJoint("mPelvis");
74 mTorsoJoint = mCharacter->getJoint("mTorso");
75 mRightHandJoint = mCharacter->getJoint("mWristRight");
76
77 // make sure character skeleton is copacetic
78 if (!mPelvisJoint ||
79 !mTorsoJoint ||
80 !mRightHandJoint)
81 {
82 llwarns << "Invalid skeleton for targeting motion!" << llendl;
83 return STATUS_FAILURE;
84 }
85
86 mTorsoState.setJoint( mTorsoJoint );
87
88 // add joint states to the pose
89 mTorsoState.setUsage(LLJointState::ROT);
90 addJointState( &mTorsoState );
91
92 return STATUS_SUCCESS;
93}
94
95//-----------------------------------------------------------------------------
96// LLTargetingMotion::onActivate()
97//-----------------------------------------------------------------------------
98BOOL LLTargetingMotion::onActivate()
99{
100 return TRUE;
101}
102
103//-----------------------------------------------------------------------------
104// LLTargetingMotion::onUpdate()
105//-----------------------------------------------------------------------------
106BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
107{
108 F32 slerp_amt = LLCriticalDamp::getInterpolant(TORSO_TARGET_HALF_LIFE);
109
110 LLVector3 target;
111 LLVector3* lookAtPoint = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
112
113 BOOL result = TRUE;
114
115 if (!lookAtPoint)
116 {
117 return TRUE;
118 }
119 else
120 {
121 target = *lookAtPoint;
122 target.normVec();
123 }
124
125 //LLVector3 target_plane_normal = LLVector3(1.f, 0.f, 0.f) * mPelvisJoint->getWorldRotation();
126 //LLVector3 torso_dir = LLVector3(1.f, 0.f, 0.f) * (mTorsoJoint->getWorldRotation() * mTorsoState.getRotation());
127
128 LLVector3 skyward(0.f, 0.f, 1.f);
129 LLVector3 left(skyward % target);
130 left.normVec();
131 LLVector3 up(target % left);
132 up.normVec();
133 LLQuaternion target_aim_rot(target, left, up);
134
135 LLQuaternion cur_torso_rot = mTorsoJoint->getWorldRotation();
136
137 LLVector3 right_hand_at = LLVector3(0.f, -1.f, 0.f) * mRightHandJoint->getWorldRotation();
138 left.setVec(skyward % right_hand_at);
139 left.normVec();
140 up.setVec(right_hand_at % left);
141 up.normVec();
142 LLQuaternion right_hand_rot(right_hand_at, left, up);
143
144 LLQuaternion new_torso_rot = (cur_torso_rot * ~right_hand_rot) * target_aim_rot;
145
146 // find ideal additive rotation to make torso point in correct direction
147 new_torso_rot = new_torso_rot * ~cur_torso_rot;
148
149 // slerp from current additive rotation to ideal additive rotation
150 new_torso_rot = nlerp(slerp_amt, mTorsoState.getRotation(), new_torso_rot);
151
152 // constraint overall torso rotation
153 LLQuaternion total_rot = new_torso_rot * mTorsoJoint->getRotation();
154 total_rot.constrain(F_PI_BY_TWO * 0.8f);
155 new_torso_rot = total_rot * ~mTorsoJoint->getRotation();
156
157 mTorsoState.setRotation(new_torso_rot);
158
159 return result;
160}
161
162//-----------------------------------------------------------------------------
163// LLTargetingMotion::onDeactivate()
164//-----------------------------------------------------------------------------
165void LLTargetingMotion::onDeactivate()
166{
167}
168
169
170// End
diff --git a/linden/indra/llcharacter/lltargetingmotion.h b/linden/indra/llcharacter/lltargetingmotion.h
new file mode 100644
index 0000000..9fd8391
--- /dev/null
+++ b/linden/indra/llcharacter/lltargetingmotion.h
@@ -0,0 +1,117 @@
1/**
2 * @file lltargetingmotion.h
3 * @brief Implementation of LLTargetingMotion class.
4 *
5 * Copyright (c) 2002-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#ifndef LL_LLTARGETINGMOTION_H
29#define LL_LLTARGETINGMOTION_H
30
31//-----------------------------------------------------------------------------
32// Header files
33//-----------------------------------------------------------------------------
34#include "llmotion.h"
35
36#define TARGETING_EASEIN_DURATION 0.3f
37#define TARGETING_EASEOUT_DURATION 0.5f
38#define TARGETING_PRIORITY LLJoint::HIGH_PRIORITY
39#define MIN_REQUIRED_PIXEL_AREA_TARGETING 1000.f;
40
41
42//-----------------------------------------------------------------------------
43// class LLTargetingMotion
44//-----------------------------------------------------------------------------
45class LLTargetingMotion :
46 public LLMotion
47{
48public:
49 // Constructor
50 LLTargetingMotion(const LLUUID &id);
51
52 // Destructor
53 virtual ~LLTargetingMotion();
54
55public:
56 //-------------------------------------------------------------------------
57 // functions to support MotionController and MotionRegistry
58 //-------------------------------------------------------------------------
59
60 // static constructor
61 // all subclasses must implement such a function and register it
62 static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); }
63
64public:
65 //-------------------------------------------------------------------------
66 // animation callbacks to be implemented by subclasses
67 //-------------------------------------------------------------------------
68
69 // motions must specify whether or not they loop
70 virtual BOOL getLoop() { return TRUE; }
71
72 // motions must report their total duration
73 virtual F32 getDuration() { return 0.0; }
74
75 // motions must report their "ease in" duration
76 virtual F32 getEaseInDuration() { return TARGETING_EASEIN_DURATION; }
77
78 // motions must report their "ease out" duration.
79 virtual F32 getEaseOutDuration() { return TARGETING_EASEOUT_DURATION; }
80
81 // motions must report their priority
82 virtual LLJoint::JointPriority getPriority() { return TARGETING_PRIORITY; }
83
84 virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
85
86 // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
87 virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_TARGETING; }
88
89 // run-time (post constructor) initialization,
90 // called after parameters have been set
91 // must return true to indicate success and be available for activation
92 virtual LLMotionInitStatus onInitialize(LLCharacter *character);
93
94 // called when a motion is activated
95 // must return TRUE to indicate success, or else
96 // it will be deactivated
97 virtual BOOL onActivate();
98
99 // called per time step
100 // must return TRUE while it is active, and
101 // must return FALSE when the motion is completed.
102 virtual BOOL onUpdate(F32 time, U8* joint_mask);
103
104 // called when a motion is deactivated
105 virtual void onDeactivate();
106
107public:
108
109 LLCharacter *mCharacter;
110 LLJointState mTorsoState;
111 LLJoint* mPelvisJoint;
112 LLJoint* mTorsoJoint;
113 LLJoint* mRightHandJoint;
114};
115
116#endif // LL_LLTARGETINGMOTION_H
117
diff --git a/linden/indra/llcharacter/llvisualparam.cpp b/linden/indra/llcharacter/llvisualparam.cpp
new file mode 100644
index 0000000..ed8a034
--- /dev/null
+++ b/linden/indra/llcharacter/llvisualparam.cpp
@@ -0,0 +1,285 @@
1/**
2 * @file llvisualparam.cpp
3 * @brief Implementation of LLPolyMesh 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 "llvisualparam.h"
34
35//-----------------------------------------------------------------------------
36// LLVisualParamInfo()
37//-----------------------------------------------------------------------------
38LLVisualParamInfo::LLVisualParamInfo()
39 :
40 mID( -1 ),
41 mGroup( VISUAL_PARAM_GROUP_TWEAKABLE ),
42 mMinWeight( 0.f ),
43 mMaxWeight( 1.f ),
44 mDefaultWeight( 0.f ),
45 mSex( SEX_BOTH )
46{
47}
48
49//-----------------------------------------------------------------------------
50// parseXml()
51//-----------------------------------------------------------------------------
52BOOL LLVisualParamInfo::parseXml(LLXmlTreeNode *node)
53{
54 // attribute: id
55 static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
56 node->getFastAttributeS32( id_string, mID );
57
58 // attribute: group
59 U32 group = 0;
60 static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
61 if( node->getFastAttributeU32( group_string, group ) )
62 {
63 if( group < NUM_VISUAL_PARAM_GROUPS )
64 {
65 mGroup = (EVisualParamGroup)group;
66 }
67 }
68
69 // attribute: value_min, value_max
70 static LLStdStringHandle value_min_string = LLXmlTree::addAttributeString("value_min");
71 static LLStdStringHandle value_max_string = LLXmlTree::addAttributeString("value_max");
72 node->getFastAttributeF32( value_min_string, mMinWeight );
73 node->getFastAttributeF32( value_max_string, mMaxWeight );
74
75 // attribute: value_default
76 F32 default_weight = 0;
77 static LLStdStringHandle value_default_string = LLXmlTree::addAttributeString("value_default");
78 if( node->getFastAttributeF32( value_default_string, default_weight ) )
79 {
80 mDefaultWeight = llclamp( default_weight, mMinWeight, mMaxWeight );
81 if( default_weight != mDefaultWeight )
82 {
83 llwarns << "value_default attribute is out of range in node " << mName << " " << default_weight << llendl;
84 }
85 }
86
87 // attribute: sex
88 LLString sex = "both";
89 static LLStdStringHandle sex_string = LLXmlTree::addAttributeString("sex");
90 node->getFastAttributeString( sex_string, sex ); // optional
91 if( sex == "both" )
92 {
93 mSex = SEX_BOTH;
94 }
95 else if( sex == "male" )
96 {
97 mSex = SEX_MALE;
98 }
99 else if( sex == "female" )
100 {
101 mSex = SEX_FEMALE;
102 }
103 else
104 {
105 llwarns << "Avatar file: <param> has invalid sex attribute: " << sex << llendl;
106 return FALSE;
107 }
108
109 // attribute: name
110 static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
111 if( !node->getFastAttributeString( name_string, mName ) )
112 {
113 llwarns << "Avatar file: <param> is missing name attribute" << llendl;
114 return FALSE;
115 }
116
117 // attribute: label
118 static LLStdStringHandle label_string = LLXmlTree::addAttributeString("label");
119 if( !node->getFastAttributeString( label_string, mDisplayName ) )
120 {
121 mDisplayName = mName;
122 }
123
124 // JC - make sure the display name includes the capitalization in the XML file,
125 // not the lowercased version.
126 LLString::toLower(mName);
127
128 // attribute: label_min
129 static LLStdStringHandle label_min_string = LLXmlTree::addAttributeString("label_min");
130 if( !node->getFastAttributeString( label_min_string, mMinName ) )
131 {
132 mMinName = "Less";
133 }
134
135 // attribute: label_max
136 static LLStdStringHandle label_max_string = LLXmlTree::addAttributeString("label_max");
137 if( !node->getFastAttributeString( label_max_string, mMaxName ) )
138 {
139 mMaxName = "More";
140 }
141
142 return TRUE;
143}
144
145//-----------------------------------------------------------------------------
146// LLVisualParam()
147//-----------------------------------------------------------------------------
148LLVisualParam::LLVisualParam()
149 :
150 mCurWeight( 0.f ),
151 mLastWeight( 0.f ),
152 mNext( NULL ),
153 mTargetWeight( 0.f ),
154 mIsAnimating( FALSE ),
155 mID( -1 ),
156 mInfo( 0 )
157{
158}
159
160//-----------------------------------------------------------------------------
161// ~LLVisualParam()
162//-----------------------------------------------------------------------------
163LLVisualParam::~LLVisualParam()
164{
165 delete mNext;
166}
167
168/*
169//=============================================================================
170// These virtual functions should always be overridden,
171// but are included here for use as templates
172//=============================================================================
173
174//-----------------------------------------------------------------------------
175// setInfo()
176//-----------------------------------------------------------------------------
177
178BOOL LLVisualParam::setInfo(LLVisualParamInfo *info)
179{
180 llassert(mInfo == NULL);
181 if (info->mID < 0)
182 return FALSE;
183 mInfo = info;
184 mID = info->mID;
185 setWeight(getDefaultWeight(), FALSE );
186 return TRUE;
187}
188
189//-----------------------------------------------------------------------------
190// parseData()
191//-----------------------------------------------------------------------------
192BOOL LLVisualParam::parseData(LLXmlTreeNode *node)
193{
194 LLVisualParamInfo *info = new LLVisualParamInfo;
195
196 info->parseXml(node);
197 if (!setInfo(info))
198 return FALSE;
199
200 return TRUE;
201}
202*/
203
204//-----------------------------------------------------------------------------
205// setWeight()
206//-----------------------------------------------------------------------------
207void LLVisualParam::setWeight(F32 weight, BOOL set_by_user)
208{
209 if (mIsAnimating)
210 {
211 //RN: allow overshoot
212 mCurWeight = weight;
213 }
214 else if (mInfo)
215 {
216 mCurWeight = llclamp(weight, mInfo->mMinWeight, mInfo->mMaxWeight);
217 }
218 else
219 {
220 mCurWeight = weight;
221 }
222
223 if (mNext)
224 {
225 mNext->setWeight(weight, set_by_user);
226 }
227}
228
229//-----------------------------------------------------------------------------
230// setAnimationTarget()
231//-----------------------------------------------------------------------------
232void LLVisualParam::setAnimationTarget(F32 target_value, BOOL set_by_user)
233{
234 if (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
235 {
236 if (mInfo)
237 {
238 mTargetWeight = llclamp(target_value, mInfo->mMinWeight, mInfo->mMaxWeight);
239 }
240 else
241 {
242 mTargetWeight = target_value;
243 }
244 }
245 mIsAnimating = TRUE;
246
247 if (mNext)
248 {
249 mNext->setAnimationTarget(target_value, set_by_user);
250 }
251}
252
253//-----------------------------------------------------------------------------
254// setNextParam()
255//-----------------------------------------------------------------------------
256void LLVisualParam::setNextParam( LLVisualParam *next )
257{
258 llassert(!mNext);
259
260 mNext = next;
261}
262
263//-----------------------------------------------------------------------------
264// animate()
265//-----------------------------------------------------------------------------
266void LLVisualParam::animate( F32 delta, BOOL set_by_user )
267{
268 if (mIsAnimating)
269 {
270 F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight;
271 setWeight(new_weight, set_by_user);
272 }
273}
274
275//-----------------------------------------------------------------------------
276// stopAnimating()
277//-----------------------------------------------------------------------------
278void LLVisualParam::stopAnimating(BOOL set_by_user)
279{
280 if (mIsAnimating && getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
281 {
282 mIsAnimating = FALSE;
283 setWeight(mTargetWeight, set_by_user);
284 }
285}
diff --git a/linden/indra/llcharacter/llvisualparam.h b/linden/indra/llcharacter/llvisualparam.h
new file mode 100644
index 0000000..74774b8
--- /dev/null
+++ b/linden/indra/llcharacter/llvisualparam.h
@@ -0,0 +1,150 @@
1/**
2 * @file llvisualparam.h
3 * @brief Implementation of LLPolyMesh 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#ifndef LL_LLVisualParam_H
29#define LL_LLVisualParam_H
30
31#include "v3math.h"
32#include "llstring.h"
33#include "llxmltree.h"
34
35class LLPolyMesh;
36class LLXmlTreeNode;
37
38enum ESex
39{
40 SEX_FEMALE = 0x01,
41 SEX_MALE = 0x02,
42 SEX_BOTH = 0x03 // values chosen to allow use as a bit field.
43};
44
45enum EVisualParamGroup
46{
47 VISUAL_PARAM_GROUP_TWEAKABLE,
48 VISUAL_PARAM_GROUP_ANIMATABLE,
49 NUM_VISUAL_PARAM_GROUPS
50};
51
52const S32 MAX_TRANSMITTED_VISUAL_PARAMS = 255;
53
54//-----------------------------------------------------------------------------
55// LLVisualParamInfo
56// Contains shared data for VisualParams
57//-----------------------------------------------------------------------------
58class LLVisualParamInfo
59{
60 friend class LLVisualParam;
61public:
62 LLVisualParamInfo();
63 virtual ~LLVisualParamInfo() {};
64
65 virtual BOOL parseXml(LLXmlTreeNode *node);
66
67protected:
68 S32 mID; // ID associated with VisualParam
69
70 LLString mName; // name (for internal purposes)
71 LLString mDisplayName; // name displayed to the user
72 LLString mMinName; // name associated with minimum value
73 LLString mMaxName; // name associated with maximum value
74 EVisualParamGroup mGroup; // morph group for separating UI controls
75 F32 mMinWeight; // minimum weight that can be assigned to this morph target
76 F32 mMaxWeight; // maximum weight that can be assigned to this morph target
77 F32 mDefaultWeight;
78 ESex mSex; // Which gender(s) this param applies to.
79};
80
81//-----------------------------------------------------------------------------
82// LLVisualParam
83// VIRTUAL CLASS
84// An interface class for a generalized parametric modification of the avatar mesh
85// Contains data that is specific to each Avatar
86//-----------------------------------------------------------------------------
87class LLVisualParam
88{
89public:
90 LLVisualParam();
91 virtual ~LLVisualParam();
92
93 // Special: These functions are overridden by child classes
94 // (They can not be virtual because they use specific derived Info classes)
95 LLVisualParamInfo* getInfo() const { return mInfo; }
96 // This sets mInfo and calls initialization functions
97 BOOL setInfo(LLVisualParamInfo *info);
98
99 // Virtual functions
100 // Pure virtuals
101 //virtual BOOL parseData( LLXmlTreeNode *node ) = 0;
102 virtual void apply( ESex avatar_sex ) = 0;
103 // Default functions
104 virtual void setWeight(F32 weight, BOOL set_by_user);
105 virtual void setAnimationTarget( F32 target_value, BOOL set_by_user );
106 virtual void animate(F32 delta, BOOL set_by_user);
107 virtual void stopAnimating(BOOL set_by_user);
108
109 // Interface methods
110 const S32 getID() { return mID; }
111 void setID(S32 id) { llassert(!mInfo); mID = id; }
112
113 const LLString& getName() const { return mInfo->mName; }
114 const LLString& getDisplayName() const { return mInfo->mDisplayName; }
115 const LLString& getMaxDisplayName() const { return mInfo->mMaxName; }
116 const LLString& getMinDisplayName() const { return mInfo->mMinName; }
117
118 void setDisplayName(const char* s) { mInfo->mDisplayName = s; }
119 void setMaxDisplayName(const char* s) { mInfo->mMaxName = s; }
120 void setMinDisplayName(const char* s) { mInfo->mMinName = s; }
121
122 const EVisualParamGroup getGroup() { return mInfo->mGroup; }
123 F32 getMinWeight() { return mInfo->mMinWeight; }
124 F32 getMaxWeight() { return mInfo->mMaxWeight; }
125 F32 getDefaultWeight() { return mInfo->mDefaultWeight; }
126 ESex getSex() { return mInfo->mSex; }
127
128 F32 getWeight() { return mIsAnimating ? mTargetWeight : mCurWeight; }
129 F32 getCurrentWeight() { return mCurWeight; }
130 F32 getLastWeight() { return mLastWeight; }
131 BOOL isAnimating() { return mIsAnimating; }
132
133 LLVisualParam* getNextParam() { return mNext; }
134 void setNextParam( LLVisualParam *next );
135
136 virtual void setAnimating(BOOL is_animating) { mIsAnimating = is_animating; }
137 BOOL getAnimating() { return mIsAnimating; }
138
139protected:
140 F32 mCurWeight; // current weight
141 F32 mLastWeight; // last weight
142 LLVisualParam* mNext; // next param in a shared chain
143 F32 mTargetWeight; // interpolation target
144 BOOL mIsAnimating; // this value has been given an interpolation target
145
146 S32 mID; // id for storing weight/morphtarget compares compactly
147 LLVisualParamInfo *mInfo;
148};
149
150#endif // LL_LLVisualParam_H