diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter | |
parent | README.txt (diff) | |
download | meta-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')
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 @@ | |||
1 | llcharacter/llanimationstates.cpp | ||
2 | llcharacter/llbvhloader.cpp | ||
3 | llcharacter/llcharacter.cpp | ||
4 | llcharacter/lleditingmotion.cpp | ||
5 | llcharacter/llgesture.cpp | ||
6 | llcharacter/llhandmotion.cpp | ||
7 | llcharacter/llheadrotmotion.cpp | ||
8 | llcharacter/lljoint.cpp | ||
9 | llcharacter/lljointsolverrp3.cpp | ||
10 | llcharacter/llkeyframefallmotion.cpp | ||
11 | llcharacter/llkeyframemotion.cpp | ||
12 | llcharacter/llkeyframemotionparam.cpp | ||
13 | llcharacter/llkeyframestandmotion.cpp | ||
14 | llcharacter/llkeyframewalkmotion.cpp | ||
15 | llcharacter/llmotioncontroller.cpp | ||
16 | llcharacter/llmotion.cpp | ||
17 | llcharacter/llmultigesture.cpp | ||
18 | llcharacter/llpose.cpp | ||
19 | llcharacter/llstatemachine.cpp | ||
20 | llcharacter/lltargetingmotion.cpp | ||
21 | llcharacter/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 | |||
39 | LLUUID AGENT_WALK_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_CROUCHWALK, ANIM_AGENT_TURNLEFT, ANIM_AGENT_TURNRIGHT}; | ||
40 | S32 NUM_AGENT_WALK_ANIMS = sizeof(AGENT_WALK_ANIMS) / sizeof(LLUUID); | ||
41 | |||
42 | LLUUID AGENT_GUN_HOLD_ANIMS[] = {ANIM_AGENT_HOLD_RIFLE_R, ANIM_AGENT_HOLD_HANDGUN_R, ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_AGENT_HOLD_BOW_L}; | ||
43 | S32 NUM_AGENT_GUN_HOLD_ANIMS = sizeof(AGENT_GUN_HOLD_ANIMS) / sizeof(LLUUID); | ||
44 | |||
45 | LLUUID AGENT_GUN_AIM_ANIMS[] = {ANIM_AGENT_AIM_RIFLE_R, ANIM_AGENT_AIM_HANDGUN_R, ANIM_AGENT_AIM_BAZOOKA_R, ANIM_AGENT_AIM_BOW_L}; | ||
46 | S32 NUM_AGENT_GUN_AIM_ANIMS = sizeof(AGENT_GUN_AIM_ANIMS) / sizeof(LLUUID); | ||
47 | |||
48 | LLUUID AGENT_NO_ROTATE_ANIMS[] = {ANIM_AGENT_SIT_GROUND, ANIM_AGENT_SIT_GROUND_CONSTRAINED, ANIM_AGENT_STANDUP}; | ||
49 | S32 NUM_AGENT_NO_ROTATE_ANIMS = sizeof(AGENT_NO_ROTATE_ANIMS) / sizeof(LLUUID); | ||
50 | |||
51 | LLUUID AGENT_STAND_ANIMS[] = {ANIM_AGENT_STAND, ANIM_AGENT_STAND_1, ANIM_AGENT_STAND_2, ANIM_AGENT_STAND_3, ANIM_AGENT_STAND_4}; | ||
52 | S32 NUM_AGENT_STAND_ANIMS = sizeof(AGENT_STAND_ANIMS) / sizeof(LLUUID); | ||
53 | |||
54 | |||
55 | LLAnimationLibrary gAnimLibrary; | ||
56 | |||
57 | //----------------------------------------------------------------------------- | ||
58 | // LLAnimationLibrary() | ||
59 | //----------------------------------------------------------------------------- | ||
60 | LLAnimationLibrary::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 | //----------------------------------------------------------------------------- | ||
204 | LLAnimationLibrary::~LLAnimationLibrary() | ||
205 | { | ||
206 | } | ||
207 | |||
208 | //----------------------------------------------------------------------------- | ||
209 | // Return the text name of an animation state | ||
210 | //----------------------------------------------------------------------------- | ||
211 | const 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 | //----------------------------------------------------------------------------- | ||
229 | LLUUID 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 | ||
261 | const 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 | |||
333 | const 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 | //----------------------------------------------------------------------------- | ||
45 | const S32 MAX_CONCURRENT_ANIMS = 16; | ||
46 | |||
47 | |||
48 | const LLUUID ANIM_AGENT_AFRAID = LLUUID("6b61c8e8-4747-0d75-12d7-e49ff207a4ca"); | ||
49 | const LLUUID ANIM_AGENT_AIM_BAZOOKA_R = LLUUID("b5b4a67d-0aee-30d2-72cd-77b333e932ef"); | ||
50 | const LLUUID ANIM_AGENT_AIM_BOW_L = LLUUID("46bb4359-de38-4ed8-6a22-f1f52fe8f506"); | ||
51 | const LLUUID ANIM_AGENT_AIM_HANDGUN_R = LLUUID("3147d815-6338-b932-f011-16b56d9ac18b"); | ||
52 | const LLUUID ANIM_AGENT_AIM_RIFLE_R = LLUUID("ea633413-8006-180a-c3ba-96dd1d756720"); | ||
53 | const LLUUID ANIM_AGENT_ANGRY = LLUUID("5747a48e-073e-c331-f6f3-7c2149613d3e"); | ||
54 | const LLUUID ANIM_AGENT_AWAY = LLUUID("fd037134-85d4-f241-72c6-4f42164fedee"); | ||
55 | const LLUUID ANIM_AGENT_BACKFLIP = LLUUID("c4ca6188-9127-4f31-0158-23c4e2f93304"); | ||
56 | const LLUUID ANIM_AGENT_BELLY_LAUGH = LLUUID("18b3a4b5-b463-bd48-e4b6-71eaac76c515"); | ||
57 | const LLUUID ANIM_AGENT_BLOW_KISS = LLUUID("db84829b-462c-ee83-1e27-9bbee66bd624"); | ||
58 | const LLUUID ANIM_AGENT_BORED = LLUUID("b906c4ba-703b-1940-32a3-0c7f7d791510"); | ||
59 | const LLUUID ANIM_AGENT_BOW = LLUUID("82e99230-c906-1403-4d9c-3889dd98daba"); | ||
60 | const LLUUID ANIM_AGENT_BRUSH = LLUUID("349a3801-54f9-bf2c-3bd0-1ac89772af01"); | ||
61 | const LLUUID ANIM_AGENT_BUSY = LLUUID("efcf670c-2d18-8128-973a-034ebc806b67"); | ||
62 | const LLUUID ANIM_AGENT_CLAP = LLUUID("9b0c1c4e-8ac7-7969-1494-28c874c4f668"); | ||
63 | const LLUUID ANIM_AGENT_COURTBOW = LLUUID("9ba1c942-08be-e43a-fb29-16ad440efc50"); | ||
64 | const LLUUID ANIM_AGENT_CROUCH = LLUUID("201f3fdf-cb1f-dbec-201f-7333e328ae7c"); | ||
65 | const LLUUID ANIM_AGENT_CROUCHWALK = LLUUID("47f5f6fb-22e5-ae44-f871-73aaaf4a6022"); | ||
66 | const LLUUID ANIM_AGENT_CRY = LLUUID("92624d3e-1068-f1aa-a5ec-8244585193ed"); | ||
67 | const LLUUID ANIM_AGENT_CUSTOMIZE = LLUUID("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53"); | ||
68 | const LLUUID ANIM_AGENT_CUSTOMIZE_DONE = LLUUID("6883a61a-b27b-5914-a61e-dda118a9ee2c"); | ||
69 | const LLUUID ANIM_AGENT_DANCE1 = LLUUID("b68a3d7c-de9e-fc87-eec8-543d787e5b0d"); | ||
70 | const LLUUID ANIM_AGENT_DANCE2 = LLUUID("928cae18-e31d-76fd-9cc9-2f55160ff818"); | ||
71 | const LLUUID ANIM_AGENT_DANCE3 = LLUUID("30047778-10ea-1af7-6881-4db7a3a5a114"); | ||
72 | const LLUUID ANIM_AGENT_DANCE4 = LLUUID("951469f4-c7b2-c818-9dee-ad7eea8c30b7"); | ||
73 | const LLUUID ANIM_AGENT_DANCE5 = LLUUID("4bd69a1d-1114-a0b4-625f-84e0a5237155"); | ||
74 | const LLUUID ANIM_AGENT_DANCE6 = LLUUID("cd28b69b-9c95-bb78-3f94-8d605ff1bb12"); | ||
75 | const LLUUID ANIM_AGENT_DANCE7 = LLUUID("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6"); | ||
76 | const LLUUID ANIM_AGENT_DANCE8 = LLUUID("b0dc417c-1f11-af36-2e80-7e7489fa7cdc"); | ||
77 | const LLUUID ANIM_AGENT_DEAD = LLUUID("57abaae6-1d17-7b1b-5f98-6d11a6411276"); | ||
78 | const LLUUID ANIM_AGENT_DRINK = LLUUID("0f86e355-dd31-a61c-fdb0-3a96b9aad05f"); | ||
79 | const LLUUID ANIM_AGENT_EMBARRASSED = LLUUID("514af488-9051-044a-b3fc-d4dbf76377c6"); | ||
80 | const LLUUID ANIM_AGENT_EXPRESS_AFRAID = LLUUID("aa2df84d-cf8f-7218-527b-424a52de766e"); | ||
81 | const LLUUID ANIM_AGENT_EXPRESS_ANGER = LLUUID("1a03b575-9634-b62a-5767-3a679e81f4de"); | ||
82 | const LLUUID ANIM_AGENT_EXPRESS_BORED = LLUUID("214aa6c1-ba6a-4578-f27c-ce7688f61d0d"); | ||
83 | const LLUUID ANIM_AGENT_EXPRESS_CRY = LLUUID("d535471b-85bf-3b4d-a542-93bea4f59d33"); | ||
84 | const LLUUID ANIM_AGENT_EXPRESS_DISDAIN = LLUUID("d4416ff1-09d3-300f-4183-1b68a19b9fc1"); | ||
85 | const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED = LLUUID("0b8c8211-d78c-33e8-fa28-c51a9594e424"); | ||
86 | const LLUUID ANIM_AGENT_EXPRESS_FROWN = LLUUID("fee3df48-fa3d-1015-1e26-a205810e3001"); | ||
87 | const LLUUID ANIM_AGENT_EXPRESS_KISS = LLUUID("1e8d90cc-a84e-e135-884c-7c82c8b03a14"); | ||
88 | const LLUUID ANIM_AGENT_EXPRESS_LAUGH = LLUUID("62570842-0950-96f8-341c-809e65110823"); | ||
89 | const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH = LLUUID("d63bc1f9-fc81-9625-a0c6-007176d82eb7"); | ||
90 | const LLUUID ANIM_AGENT_EXPRESS_REPULSED = LLUUID("f76cda94-41d4-a229-2872-e0296e58afe1"); | ||
91 | const LLUUID ANIM_AGENT_EXPRESS_SAD = LLUUID("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7"); | ||
92 | const LLUUID ANIM_AGENT_EXPRESS_SHRUG = LLUUID("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef"); | ||
93 | const LLUUID ANIM_AGENT_EXPRESS_SMILE = LLUUID("b7c7c833-e3d3-c4e3-9fc0-131237446312"); | ||
94 | const LLUUID ANIM_AGENT_EXPRESS_SURPRISE = LLUUID("728646d9-cc79-08b2-32d6-937f0a835c24"); | ||
95 | const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT = LLUUID("835965c6-7f2f-bda2-5deb-2478737f91bf"); | ||
96 | const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE = LLUUID("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e"); | ||
97 | const LLUUID ANIM_AGENT_EXPRESS_WINK = LLUUID("da020525-4d94-59d6-23d7-81fdebf33148"); | ||
98 | const LLUUID ANIM_AGENT_EXPRESS_WORRY = LLUUID("9c05e5c7-6f07-6ca4-ed5a-b230390c3950"); | ||
99 | const LLUUID ANIM_AGENT_FALLDOWN = LLUUID("666307d9-a860-572d-6fd4-c3ab8865c094"); | ||
100 | const LLUUID ANIM_AGENT_FEMALE_WALK = LLUUID("f5fc7433-043d-e819-8298-f519a119b688"); | ||
101 | const LLUUID ANIM_AGENT_FINGER_WAG = LLUUID("c1bc7f36-3ba0-d844-f93c-93be945d644f"); | ||
102 | const LLUUID ANIM_AGENT_FIST_PUMP = LLUUID("7db00ccd-f380-f3ee-439d-61968ec69c8a"); | ||
103 | const LLUUID ANIM_AGENT_FLY = LLUUID("aec4610c-757f-bc4e-c092-c6e9caf18daf"); | ||
104 | const LLUUID ANIM_AGENT_FLYSLOW = LLUUID("2b5a38b2-5e00-3a97-a495-4c826bc443e6"); | ||
105 | const LLUUID ANIM_AGENT_HELLO = LLUUID("9b29cd61-c45b-5689-ded2-91756b8d76a9"); | ||
106 | const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R = LLUUID("ef62d355-c815-4816-2474-b1acc21094a6"); | ||
107 | const LLUUID ANIM_AGENT_HOLD_BOW_L = LLUUID("8b102617-bcba-037b-86c1-b76219f90c88"); | ||
108 | const LLUUID ANIM_AGENT_HOLD_HANDGUN_R = LLUUID("efdc1727-8b8a-c800-4077-975fc27ee2f2"); | ||
109 | const LLUUID ANIM_AGENT_HOLD_RIFLE_R = LLUUID("3d94bad0-c55b-7dcc-8763-033c59405d33"); | ||
110 | const LLUUID ANIM_AGENT_HOLD_THROW_R = LLUUID("7570c7b5-1f22-56dd-56ef-a9168241bbb6"); | ||
111 | const LLUUID ANIM_AGENT_HOVER = LLUUID("4ae8016b-31b9-03bb-c401-b1ea941db41d"); | ||
112 | const LLUUID ANIM_AGENT_HOVER_DOWN = LLUUID("20f063ea-8306-2562-0b07-5c853b37b31e"); | ||
113 | const LLUUID ANIM_AGENT_HOVER_UP = LLUUID("62c5de58-cb33-5743-3d07-9e4cd4352864"); | ||
114 | const LLUUID ANIM_AGENT_IMPATIENT = LLUUID("5ea3991f-c293-392e-6860-91dfa01278a3"); | ||
115 | const LLUUID ANIM_AGENT_JUMP = LLUUID("2305bd75-1ca9-b03b-1faa-b176b8a8c49e"); | ||
116 | const LLUUID ANIM_AGENT_JUMP_FOR_JOY = LLUUID("709ea28e-1573-c023-8bf8-520c8bc637fa"); | ||
117 | const LLUUID ANIM_AGENT_KISS_MY_BUTT = LLUUID("19999406-3a3a-d58c-a2ac-d72e555dcf51"); | ||
118 | const LLUUID ANIM_AGENT_LAND = LLUUID("7a17b059-12b2-41b1-570a-186368b6aa6f"); | ||
119 | const LLUUID ANIM_AGENT_LAUGH_SHORT = LLUUID("ca5b3f14-3194-7a2b-c894-aa699b718d1f"); | ||
120 | const LLUUID ANIM_AGENT_MEDIUM_LAND = LLUUID("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57"); | ||
121 | const LLUUID ANIM_AGENT_MOTORCYCLE_SIT = LLUUID("08464f78-3a8e-2944-cba5-0c94aff3af29"); | ||
122 | const LLUUID ANIM_AGENT_MUSCLE_BEACH = LLUUID("315c3a41-a5f3-0ba4-27da-f893f769e69b"); | ||
123 | const LLUUID ANIM_AGENT_NO = LLUUID("5a977ed9-7f72-44e9-4c4c-6e913df8ae74"); | ||
124 | const LLUUID ANIM_AGENT_NO_UNHAPPY = LLUUID("d83fa0e5-97ed-7eb2-e798-7bd006215cb4"); | ||
125 | const LLUUID ANIM_AGENT_NYAH_NYAH = LLUUID("f061723d-0a18-754f-66ee-29a44795a32f"); | ||
126 | const LLUUID ANIM_AGENT_ONETWO_PUNCH = LLUUID("eefc79be-daae-a239-8c04-890f5d23654a"); | ||
127 | const LLUUID ANIM_AGENT_PEACE = LLUUID("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9"); | ||
128 | const LLUUID ANIM_AGENT_POINT_ME = LLUUID("17c024cc-eef2-f6a0-3527-9869876d7752"); | ||
129 | const LLUUID ANIM_AGENT_POINT_YOU = LLUUID("ec952cca-61ef-aa3b-2789-4d1344f016de"); | ||
130 | const LLUUID ANIM_AGENT_PRE_JUMP = LLUUID("7a4e87fe-de39-6fcb-6223-024b00893244"); | ||
131 | const LLUUID ANIM_AGENT_PUNCH_LEFT = LLUUID("f3300ad9-3462-1d07-2044-0fef80062da0"); | ||
132 | const LLUUID ANIM_AGENT_PUNCH_RIGHT = LLUUID("c8e42d32-7310-6906-c903-cab5d4a34656"); | ||
133 | const LLUUID ANIM_AGENT_REPULSED = LLUUID("36f81a92-f076-5893-dc4b-7c3795e487cf"); | ||
134 | const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK = LLUUID("49aea43b-5ac3-8a44-b595-96100af0beda"); | ||
135 | const LLUUID ANIM_AGENT_RPS_COUNTDOWN = LLUUID("35db4f7e-28c2-6679-cea9-3ee108f7fc7f"); | ||
136 | const LLUUID ANIM_AGENT_RPS_PAPER = LLUUID("0836b67f-7f7b-f37b-c00a-460dc1521f5a"); | ||
137 | const LLUUID ANIM_AGENT_RPS_ROCK = LLUUID("42dd95d5-0bc6-6392-f650-777304946c0f"); | ||
138 | const LLUUID ANIM_AGENT_RPS_SCISSORS = LLUUID("16803a9f-5140-e042-4d7b-d28ba247c325"); | ||
139 | const LLUUID ANIM_AGENT_RUN = LLUUID("05ddbff8-aaa9-92a1-2b74-8fe77a29b445"); | ||
140 | const LLUUID ANIM_AGENT_SAD = LLUUID("0eb702e2-cc5a-9a88-56a5-661a55c0676a"); | ||
141 | const LLUUID ANIM_AGENT_SALUTE = LLUUID("cd7668a6-7011-d7e2-ead8-fc69eff1a104"); | ||
142 | const LLUUID ANIM_AGENT_SHOOT_BOW_L = LLUUID("e04d450d-fdb5-0432-fd68-818aaf5935f8"); | ||
143 | const LLUUID ANIM_AGENT_SHOUT = LLUUID("6bd01860-4ebd-127a-bb3d-d1427e8e0c42"); | ||
144 | const LLUUID ANIM_AGENT_SHRUG = LLUUID("70ea714f-3a97-d742-1b01-590a8fcd1db5"); | ||
145 | const LLUUID ANIM_AGENT_SIT = LLUUID("1a5fe8ac-a804-8a5d-7cbd-56bd83184568"); | ||
146 | const LLUUID ANIM_AGENT_SIT_FEMALE = LLUUID("b1709c8d-ecd3-54a1-4f28-d55ac0840782"); | ||
147 | const LLUUID ANIM_AGENT_SIT_GENERIC = LLUUID("245f3c54-f1c0-bf2e-811f-46d8eeb386e7"); | ||
148 | const LLUUID ANIM_AGENT_SIT_GROUND = LLUUID("1c7600d6-661f-b87b-efe2-d7421eb93c86"); | ||
149 | const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED = LLUUID("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e"); | ||
150 | const LLUUID ANIM_AGENT_SIT_TO_STAND = LLUUID("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e"); | ||
151 | const LLUUID ANIM_AGENT_SLEEP = LLUUID("f2bed5f9-9d44-39af-b0cd-257b2a17fe40"); | ||
152 | const LLUUID ANIM_AGENT_SMOKE_IDLE = LLUUID("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a"); | ||
153 | const LLUUID ANIM_AGENT_SMOKE_INHALE = LLUUID("6802d553-49da-0778-9f85-1599a2266526"); | ||
154 | const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN = LLUUID("0a9fb970-8b44-9114-d3a9-bf69cfe804d6"); | ||
155 | const LLUUID ANIM_AGENT_SNAPSHOT = LLUUID("eae8905b-271a-99e2-4c0e-31106afd100c"); | ||
156 | const LLUUID ANIM_AGENT_STAND = LLUUID("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f"); | ||
157 | const LLUUID ANIM_AGENT_STANDUP = LLUUID("3da1d753-028a-5446-24f3-9c9b856d9422"); | ||
158 | const LLUUID ANIM_AGENT_STAND_1 = LLUUID("15468e00-3400-bb66-cecc-646d7c14458e"); | ||
159 | const LLUUID ANIM_AGENT_STAND_2 = LLUUID("370f3a20-6ca6-9971-848c-9a01bc42ae3c"); | ||
160 | const LLUUID ANIM_AGENT_STAND_3 = LLUUID("42b46214-4b44-79ae-deb8-0df61424ff4b"); | ||
161 | const LLUUID ANIM_AGENT_STAND_4 = LLUUID("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f"); | ||
162 | const LLUUID ANIM_AGENT_STRETCH = LLUUID("80700431-74ec-a008-14f8-77575e73693f"); | ||
163 | const LLUUID ANIM_AGENT_STRIDE = LLUUID("1cb562b0-ba21-2202-efb3-30f82cdf9595"); | ||
164 | const LLUUID ANIM_AGENT_SURF = LLUUID("41426836-7437-7e89-025d-0aa4d10f1d69"); | ||
165 | const LLUUID ANIM_AGENT_SURPRISE = LLUUID("313b9881-4302-73c0-c7d0-0e7a36b6c224"); | ||
166 | const LLUUID ANIM_AGENT_SWORD_STRIKE = LLUUID("85428680-6bf9-3e64-b489-6f81087c24bd"); | ||
167 | const LLUUID ANIM_AGENT_TALK = LLUUID("5c682a95-6da4-a463-0bf6-0f5b7be129d1"); | ||
168 | const LLUUID ANIM_AGENT_TANTRUM = LLUUID("11000694-3f41-adc2-606b-eee1d66f3724"); | ||
169 | const LLUUID ANIM_AGENT_THROW_R = LLUUID("aa134404-7dac-7aca-2cba-435f9db875ca"); | ||
170 | const LLUUID ANIM_AGENT_TRYON_SHIRT = LLUUID("83ff59fe-2346-f236-9009-4e3608af64c1"); | ||
171 | const LLUUID ANIM_AGENT_TURNLEFT = LLUUID("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135"); | ||
172 | const LLUUID ANIM_AGENT_TURNRIGHT = LLUUID("2d6daa51-3192-6794-8e2e-a15f8338ec30"); | ||
173 | const LLUUID ANIM_AGENT_TYPE = LLUUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9"); | ||
174 | const LLUUID ANIM_AGENT_WALK = LLUUID("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0"); | ||
175 | const LLUUID ANIM_AGENT_WHISPER = LLUUID("7693f268-06c7-ea71-fa21-2b30d6533f8f"); | ||
176 | const LLUUID ANIM_AGENT_WHISTLE = LLUUID("b1ed7982-c68e-a982-7561-52a88a5298c0"); | ||
177 | const LLUUID ANIM_AGENT_WINK = LLUUID("869ecdad-a44b-671e-3266-56aef2e3ac2e"); | ||
178 | const LLUUID ANIM_AGENT_WINK_HOLLYWOOD = LLUUID("c0c4030f-c02b-49de-24ba-2331f43fe41c"); | ||
179 | const LLUUID ANIM_AGENT_WORRY = LLUUID("9f496bd2-589a-709f-16cc-69bf7df1d36c"); | ||
180 | const LLUUID ANIM_AGENT_YES = LLUUID("15dd911d-be82-2856-26db-27659b142875"); | ||
181 | const LLUUID ANIM_AGENT_YES_HAPPY = LLUUID("b8c8b2a3-9008-1771-3bfc-90924955ab2d"); | ||
182 | const LLUUID ANIM_AGENT_YOGA_FLOAT = LLUUID("42ecd00b-9947-a97c-400a-bbc9174c7aeb"); | ||
183 | |||
184 | extern LLUUID AGENT_WALK_ANIMS[]; | ||
185 | extern S32 NUM_AGENT_WALK_ANIMS; | ||
186 | |||
187 | extern LLUUID AGENT_GUN_HOLD_ANIMS[]; | ||
188 | extern S32 NUM_AGENT_GUN_HOLD_ANIMS; | ||
189 | |||
190 | extern LLUUID AGENT_GUN_AIM_ANIMS[]; | ||
191 | extern S32 NUM_AGENT_GUN_AIM_ANIMS; | ||
192 | |||
193 | extern LLUUID AGENT_NO_ROTATE_ANIMS[]; | ||
194 | extern S32 NUM_AGENT_NO_ROTATE_ANIMS; | ||
195 | |||
196 | extern LLUUID AGENT_STAND_ANIMS[]; | ||
197 | extern S32 NUM_AGENT_STAND_ANIMS; | ||
198 | |||
199 | class LLAnimationLibrary | ||
200 | { | ||
201 | private: | ||
202 | LLStringTable mAnimStringTable; | ||
203 | |||
204 | typedef std::map<LLUUID, char *> anim_map_t; | ||
205 | anim_map_t mAnimMap; | ||
206 | |||
207 | public: | ||
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 | |||
224 | struct 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 | ||
238 | extern const LLAnimStateEntry gUserAnimStates[]; | ||
239 | extern const S32 gUserAnimStatesCount; | ||
240 | extern 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 | |||
44 | using namespace std; | ||
45 | |||
46 | #define INCHES_TO_METERS 0.02540005f | ||
47 | |||
48 | const F32 POSITION_KEYFRAME_THRESHOLD = 0.03f; | ||
49 | const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f; | ||
50 | |||
51 | const F32 POSITION_MOTION_THRESHOLD = 0.001f; | ||
52 | const F32 ROTATION_MOTION_THRESHOLD = 0.001f; | ||
53 | |||
54 | char gInFile[1024]; /* Flawfinder: ignore */ | ||
55 | char gOutFile[1024]; /* Flawfinder: ignore */ | ||
56 | |||
57 | //------------------------------------------------------------------------ | ||
58 | // Status Codes | ||
59 | //------------------------------------------------------------------------ | ||
60 | char *LLBVHLoader::ST_OK = "Ok"; | ||
61 | char *LLBVHLoader::ST_EOF = "Premature end of file."; | ||
62 | char *LLBVHLoader::ST_NO_CONSTRAINT = "Can't read constraint definition."; | ||
63 | char *LLBVHLoader::ST_NO_FILE = "Can't open BVH file."; | ||
64 | char *LLBVHLoader::ST_NO_HIER = "Invalid HIERARCHY header."; | ||
65 | char *LLBVHLoader::ST_NO_JOINT = "Can't find ROOT or JOINT."; | ||
66 | char *LLBVHLoader::ST_NO_NAME = "Can't get JOINT name."; | ||
67 | char *LLBVHLoader::ST_NO_OFFSET = "Can't find OFFSET."; | ||
68 | char *LLBVHLoader::ST_NO_CHANNELS = "Can't find CHANNELS."; | ||
69 | char *LLBVHLoader::ST_NO_ROTATION = "Can't get rotation order."; | ||
70 | char *LLBVHLoader::ST_NO_AXIS = "Can't get rotation axis."; | ||
71 | char *LLBVHLoader::ST_NO_MOTION = "Can't find MOTION."; | ||
72 | char *LLBVHLoader::ST_NO_FRAMES = "Can't get number of frames."; | ||
73 | char *LLBVHLoader::ST_NO_FRAME_TIME = "Can't get frame time."; | ||
74 | char *LLBVHLoader::ST_NO_POS = "Can't get position values."; | ||
75 | char *LLBVHLoader::ST_NO_ROT = "Can't get rotation values."; | ||
76 | char *LLBVHLoader::ST_NO_XLT_FILE = "Can't open translation file."; | ||
77 | char *LLBVHLoader::ST_NO_XLT_HEADER = "Can't read translation header."; | ||
78 | char *LLBVHLoader::ST_NO_XLT_NAME = "Can't read translation names."; | ||
79 | char *LLBVHLoader::ST_NO_XLT_IGNORE = "Can't read translation ignore value."; | ||
80 | char *LLBVHLoader::ST_NO_XLT_RELATIVE = "Can't read translation relative value."; | ||
81 | char *LLBVHLoader::ST_NO_XLT_OUTNAME = "Can't read translation outname value."; | ||
82 | char *LLBVHLoader::ST_NO_XLT_MATRIX = "Can't read translation matrix."; | ||
83 | char *LLBVHLoader::ST_NO_XLT_MERGECHILD = "Can't get mergechild name."; | ||
84 | char *LLBVHLoader::ST_NO_XLT_MERGEPARENT = "Can't get mergeparent name."; | ||
85 | char *LLBVHLoader::ST_NO_XLT_PRIORITY = "Can't get priority value."; | ||
86 | char *LLBVHLoader::ST_NO_XLT_LOOP = "Can't get loop value."; | ||
87 | char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values."; | ||
88 | char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values."; | ||
89 | char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value."; | ||
90 | char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name."; | ||
91 | |||
92 | //------------------------------------------------------------------------ | ||
93 | // find_next_whitespace() | ||
94 | //------------------------------------------------------------------------ | ||
95 | const 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 | //------------------------------------------------------------------------ | ||
110 | LLQuaternion::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 | //----------------------------------------------------------------------------- | ||
124 | LLBVHLoader::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 | |||
159 | LLBVHLoader::~LLBVHLoader() | ||
160 | { | ||
161 | std::for_each(mJoints.begin(),mJoints.end(),DeletePointer()); | ||
162 | } | ||
163 | |||
164 | //------------------------------------------------------------------------ | ||
165 | // LLBVHLoader::loadTranslationTable() | ||
166 | //------------------------------------------------------------------------ | ||
167 | LLBVHLoader::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 | //------------------------------------------------------------------------ | ||
629 | LLBVHLoader::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 | //------------------------------------------------------------------------ | ||
970 | void 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 | //----------------------------------------------------------------------------- | ||
1079 | void 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 | |||
1238 | void 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 | //------------------------------------------------------------------------ | ||
1260 | BOOL 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 | ||
1276 | U32 LLBVHLoader::getOutputSize() | ||
1277 | { | ||
1278 | LLDataPackerBinaryBuffer dp; | ||
1279 | serialize(dp); | ||
1280 | |||
1281 | return dp.getCurrentSize(); | ||
1282 | } | ||
1283 | |||
1284 | // writes contents to datapacker | ||
1285 | BOOL 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 | |||
41 | const S32 BVH_PARSER_LINE_SIZE = 2048; | ||
42 | const F32 MAX_ANIM_DURATION = 30.f; | ||
43 | class LLDataPacker; | ||
44 | |||
45 | //------------------------------------------------------------------------ | ||
46 | // FileCloser | ||
47 | //------------------------------------------------------------------------ | ||
48 | class FileCloser | ||
49 | { | ||
50 | public: | ||
51 | FileCloser( apr_file_t *file ) | ||
52 | { | ||
53 | mFile = file; | ||
54 | } | ||
55 | |||
56 | ~FileCloser() | ||
57 | { | ||
58 | apr_file_close(mFile); | ||
59 | } | ||
60 | protected: | ||
61 | apr_file_t* mFile; | ||
62 | }; | ||
63 | |||
64 | |||
65 | //------------------------------------------------------------------------ | ||
66 | // Key | ||
67 | //------------------------------------------------------------------------ | ||
68 | struct 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 | //------------------------------------------------------------------------ | ||
88 | typedef std::vector<Key> KeyVector; | ||
89 | |||
90 | //------------------------------------------------------------------------ | ||
91 | // Joint | ||
92 | //------------------------------------------------------------------------ | ||
93 | struct 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 | |||
135 | typedef enum e_constraint_type | ||
136 | { | ||
137 | CONSTRAINT_TYPE_POINT, | ||
138 | CONSTRAINT_TYPE_PLANE | ||
139 | } EConstraintType; | ||
140 | |||
141 | struct 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 | //------------------------------------------------------------------------ | ||
159 | typedef std::vector<Joint*> JointVector; | ||
160 | |||
161 | //------------------------------------------------------------------------ | ||
162 | // ConstraintVector | ||
163 | //------------------------------------------------------------------------ | ||
164 | typedef std::vector<Constraint> ConstraintVector; | ||
165 | |||
166 | //------------------------------------------------------------------------ | ||
167 | // Translation | ||
168 | //------------------------------------------------------------------------ | ||
169 | class Translation | ||
170 | { | ||
171 | public: | ||
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 | //------------------------------------------------------------------------ | ||
196 | typedef std::map<std::string, Translation> TranslationMap; | ||
197 | |||
198 | class LLBVHLoader | ||
199 | { | ||
200 | friend class LLKeyframeMotion; | ||
201 | public: | ||
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 | |||
271 | protected: | ||
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 | |||
39 | LLStringTable LLCharacter::sVisualParamNames(1024); | ||
40 | |||
41 | // helper functions | ||
42 | BOOL larger_screen_area( LLCharacter* data_new, LLCharacter* data_tested ) | ||
43 | { | ||
44 | return data_new->getPixelArea() > data_tested->getPixelArea(); | ||
45 | } | ||
46 | |||
47 | LLLinkedList< LLCharacter > LLCharacter::sInstances( larger_screen_area ); | ||
48 | |||
49 | |||
50 | //----------------------------------------------------------------------------- | ||
51 | // LLCharacter() | ||
52 | // Class Constructor | ||
53 | //----------------------------------------------------------------------------- | ||
54 | LLCharacter::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 | //----------------------------------------------------------------------------- | ||
71 | LLCharacter::~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 | //----------------------------------------------------------------------------- | ||
86 | LLJoint *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 | //----------------------------------------------------------------------------- | ||
106 | BOOL LLCharacter::addMotion( const LLUUID& id, LLMotionConstructor create ) | ||
107 | { | ||
108 | return mMotionController.addMotion(id, create); | ||
109 | } | ||
110 | |||
111 | //----------------------------------------------------------------------------- | ||
112 | // removeMotion() | ||
113 | //----------------------------------------------------------------------------- | ||
114 | void LLCharacter::removeMotion( const LLUUID& id ) | ||
115 | { | ||
116 | mMotionController.removeMotion(id); | ||
117 | } | ||
118 | |||
119 | //----------------------------------------------------------------------------- | ||
120 | // getMotion() | ||
121 | //----------------------------------------------------------------------------- | ||
122 | LLMotion* LLCharacter::createMotion( const LLUUID &id ) | ||
123 | { | ||
124 | return mMotionController.createMotion( id ); | ||
125 | } | ||
126 | |||
127 | //----------------------------------------------------------------------------- | ||
128 | // startMotion() | ||
129 | //----------------------------------------------------------------------------- | ||
130 | BOOL LLCharacter::startMotion(const LLUUID &id, F32 start_offset) | ||
131 | { | ||
132 | return mMotionController.startMotion(id, start_offset); | ||
133 | } | ||
134 | |||
135 | |||
136 | //----------------------------------------------------------------------------- | ||
137 | // stopMotion() | ||
138 | //----------------------------------------------------------------------------- | ||
139 | BOOL LLCharacter::stopMotion(const LLUUID& id, BOOL stop_immediate) | ||
140 | { | ||
141 | return mMotionController.stopMotionLocally(id, stop_immediate); | ||
142 | } | ||
143 | |||
144 | //----------------------------------------------------------------------------- | ||
145 | // isMotionActive() | ||
146 | //----------------------------------------------------------------------------- | ||
147 | BOOL 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 | //----------------------------------------------------------------------------- | ||
162 | void LLCharacter::requestStopMotion( LLMotion* motion) | ||
163 | { | ||
164 | // llinfos << "DEBUG: Char::onDeactivateMotion( " << motionName << " )" << llendl; | ||
165 | } | ||
166 | |||
167 | |||
168 | //----------------------------------------------------------------------------- | ||
169 | // updateMotion() | ||
170 | //----------------------------------------------------------------------------- | ||
171 | void 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 | //----------------------------------------------------------------------------- | ||
196 | void LLCharacter::flushAllMotions() | ||
197 | { | ||
198 | mMotionController.flushAllMotions(); | ||
199 | } | ||
200 | |||
201 | |||
202 | //----------------------------------------------------------------------------- | ||
203 | // dumpCharacter() | ||
204 | //----------------------------------------------------------------------------- | ||
205 | void 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 | //----------------------------------------------------------------------------- | ||
231 | void 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 | //----------------------------------------------------------------------------- | ||
246 | void * 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 | //----------------------------------------------------------------------------- | ||
265 | void LLCharacter::removeAnimationData(std::string name) | ||
266 | { | ||
267 | mAnimationData.remove(name); | ||
268 | } | ||
269 | |||
270 | //----------------------------------------------------------------------------- | ||
271 | // setVisualParamWeight() | ||
272 | //----------------------------------------------------------------------------- | ||
273 | BOOL 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 | //----------------------------------------------------------------------------- | ||
288 | BOOL 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 | //----------------------------------------------------------------------------- | ||
306 | BOOL 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 | //----------------------------------------------------------------------------- | ||
321 | F32 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 | //----------------------------------------------------------------------------- | ||
339 | F32 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 | //----------------------------------------------------------------------------- | ||
356 | F32 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 | //----------------------------------------------------------------------------- | ||
373 | void 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 | //----------------------------------------------------------------------------- | ||
389 | LLVisualParam* 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 | //----------------------------------------------------------------------------- | ||
406 | void 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 | //----------------------------------------------------------------------------- | ||
432 | void 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 | //----------------------------------------------------------------------------- | ||
467 | void 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 | |||
486 | LLAnimPauseRequest 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 | |||
44 | class LLPolyMesh; | ||
45 | |||
46 | class LLPauseRequestHandle : public LLThreadSafeRefCount | ||
47 | { | ||
48 | public: | ||
49 | LLPauseRequestHandle() {}; | ||
50 | }; | ||
51 | |||
52 | typedef LLPointer<LLPauseRequestHandle> LLAnimPauseRequest; | ||
53 | |||
54 | //----------------------------------------------------------------------------- | ||
55 | // class LLCharacter | ||
56 | //----------------------------------------------------------------------------- | ||
57 | class LLCharacter | ||
58 | { | ||
59 | public: | ||
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 | |||
247 | protected: | ||
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 | |||
259 | private: | ||
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 | //----------------------------------------------------------------------------- | ||
41 | const LLQuaternion EDIT_MOTION_WRIST_ROTATION(F_PI_BY_TWO * 0.7f, LLVector3(1.0f, 0.0f, 0.0f)); | ||
42 | const F32 TARGET_LAG_HALF_LIFE = 0.1f; // half-life of IK targeting | ||
43 | const F32 TORSO_LAG_HALF_LIFE = 0.2f; | ||
44 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
45 | |||
46 | S32 LLEditingMotion::sHandPose = LLHandMotion::HAND_POSE_RELAXED_R; | ||
47 | S32 LLEditingMotion::sHandPosePriority = 3; | ||
48 | |||
49 | //----------------------------------------------------------------------------- | ||
50 | // LLEditingMotion() | ||
51 | // Class Constructor | ||
52 | //----------------------------------------------------------------------------- | ||
53 | LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id) | ||
54 | { | ||
55 | mCharacter = NULL; | ||
56 | |||
57 | // create kinematic chain | ||
58 | mParentJoint.addChild( &mShoulderJoint ); | ||
59 | mShoulderJoint.addChild( &mElbowJoint ); | ||
60 | mElbowJoint.addChild( &mWristJoint ); | ||
61 | |||
62 | mName = "editing"; | ||
63 | } | ||
64 | |||
65 | |||
66 | //----------------------------------------------------------------------------- | ||
67 | // ~LLEditingMotion() | ||
68 | // Class Destructor | ||
69 | //----------------------------------------------------------------------------- | ||
70 | LLEditingMotion::~LLEditingMotion() | ||
71 | { | ||
72 | } | ||
73 | |||
74 | //----------------------------------------------------------------------------- | ||
75 | // LLEditingMotion::onInitialize(LLCharacter *character) | ||
76 | //----------------------------------------------------------------------------- | ||
77 | LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *character) | ||
78 | { | ||
79 | // save character for future use | ||
80 | mCharacter = character; | ||
81 | |||
82 | // make sure character skeleton is copacetic | ||
83 | if (!mCharacter->getJoint("mShoulderLeft") || | ||
84 | !mCharacter->getJoint("mElbowLeft") || | ||
85 | !mCharacter->getJoint("mWristLeft")) | ||
86 | { | ||
87 | llwarns << "Invalid skeleton for editing motion!" << llendl; | ||
88 | return STATUS_FAILURE; | ||
89 | } | ||
90 | |||
91 | // get the shoulder, elbow, wrist joints from the character | ||
92 | mParentState.setJoint( mCharacter->getJoint("mShoulderLeft")->getParent() ); | ||
93 | mShoulderState.setJoint( mCharacter->getJoint("mShoulderLeft") ); | ||
94 | mElbowState.setJoint( mCharacter->getJoint("mElbowLeft") ); | ||
95 | mWristState.setJoint( mCharacter->getJoint("mWristLeft") ); | ||
96 | mTorsoState.setJoint( mCharacter->getJoint("mTorso")); | ||
97 | |||
98 | if ( ! mParentState.getJoint() ) | ||
99 | { | ||
100 | llinfos << getName() << ": Can't get parent joint." << llendl; | ||
101 | return STATUS_FAILURE; | ||
102 | } | ||
103 | |||
104 | mWristOffset = LLVector3(0.0f, 0.2f, 0.0f); | ||
105 | |||
106 | // add joint states to the pose | ||
107 | mShoulderState.setUsage(LLJointState::ROT); | ||
108 | mElbowState.setUsage(LLJointState::ROT); | ||
109 | mTorsoState.setUsage(LLJointState::ROT); | ||
110 | mWristState.setUsage(LLJointState::ROT); | ||
111 | addJointState( &mShoulderState ); | ||
112 | addJointState( &mElbowState ); | ||
113 | addJointState( &mTorsoState ); | ||
114 | addJointState( &mWristState ); | ||
115 | |||
116 | // propagate joint positions to kinematic chain | ||
117 | mParentJoint.setPosition( mParentState.getJoint()->getWorldPosition() ); | ||
118 | mShoulderJoint.setPosition( mShoulderState.getJoint()->getPosition() ); | ||
119 | mElbowJoint.setPosition( mElbowState.getJoint()->getPosition() ); | ||
120 | mWristJoint.setPosition( mWristState.getJoint()->getPosition() + mWristOffset ); | ||
121 | |||
122 | // propagate current joint rotations to kinematic chain | ||
123 | mParentJoint.setRotation( mParentState.getJoint()->getWorldRotation() ); | ||
124 | mShoulderJoint.setRotation( mShoulderState.getJoint()->getRotation() ); | ||
125 | mElbowJoint.setRotation( mElbowState.getJoint()->getRotation() ); | ||
126 | |||
127 | // connect the ikSolver to the chain | ||
128 | mIKSolver.setPoleVector( LLVector3( -1.0f, 1.0f, 0.0f ) ); | ||
129 | // specifying the elbow's axis will prevent bad IK for the more | ||
130 | // singular configurations, but the axis is limb-specific -- Leviathan | ||
131 | mIKSolver.setBAxis( LLVector3( -0.682683f, 0.0f, -0.730714f ) ); | ||
132 | mIKSolver.setupJoints( &mShoulderJoint, &mElbowJoint, &mWristJoint, &mTarget ); | ||
133 | |||
134 | return STATUS_SUCCESS; | ||
135 | } | ||
136 | |||
137 | //----------------------------------------------------------------------------- | ||
138 | // LLEditingMotion::onActivate() | ||
139 | //----------------------------------------------------------------------------- | ||
140 | BOOL LLEditingMotion::onActivate() | ||
141 | { | ||
142 | // propagate joint positions to kinematic chain | ||
143 | mParentJoint.setPosition( mParentState.getJoint()->getWorldPosition() ); | ||
144 | mShoulderJoint.setPosition( mShoulderState.getJoint()->getPosition() ); | ||
145 | mElbowJoint.setPosition( mElbowState.getJoint()->getPosition() ); | ||
146 | mWristJoint.setPosition( mWristState.getJoint()->getPosition() + mWristOffset ); | ||
147 | |||
148 | // propagate current joint rotations to kinematic chain | ||
149 | mParentJoint.setRotation( mParentState.getJoint()->getWorldRotation() ); | ||
150 | mShoulderJoint.setRotation( mShoulderState.getJoint()->getRotation() ); | ||
151 | mElbowJoint.setRotation( mElbowState.getJoint()->getRotation() ); | ||
152 | |||
153 | return TRUE; | ||
154 | } | ||
155 | |||
156 | //----------------------------------------------------------------------------- | ||
157 | // LLEditingMotion::onUpdate() | ||
158 | //----------------------------------------------------------------------------- | ||
159 | BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) | ||
160 | { | ||
161 | LLVector3 focus_pt; | ||
162 | LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint"); | ||
163 | |||
164 | |||
165 | BOOL result = TRUE; | ||
166 | |||
167 | if (!pointAtPt) | ||
168 | { | ||
169 | focus_pt = mLastSelectPt; | ||
170 | result = FALSE; | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | focus_pt = *pointAtPt; | ||
175 | mLastSelectPt = focus_pt; | ||
176 | } | ||
177 | |||
178 | focus_pt += mCharacter->getCharacterPosition(); | ||
179 | |||
180 | // propagate joint positions to kinematic chain | ||
181 | mParentJoint.setPosition( mParentState.getJoint()->getWorldPosition() ); | ||
182 | mShoulderJoint.setPosition( mShoulderState.getJoint()->getPosition() ); | ||
183 | mElbowJoint.setPosition( mElbowState.getJoint()->getPosition() ); | ||
184 | mWristJoint.setPosition( mWristState.getJoint()->getPosition() + mWristOffset ); | ||
185 | |||
186 | // propagate current joint rotations to kinematic chain | ||
187 | mParentJoint.setRotation( mParentState.getJoint()->getWorldRotation() ); | ||
188 | mShoulderJoint.setRotation( mShoulderState.getJoint()->getRotation() ); | ||
189 | mElbowJoint.setRotation( mElbowState.getJoint()->getRotation() ); | ||
190 | |||
191 | // update target position from character | ||
192 | LLVector3 target = focus_pt - mParentJoint.getPosition(); | ||
193 | F32 target_dist = target.normVec(); | ||
194 | |||
195 | LLVector3 edit_plane_normal(1.f / F_SQRT2, 1.f / F_SQRT2, 0.f); | ||
196 | edit_plane_normal.normVec(); | ||
197 | |||
198 | edit_plane_normal.rotVec(mTorsoState.getJoint()->getWorldRotation()); | ||
199 | |||
200 | F32 dot = edit_plane_normal * target; | ||
201 | |||
202 | if (dot < 0.f) | ||
203 | { | ||
204 | target = target + (edit_plane_normal * (dot * 2.f)); | ||
205 | target.mV[VZ] += clamp_rescale(dot, 0.f, -1.f, 0.f, 5.f); | ||
206 | target.normVec(); | ||
207 | } | ||
208 | |||
209 | target = target * target_dist; | ||
210 | if (!target.isFinite()) | ||
211 | { | ||
212 | llerrs << "Non finite target in editing motion with target distance of " << target_dist << | ||
213 | " and focus point " << focus_pt << llendl; | ||
214 | } | ||
215 | |||
216 | mTarget.setPosition( target + mParentJoint.getPosition()); | ||
217 | |||
218 | // llinfos << "Point At: " << mTarget.getPosition() << llendl; | ||
219 | |||
220 | // update the ikSolver | ||
221 | if (!mTarget.getPosition().isExactlyZero()) | ||
222 | { | ||
223 | LLQuaternion shoulderRot = mShoulderJoint.getRotation(); | ||
224 | LLQuaternion elbowRot = mElbowJoint.getRotation(); | ||
225 | mIKSolver.solve(); | ||
226 | |||
227 | // use blending... | ||
228 | F32 slerp_amt = LLCriticalDamp::getInterpolant(TARGET_LAG_HALF_LIFE); | ||
229 | shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot); | ||
230 | elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot); | ||
231 | |||
232 | // now put blended values back into joints | ||
233 | llassert(shoulderRot.isFinite()); | ||
234 | llassert(elbowRot.isFinite()); | ||
235 | mShoulderState.setRotation(shoulderRot); | ||
236 | mElbowState.setRotation(elbowRot); | ||
237 | mWristState.setRotation(LLQuaternion::DEFAULT); | ||
238 | } | ||
239 | |||
240 | mCharacter->setAnimationData("Hand Pose", &sHandPose); | ||
241 | mCharacter->setAnimationData("Hand Pose Priority", &sHandPosePriority); | ||
242 | return result; | ||
243 | } | ||
244 | |||
245 | //----------------------------------------------------------------------------- | ||
246 | // LLEditingMotion::onDeactivate() | ||
247 | //----------------------------------------------------------------------------- | ||
248 | void LLEditingMotion::onDeactivate() | ||
249 | { | ||
250 | } | ||
251 | |||
252 | |||
253 | // End | ||
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 | //----------------------------------------------------------------------------- | ||
46 | class LLEditingMotion : | ||
47 | public LLMotion | ||
48 | { | ||
49 | public: | ||
50 | // Constructor | ||
51 | LLEditingMotion(const LLUUID &id); | ||
52 | |||
53 | // Destructor | ||
54 | virtual ~LLEditingMotion(); | ||
55 | |||
56 | public: | ||
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 | |||
65 | public: | ||
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 | |||
108 | public: | ||
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 | ||
37 | const S32 LLGestureList::SERIAL_HEADER_SIZE = sizeof(S32); | ||
38 | const S32 LLGesture::MAX_SERIAL_SIZE = sizeof(KEY) + sizeof(MASK) + 16 + 26 + 41 + 41; | ||
39 | |||
40 | LLGesture::LLGesture() | ||
41 | : mKey(KEY_NONE), | ||
42 | mMask(MASK_NONE), | ||
43 | mTrigger(), | ||
44 | mTriggerLower(), | ||
45 | mSoundItemID(), | ||
46 | mAnimation(), | ||
47 | mOutputString() | ||
48 | { } | ||
49 | |||
50 | LLGesture::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 | |||
66 | LLGesture::LLGesture(U8 **buffer, S32 max_size) | ||
67 | { | ||
68 | *buffer = deserialize(*buffer, max_size); | ||
69 | } | ||
70 | |||
71 | LLGesture::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 | |||
82 | const 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 | |||
95 | BOOL 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 | |||
102 | BOOL 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 | ||
109 | U8 *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 | |||
128 | U8 *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 | |||
166 | S32 LLGesture::getMaxSerialSize() | ||
167 | { | ||
168 | return MAX_SERIAL_SIZE; | ||
169 | } | ||
170 | |||
171 | //--------------------------------------------------------------------- | ||
172 | // LLGestureList | ||
173 | //--------------------------------------------------------------------- | ||
174 | |||
175 | LLGestureList::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 | |||
199 | LLGestureList::~LLGestureList() | ||
200 | { | ||
201 | deleteAll(); | ||
202 | } | ||
203 | |||
204 | |||
205 | void 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. | ||
218 | BOOL 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 | |||
288 | BOOL 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 | ||
309 | U8 *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 | |||
324 | const S32 MAX_GESTURES = 4096; | ||
325 | |||
326 | U8 *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 | ||
367 | LLGesture *LLGestureList::create_gesture(U8 **buffer, S32 max_size) | ||
368 | { | ||
369 | return new LLGesture(buffer, max_size); | ||
370 | } | ||
371 | |||
372 | S32 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 | |||
37 | class LLGesture | ||
38 | { | ||
39 | public: | ||
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 | |||
70 | protected: | ||
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 | |||
82 | class LLGestureList | ||
83 | { | ||
84 | public: | ||
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 | |||
105 | protected: | ||
106 | // overridden by child class to use local LLGesture implementation | ||
107 | virtual LLGesture *create_gesture(U8 **buffer, S32 max_size); | ||
108 | |||
109 | protected: | ||
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 | |||
41 | const 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 | |||
59 | const F32 HAND_MORPH_BLEND_TIME = 0.2f; | ||
60 | |||
61 | //----------------------------------------------------------------------------- | ||
62 | // LLHandMotion() | ||
63 | // Class Constructor | ||
64 | //----------------------------------------------------------------------------- | ||
65 | LLHandMotion::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 | //----------------------------------------------------------------------------- | ||
84 | LLHandMotion::~LLHandMotion() | ||
85 | { | ||
86 | } | ||
87 | |||
88 | //----------------------------------------------------------------------------- | ||
89 | // LLHandMotion::onInitialize(LLCharacter *character) | ||
90 | //----------------------------------------------------------------------------- | ||
91 | LLMotion::LLMotionInitStatus LLHandMotion::onInitialize(LLCharacter *character) | ||
92 | { | ||
93 | mCharacter = character; | ||
94 | |||
95 | return STATUS_SUCCESS; | ||
96 | } | ||
97 | |||
98 | |||
99 | //----------------------------------------------------------------------------- | ||
100 | // LLHandMotion::onActivate() | ||
101 | //----------------------------------------------------------------------------- | ||
102 | BOOL 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 | //----------------------------------------------------------------------------- | ||
123 | BOOL 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 | //----------------------------------------------------------------------------- | ||
193 | void LLHandMotion::onDeactivate() | ||
194 | { | ||
195 | } | ||
196 | |||
197 | //----------------------------------------------------------------------------- | ||
198 | // LLHandMotion::getHandPoseName() | ||
199 | //----------------------------------------------------------------------------- | ||
200 | LLString 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 | |||
209 | LLHandMotion::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 | //----------------------------------------------------------------------------- | ||
42 | class LLHandMotion : | ||
43 | public LLMotion | ||
44 | { | ||
45 | public: | ||
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 | |||
71 | public: | ||
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 | |||
80 | public: | ||
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 | |||
126 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
43 | const F32 TORSO_LAG = 0.35f; // torso rotation factor | ||
44 | const F32 NECK_LAG = 0.5f; // neck rotation factor | ||
45 | const F32 HEAD_LOOKAT_LAG_HALF_LIFE = 0.15f; // half-life of lookat targeting for head | ||
46 | const F32 TORSO_LOOKAT_LAG_HALF_LIFE = 0.27f; // half-life of lookat targeting for torso | ||
47 | const F32 EYE_LOOKAT_LAG_HALF_LIFE = 0.06f; // half-life of lookat targeting for eye | ||
48 | const F32 HEAD_ROTATION_CONSTRAINT = F_PI_BY_TWO * 0.8f; // limit angle for head rotation | ||
49 | |||
50 | const F32 MIN_HEAD_LOOKAT_DISTANCE = 0.3f; // minimum distance from head before we turn to look at it | ||
51 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
52 | const F32 EYE_JITTER_MIN_TIME = 0.3f; // min amount of time between eye "jitter" motions | ||
53 | const F32 EYE_JITTER_MAX_TIME = 2.5f; // max amount of time between eye "jitter" motions | ||
54 | const F32 EYE_JITTER_MAX_YAW = 0.08f; // max yaw of eye jitter motion | ||
55 | const F32 EYE_JITTER_MAX_PITCH = 0.015f; // max pitch of eye jitter motion | ||
56 | const F32 EYE_LOOK_AWAY_MIN_TIME = 5.f; // min amount of time between eye "look away" motions | ||
57 | const F32 EYE_LOOK_AWAY_MAX_TIME = 15.f; // max amount of time between eye "look away" motions | ||
58 | const F32 EYE_LOOK_BACK_MIN_TIME = 1.f; // min amount of time before looking back after looking away | ||
59 | const F32 EYE_LOOK_BACK_MAX_TIME = 5.f; // max amount of time before looking back after looking away | ||
60 | const F32 EYE_LOOK_AWAY_MAX_YAW = 0.15f; // max yaw of eye look away motion | ||
61 | const F32 EYE_LOOK_AWAY_MAX_PITCH = 0.12f; // max pitch of look away motion | ||
62 | const F32 EYE_ROT_LIMIT_ANGLE = F_PI_BY_TWO * 0.3f; //max angle in radians for eye rotation | ||
63 | |||
64 | const F32 EYE_BLINK_MIN_TIME = 0.5f; // minimum amount of time between blinks | ||
65 | const F32 EYE_BLINK_MAX_TIME = 8.f; // maximum amount of time between blinks | ||
66 | const F32 EYE_BLINK_CLOSE_TIME = 0.03f; // how long the eye stays closed in a blink | ||
67 | const F32 EYE_BLINK_SPEED = 0.015f; // seconds it takes for a eye open/close movement | ||
68 | const 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 | //----------------------------------------------------------------------------- | ||
74 | LLHeadRotMotion::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 | //----------------------------------------------------------------------------- | ||
88 | LLHeadRotMotion::~LLHeadRotMotion() | ||
89 | { | ||
90 | } | ||
91 | |||
92 | //----------------------------------------------------------------------------- | ||
93 | // LLHeadRotMotion::onInitialize(LLCharacter *character) | ||
94 | //----------------------------------------------------------------------------- | ||
95 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
167 | BOOL LLHeadRotMotion::onActivate() | ||
168 | { | ||
169 | return TRUE; | ||
170 | } | ||
171 | |||
172 | |||
173 | //----------------------------------------------------------------------------- | ||
174 | // LLHeadRotMotion::onUpdate() | ||
175 | //----------------------------------------------------------------------------- | ||
176 | BOOL 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 | //----------------------------------------------------------------------------- | ||
257 | void LLHeadRotMotion::onDeactivate() | ||
258 | { | ||
259 | } | ||
260 | |||
261 | |||
262 | //----------------------------------------------------------------------------- | ||
263 | // LLEyeMotion() | ||
264 | // Class Constructor | ||
265 | //----------------------------------------------------------------------------- | ||
266 | LLEyeMotion::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 | //----------------------------------------------------------------------------- | ||
290 | LLEyeMotion::~LLEyeMotion() | ||
291 | { | ||
292 | } | ||
293 | |||
294 | //----------------------------------------------------------------------------- | ||
295 | // LLEyeMotion::onInitialize(LLCharacter *character) | ||
296 | //----------------------------------------------------------------------------- | ||
297 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
335 | BOOL LLEyeMotion::onActivate() | ||
336 | { | ||
337 | return TRUE; | ||
338 | } | ||
339 | |||
340 | |||
341 | //----------------------------------------------------------------------------- | ||
342 | // LLEyeMotion::onUpdate() | ||
343 | //----------------------------------------------------------------------------- | ||
344 | BOOL 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 | //----------------------------------------------------------------------------- | ||
509 | void 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 | //----------------------------------------------------------------------------- | ||
43 | class LLHeadRotMotion : | ||
44 | public LLMotion | ||
45 | { | ||
46 | public: | ||
47 | // Constructor | ||
48 | LLHeadRotMotion(const LLUUID &id); | ||
49 | |||
50 | // Destructor | ||
51 | virtual ~LLHeadRotMotion(); | ||
52 | |||
53 | public: | ||
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 | |||
62 | public: | ||
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 | |||
105 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
126 | class LLEyeMotion : | ||
127 | public LLMotion | ||
128 | { | ||
129 | public: | ||
130 | // Constructor | ||
131 | LLEyeMotion(const LLUUID &id); | ||
132 | |||
133 | // Destructor | ||
134 | virtual ~LLEyeMotion(); | ||
135 | |||
136 | public: | ||
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 | |||
145 | public: | ||
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 | |||
188 | public: | ||
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 | |||
37 | S32 LLJoint::sNumUpdates = 0; | ||
38 | S32 LLJoint::sNumTouches = 0; | ||
39 | |||
40 | //----------------------------------------------------------------------------- | ||
41 | // LLJoint() | ||
42 | // Class Constructor | ||
43 | //----------------------------------------------------------------------------- | ||
44 | LLJoint::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 | //----------------------------------------------------------------------------- | ||
61 | LLJoint::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 | //----------------------------------------------------------------------------- | ||
81 | LLJoint::~LLJoint() | ||
82 | { | ||
83 | removeAllChildren(); | ||
84 | } | ||
85 | |||
86 | |||
87 | //----------------------------------------------------------------------------- | ||
88 | // setup() | ||
89 | //----------------------------------------------------------------------------- | ||
90 | void 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 | //----------------------------------------------------------------------------- | ||
101 | void 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 | //----------------------------------------------------------------------------- | ||
125 | LLJoint *LLJoint::getRoot() | ||
126 | { | ||
127 | if ( getParent() == NULL ) | ||
128 | { | ||
129 | return this; | ||
130 | } | ||
131 | return getParent()->getRoot(); | ||
132 | } | ||
133 | |||
134 | |||
135 | //----------------------------------------------------------------------------- | ||
136 | // findJoint() | ||
137 | //----------------------------------------------------------------------------- | ||
138 | LLJoint *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 | //-------------------------------------------------------------------- | ||
159 | void 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 | //-------------------------------------------------------------------- | ||
174 | void 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 | //-------------------------------------------------------------------- | ||
186 | void 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 | //-------------------------------------------------------------------- | ||
200 | const LLVector3& LLJoint::getPosition() | ||
201 | { | ||
202 | return mXform.getPosition(); | ||
203 | } | ||
204 | |||
205 | |||
206 | //-------------------------------------------------------------------- | ||
207 | // setPosition() | ||
208 | //-------------------------------------------------------------------- | ||
209 | void LLJoint::setPosition( const LLVector3& pos ) | ||
210 | { | ||
211 | mXform.setPosition(pos); | ||
212 | touch(MATRIX_DIRTY | POSITION_DIRTY); | ||
213 | } | ||
214 | |||
215 | |||
216 | //-------------------------------------------------------------------- | ||
217 | // getWorldPosition() | ||
218 | //-------------------------------------------------------------------- | ||
219 | LLVector3 LLJoint::getWorldPosition() | ||
220 | { | ||
221 | updateWorldPRSParent(); | ||
222 | return mXform.getWorldPosition(); | ||
223 | } | ||
224 | |||
225 | //----------------------------------------------------------------------------- | ||
226 | // getLastWorldPosition() | ||
227 | //----------------------------------------------------------------------------- | ||
228 | LLVector3 LLJoint::getLastWorldPosition() | ||
229 | { | ||
230 | return mXform.getWorldPosition(); | ||
231 | } | ||
232 | |||
233 | |||
234 | //-------------------------------------------------------------------- | ||
235 | // setWorldPosition() | ||
236 | //-------------------------------------------------------------------- | ||
237 | void 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 | //-------------------------------------------------------------------- | ||
266 | const LLQuaternion& LLJoint::getRotation() | ||
267 | { | ||
268 | return mXform.getRotation(); | ||
269 | } | ||
270 | |||
271 | |||
272 | //-------------------------------------------------------------------- | ||
273 | // setRotation() | ||
274 | //-------------------------------------------------------------------- | ||
275 | void 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 | //-------------------------------------------------------------------- | ||
288 | LLQuaternion LLJoint::getWorldRotation() | ||
289 | { | ||
290 | updateWorldPRSParent(); | ||
291 | |||
292 | return mXform.getWorldRotation(); | ||
293 | } | ||
294 | |||
295 | //----------------------------------------------------------------------------- | ||
296 | // getLastWorldRotation() | ||
297 | //----------------------------------------------------------------------------- | ||
298 | LLQuaternion LLJoint::getLastWorldRotation() | ||
299 | { | ||
300 | return mXform.getWorldRotation(); | ||
301 | } | ||
302 | |||
303 | //-------------------------------------------------------------------- | ||
304 | // setWorldRotation() | ||
305 | //-------------------------------------------------------------------- | ||
306 | void 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 | //-------------------------------------------------------------------- | ||
332 | const LLVector3& LLJoint::getScale() | ||
333 | { | ||
334 | return mXform.getScale(); | ||
335 | } | ||
336 | |||
337 | //-------------------------------------------------------------------- | ||
338 | // setScale() | ||
339 | //-------------------------------------------------------------------- | ||
340 | void LLJoint::setScale( const LLVector3& scale ) | ||
341 | { | ||
342 | mXform.setScale(scale); | ||
343 | touch(); | ||
344 | } | ||
345 | |||
346 | |||
347 | |||
348 | //-------------------------------------------------------------------- | ||
349 | // getWorldMatrix() | ||
350 | //-------------------------------------------------------------------- | ||
351 | const LLMatrix4 &LLJoint::getWorldMatrix() | ||
352 | { | ||
353 | updateWorldMatrixParent(); | ||
354 | |||
355 | return mXform.getWorldMatrix(); | ||
356 | } | ||
357 | |||
358 | |||
359 | //-------------------------------------------------------------------- | ||
360 | // setWorldMatrix() | ||
361 | //-------------------------------------------------------------------- | ||
362 | void LLJoint::setWorldMatrix( const LLMatrix4& mat ) | ||
363 | { | ||
364 | llinfos << "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 | //----------------------------------------------------------------------------- | ||
380 | void 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 | //----------------------------------------------------------------------------- | ||
396 | void 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 | //----------------------------------------------------------------------------- | ||
414 | void 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 | //----------------------------------------------------------------------------- | ||
429 | void 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 | //-------------------------------------------------------------------- | ||
442 | const LLVector3 &LLJoint::getSkinOffset() | ||
443 | { | ||
444 | return mSkinOffset; | ||
445 | } | ||
446 | |||
447 | |||
448 | //-------------------------------------------------------------------- | ||
449 | // setSkinOffset() | ||
450 | //-------------------------------------------------------------------- | ||
451 | void LLJoint::setSkinOffset( const LLVector3& offset ) | ||
452 | { | ||
453 | mSkinOffset = offset; | ||
454 | } | ||
455 | |||
456 | //----------------------------------------------------------------------------- | ||
457 | // setConstraintSilhouette() | ||
458 | //----------------------------------------------------------------------------- | ||
459 | void 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 | //----------------------------------------------------------------------------- | ||
493 | void 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 | |||
44 | const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; | ||
45 | const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4! | ||
46 | const U32 LL_HAND_JOINT_NUM = 31; | ||
47 | const U32 LL_FACE_JOINT_NUM = 30; | ||
48 | const S32 LL_CHARACTER_MAX_PRIORITY = 7; | ||
49 | const F32 LL_MAX_PELVIS_OFFSET = 5.f; | ||
50 | |||
51 | //----------------------------------------------------------------------------- | ||
52 | // class LLJoint | ||
53 | //----------------------------------------------------------------------------- | ||
54 | class LLJoint | ||
55 | { | ||
56 | public: | ||
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 | }; | ||
76 | protected: | ||
77 | std::string mName; | ||
78 | |||
79 | // parent joint | ||
80 | LLJoint *mParent; | ||
81 | |||
82 | // explicit transformation members | ||
83 | LLXformMatrix mXform; | ||
84 | |||
85 | public: | ||
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 | |||
104 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
45 | LLJointSolverRP3::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 | //----------------------------------------------------------------------------- | ||
71 | void 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 | //----------------------------------------------------------------------------- | ||
92 | const LLVector3& LLJointSolverRP3::getPoleVector() | ||
93 | { | ||
94 | return mPoleVector; | ||
95 | } | ||
96 | |||
97 | |||
98 | //----------------------------------------------------------------------------- | ||
99 | // setPoleVector() | ||
100 | //----------------------------------------------------------------------------- | ||
101 | void LLJointSolverRP3::setPoleVector( const LLVector3& poleVector ) | ||
102 | { | ||
103 | mPoleVector = poleVector; | ||
104 | mPoleVector.normVec(); | ||
105 | } | ||
106 | |||
107 | |||
108 | //----------------------------------------------------------------------------- | ||
109 | // setPoleVector() | ||
110 | //----------------------------------------------------------------------------- | ||
111 | void LLJointSolverRP3::setBAxis( const LLVector3& bAxis ) | ||
112 | { | ||
113 | mBAxis = bAxis; | ||
114 | mBAxis.normVec(); | ||
115 | mbUseBAxis = TRUE; | ||
116 | } | ||
117 | |||
118 | //----------------------------------------------------------------------------- | ||
119 | // getTwist() | ||
120 | //----------------------------------------------------------------------------- | ||
121 | F32 LLJointSolverRP3::getTwist() | ||
122 | { | ||
123 | return mTwist; | ||
124 | } | ||
125 | |||
126 | |||
127 | //----------------------------------------------------------------------------- | ||
128 | // setTwist() | ||
129 | //----------------------------------------------------------------------------- | ||
130 | void LLJointSolverRP3::setTwist( F32 twist ) | ||
131 | { | ||
132 | mTwist = twist; | ||
133 | } | ||
134 | |||
135 | |||
136 | //----------------------------------------------------------------------------- | ||
137 | // solve() | ||
138 | //----------------------------------------------------------------------------- | ||
139 | void 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 | |||
88 | class LLJointSolverRP3 | ||
89 | { | ||
90 | protected: | ||
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 | |||
112 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
39 | class LLJointState | ||
40 | { | ||
41 | public: | ||
42 | enum BlendPhase | ||
43 | { | ||
44 | INACTIVE, | ||
45 | EASE_IN, | ||
46 | ACTIVE, | ||
47 | EASE_OUT | ||
48 | }; | ||
49 | protected: | ||
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 | ||
64 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
47 | LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id) | ||
48 | { | ||
49 | mVelocityZ = 0.f; | ||
50 | mCharacter = NULL; | ||
51 | } | ||
52 | |||
53 | |||
54 | //----------------------------------------------------------------------------- | ||
55 | // ~LLKeyframeFallMotion() | ||
56 | // Class Destructor | ||
57 | //----------------------------------------------------------------------------- | ||
58 | LLKeyframeFallMotion::~LLKeyframeFallMotion() | ||
59 | { | ||
60 | } | ||
61 | |||
62 | |||
63 | //----------------------------------------------------------------------------- | ||
64 | // LLKeyframeFallMotion::onInitialize() | ||
65 | //----------------------------------------------------------------------------- | ||
66 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
90 | BOOL 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 | //----------------------------------------------------------------------------- | ||
118 | BOOL 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 | //----------------------------------------------------------------------------- | ||
131 | F32 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 | //----------------------------------------------------------------------------- | ||
40 | class LLKeyframeFallMotion : | ||
41 | public LLKeyframeMotion | ||
42 | { | ||
43 | public: | ||
44 | // Constructor | ||
45 | LLKeyframeFallMotion(const LLUUID &id); | ||
46 | |||
47 | // Destructor | ||
48 | virtual ~LLKeyframeFallMotion(); | ||
49 | |||
50 | public: | ||
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 | |||
59 | public: | ||
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 | |||
68 | protected: | ||
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 | //----------------------------------------------------------------------------- | ||
50 | LLVFS* LLKeyframeMotion::sVFS = NULL; | ||
51 | LLKeyframeDataCache::LLKeyframeDataMap LLKeyframeDataCache::sKeyframeDataMap; | ||
52 | |||
53 | //----------------------------------------------------------------------------- | ||
54 | // Globals | ||
55 | //----------------------------------------------------------------------------- | ||
56 | static F32 JOINT_LENGTH_K = 0.7f; | ||
57 | static S32 MAX_ITERATIONS = 20; | ||
58 | static S32 MIN_ITERATIONS = 1; | ||
59 | static S32 MIN_ITERATION_COUNT = 2; | ||
60 | static F32 MAX_PIXEL_AREA_CONSTRAINTS = 80000.f; | ||
61 | static F32 MIN_PIXEL_AREA_CONSTRAINTS = 1000.f; | ||
62 | static F32 MIN_ACCELERATION_SQUARED = 0.0005f * 0.0005f; | ||
63 | |||
64 | static F32 MAX_CONSTRAINTS = 10; | ||
65 | |||
66 | //----------------------------------------------------------------------------- | ||
67 | // JointMotionList::dumpDiagInfo() | ||
68 | //----------------------------------------------------------------------------- | ||
69 | U32 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 | //----------------------------------------------------------------------------- | ||
114 | LLKeyframeMotion::ScaleCurve::ScaleCurve() | ||
115 | { | ||
116 | mInterpolationType = LLKeyframeMotion::IT_LINEAR; | ||
117 | mNumKeys = 0; | ||
118 | } | ||
119 | |||
120 | //----------------------------------------------------------------------------- | ||
121 | // ScaleCurve::~ScaleCurve() | ||
122 | //----------------------------------------------------------------------------- | ||
123 | LLKeyframeMotion::ScaleCurve::~ScaleCurve() | ||
124 | { | ||
125 | mKeys.deleteAllData(); | ||
126 | mNumKeys = 0; | ||
127 | } | ||
128 | |||
129 | //----------------------------------------------------------------------------- | ||
130 | // getValue() | ||
131 | //----------------------------------------------------------------------------- | ||
132 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
178 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
195 | LLKeyframeMotion::RotationCurve::RotationCurve() | ||
196 | { | ||
197 | mInterpolationType = LLKeyframeMotion::IT_LINEAR; | ||
198 | mNumKeys = 0; | ||
199 | } | ||
200 | |||
201 | //----------------------------------------------------------------------------- | ||
202 | // RotationCurve::~RotationCurve() | ||
203 | //----------------------------------------------------------------------------- | ||
204 | LLKeyframeMotion::RotationCurve::~RotationCurve() | ||
205 | { | ||
206 | mKeys.deleteAllData(); | ||
207 | mNumKeys = 0; | ||
208 | } | ||
209 | |||
210 | //----------------------------------------------------------------------------- | ||
211 | // RotationCurve::getValue() | ||
212 | //----------------------------------------------------------------------------- | ||
213 | LLQuaternion 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 | //----------------------------------------------------------------------------- | ||
260 | LLQuaternion 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 | //----------------------------------------------------------------------------- | ||
278 | LLKeyframeMotion::PositionCurve::PositionCurve() | ||
279 | { | ||
280 | mInterpolationType = LLKeyframeMotion::IT_LINEAR; | ||
281 | mNumKeys = 0; | ||
282 | } | ||
283 | |||
284 | //----------------------------------------------------------------------------- | ||
285 | // PositionCurve::~PositionCurve() | ||
286 | //----------------------------------------------------------------------------- | ||
287 | LLKeyframeMotion::PositionCurve::~PositionCurve() | ||
288 | { | ||
289 | mKeys.deleteAllData(); | ||
290 | mNumKeys = 0; | ||
291 | } | ||
292 | |||
293 | //----------------------------------------------------------------------------- | ||
294 | // PositionCurve::getValue() | ||
295 | //----------------------------------------------------------------------------- | ||
296 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
345 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
368 | void 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 | //----------------------------------------------------------------------------- | ||
415 | LLKeyframeMotion::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 | //----------------------------------------------------------------------------- | ||
431 | LLKeyframeMotion::~LLKeyframeMotion() | ||
432 | { | ||
433 | if (mJointStates) | ||
434 | { | ||
435 | delete [] mJointStates; | ||
436 | } | ||
437 | mConstraints.deleteAllData(); | ||
438 | } | ||
439 | |||
440 | //----------------------------------------------------------------------------- | ||
441 | // create() | ||
442 | //----------------------------------------------------------------------------- | ||
443 | LLMotion *LLKeyframeMotion::create(const LLUUID &id) | ||
444 | { | ||
445 | return new LLKeyframeMotion(id); | ||
446 | } | ||
447 | |||
448 | //----------------------------------------------------------------------------- | ||
449 | // LLKeyframeMotion::onInitialize(LLCharacter *character) | ||
450 | //----------------------------------------------------------------------------- | ||
451 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
569 | BOOL 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 | //----------------------------------------------------------------------------- | ||
610 | BOOL 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 | //----------------------------------------------------------------------------- | ||
626 | BOOL 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 | //----------------------------------------------------------------------------- | ||
676 | void 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 | //----------------------------------------------------------------------------- | ||
706 | void 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 | //----------------------------------------------------------------------------- | ||
734 | void 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 | ||
748 | void 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 | //----------------------------------------------------------------------------- | ||
773 | void 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 | //----------------------------------------------------------------------------- | ||
813 | void 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 | //----------------------------------------------------------------------------- | ||
840 | void 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 | //----------------------------------------------------------------------------- | ||
860 | void 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 | //----------------------------------------------------------------------------- | ||
1127 | BOOL 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 | //----------------------------------------------------------------------------- | ||
1654 | BOOL 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 | //----------------------------------------------------------------------------- | ||
1752 | U32 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 | //----------------------------------------------------------------------------- | ||
1764 | const LLBBoxLocal &LLKeyframeMotion::getPelvisBBox() | ||
1765 | { | ||
1766 | return mJointMotionList->mPelvisBBox; | ||
1767 | } | ||
1768 | |||
1769 | //----------------------------------------------------------------------------- | ||
1770 | // setPriority() | ||
1771 | //----------------------------------------------------------------------------- | ||
1772 | void 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 | //----------------------------------------------------------------------------- | ||
1794 | void 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 | //----------------------------------------------------------------------------- | ||
1810 | void 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 | //----------------------------------------------------------------------------- | ||
1821 | void 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 | //----------------------------------------------------------------------------- | ||
1833 | void LLKeyframeMotion::flushKeyframeCache() | ||
1834 | { | ||
1835 | LLKeyframeDataCache::clear(); | ||
1836 | } | ||
1837 | |||
1838 | //----------------------------------------------------------------------------- | ||
1839 | // setLoop() | ||
1840 | //----------------------------------------------------------------------------- | ||
1841 | void 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 | //----------------------------------------------------------------------------- | ||
1854 | void 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 | //----------------------------------------------------------------------------- | ||
1881 | void 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 | //----------------------------------------------------------------------------- | ||
1908 | void 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 | //----------------------------------------------------------------------------- | ||
1977 | void 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 | //-------------------------------------------------------------------- | ||
2034 | void 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 | //-------------------------------------------------------------------- | ||
2071 | void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp) | ||
2072 | { | ||
2073 | sKeyframeDataMap[id] = joint_motion_listp; | ||
2074 | } | ||
2075 | |||
2076 | //-------------------------------------------------------------------- | ||
2077 | // LLKeyframeDataCache::removeKeyframeData() | ||
2078 | //-------------------------------------------------------------------- | ||
2079 | void 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 | //-------------------------------------------------------------------- | ||
2092 | LLKeyframeMotion::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 | //-------------------------------------------------------------------- | ||
2105 | LLKeyframeDataCache::~LLKeyframeDataCache() | ||
2106 | { | ||
2107 | clear(); | ||
2108 | } | ||
2109 | |||
2110 | //----------------------------------------------------------------------------- | ||
2111 | // clear() | ||
2112 | //----------------------------------------------------------------------------- | ||
2113 | void LLKeyframeDataCache::clear() | ||
2114 | { | ||
2115 | for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer()); | ||
2116 | sKeyframeDataMap.clear(); | ||
2117 | } | ||
2118 | |||
2119 | //----------------------------------------------------------------------------- | ||
2120 | // JointConstraint() | ||
2121 | //----------------------------------------------------------------------------- | ||
2122 | LLKeyframeMotion::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 | //----------------------------------------------------------------------------- | ||
2134 | LLKeyframeMotion::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 | |||
49 | class LLKeyframeDataCache; | ||
50 | class LLVFS; | ||
51 | class LLDataPacker; | ||
52 | |||
53 | #define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f) | ||
54 | #define MAX_CHAIN_LENGTH (4) | ||
55 | |||
56 | const S32 KEYFRAME_MOTION_VERSION = 1; | ||
57 | const S32 KEYFRAME_MOTION_SUBVERSION = 0; | ||
58 | |||
59 | //----------------------------------------------------------------------------- | ||
60 | // class LLKeyframeMotion | ||
61 | //----------------------------------------------------------------------------- | ||
62 | class LLKeyframeMotion : | ||
63 | public LLMotion | ||
64 | { | ||
65 | friend class LLKeyframeDataCache; | ||
66 | public: | ||
67 | // Constructor | ||
68 | LLKeyframeMotion(const LLUUID &id); | ||
69 | |||
70 | // Destructor | ||
71 | virtual ~LLKeyframeMotion(); | ||
72 | |||
73 | public: | ||
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 | |||
82 | public: | ||
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 | |||
149 | public: | ||
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 | |||
206 | protected: | ||
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 | |||
277 | public: | ||
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 | |||
417 | protected: | ||
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 | |||
435 | class LLKeyframeDataCache | ||
436 | { | ||
437 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
49 | BOOL 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 | //----------------------------------------------------------------------------- | ||
58 | LLKeyframeMotionParam::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 | //----------------------------------------------------------------------------- | ||
75 | LLKeyframeMotionParam::~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 | //----------------------------------------------------------------------------- | ||
93 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
146 | BOOL 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 | //----------------------------------------------------------------------------- | ||
163 | BOOL 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 | //----------------------------------------------------------------------------- | ||
275 | void 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 | //----------------------------------------------------------------------------- | ||
290 | BOOL 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 | //----------------------------------------------------------------------------- | ||
326 | void 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 | //----------------------------------------------------------------------------- | ||
344 | BOOL 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 | //----------------------------------------------------------------------------- | ||
47 | class LLKeyframeMotionParam : | ||
48 | public LLMotion | ||
49 | { | ||
50 | public: | ||
51 | // Constructor | ||
52 | LLKeyframeMotionParam(const LLUUID &id); | ||
53 | |||
54 | // Destructor | ||
55 | virtual ~LLKeyframeMotionParam(); | ||
56 | |||
57 | public: | ||
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 | |||
66 | public: | ||
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 | |||
121 | protected: | ||
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 | |||
137 | protected: | ||
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 | ||
41 | const F32 ROTATION_THRESHOLD = 0.6f; | ||
42 | const F32 POSITION_THRESHOLD = 0.1f; | ||
43 | |||
44 | //----------------------------------------------------------------------------- | ||
45 | // LLKeyframeStandMotion() | ||
46 | // Class Constructor | ||
47 | //----------------------------------------------------------------------------- | ||
48 | LLKeyframeStandMotion::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 | //----------------------------------------------------------------------------- | ||
81 | LLKeyframeStandMotion::~LLKeyframeStandMotion() | ||
82 | { | ||
83 | } | ||
84 | |||
85 | |||
86 | //----------------------------------------------------------------------------- | ||
87 | // LLKeyframeStandMotion::onInitialize() | ||
88 | //----------------------------------------------------------------------------- | ||
89 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
133 | BOOL 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 | //----------------------------------------------------------------------------- | ||
154 | void LLKeyframeStandMotion::onDeactivate() | ||
155 | { | ||
156 | LLKeyframeMotion::onDeactivate(); | ||
157 | } | ||
158 | |||
159 | //----------------------------------------------------------------------------- | ||
160 | // LLKeyframeStandMotion::onUpdate() | ||
161 | //----------------------------------------------------------------------------- | ||
162 | BOOL 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 | //----------------------------------------------------------------------------- | ||
41 | class LLKeyframeStandMotion : | ||
42 | public LLKeyframeMotion | ||
43 | { | ||
44 | public: | ||
45 | // Constructor | ||
46 | LLKeyframeStandMotion(const LLUUID &id); | ||
47 | |||
48 | // Destructor | ||
49 | virtual ~LLKeyframeStandMotion(); | ||
50 | |||
51 | public: | ||
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 | |||
60 | public: | ||
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 | |||
69 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
42 | const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed | ||
43 | |||
44 | const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection | ||
45 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
46 | const F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed | ||
47 | const F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second | ||
48 | const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction | ||
49 | const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out | ||
50 | const F32 MAX_ROLL = 0.6f; | ||
51 | |||
52 | //----------------------------------------------------------------------------- | ||
53 | // LLKeyframeWalkMotion() | ||
54 | // Class Constructor | ||
55 | //----------------------------------------------------------------------------- | ||
56 | LLKeyframeWalkMotion::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 | //----------------------------------------------------------------------------- | ||
68 | LLKeyframeWalkMotion::~LLKeyframeWalkMotion() | ||
69 | { | ||
70 | } | ||
71 | |||
72 | |||
73 | //----------------------------------------------------------------------------- | ||
74 | // LLKeyframeWalkMotion::onInitialize() | ||
75 | //----------------------------------------------------------------------------- | ||
76 | LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character) | ||
77 | { | ||
78 | mCharacter = character; | ||
79 | |||
80 | return LLKeyframeMotion::onInitialize(character); | ||
81 | } | ||
82 | |||
83 | //----------------------------------------------------------------------------- | ||
84 | // LLKeyframeWalkMotion::onActivate() | ||
85 | //----------------------------------------------------------------------------- | ||
86 | BOOL LLKeyframeWalkMotion::onActivate() | ||
87 | { | ||
88 | mRealTimeLast = 0.0f; | ||
89 | mAdjTimeLast = 0.0f; | ||
90 | |||
91 | return LLKeyframeMotion::onActivate(); | ||
92 | } | ||
93 | |||
94 | //----------------------------------------------------------------------------- | ||
95 | // LLKeyframeWalkMotion::onDeactivate() | ||
96 | //----------------------------------------------------------------------------- | ||
97 | void LLKeyframeWalkMotion::onDeactivate() | ||
98 | { | ||
99 | mCharacter->removeAnimationData("Down Foot"); | ||
100 | LLKeyframeMotion::onDeactivate(); | ||
101 | } | ||
102 | |||
103 | //----------------------------------------------------------------------------- | ||
104 | // LLKeyframeWalkMotion::onUpdate() | ||
105 | //----------------------------------------------------------------------------- | ||
106 | BOOL 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 | //----------------------------------------------------------------------------- | ||
138 | LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : LLMotion(id) | ||
139 | { | ||
140 | mLastTime = 0.f; | ||
141 | mName = "walk_adjust"; | ||
142 | } | ||
143 | |||
144 | //----------------------------------------------------------------------------- | ||
145 | // LLWalkAdjustMotion::onInitialize() | ||
146 | //----------------------------------------------------------------------------- | ||
147 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
170 | BOOL 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 | //----------------------------------------------------------------------------- | ||
192 | BOOL 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 | //----------------------------------------------------------------------------- | ||
337 | void LLWalkAdjustMotion::onDeactivate() | ||
338 | { | ||
339 | mCharacter->removeAnimationData("Walk Speed"); | ||
340 | } | ||
341 | |||
342 | //----------------------------------------------------------------------------- | ||
343 | // LLFlyAdjustMotion::onInitialize() | ||
344 | //----------------------------------------------------------------------------- | ||
345 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
366 | BOOL 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 | //----------------------------------------------------------------------------- | ||
377 | BOOL 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 | //----------------------------------------------------------------------------- | ||
44 | class LLKeyframeWalkMotion : | ||
45 | public LLKeyframeMotion | ||
46 | { | ||
47 | friend class LLWalkAdjustMotion; | ||
48 | public: | ||
49 | // Constructor | ||
50 | LLKeyframeWalkMotion(const LLUUID &id); | ||
51 | |||
52 | // Destructor | ||
53 | virtual ~LLKeyframeWalkMotion(); | ||
54 | |||
55 | public: | ||
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 | |||
64 | public: | ||
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 | |||
73 | public: | ||
74 | //------------------------------------------------------------------------- | ||
75 | // Member Data | ||
76 | //------------------------------------------------------------------------- | ||
77 | LLCharacter *mCharacter; | ||
78 | F32 mCyclePhase; | ||
79 | F32 mRealTimeLast; | ||
80 | F32 mAdjTimeLast; | ||
81 | S32 mDownFoot; | ||
82 | }; | ||
83 | |||
84 | class LLWalkAdjustMotion : public LLMotion | ||
85 | { | ||
86 | public: | ||
87 | // Constructor | ||
88 | LLWalkAdjustMotion(const LLUUID &id); | ||
89 | |||
90 | public: | ||
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 | |||
99 | public: | ||
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 | |||
115 | public: | ||
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 | |||
136 | class LLFlyAdjustMotion : public LLMotion | ||
137 | { | ||
138 | public: | ||
139 | // Constructor | ||
140 | LLFlyAdjustMotion(const LLUUID &id) : LLMotion(id) {mName = "fly_adjust";} | ||
141 | |||
142 | public: | ||
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 | |||
151 | public: | ||
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 | |||
167 | protected: | ||
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 | //----------------------------------------------------------------------------- | ||
46 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
68 | LLMotion::~LLMotion() | ||
69 | { | ||
70 | } | ||
71 | |||
72 | //----------------------------------------------------------------------------- | ||
73 | // fadeOut() | ||
74 | //----------------------------------------------------------------------------- | ||
75 | void 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 | //----------------------------------------------------------------------------- | ||
90 | void 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 | //----------------------------------------------------------------------------- | ||
105 | void 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 | |||
122 | void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata ) | ||
123 | { | ||
124 | mDeactivateCallback = cb; | ||
125 | mDeactivateCallbackUserData = userdata; | ||
126 | } | ||
127 | |||
128 | //----------------------------------------------------------------------------- | ||
129 | // activate() | ||
130 | //----------------------------------------------------------------------------- | ||
131 | void LLMotion::activate() | ||
132 | { | ||
133 | mStopped = FALSE; | ||
134 | mActive = TRUE; | ||
135 | onActivate(); | ||
136 | } | ||
137 | |||
138 | //----------------------------------------------------------------------------- | ||
139 | // deactivate() | ||
140 | //----------------------------------------------------------------------------- | ||
141 | void 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 | |||
40 | class LLCharacter; | ||
41 | |||
42 | //----------------------------------------------------------------------------- | ||
43 | // class LLMotion | ||
44 | //----------------------------------------------------------------------------- | ||
45 | class LLMotion | ||
46 | { | ||
47 | public: | ||
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 | |||
67 | public: | ||
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 | |||
108 | public: | ||
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 | |||
150 | protected: | ||
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 | |||
158 | protected: | ||
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 | |||
163 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
185 | class LLTestMotion : public LLMotion | ||
186 | { | ||
187 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
209 | class LLNullMotion : public LLMotion | ||
210 | { | ||
211 | public: | ||
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 | |||
40 | const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4; | ||
41 | const U32 MAX_MOTION_INSTANCES = 32; | ||
42 | |||
43 | //----------------------------------------------------------------------------- | ||
44 | // Constants and statics | ||
45 | //----------------------------------------------------------------------------- | ||
46 | LLMotionRegistry LLMotionController::sRegistry; | ||
47 | |||
48 | //----------------------------------------------------------------------------- | ||
49 | // LLMotionTableEntry() | ||
50 | //----------------------------------------------------------------------------- | ||
51 | LLMotionTableEntry::LLMotionTableEntry() | ||
52 | { | ||
53 | mConstructor = NULL; | ||
54 | mID.setNull(); | ||
55 | } | ||
56 | |||
57 | LLMotionTableEntry::LLMotionTableEntry(LLMotionConstructor constructor, const LLUUID& id) | ||
58 | : mConstructor(constructor), mID(id) | ||
59 | { | ||
60 | |||
61 | } | ||
62 | |||
63 | //----------------------------------------------------------------------------- | ||
64 | // create() | ||
65 | //----------------------------------------------------------------------------- | ||
66 | LLMotion* 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 | //----------------------------------------------------------------------------- | ||
84 | LLMotionRegistry::LLMotionRegistry() : mMotionTable(LLMotionTableEntry::uuidEq, LLMotionTableEntry()) | ||
85 | { | ||
86 | |||
87 | } | ||
88 | |||
89 | |||
90 | //----------------------------------------------------------------------------- | ||
91 | // ~LLMotionRegistry() | ||
92 | // Class Destructor | ||
93 | //----------------------------------------------------------------------------- | ||
94 | LLMotionRegistry::~LLMotionRegistry() | ||
95 | { | ||
96 | mMotionTable.removeAll(); | ||
97 | } | ||
98 | |||
99 | |||
100 | //----------------------------------------------------------------------------- | ||
101 | // addMotion() | ||
102 | //----------------------------------------------------------------------------- | ||
103 | BOOL 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 | //----------------------------------------------------------------------------- | ||
118 | void LLMotionRegistry::markBad( const LLUUID& id ) | ||
119 | { | ||
120 | mMotionTable.set(id, LLMotionTableEntry()); | ||
121 | } | ||
122 | |||
123 | //----------------------------------------------------------------------------- | ||
124 | // createMotion() | ||
125 | //----------------------------------------------------------------------------- | ||
126 | LLMotion *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 | //----------------------------------------------------------------------------- | ||
154 | LLMotionController::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 | //----------------------------------------------------------------------------- | ||
173 | LLMotionController::~LLMotionController() | ||
174 | { | ||
175 | deleteAllMotions(); | ||
176 | } | ||
177 | |||
178 | //----------------------------------------------------------------------------- | ||
179 | // deleteAllMotions() | ||
180 | //----------------------------------------------------------------------------- | ||
181 | void 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 | //----------------------------------------------------------------------------- | ||
194 | void 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 | //----------------------------------------------------------------------------- | ||
230 | void 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 | //----------------------------------------------------------------------------- | ||
253 | void LLMotionController::setTimeFactor(F32 time_factor) | ||
254 | { | ||
255 | mTimeOffset += mTimer.getElapsedTimeAndResetF32() * mTimeFactor; | ||
256 | mTimeFactor = time_factor; | ||
257 | } | ||
258 | |||
259 | //----------------------------------------------------------------------------- | ||
260 | // getFirstActiveMotion() | ||
261 | //----------------------------------------------------------------------------- | ||
262 | LLMotion* LLMotionController::getFirstActiveMotion() | ||
263 | { | ||
264 | return mActiveMotions.getFirstData(); | ||
265 | } | ||
266 | |||
267 | //----------------------------------------------------------------------------- | ||
268 | // getNextActiveMotion() | ||
269 | //----------------------------------------------------------------------------- | ||
270 | LLMotion* LLMotionController::getNextActiveMotion() | ||
271 | { | ||
272 | return mActiveMotions.getNextData(); | ||
273 | } | ||
274 | |||
275 | |||
276 | //----------------------------------------------------------------------------- | ||
277 | // setCharacter() | ||
278 | //----------------------------------------------------------------------------- | ||
279 | void LLMotionController::setCharacter(LLCharacter *character) | ||
280 | { | ||
281 | mCharacter = character; | ||
282 | } | ||
283 | |||
284 | |||
285 | //----------------------------------------------------------------------------- | ||
286 | // addMotion() | ||
287 | //----------------------------------------------------------------------------- | ||
288 | BOOL LLMotionController::addMotion( const LLUUID& id, LLMotionConstructor constructor ) | ||
289 | { | ||
290 | return sRegistry.addMotion(id, constructor); | ||
291 | } | ||
292 | |||
293 | //----------------------------------------------------------------------------- | ||
294 | // removeMotion() | ||
295 | //----------------------------------------------------------------------------- | ||
296 | void 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 | //----------------------------------------------------------------------------- | ||
322 | LLMotion* 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 | //----------------------------------------------------------------------------- | ||
373 | BOOL 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 | //----------------------------------------------------------------------------- | ||
403 | BOOL 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 | //----------------------------------------------------------------------------- | ||
440 | void LLMotionController::updateRegularMotions() | ||
441 | { | ||
442 | updateMotionsByType(LLMotion::NORMAL_BLEND); | ||
443 | } | ||
444 | |||
445 | //----------------------------------------------------------------------------- | ||
446 | // updateAdditiveMotions() | ||
447 | //----------------------------------------------------------------------------- | ||
448 | void LLMotionController::updateAdditiveMotions() | ||
449 | { | ||
450 | updateMotionsByType(LLMotion::ADDITIVE_BLEND); | ||
451 | } | ||
452 | |||
453 | //----------------------------------------------------------------------------- | ||
454 | // resetJointSignatures() | ||
455 | //----------------------------------------------------------------------------- | ||
456 | void 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 | //----------------------------------------------------------------------------- | ||
465 | void 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 | //----------------------------------------------------------------------------- | ||
704 | void 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 | //----------------------------------------------------------------------------- | ||
805 | BOOL 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 | //----------------------------------------------------------------------------- | ||
849 | BOOL LLMotionController::deactivateMotion(LLMotion *motion) | ||
850 | { | ||
851 | motion->deactivate(); | ||
852 | mActiveMotions.removeData(motion); | ||
853 | |||
854 | return TRUE; | ||
855 | } | ||
856 | |||
857 | //----------------------------------------------------------------------------- | ||
858 | // isMotionActive() | ||
859 | //----------------------------------------------------------------------------- | ||
860 | BOOL 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 | //----------------------------------------------------------------------------- | ||
873 | BOOL LLMotionController::isMotionLoading(LLMotion* motion) | ||
874 | { | ||
875 | return mLoadingMotions.checkData(motion); | ||
876 | } | ||
877 | |||
878 | |||
879 | //----------------------------------------------------------------------------- | ||
880 | // findMotion() | ||
881 | //----------------------------------------------------------------------------- | ||
882 | LLMotion *LLMotionController::findMotion(const LLUUID& id) | ||
883 | { | ||
884 | return mAllMotions[id]; | ||
885 | } | ||
886 | |||
887 | |||
888 | //----------------------------------------------------------------------------- | ||
889 | // flushAllMotions() | ||
890 | //----------------------------------------------------------------------------- | ||
891 | void 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 | //----------------------------------------------------------------------------- | ||
922 | void 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 | //----------------------------------------------------------------------------- | ||
936 | void 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 | //----------------------------------------------------------------------------- | ||
50 | class LLCharacter; | ||
51 | |||
52 | //----------------------------------------------------------------------------- | ||
53 | // LLMotionRegistry | ||
54 | //----------------------------------------------------------------------------- | ||
55 | typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id); | ||
56 | |||
57 | class LLMotionTableEntry | ||
58 | { | ||
59 | public: | ||
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 | |||
76 | protected: | ||
77 | LLMotionConstructor mConstructor; | ||
78 | LLUUID mID; | ||
79 | }; | ||
80 | |||
81 | class LLMotionRegistry | ||
82 | { | ||
83 | public: | ||
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 | |||
102 | protected: | ||
103 | LLUUIDHashMap<LLMotionTableEntry, 32> mMotionTable; | ||
104 | }; | ||
105 | |||
106 | //----------------------------------------------------------------------------- | ||
107 | // class LLMotionController | ||
108 | //----------------------------------------------------------------------------- | ||
109 | class LLMotionController | ||
110 | { | ||
111 | public: | ||
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 | |||
175 | protected: | ||
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); | ||
184 | protected: | ||
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 | |||
40 | const S32 GESTURE_VERSION = 2; | ||
41 | |||
42 | //--------------------------------------------------------------------------- | ||
43 | // LLMultiGesture | ||
44 | //--------------------------------------------------------------------------- | ||
45 | LLMultiGesture::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 | |||
59 | LLMultiGesture::~LLMultiGesture() | ||
60 | { | ||
61 | std::for_each(mSteps.begin(), mSteps.end(), DeletePointer()); | ||
62 | } | ||
63 | |||
64 | void 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 | |||
76 | S32 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 | |||
118 | BOOL 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 | |||
143 | BOOL 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 | |||
222 | void 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 | //--------------------------------------------------------------------------- | ||
239 | LLGestureStepAnimation::LLGestureStepAnimation() | ||
240 | : LLGestureStep(), | ||
241 | mAnimName("None"), | ||
242 | mAnimAssetID(), | ||
243 | mFlags(0x0) | ||
244 | { } | ||
245 | |||
246 | LLGestureStepAnimation::~LLGestureStepAnimation() | ||
247 | { } | ||
248 | |||
249 | S32 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 | |||
266 | BOOL 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 | |||
274 | BOOL 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 | |||
291 | std::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 | |||
306 | void LLGestureStepAnimation::dump() | ||
307 | { | ||
308 | llinfos << "step animation " << mAnimName | ||
309 | << " id " << mAnimAssetID | ||
310 | << " flags " << mFlags | ||
311 | << llendl; | ||
312 | } | ||
313 | |||
314 | //--------------------------------------------------------------------------- | ||
315 | // LLGestureStepSound | ||
316 | //--------------------------------------------------------------------------- | ||
317 | LLGestureStepSound::LLGestureStepSound() | ||
318 | : LLGestureStep(), | ||
319 | mSoundName("None"), | ||
320 | mSoundAssetID(), | ||
321 | mFlags(0x0) | ||
322 | { } | ||
323 | |||
324 | LLGestureStepSound::~LLGestureStepSound() | ||
325 | { } | ||
326 | |||
327 | S32 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 | |||
341 | BOOL 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 | |||
349 | BOOL 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 | |||
358 | std::string LLGestureStepSound::getLabel() const | ||
359 | { | ||
360 | std::string label("Sound: "); | ||
361 | label += mSoundName; | ||
362 | return label; | ||
363 | } | ||
364 | |||
365 | void LLGestureStepSound::dump() | ||
366 | { | ||
367 | llinfos << "step sound " << mSoundName | ||
368 | << " id " << mSoundAssetID | ||
369 | << " flags " << mFlags | ||
370 | << llendl; | ||
371 | } | ||
372 | |||
373 | |||
374 | //--------------------------------------------------------------------------- | ||
375 | // LLGestureStepChat | ||
376 | //--------------------------------------------------------------------------- | ||
377 | LLGestureStepChat::LLGestureStepChat() | ||
378 | : LLGestureStep(), | ||
379 | mChatText(), | ||
380 | mFlags(0x0) | ||
381 | { } | ||
382 | |||
383 | LLGestureStepChat::~LLGestureStepChat() | ||
384 | { } | ||
385 | |||
386 | S32 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 | |||
398 | BOOL LLGestureStepChat::serialize(LLDataPacker& dp) const | ||
399 | { | ||
400 | dp.packString(mChatText.c_str(), "chat_text"); | ||
401 | dp.packU32(mFlags, "flags"); | ||
402 | return TRUE; | ||
403 | } | ||
404 | |||
405 | BOOL LLGestureStepChat::deserialize(LLDataPacker& dp) | ||
406 | { | ||
407 | dp.unpackString(mChatText, "chat_text"); | ||
408 | |||
409 | dp.unpackU32(mFlags, "flags"); | ||
410 | return TRUE; | ||
411 | } | ||
412 | |||
413 | std::string LLGestureStepChat::getLabel() const | ||
414 | { | ||
415 | std::string label("Chat: "); | ||
416 | label += mChatText; | ||
417 | return label; | ||
418 | } | ||
419 | |||
420 | void LLGestureStepChat::dump() | ||
421 | { | ||
422 | llinfos << "step chat " << mChatText | ||
423 | << " flags " << mFlags | ||
424 | << llendl; | ||
425 | } | ||
426 | |||
427 | |||
428 | //--------------------------------------------------------------------------- | ||
429 | // LLGestureStepWait | ||
430 | //--------------------------------------------------------------------------- | ||
431 | LLGestureStepWait::LLGestureStepWait() | ||
432 | : LLGestureStep(), | ||
433 | mWaitSeconds(0.f), | ||
434 | mFlags(0x0) | ||
435 | { } | ||
436 | |||
437 | LLGestureStepWait::~LLGestureStepWait() | ||
438 | { } | ||
439 | |||
440 | S32 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 | |||
452 | BOOL LLGestureStepWait::serialize(LLDataPacker& dp) const | ||
453 | { | ||
454 | dp.packF32(mWaitSeconds, "wait_seconds"); | ||
455 | dp.packU32(mFlags, "flags"); | ||
456 | return TRUE; | ||
457 | } | ||
458 | |||
459 | BOOL LLGestureStepWait::deserialize(LLDataPacker& dp) | ||
460 | { | ||
461 | dp.unpackF32(mWaitSeconds, "wait_seconds"); | ||
462 | dp.unpackU32(mFlags, "flags"); | ||
463 | return TRUE; | ||
464 | } | ||
465 | |||
466 | std::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 | |||
484 | void 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 | |||
38 | class LLDataPacker; | ||
39 | class LLGestureStep; | ||
40 | |||
41 | class LLMultiGesture | ||
42 | { | ||
43 | public: | ||
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; } | ||
58 | protected: | ||
59 | LLMultiGesture(const LLMultiGesture& gest); | ||
60 | const LLMultiGesture& operator=(const LLMultiGesture& rhs); | ||
61 | |||
62 | public: | ||
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 | |||
106 | enum 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 | |||
117 | class LLGestureStep | ||
118 | { | ||
119 | public: | ||
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. | ||
138 | const U32 ANIM_FLAG_STOP = 0x01; | ||
139 | |||
140 | class LLGestureStepAnimation : public LLGestureStep | ||
141 | { | ||
142 | public: | ||
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 | |||
156 | public: | ||
157 | std::string mAnimName; | ||
158 | LLUUID mAnimAssetID; | ||
159 | U32 mFlags; | ||
160 | }; | ||
161 | |||
162 | |||
163 | class LLGestureStepSound : public LLGestureStep | ||
164 | { | ||
165 | public: | ||
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 | |||
179 | public: | ||
180 | std::string mSoundName; | ||
181 | LLUUID mSoundAssetID; | ||
182 | U32 mFlags; | ||
183 | }; | ||
184 | |||
185 | |||
186 | class LLGestureStepChat : public LLGestureStep | ||
187 | { | ||
188 | public: | ||
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 | |||
202 | public: | ||
203 | std::string mChatText; | ||
204 | U32 mFlags; | ||
205 | }; | ||
206 | |||
207 | |||
208 | const U32 WAIT_FLAG_TIME = 0x01; | ||
209 | const U32 WAIT_FLAG_ALL_ANIM = 0x02; | ||
210 | |||
211 | class LLGestureStepWait : public LLGestureStep | ||
212 | { | ||
213 | public: | ||
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 | |||
227 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
45 | LLPose::~LLPose() | ||
46 | { | ||
47 | } | ||
48 | |||
49 | //----------------------------------------------------------------------------- | ||
50 | // getFirstJointState() | ||
51 | //----------------------------------------------------------------------------- | ||
52 | LLJointState *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 | //----------------------------------------------------------------------------- | ||
68 | LLJointState *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 | //----------------------------------------------------------------------------- | ||
84 | BOOL 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 | //----------------------------------------------------------------------------- | ||
96 | BOOL LLPose::removeJointState(LLJointState *jointState) | ||
97 | { | ||
98 | mJointMap.erase(jointState->getJoint()->getName()); | ||
99 | return TRUE; | ||
100 | } | ||
101 | |||
102 | //----------------------------------------------------------------------------- | ||
103 | // removeAllJointStates() | ||
104 | //----------------------------------------------------------------------------- | ||
105 | BOOL LLPose::removeAllJointStates() | ||
106 | { | ||
107 | mJointMap.clear(); | ||
108 | return TRUE; | ||
109 | } | ||
110 | |||
111 | //----------------------------------------------------------------------------- | ||
112 | // findJointState() | ||
113 | //----------------------------------------------------------------------------- | ||
114 | LLJointState* 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 | //----------------------------------------------------------------------------- | ||
131 | LLJointState* 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 | //----------------------------------------------------------------------------- | ||
148 | void 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 | //----------------------------------------------------------------------------- | ||
163 | F32 LLPose::getWeight() const | ||
164 | { | ||
165 | return mWeight; | ||
166 | } | ||
167 | |||
168 | //----------------------------------------------------------------------------- | ||
169 | // getNumJointStates() | ||
170 | //----------------------------------------------------------------------------- | ||
171 | S32 LLPose::getNumJointStates() const | ||
172 | { | ||
173 | return (S32)mJointMap.size(); | ||
174 | } | ||
175 | |||
176 | //----------------------------------------------------------------------------- | ||
177 | // LLJointStateBlender | ||
178 | //----------------------------------------------------------------------------- | ||
179 | |||
180 | LLJointStateBlender::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 | |||
189 | LLJointStateBlender::~LLJointStateBlender() | ||
190 | { | ||
191 | |||
192 | } | ||
193 | |||
194 | //----------------------------------------------------------------------------- | ||
195 | // addJointState() | ||
196 | //----------------------------------------------------------------------------- | ||
197 | BOOL 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 | //----------------------------------------------------------------------------- | ||
239 | void 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 | //----------------------------------------------------------------------------- | ||
404 | void 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 | //----------------------------------------------------------------------------- | ||
426 | void 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 | //----------------------------------------------------------------------------- | ||
438 | void 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 | |||
454 | LLPoseBlender::LLPoseBlender() | ||
455 | { | ||
456 | } | ||
457 | |||
458 | LLPoseBlender::~LLPoseBlender() | ||
459 | { | ||
460 | mJointStateBlenderPool.deleteAllData(); | ||
461 | } | ||
462 | |||
463 | //----------------------------------------------------------------------------- | ||
464 | // addMotion() | ||
465 | //----------------------------------------------------------------------------- | ||
466 | BOOL 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 | //----------------------------------------------------------------------------- | ||
506 | void 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 | //----------------------------------------------------------------------------- | ||
522 | void 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 | //----------------------------------------------------------------------------- | ||
539 | void 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 | //----------------------------------------------------------------------------- | ||
552 | void 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 | //----------------------------------------------------------------------------- | ||
47 | class LLPose | ||
48 | { | ||
49 | friend class LLPoseBlender; | ||
50 | protected: | ||
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; | ||
58 | public: | ||
59 | // Iterate through jointStates | ||
60 | LLJointState *getFirstJointState(); | ||
61 | LLJointState *getNextJointState(); | ||
62 | LLJointState *findJointState(LLJoint *joint); | ||
63 | LLJointState *findJointState(const std::string &name); | ||
64 | public: | ||
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 | |||
83 | const S32 JSB_NUM_JOINT_STATES = 4; | ||
84 | |||
85 | class LLJointStateBlender | ||
86 | { | ||
87 | protected: | ||
88 | LLJointState* mJointStates[JSB_NUM_JOINT_STATES]; | ||
89 | S32 mPriorities[JSB_NUM_JOINT_STATES]; | ||
90 | BOOL mAdditiveBlends[JSB_NUM_JOINT_STATES]; | ||
91 | public: | ||
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 | |||
100 | public: | ||
101 | LLJoint mJointCache; | ||
102 | }; | ||
103 | |||
104 | class LLMotion; | ||
105 | |||
106 | class LLPoseBlender | ||
107 | { | ||
108 | protected: | ||
109 | LLMap<LLJoint*,LLJointStateBlender*> mJointStateBlenderPool; | ||
110 | LLLinkedList<LLJointStateBlender> mActiveBlenders; | ||
111 | |||
112 | S32 mNextPoseSlot; | ||
113 | LLPose mBlendedPose; | ||
114 | public: | ||
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 | |||
35 | U32 LLUniqueID::sNextID = 0; | ||
36 | |||
37 | bool operator==(const LLUniqueID &a, const LLUniqueID &b) | ||
38 | { | ||
39 | return (a.mId == b.mId); | ||
40 | } | ||
41 | |||
42 | bool operator!=(const LLUniqueID &a, const LLUniqueID &b) | ||
43 | { | ||
44 | return (a.mId != b.mId); | ||
45 | } | ||
46 | |||
47 | //----------------------------------------------------------------------------- | ||
48 | // LLStateDiagram | ||
49 | //----------------------------------------------------------------------------- | ||
50 | LLStateDiagram::LLStateDiagram() | ||
51 | { | ||
52 | mUseDefaultState = FALSE; | ||
53 | } | ||
54 | |||
55 | LLStateDiagram::~LLStateDiagram() | ||
56 | { | ||
57 | |||
58 | } | ||
59 | |||
60 | // add a state to the state graph | ||
61 | BOOL LLStateDiagram::addState(LLFSMState *state) | ||
62 | { | ||
63 | mStates[state] = Transitions(); | ||
64 | return TRUE; | ||
65 | } | ||
66 | |||
67 | // add a directed transition between 2 states | ||
68 | BOOL 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 | ||
100 | BOOL 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 | ||
112 | void 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 | ||
118 | LLFSMState* 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 | |||
163 | void LLStateDiagram::setDefaultState(LLFSMState& default_state) | ||
164 | { | ||
165 | mUseDefaultState = TRUE; | ||
166 | mDefaultState = &default_state; | ||
167 | } | ||
168 | |||
169 | S32 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 | |||
183 | BOOL LLStateDiagram::stateIsValid(LLFSMState& state) | ||
184 | { | ||
185 | if (mStates.find(&state) != mStates.end()) | ||
186 | { | ||
187 | return TRUE; | ||
188 | } | ||
189 | return FALSE; | ||
190 | } | ||
191 | |||
192 | LLFSMState* 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 | |||
205 | BOOL 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 | |||
261 | std::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 | |||
298 | LLStateMachine::LLStateMachine() | ||
299 | { | ||
300 | // we haven't received a starting state yet | ||
301 | mCurrentState = NULL; | ||
302 | mLastState = NULL; | ||
303 | mStateDiagram = NULL; | ||
304 | } | ||
305 | |||
306 | LLStateMachine::~LLStateMachine() | ||
307 | { | ||
308 | |||
309 | } | ||
310 | |||
311 | // returns current state | ||
312 | LLFSMState* LLStateMachine::getCurrentState() const | ||
313 | { | ||
314 | return mCurrentState; | ||
315 | } | ||
316 | |||
317 | // executes current state | ||
318 | void LLStateMachine::runCurrentState(void *data) | ||
319 | { | ||
320 | mCurrentState->execute(data); | ||
321 | } | ||
322 | |||
323 | // set current state | ||
324 | BOOL 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 | |||
341 | BOOL 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 | |||
360 | void 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 | |||
394 | void 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 | |||
37 | class LLUniqueID | ||
38 | { | ||
39 | friend bool operator==(const LLUniqueID &a, const LLUniqueID &b); | ||
40 | friend bool operator!=(const LLUniqueID &a, const LLUniqueID &b); | ||
41 | protected: | ||
42 | static U32 sNextID; | ||
43 | U32 mId; | ||
44 | public: | ||
45 | LLUniqueID(){mId = sNextID++;} | ||
46 | virtual ~LLUniqueID(){} | ||
47 | U32 getID() {return mId;} | ||
48 | }; | ||
49 | |||
50 | class LLFSMTransition : public LLUniqueID | ||
51 | { | ||
52 | public: | ||
53 | LLFSMTransition() : LLUniqueID(){}; | ||
54 | virtual std::string getName(){ return "unnamed"; } | ||
55 | }; | ||
56 | |||
57 | class LLFSMState : public LLUniqueID | ||
58 | { | ||
59 | public: | ||
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 | |||
67 | class LLStateDiagram | ||
68 | { | ||
69 | typedef std::map<LLFSMTransition*, LLFSMState*> Transitions; | ||
70 | |||
71 | friend std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM); | ||
72 | friend class LLStateMachine; | ||
73 | |||
74 | protected: | ||
75 | typedef std::map<LLFSMState*, Transitions> StateMap; | ||
76 | StateMap mStates; | ||
77 | Transitions mDefaultTransitions; | ||
78 | LLFSMState* mDefaultState; | ||
79 | BOOL mUseDefaultState; | ||
80 | |||
81 | public: | ||
82 | LLStateDiagram(); | ||
83 | virtual ~LLStateDiagram(); | ||
84 | |||
85 | protected: | ||
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 | |||
113 | public: | ||
114 | // save the graph in a DOT file for rendering and visualization | ||
115 | BOOL saveDotFile(const char* filename); | ||
116 | }; | ||
117 | |||
118 | class LLStateMachine | ||
119 | { | ||
120 | protected: | ||
121 | LLFSMState* mCurrentState; | ||
122 | LLFSMState* mLastState; | ||
123 | LLFSMTransition* mLastTransition; | ||
124 | LLStateDiagram* mStateDiagram; | ||
125 | |||
126 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
41 | const F32 TORSO_TARGET_HALF_LIFE = 0.25f; | ||
42 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
43 | const F32 TARGET_PLANE_THRESHOLD_DOT = 0.6f; | ||
44 | const F32 TORSO_ROT_FRACTION = 0.5f; | ||
45 | |||
46 | //----------------------------------------------------------------------------- | ||
47 | // LLTargetingMotion() | ||
48 | // Class Constructor | ||
49 | //----------------------------------------------------------------------------- | ||
50 | LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id) | ||
51 | { | ||
52 | mCharacter = NULL; | ||
53 | mName = "targeting"; | ||
54 | } | ||
55 | |||
56 | |||
57 | //----------------------------------------------------------------------------- | ||
58 | // ~LLTargetingMotion() | ||
59 | // Class Destructor | ||
60 | //----------------------------------------------------------------------------- | ||
61 | LLTargetingMotion::~LLTargetingMotion() | ||
62 | { | ||
63 | } | ||
64 | |||
65 | //----------------------------------------------------------------------------- | ||
66 | // LLTargetingMotion::onInitialize(LLCharacter *character) | ||
67 | //----------------------------------------------------------------------------- | ||
68 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
98 | BOOL LLTargetingMotion::onActivate() | ||
99 | { | ||
100 | return TRUE; | ||
101 | } | ||
102 | |||
103 | //----------------------------------------------------------------------------- | ||
104 | // LLTargetingMotion::onUpdate() | ||
105 | //----------------------------------------------------------------------------- | ||
106 | BOOL 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 | //----------------------------------------------------------------------------- | ||
165 | void 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 | //----------------------------------------------------------------------------- | ||
45 | class LLTargetingMotion : | ||
46 | public LLMotion | ||
47 | { | ||
48 | public: | ||
49 | // Constructor | ||
50 | LLTargetingMotion(const LLUUID &id); | ||
51 | |||
52 | // Destructor | ||
53 | virtual ~LLTargetingMotion(); | ||
54 | |||
55 | public: | ||
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 | |||
64 | public: | ||
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 | |||
107 | public: | ||
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 | //----------------------------------------------------------------------------- | ||
38 | LLVisualParamInfo::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 | //----------------------------------------------------------------------------- | ||
52 | BOOL 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 | //----------------------------------------------------------------------------- | ||
148 | LLVisualParam::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 | //----------------------------------------------------------------------------- | ||
163 | LLVisualParam::~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 | |||
178 | BOOL 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 | //----------------------------------------------------------------------------- | ||
192 | BOOL 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 | //----------------------------------------------------------------------------- | ||
207 | void 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 | //----------------------------------------------------------------------------- | ||
232 | void 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 | //----------------------------------------------------------------------------- | ||
256 | void LLVisualParam::setNextParam( LLVisualParam *next ) | ||
257 | { | ||
258 | llassert(!mNext); | ||
259 | |||
260 | mNext = next; | ||
261 | } | ||
262 | |||
263 | //----------------------------------------------------------------------------- | ||
264 | // animate() | ||
265 | //----------------------------------------------------------------------------- | ||
266 | void 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 | //----------------------------------------------------------------------------- | ||
278 | void 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 | |||
35 | class LLPolyMesh; | ||
36 | class LLXmlTreeNode; | ||
37 | |||
38 | enum 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 | |||
45 | enum EVisualParamGroup | ||
46 | { | ||
47 | VISUAL_PARAM_GROUP_TWEAKABLE, | ||
48 | VISUAL_PARAM_GROUP_ANIMATABLE, | ||
49 | NUM_VISUAL_PARAM_GROUPS | ||
50 | }; | ||
51 | |||
52 | const S32 MAX_TRANSMITTED_VISUAL_PARAMS = 255; | ||
53 | |||
54 | //----------------------------------------------------------------------------- | ||
55 | // LLVisualParamInfo | ||
56 | // Contains shared data for VisualParams | ||
57 | //----------------------------------------------------------------------------- | ||
58 | class LLVisualParamInfo | ||
59 | { | ||
60 | friend class LLVisualParam; | ||
61 | public: | ||
62 | LLVisualParamInfo(); | ||
63 | virtual ~LLVisualParamInfo() {}; | ||
64 | |||
65 | virtual BOOL parseXml(LLXmlTreeNode *node); | ||
66 | |||
67 | protected: | ||
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 | //----------------------------------------------------------------------------- | ||
87 | class LLVisualParam | ||
88 | { | ||
89 | public: | ||
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 | |||
139 | protected: | ||
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 | ||