diff options
Diffstat (limited to 'indra/llcharacter')
43 files changed, 17066 insertions, 17066 deletions
diff --git a/indra/llcharacter/llanimationstates.cpp b/indra/llcharacter/llanimationstates.cpp index 11c396fa9f..7710589b06 100644 --- a/indra/llcharacter/llanimationstates.cpp +++ b/indra/llcharacter/llanimationstates.cpp @@ -1,495 +1,495 @@ -/**
- * @file llanimationstates.cpp
- * @brief Implementation of animation state related functions.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Agent Animation State
-//-----------------------------------------------------------------------------
-
-#include "linden_common.h"
-
-#include "llanimationstates.h"
-#include "llstring.h"
-
-LLUUID const ANIM_AGENT_AFRAID ("6b61c8e8-4747-0d75-12d7-e49ff207a4ca");
-LLUUID const ANIM_AGENT_AIM_BAZOOKA_R ("b5b4a67d-0aee-30d2-72cd-77b333e932ef");
-LLUUID const ANIM_AGENT_AIM_BOW_L ("46bb4359-de38-4ed8-6a22-f1f52fe8f506");
-LLUUID const ANIM_AGENT_AIM_HANDGUN_R ("3147d815-6338-b932-f011-16b56d9ac18b");
-LLUUID const ANIM_AGENT_AIM_RIFLE_R ("ea633413-8006-180a-c3ba-96dd1d756720");
-LLUUID const ANIM_AGENT_ANGRY ("5747a48e-073e-c331-f6f3-7c2149613d3e");
-LLUUID const ANIM_AGENT_AWAY ("fd037134-85d4-f241-72c6-4f42164fedee");
-LLUUID const ANIM_AGENT_BACKFLIP ("c4ca6188-9127-4f31-0158-23c4e2f93304");
-LLUUID const ANIM_AGENT_BELLY_LAUGH ("18b3a4b5-b463-bd48-e4b6-71eaac76c515");
-LLUUID const ANIM_AGENT_BLOW_KISS ("db84829b-462c-ee83-1e27-9bbee66bd624");
-LLUUID const ANIM_AGENT_BORED ("b906c4ba-703b-1940-32a3-0c7f7d791510");
-LLUUID const ANIM_AGENT_BOW ("82e99230-c906-1403-4d9c-3889dd98daba");
-LLUUID const ANIM_AGENT_BRUSH ("349a3801-54f9-bf2c-3bd0-1ac89772af01");
-LLUUID const ANIM_AGENT_DO_NOT_DISTURB ("efcf670c-2d18-8128-973a-034ebc806b67");
-LLUUID const ANIM_AGENT_CLAP ("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
-LLUUID const ANIM_AGENT_COURTBOW ("9ba1c942-08be-e43a-fb29-16ad440efc50");
-LLUUID const ANIM_AGENT_CROUCH ("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
-LLUUID const ANIM_AGENT_CROUCHWALK ("47f5f6fb-22e5-ae44-f871-73aaaf4a6022");
-LLUUID const ANIM_AGENT_CRY ("92624d3e-1068-f1aa-a5ec-8244585193ed");
-LLUUID const ANIM_AGENT_CUSTOMIZE ("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53");
-LLUUID const ANIM_AGENT_CUSTOMIZE_DONE ("6883a61a-b27b-5914-a61e-dda118a9ee2c");
-LLUUID const ANIM_AGENT_DANCE1 ("b68a3d7c-de9e-fc87-eec8-543d787e5b0d");
-LLUUID const ANIM_AGENT_DANCE2 ("928cae18-e31d-76fd-9cc9-2f55160ff818");
-LLUUID const ANIM_AGENT_DANCE3 ("30047778-10ea-1af7-6881-4db7a3a5a114");
-LLUUID const ANIM_AGENT_DANCE4 ("951469f4-c7b2-c818-9dee-ad7eea8c30b7");
-LLUUID const ANIM_AGENT_DANCE5 ("4bd69a1d-1114-a0b4-625f-84e0a5237155");
-LLUUID const ANIM_AGENT_DANCE6 ("cd28b69b-9c95-bb78-3f94-8d605ff1bb12");
-LLUUID const ANIM_AGENT_DANCE7 ("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6");
-LLUUID const ANIM_AGENT_DANCE8 ("b0dc417c-1f11-af36-2e80-7e7489fa7cdc");
-LLUUID const ANIM_AGENT_DEAD ("57abaae6-1d17-7b1b-5f98-6d11a6411276");
-LLUUID const ANIM_AGENT_DRINK ("0f86e355-dd31-a61c-fdb0-3a96b9aad05f");
-LLUUID const ANIM_AGENT_EMBARRASSED ("514af488-9051-044a-b3fc-d4dbf76377c6");
-LLUUID const ANIM_AGENT_EXPRESS_AFRAID ("aa2df84d-cf8f-7218-527b-424a52de766e");
-LLUUID const ANIM_AGENT_EXPRESS_ANGER ("1a03b575-9634-b62a-5767-3a679e81f4de");
-LLUUID const ANIM_AGENT_EXPRESS_BORED ("214aa6c1-ba6a-4578-f27c-ce7688f61d0d");
-LLUUID const ANIM_AGENT_EXPRESS_CRY ("d535471b-85bf-3b4d-a542-93bea4f59d33");
-LLUUID const ANIM_AGENT_EXPRESS_DISDAIN ("d4416ff1-09d3-300f-4183-1b68a19b9fc1");
-LLUUID const ANIM_AGENT_EXPRESS_EMBARRASSED ("0b8c8211-d78c-33e8-fa28-c51a9594e424");
-LLUUID const ANIM_AGENT_EXPRESS_FROWN ("fee3df48-fa3d-1015-1e26-a205810e3001");
-LLUUID const ANIM_AGENT_EXPRESS_KISS ("1e8d90cc-a84e-e135-884c-7c82c8b03a14");
-LLUUID const ANIM_AGENT_EXPRESS_LAUGH ("62570842-0950-96f8-341c-809e65110823");
-LLUUID const ANIM_AGENT_EXPRESS_OPEN_MOUTH ("d63bc1f9-fc81-9625-a0c6-007176d82eb7");
-LLUUID const ANIM_AGENT_EXPRESS_REPULSED ("f76cda94-41d4-a229-2872-e0296e58afe1");
-LLUUID const ANIM_AGENT_EXPRESS_SAD ("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7");
-LLUUID const ANIM_AGENT_EXPRESS_SHRUG ("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef");
-LLUUID const ANIM_AGENT_EXPRESS_SMILE ("b7c7c833-e3d3-c4e3-9fc0-131237446312");
-LLUUID const ANIM_AGENT_EXPRESS_SURPRISE ("728646d9-cc79-08b2-32d6-937f0a835c24");
-LLUUID const ANIM_AGENT_EXPRESS_TONGUE_OUT ("835965c6-7f2f-bda2-5deb-2478737f91bf");
-LLUUID const ANIM_AGENT_EXPRESS_TOOTHSMILE ("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e");
-LLUUID const ANIM_AGENT_EXPRESS_WINK ("da020525-4d94-59d6-23d7-81fdebf33148");
-LLUUID const ANIM_AGENT_EXPRESS_WORRY ("9c05e5c7-6f07-6ca4-ed5a-b230390c3950");
-LLUUID const ANIM_AGENT_FALLDOWN ("666307d9-a860-572d-6fd4-c3ab8865c094");
-LLUUID const ANIM_AGENT_FEMALE_RUN_NEW ("85995026-eade-5d78-d364-94a64512cb66");
-LLUUID const ANIM_AGENT_FEMALE_WALK ("f5fc7433-043d-e819-8298-f519a119b688");
-LLUUID const ANIM_AGENT_FEMALE_WALK_NEW ("d60c41d2-7c24-7074-d3fa-6101cea22a51");
-LLUUID const ANIM_AGENT_FINGER_WAG ("c1bc7f36-3ba0-d844-f93c-93be945d644f");
-LLUUID const ANIM_AGENT_FIST_PUMP ("7db00ccd-f380-f3ee-439d-61968ec69c8a");
-LLUUID const ANIM_AGENT_FLY ("aec4610c-757f-bc4e-c092-c6e9caf18daf");
-LLUUID const ANIM_AGENT_FLYSLOW ("2b5a38b2-5e00-3a97-a495-4c826bc443e6");
-LLUUID const ANIM_AGENT_HELLO ("9b29cd61-c45b-5689-ded2-91756b8d76a9");
-LLUUID const ANIM_AGENT_HOLD_BAZOOKA_R ("ef62d355-c815-4816-2474-b1acc21094a6");
-LLUUID const ANIM_AGENT_HOLD_BOW_L ("8b102617-bcba-037b-86c1-b76219f90c88");
-LLUUID const ANIM_AGENT_HOLD_HANDGUN_R ("efdc1727-8b8a-c800-4077-975fc27ee2f2");
-LLUUID const ANIM_AGENT_HOLD_RIFLE_R ("3d94bad0-c55b-7dcc-8763-033c59405d33");
-LLUUID const ANIM_AGENT_HOLD_THROW_R ("7570c7b5-1f22-56dd-56ef-a9168241bbb6");
-LLUUID const ANIM_AGENT_HOVER ("4ae8016b-31b9-03bb-c401-b1ea941db41d");
-LLUUID const ANIM_AGENT_HOVER_DOWN ("20f063ea-8306-2562-0b07-5c853b37b31e");
-LLUUID const ANIM_AGENT_HOVER_UP ("62c5de58-cb33-5743-3d07-9e4cd4352864");
-LLUUID const ANIM_AGENT_IMPATIENT ("5ea3991f-c293-392e-6860-91dfa01278a3");
-LLUUID const ANIM_AGENT_JUMP ("2305bd75-1ca9-b03b-1faa-b176b8a8c49e");
-LLUUID const ANIM_AGENT_JUMP_FOR_JOY ("709ea28e-1573-c023-8bf8-520c8bc637fa");
-LLUUID const ANIM_AGENT_KISS_MY_BUTT ("19999406-3a3a-d58c-a2ac-d72e555dcf51");
-LLUUID const ANIM_AGENT_LAND ("7a17b059-12b2-41b1-570a-186368b6aa6f");
-LLUUID const ANIM_AGENT_LAUGH_SHORT ("ca5b3f14-3194-7a2b-c894-aa699b718d1f");
-LLUUID const ANIM_AGENT_MEDIUM_LAND ("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57");
-LLUUID const ANIM_AGENT_MOTORCYCLE_SIT ("08464f78-3a8e-2944-cba5-0c94aff3af29");
-LLUUID const ANIM_AGENT_MUSCLE_BEACH ("315c3a41-a5f3-0ba4-27da-f893f769e69b");
-LLUUID const ANIM_AGENT_NO ("5a977ed9-7f72-44e9-4c4c-6e913df8ae74");
-LLUUID const ANIM_AGENT_NO_UNHAPPY ("d83fa0e5-97ed-7eb2-e798-7bd006215cb4");
-LLUUID const ANIM_AGENT_NYAH_NYAH ("f061723d-0a18-754f-66ee-29a44795a32f");
-LLUUID const ANIM_AGENT_ONETWO_PUNCH ("eefc79be-daae-a239-8c04-890f5d23654a");
-LLUUID const ANIM_AGENT_PEACE ("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9");
-LLUUID const ANIM_AGENT_POINT_ME ("17c024cc-eef2-f6a0-3527-9869876d7752");
-LLUUID const ANIM_AGENT_POINT_YOU ("ec952cca-61ef-aa3b-2789-4d1344f016de");
-LLUUID const ANIM_AGENT_PRE_JUMP ("7a4e87fe-de39-6fcb-6223-024b00893244");
-LLUUID const ANIM_AGENT_PUNCH_LEFT ("f3300ad9-3462-1d07-2044-0fef80062da0");
-LLUUID const ANIM_AGENT_PUNCH_RIGHT ("c8e42d32-7310-6906-c903-cab5d4a34656");
-LLUUID const ANIM_AGENT_REPULSED ("36f81a92-f076-5893-dc4b-7c3795e487cf");
-LLUUID const ANIM_AGENT_ROUNDHOUSE_KICK ("49aea43b-5ac3-8a44-b595-96100af0beda");
-LLUUID const ANIM_AGENT_RPS_COUNTDOWN ("35db4f7e-28c2-6679-cea9-3ee108f7fc7f");
-LLUUID const ANIM_AGENT_RPS_PAPER ("0836b67f-7f7b-f37b-c00a-460dc1521f5a");
-LLUUID const ANIM_AGENT_RPS_ROCK ("42dd95d5-0bc6-6392-f650-777304946c0f");
-LLUUID const ANIM_AGENT_RPS_SCISSORS ("16803a9f-5140-e042-4d7b-d28ba247c325");
-LLUUID const ANIM_AGENT_RUN ("05ddbff8-aaa9-92a1-2b74-8fe77a29b445");
-LLUUID const ANIM_AGENT_RUN_NEW ("1ab1b236-cd08-21e6-0cbc-0d923fc6eca2");
-LLUUID const ANIM_AGENT_SAD ("0eb702e2-cc5a-9a88-56a5-661a55c0676a");
-LLUUID const ANIM_AGENT_SALUTE ("cd7668a6-7011-d7e2-ead8-fc69eff1a104");
-LLUUID const ANIM_AGENT_SHOOT_BOW_L ("e04d450d-fdb5-0432-fd68-818aaf5935f8");
-LLUUID const ANIM_AGENT_SHOUT ("6bd01860-4ebd-127a-bb3d-d1427e8e0c42");
-LLUUID const ANIM_AGENT_SHRUG ("70ea714f-3a97-d742-1b01-590a8fcd1db5");
-LLUUID const ANIM_AGENT_SIT ("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
-LLUUID const ANIM_AGENT_SIT_FEMALE ("b1709c8d-ecd3-54a1-4f28-d55ac0840782");
-LLUUID const ANIM_AGENT_SIT_GENERIC ("245f3c54-f1c0-bf2e-811f-46d8eeb386e7");
-LLUUID const ANIM_AGENT_SIT_GROUND ("1c7600d6-661f-b87b-efe2-d7421eb93c86");
-LLUUID const ANIM_AGENT_SIT_GROUND_CONSTRAINED("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e");
-LLUUID const ANIM_AGENT_SIT_TO_STAND ("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e");
-LLUUID const ANIM_AGENT_SLEEP ("f2bed5f9-9d44-39af-b0cd-257b2a17fe40");
-LLUUID const ANIM_AGENT_SMOKE_IDLE ("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a");
-LLUUID const ANIM_AGENT_SMOKE_INHALE ("6802d553-49da-0778-9f85-1599a2266526");
-LLUUID const ANIM_AGENT_SMOKE_THROW_DOWN ("0a9fb970-8b44-9114-d3a9-bf69cfe804d6");
-LLUUID const ANIM_AGENT_SNAPSHOT ("eae8905b-271a-99e2-4c0e-31106afd100c");
-LLUUID const ANIM_AGENT_STAND ("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f");
-LLUUID const ANIM_AGENT_STANDUP ("3da1d753-028a-5446-24f3-9c9b856d9422");
-LLUUID const ANIM_AGENT_STAND_1 ("15468e00-3400-bb66-cecc-646d7c14458e");
-LLUUID const ANIM_AGENT_STAND_2 ("370f3a20-6ca6-9971-848c-9a01bc42ae3c");
-LLUUID const ANIM_AGENT_STAND_3 ("42b46214-4b44-79ae-deb8-0df61424ff4b");
-LLUUID const ANIM_AGENT_STAND_4 ("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f");
-LLUUID const ANIM_AGENT_STRETCH ("80700431-74ec-a008-14f8-77575e73693f");
-LLUUID const ANIM_AGENT_STRIDE ("1cb562b0-ba21-2202-efb3-30f82cdf9595");
-LLUUID const ANIM_AGENT_SURF ("41426836-7437-7e89-025d-0aa4d10f1d69");
-LLUUID const ANIM_AGENT_SURPRISE ("313b9881-4302-73c0-c7d0-0e7a36b6c224");
-LLUUID const ANIM_AGENT_SWORD_STRIKE ("85428680-6bf9-3e64-b489-6f81087c24bd");
-LLUUID const ANIM_AGENT_TALK ("5c682a95-6da4-a463-0bf6-0f5b7be129d1");
-LLUUID const ANIM_AGENT_TANTRUM ("11000694-3f41-adc2-606b-eee1d66f3724");
-LLUUID const ANIM_AGENT_THROW_R ("aa134404-7dac-7aca-2cba-435f9db875ca");
-LLUUID const ANIM_AGENT_TRYON_SHIRT ("83ff59fe-2346-f236-9009-4e3608af64c1");
-LLUUID const ANIM_AGENT_TURNLEFT ("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135");
-LLUUID const ANIM_AGENT_TURNRIGHT ("2d6daa51-3192-6794-8e2e-a15f8338ec30");
-LLUUID const ANIM_AGENT_TYPE ("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
-LLUUID const ANIM_AGENT_WALK ("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0");
-LLUUID const ANIM_AGENT_WALK_NEW ("33339176-7ddc-9397-94a4-bf3403cbc8f5");
-LLUUID const ANIM_AGENT_WHISPER ("7693f268-06c7-ea71-fa21-2b30d6533f8f");
-LLUUID const ANIM_AGENT_WHISTLE ("b1ed7982-c68e-a982-7561-52a88a5298c0");
-LLUUID const ANIM_AGENT_WINK ("869ecdad-a44b-671e-3266-56aef2e3ac2e");
-LLUUID const ANIM_AGENT_WINK_HOLLYWOOD ("c0c4030f-c02b-49de-24ba-2331f43fe41c");
-LLUUID const ANIM_AGENT_WORRY ("9f496bd2-589a-709f-16cc-69bf7df1d36c");
-LLUUID const ANIM_AGENT_YES ("15dd911d-be82-2856-26db-27659b142875");
-LLUUID const ANIM_AGENT_YES_HAPPY ("b8c8b2a3-9008-1771-3bfc-90924955ab2d");
-LLUUID const ANIM_AGENT_YOGA_FLOAT ("42ecd00b-9947-a97c-400a-bbc9174c7aeb");
-
-LLUUID AGENT_WALK_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_CROUCHWALK, ANIM_AGENT_TURNLEFT, ANIM_AGENT_TURNRIGHT};
-S32 NUM_AGENT_WALK_ANIMS = LL_ARRAY_SIZE(AGENT_WALK_ANIMS);
-
-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};
-S32 NUM_AGENT_GUN_HOLD_ANIMS = LL_ARRAY_SIZE(AGENT_GUN_HOLD_ANIMS);
-
-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};
-S32 NUM_AGENT_GUN_AIM_ANIMS = LL_ARRAY_SIZE(AGENT_GUN_AIM_ANIMS);
-
-LLUUID AGENT_NO_ROTATE_ANIMS[] = {ANIM_AGENT_SIT_GROUND, ANIM_AGENT_SIT_GROUND_CONSTRAINED, ANIM_AGENT_STANDUP};
-S32 NUM_AGENT_NO_ROTATE_ANIMS = LL_ARRAY_SIZE(AGENT_NO_ROTATE_ANIMS);
-
-LLUUID AGENT_STAND_ANIMS[] = {ANIM_AGENT_STAND, ANIM_AGENT_STAND_1, ANIM_AGENT_STAND_2, ANIM_AGENT_STAND_3, ANIM_AGENT_STAND_4};
-S32 NUM_AGENT_STAND_ANIMS = LL_ARRAY_SIZE(AGENT_STAND_ANIMS);
-
-
-LLAnimationLibrary gAnimLibrary;
-
-//-----------------------------------------------------------------------------
-// LLAnimationLibrary()
-//-----------------------------------------------------------------------------
-LLAnimationLibrary::LLAnimationLibrary() :
- mAnimStringTable(16384)
-{
- //add animation names to animmap
- mAnimMap[ANIM_AGENT_AFRAID]= mAnimStringTable.addString("express_afraid");
- mAnimMap[ANIM_AGENT_AIM_BAZOOKA_R]= mAnimStringTable.addString("aim_r_bazooka");
- mAnimMap[ANIM_AGENT_AIM_BOW_L]= mAnimStringTable.addString("aim_l_bow");
- mAnimMap[ANIM_AGENT_AIM_HANDGUN_R]= mAnimStringTable.addString("aim_r_handgun");
- mAnimMap[ANIM_AGENT_AIM_RIFLE_R]= mAnimStringTable.addString("aim_r_rifle");
- mAnimMap[ANIM_AGENT_ANGRY]= mAnimStringTable.addString("express_anger");
- mAnimMap[ANIM_AGENT_AWAY]= mAnimStringTable.addString("away");
- mAnimMap[ANIM_AGENT_BACKFLIP]= mAnimStringTable.addString("backflip");
- mAnimMap[ANIM_AGENT_BELLY_LAUGH]= mAnimStringTable.addString("express_laugh");
- mAnimMap[ANIM_AGENT_BLOW_KISS]= mAnimStringTable.addString("blowkiss");
- mAnimMap[ANIM_AGENT_BORED]= mAnimStringTable.addString("express_bored");
- mAnimMap[ANIM_AGENT_BOW]= mAnimStringTable.addString("bow");
- mAnimMap[ANIM_AGENT_BRUSH]= mAnimStringTable.addString("brush");
- mAnimMap[ANIM_AGENT_DO_NOT_DISTURB]= mAnimStringTable.addString("busy");
- mAnimMap[ANIM_AGENT_CLAP]= mAnimStringTable.addString("clap");
- mAnimMap[ANIM_AGENT_COURTBOW]= mAnimStringTable.addString("courtbow");
- mAnimMap[ANIM_AGENT_CROUCH]= mAnimStringTable.addString("crouch");
- mAnimMap[ANIM_AGENT_CROUCHWALK]= mAnimStringTable.addString("crouchwalk");
- mAnimMap[ANIM_AGENT_CRY]= mAnimStringTable.addString("express_cry");
- mAnimMap[ANIM_AGENT_CUSTOMIZE]= mAnimStringTable.addString("turn_180");
- mAnimMap[ANIM_AGENT_CUSTOMIZE_DONE]= mAnimStringTable.addString("turnback_180");
- mAnimMap[ANIM_AGENT_DANCE1]= mAnimStringTable.addString("dance1");
- mAnimMap[ANIM_AGENT_DANCE2]= mAnimStringTable.addString("dance2");
- mAnimMap[ANIM_AGENT_DANCE3]= mAnimStringTable.addString("dance3");
- mAnimMap[ANIM_AGENT_DANCE4]= mAnimStringTable.addString("dance4");
- mAnimMap[ANIM_AGENT_DANCE5]= mAnimStringTable.addString("dance5");
- mAnimMap[ANIM_AGENT_DANCE6]= mAnimStringTable.addString("dance6");
- mAnimMap[ANIM_AGENT_DANCE7]= mAnimStringTable.addString("dance7");
- mAnimMap[ANIM_AGENT_DANCE8]= mAnimStringTable.addString("dance8");
- mAnimMap[ANIM_AGENT_DEAD]= mAnimStringTable.addString("dead");
- mAnimMap[ANIM_AGENT_DRINK]= mAnimStringTable.addString("drink");
- mAnimMap[ANIM_AGENT_EMBARRASSED]= mAnimStringTable.addString("express_embarrased");
- mAnimMap[ANIM_AGENT_EXPRESS_AFRAID]= mAnimStringTable.addString("express_afraid_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_ANGER]= mAnimStringTable.addString("express_anger_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_BORED]= mAnimStringTable.addString("express_bored_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_CRY]= mAnimStringTable.addString("express_cry_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_DISDAIN]= mAnimStringTable.addString("express_disdain");
- mAnimMap[ANIM_AGENT_EXPRESS_EMBARRASSED]= mAnimStringTable.addString("express_embarrassed_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_FROWN]= mAnimStringTable.addString("express_frown");
- mAnimMap[ANIM_AGENT_EXPRESS_KISS]= mAnimStringTable.addString("express_kiss");
- mAnimMap[ANIM_AGENT_EXPRESS_LAUGH]= mAnimStringTable.addString("express_laugh_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_OPEN_MOUTH]= mAnimStringTable.addString("express_open_mouth");
- mAnimMap[ANIM_AGENT_EXPRESS_REPULSED]= mAnimStringTable.addString("express_repulsed_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_SAD]= mAnimStringTable.addString("express_sad_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_SHRUG]= mAnimStringTable.addString("express_shrug_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_SMILE]= mAnimStringTable.addString("express_smile");
- mAnimMap[ANIM_AGENT_EXPRESS_SURPRISE]= mAnimStringTable.addString("express_surprise_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_TONGUE_OUT]= mAnimStringTable.addString("express_tongue_out");
- mAnimMap[ANIM_AGENT_EXPRESS_TOOTHSMILE]= mAnimStringTable.addString("express_toothsmile");
- mAnimMap[ANIM_AGENT_EXPRESS_WINK]= mAnimStringTable.addString("express_wink_emote");
- mAnimMap[ANIM_AGENT_EXPRESS_WORRY]= mAnimStringTable.addString("express_worry_emote");
- mAnimMap[ANIM_AGENT_FALLDOWN]= mAnimStringTable.addString("falldown");
- mAnimMap[ANIM_AGENT_FEMALE_RUN_NEW]= mAnimStringTable.addString("female_run_new");
- mAnimMap[ANIM_AGENT_FEMALE_WALK]= mAnimStringTable.addString("female_walk");
- mAnimMap[ANIM_AGENT_FEMALE_WALK_NEW]= mAnimStringTable.addString("female_walk_new");
- mAnimMap[ANIM_AGENT_FINGER_WAG]= mAnimStringTable.addString("angry_fingerwag");
- mAnimMap[ANIM_AGENT_FIST_PUMP]= mAnimStringTable.addString("fist_pump");
- mAnimMap[ANIM_AGENT_FLY]= mAnimStringTable.addString("fly");
- mAnimMap[ANIM_AGENT_FLYSLOW]= mAnimStringTable.addString("flyslow");
- mAnimMap[ANIM_AGENT_HELLO]= mAnimStringTable.addString("hello");
- mAnimMap[ANIM_AGENT_HOLD_BAZOOKA_R]= mAnimStringTable.addString("hold_r_bazooka");
- mAnimMap[ANIM_AGENT_HOLD_BOW_L]= mAnimStringTable.addString("hold_l_bow");
- mAnimMap[ANIM_AGENT_HOLD_HANDGUN_R]= mAnimStringTable.addString("hold_r_handgun");
- mAnimMap[ANIM_AGENT_HOLD_RIFLE_R]= mAnimStringTable.addString("hold_r_rifle");
- mAnimMap[ANIM_AGENT_HOLD_THROW_R]= mAnimStringTable.addString("hold_throw_r");
- mAnimMap[ANIM_AGENT_HOVER]= mAnimStringTable.addString("hover");
- mAnimMap[ANIM_AGENT_HOVER_DOWN]= mAnimStringTable.addString("hover_down");
- mAnimMap[ANIM_AGENT_HOVER_UP]= mAnimStringTable.addString("hover_up");
- mAnimMap[ANIM_AGENT_IMPATIENT]= mAnimStringTable.addString("impatient");
- mAnimMap[ANIM_AGENT_JUMP]= mAnimStringTable.addString("jump");
- mAnimMap[ANIM_AGENT_JUMP_FOR_JOY]= mAnimStringTable.addString("jumpforjoy");
- mAnimMap[ANIM_AGENT_KISS_MY_BUTT]= mAnimStringTable.addString("kissmybutt");
- mAnimMap[ANIM_AGENT_LAND]= mAnimStringTable.addString("land");
- mAnimMap[ANIM_AGENT_LAUGH_SHORT]= mAnimStringTable.addString("laugh_short");
- mAnimMap[ANIM_AGENT_MEDIUM_LAND]= mAnimStringTable.addString("soft_land");
- mAnimMap[ANIM_AGENT_MOTORCYCLE_SIT]= mAnimStringTable.addString("motorcycle_sit");
- mAnimMap[ANIM_AGENT_MUSCLE_BEACH]= mAnimStringTable.addString("musclebeach");
- mAnimMap[ANIM_AGENT_NO]= mAnimStringTable.addString("no_head");
- mAnimMap[ANIM_AGENT_NO_UNHAPPY]= mAnimStringTable.addString("no_unhappy");
- mAnimMap[ANIM_AGENT_NYAH_NYAH]= mAnimStringTable.addString("nyanya");
- mAnimMap[ANIM_AGENT_ONETWO_PUNCH]= mAnimStringTable.addString("punch_onetwo");
- mAnimMap[ANIM_AGENT_PEACE]= mAnimStringTable.addString("peace");
- mAnimMap[ANIM_AGENT_POINT_ME]= mAnimStringTable.addString("point_me");
- mAnimMap[ANIM_AGENT_POINT_YOU]= mAnimStringTable.addString("point_you");
- mAnimMap[ANIM_AGENT_PRE_JUMP]= mAnimStringTable.addString("prejump");
- mAnimMap[ANIM_AGENT_PUNCH_LEFT]= mAnimStringTable.addString("punch_l");
- mAnimMap[ANIM_AGENT_PUNCH_RIGHT]= mAnimStringTable.addString("punch_r");
- mAnimMap[ANIM_AGENT_REPULSED]= mAnimStringTable.addString("express_repulsed");
- mAnimMap[ANIM_AGENT_ROUNDHOUSE_KICK]= mAnimStringTable.addString("kick_roundhouse_r");
- mAnimMap[ANIM_AGENT_RPS_COUNTDOWN]= mAnimStringTable.addString("rps_countdown");
- mAnimMap[ANIM_AGENT_RPS_PAPER]= mAnimStringTable.addString("rps_paper");
- mAnimMap[ANIM_AGENT_RPS_ROCK]= mAnimStringTable.addString("rps_rock");
- mAnimMap[ANIM_AGENT_RPS_SCISSORS]= mAnimStringTable.addString("rps_scissors");
- mAnimMap[ANIM_AGENT_RUN]= mAnimStringTable.addString("run");
- mAnimMap[ANIM_AGENT_RUN_NEW]= mAnimStringTable.addString("run_new");
- mAnimMap[ANIM_AGENT_SAD]= mAnimStringTable.addString("express_sad");
- mAnimMap[ANIM_AGENT_SALUTE]= mAnimStringTable.addString("salute");
- mAnimMap[ANIM_AGENT_SHOOT_BOW_L]= mAnimStringTable.addString("shoot_l_bow");
- mAnimMap[ANIM_AGENT_SHOUT]= mAnimStringTable.addString("shout");
- mAnimMap[ANIM_AGENT_SHRUG]= mAnimStringTable.addString("express_shrug");
- mAnimMap[ANIM_AGENT_SIT]= mAnimStringTable.addString("sit");
- mAnimMap[ANIM_AGENT_SIT_FEMALE]= mAnimStringTable.addString("sit_female");
- mAnimMap[ANIM_AGENT_SIT_GROUND]= mAnimStringTable.addString("sit_ground");
- mAnimMap[ANIM_AGENT_SIT_GROUND_CONSTRAINED]= mAnimStringTable.addString("sit_ground_constrained");
- mAnimMap[ANIM_AGENT_SIT_GENERIC]= mAnimStringTable.addString("sit_generic");
- mAnimMap[ANIM_AGENT_SIT_TO_STAND]= mAnimStringTable.addString("sit_to_stand");
- mAnimMap[ANIM_AGENT_SLEEP]= mAnimStringTable.addString("sleep");
- mAnimMap[ANIM_AGENT_SMOKE_IDLE]= mAnimStringTable.addString("smoke_idle");
- mAnimMap[ANIM_AGENT_SMOKE_INHALE]= mAnimStringTable.addString("smoke_inhale");
- mAnimMap[ANIM_AGENT_SMOKE_THROW_DOWN]= mAnimStringTable.addString("smoke_throw_down");
- mAnimMap[ANIM_AGENT_SNAPSHOT]= mAnimStringTable.addString("snapshot");
- mAnimMap[ANIM_AGENT_STAND]= mAnimStringTable.addString("stand");
- mAnimMap[ANIM_AGENT_STANDUP]= mAnimStringTable.addString("standup");
- mAnimMap[ANIM_AGENT_STAND_1]= mAnimStringTable.addString("stand_1");
- mAnimMap[ANIM_AGENT_STAND_2]= mAnimStringTable.addString("stand_2");
- mAnimMap[ANIM_AGENT_STAND_3]= mAnimStringTable.addString("stand_3");
- mAnimMap[ANIM_AGENT_STAND_4]= mAnimStringTable.addString("stand_4");
- mAnimMap[ANIM_AGENT_STRETCH]= mAnimStringTable.addString("stretch");
- mAnimMap[ANIM_AGENT_STRIDE]= mAnimStringTable.addString("stride");
- mAnimMap[ANIM_AGENT_SURF]= mAnimStringTable.addString("surf");
- mAnimMap[ANIM_AGENT_SURPRISE]= mAnimStringTable.addString("express_surprise");
- mAnimMap[ANIM_AGENT_SWORD_STRIKE]= mAnimStringTable.addString("sword_strike_r");
- mAnimMap[ANIM_AGENT_TALK]= mAnimStringTable.addString("talk");
- mAnimMap[ANIM_AGENT_TANTRUM]= mAnimStringTable.addString("angry_tantrum");
- mAnimMap[ANIM_AGENT_THROW_R]= mAnimStringTable.addString("throw_r");
- mAnimMap[ANIM_AGENT_TRYON_SHIRT]= mAnimStringTable.addString("tryon_shirt");
- mAnimMap[ANIM_AGENT_TURNLEFT]= mAnimStringTable.addString("turnleft");
- mAnimMap[ANIM_AGENT_TURNRIGHT]= mAnimStringTable.addString("turnright");
- mAnimMap[ANIM_AGENT_TYPE]= mAnimStringTable.addString("type");
- mAnimMap[ANIM_AGENT_WALK]= mAnimStringTable.addString("walk");
- mAnimMap[ANIM_AGENT_WALK_NEW]= mAnimStringTable.addString("walk_new");
- mAnimMap[ANIM_AGENT_WHISPER]= mAnimStringTable.addString("whisper");
- mAnimMap[ANIM_AGENT_WHISTLE]= mAnimStringTable.addString("whistle");
- mAnimMap[ANIM_AGENT_WINK]= mAnimStringTable.addString("express_wink");
- mAnimMap[ANIM_AGENT_WINK_HOLLYWOOD]= mAnimStringTable.addString("wink_hollywood");
- mAnimMap[ANIM_AGENT_WORRY]= mAnimStringTable.addString("express_worry");
- mAnimMap[ANIM_AGENT_YES]= mAnimStringTable.addString("yes_head");
- mAnimMap[ANIM_AGENT_YES_HAPPY]= mAnimStringTable.addString("yes_happy");
- mAnimMap[ANIM_AGENT_YOGA_FLOAT]= mAnimStringTable.addString("yoga_float");
-}
-
-//-----------------------------------------------------------------------------
-// ~LLAnimationLibrary()
-//-----------------------------------------------------------------------------
-LLAnimationLibrary::~LLAnimationLibrary()
-{
-}
-
-//-----------------------------------------------------------------------------
-// Return the text name of an animation state
-//-----------------------------------------------------------------------------
-const char *LLAnimationLibrary::animStateToString( const LLUUID& state )
-{
- if (state.isNull())
- {
- return NULL;
- }
- if (mAnimMap.count(state))
- {
- return mAnimMap[state];
- }
-
- return NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// Return the animation state for a given name
-//-----------------------------------------------------------------------------
-LLUUID LLAnimationLibrary::stringToAnimState( const std::string& name, bool allow_ids )
-{
- std::string lower_case_name(name);
- LLStringUtil::toLower(lower_case_name);
-
- char *true_name = mAnimStringTable.checkString(lower_case_name.c_str());
-
- LLUUID id;
- id.setNull();
-
- if (true_name)
- {
- for (anim_map_t::value_type& anim_pair : mAnimMap)
- {
- if (anim_pair.second == true_name)
- {
- id = anim_pair.first;
- break;
- }
- }
- }
- else if (allow_ids)
- {
- // try to convert string to LLUUID
- id.set(name, false);
- }
-
- return id;
-}
-
-//-----------------------------------------------------------------------------
-// Associate an anim state with a name
-//-----------------------------------------------------------------------------
-void LLAnimationLibrary::animStateSetString( const LLUUID& state, const std::string& name)
-{
- mAnimMap[state] = mAnimStringTable.addString(name);
-}
-
-std::string LLAnimationLibrary::animationName( const LLUUID& id ) const
-{
- const char *cptr = gAnimLibrary.animStateToString(id);
- if (cptr)
- return std::string(cptr);
- else
- return std::string("[") + id.asString() + std::string("]");
-}
-
-// Animation states that the user can trigger as part of a gesture
-// See struct LLAnimStateEntry in header for label location information
-const LLAnimStateEntry gUserAnimStates[] = {
- LLAnimStateEntry("express_afraid", ANIM_AGENT_AFRAID),
- LLAnimStateEntry("express_anger", ANIM_AGENT_ANGRY),
- LLAnimStateEntry("away", ANIM_AGENT_AWAY),
- LLAnimStateEntry("backflip", ANIM_AGENT_BACKFLIP),
- LLAnimStateEntry("express_laugh", ANIM_AGENT_BELLY_LAUGH),
- LLAnimStateEntry("express_toothsmile", ANIM_AGENT_EXPRESS_TOOTHSMILE),
- LLAnimStateEntry("blowkiss", ANIM_AGENT_BLOW_KISS),
- LLAnimStateEntry("express_bored", ANIM_AGENT_BORED),
- LLAnimStateEntry("bow", ANIM_AGENT_BOW),
- LLAnimStateEntry("clap", ANIM_AGENT_CLAP),
- LLAnimStateEntry("courtbow", ANIM_AGENT_COURTBOW),
- LLAnimStateEntry("express_cry", ANIM_AGENT_CRY),
- LLAnimStateEntry("dance1", ANIM_AGENT_DANCE1),
- LLAnimStateEntry("dance2", ANIM_AGENT_DANCE2),
- LLAnimStateEntry("dance3", ANIM_AGENT_DANCE3),
- LLAnimStateEntry("dance4", ANIM_AGENT_DANCE4),
- LLAnimStateEntry("dance5", ANIM_AGENT_DANCE5),
- LLAnimStateEntry("dance6", ANIM_AGENT_DANCE6),
- LLAnimStateEntry("dance7", ANIM_AGENT_DANCE7),
- LLAnimStateEntry("dance8", ANIM_AGENT_DANCE8),
- LLAnimStateEntry("express_disdain", ANIM_AGENT_EXPRESS_DISDAIN),
- LLAnimStateEntry("drink", ANIM_AGENT_DRINK),
- LLAnimStateEntry("express_embarrased", ANIM_AGENT_EMBARRASSED),
- LLAnimStateEntry("angry_fingerwag", ANIM_AGENT_FINGER_WAG),
- LLAnimStateEntry("fist_pump", ANIM_AGENT_FIST_PUMP),
- LLAnimStateEntry("yoga_float", ANIM_AGENT_YOGA_FLOAT),
- LLAnimStateEntry("express_frown", ANIM_AGENT_EXPRESS_FROWN),
- LLAnimStateEntry("impatient", ANIM_AGENT_IMPATIENT),
- LLAnimStateEntry("jumpforjoy", ANIM_AGENT_JUMP_FOR_JOY),
- LLAnimStateEntry("kissmybutt", ANIM_AGENT_KISS_MY_BUTT),
- LLAnimStateEntry("express_kiss", ANIM_AGENT_EXPRESS_KISS),
- LLAnimStateEntry("laugh_short", ANIM_AGENT_LAUGH_SHORT),
- LLAnimStateEntry("musclebeach", ANIM_AGENT_MUSCLE_BEACH),
- LLAnimStateEntry("no_unhappy", ANIM_AGENT_NO_UNHAPPY),
- LLAnimStateEntry("no_head", ANIM_AGENT_NO),
- LLAnimStateEntry("nyanya", ANIM_AGENT_NYAH_NYAH),
- LLAnimStateEntry("punch_onetwo", ANIM_AGENT_ONETWO_PUNCH),
- LLAnimStateEntry("express_open_mouth", ANIM_AGENT_EXPRESS_OPEN_MOUTH),
- LLAnimStateEntry("peace", ANIM_AGENT_PEACE),
- LLAnimStateEntry("point_you", ANIM_AGENT_POINT_YOU),
- LLAnimStateEntry("point_me", ANIM_AGENT_POINT_ME),
- LLAnimStateEntry("punch_l", ANIM_AGENT_PUNCH_LEFT),
- LLAnimStateEntry("punch_r", ANIM_AGENT_PUNCH_RIGHT),
- LLAnimStateEntry("rps_countdown", ANIM_AGENT_RPS_COUNTDOWN),
- LLAnimStateEntry("rps_paper", ANIM_AGENT_RPS_PAPER),
- LLAnimStateEntry("rps_rock", ANIM_AGENT_RPS_ROCK),
- LLAnimStateEntry("rps_scissors", ANIM_AGENT_RPS_SCISSORS),
- LLAnimStateEntry("express_repulsed", ANIM_AGENT_EXPRESS_REPULSED),
- LLAnimStateEntry("kick_roundhouse_r", ANIM_AGENT_ROUNDHOUSE_KICK),
- LLAnimStateEntry("express_sad", ANIM_AGENT_SAD),
- LLAnimStateEntry("salute", ANIM_AGENT_SALUTE),
- LLAnimStateEntry("shout", ANIM_AGENT_SHOUT),
- LLAnimStateEntry("express_shrug", ANIM_AGENT_SHRUG),
- LLAnimStateEntry("express_smile", ANIM_AGENT_EXPRESS_SMILE),
- LLAnimStateEntry("smoke_idle", ANIM_AGENT_SMOKE_IDLE),
- LLAnimStateEntry("smoke_inhale", ANIM_AGENT_SMOKE_INHALE),
- LLAnimStateEntry("smoke_throw_down", ANIM_AGENT_SMOKE_THROW_DOWN),
- LLAnimStateEntry("express_surprise", ANIM_AGENT_SURPRISE),
- LLAnimStateEntry("sword_strike_r", ANIM_AGENT_SWORD_STRIKE),
- LLAnimStateEntry("angry_tantrum", ANIM_AGENT_TANTRUM),
- LLAnimStateEntry("express_tongue_out", ANIM_AGENT_EXPRESS_TONGUE_OUT),
- LLAnimStateEntry("hello", ANIM_AGENT_HELLO),
- LLAnimStateEntry("whisper", ANIM_AGENT_WHISPER),
- LLAnimStateEntry("whistle", ANIM_AGENT_WHISTLE),
- LLAnimStateEntry("express_wink", ANIM_AGENT_WINK),
- LLAnimStateEntry("wink_hollywood", ANIM_AGENT_WINK_HOLLYWOOD),
- LLAnimStateEntry("express_worry", ANIM_AGENT_EXPRESS_WORRY),
- LLAnimStateEntry("yes_happy", ANIM_AGENT_YES_HAPPY),
- LLAnimStateEntry("yes_head", ANIM_AGENT_YES),
-};
-
-const S32 gUserAnimStatesCount = LL_ARRAY_SIZE(gUserAnimStates);
-
-
-// End
-
+/** + * @file llanimationstates.cpp + * @brief Implementation of animation state related functions. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Agent Animation State +//----------------------------------------------------------------------------- + +#include "linden_common.h" + +#include "llanimationstates.h" +#include "llstring.h" + +LLUUID const ANIM_AGENT_AFRAID ("6b61c8e8-4747-0d75-12d7-e49ff207a4ca"); +LLUUID const ANIM_AGENT_AIM_BAZOOKA_R ("b5b4a67d-0aee-30d2-72cd-77b333e932ef"); +LLUUID const ANIM_AGENT_AIM_BOW_L ("46bb4359-de38-4ed8-6a22-f1f52fe8f506"); +LLUUID const ANIM_AGENT_AIM_HANDGUN_R ("3147d815-6338-b932-f011-16b56d9ac18b"); +LLUUID const ANIM_AGENT_AIM_RIFLE_R ("ea633413-8006-180a-c3ba-96dd1d756720"); +LLUUID const ANIM_AGENT_ANGRY ("5747a48e-073e-c331-f6f3-7c2149613d3e"); +LLUUID const ANIM_AGENT_AWAY ("fd037134-85d4-f241-72c6-4f42164fedee"); +LLUUID const ANIM_AGENT_BACKFLIP ("c4ca6188-9127-4f31-0158-23c4e2f93304"); +LLUUID const ANIM_AGENT_BELLY_LAUGH ("18b3a4b5-b463-bd48-e4b6-71eaac76c515"); +LLUUID const ANIM_AGENT_BLOW_KISS ("db84829b-462c-ee83-1e27-9bbee66bd624"); +LLUUID const ANIM_AGENT_BORED ("b906c4ba-703b-1940-32a3-0c7f7d791510"); +LLUUID const ANIM_AGENT_BOW ("82e99230-c906-1403-4d9c-3889dd98daba"); +LLUUID const ANIM_AGENT_BRUSH ("349a3801-54f9-bf2c-3bd0-1ac89772af01"); +LLUUID const ANIM_AGENT_DO_NOT_DISTURB ("efcf670c-2d18-8128-973a-034ebc806b67"); +LLUUID const ANIM_AGENT_CLAP ("9b0c1c4e-8ac7-7969-1494-28c874c4f668"); +LLUUID const ANIM_AGENT_COURTBOW ("9ba1c942-08be-e43a-fb29-16ad440efc50"); +LLUUID const ANIM_AGENT_CROUCH ("201f3fdf-cb1f-dbec-201f-7333e328ae7c"); +LLUUID const ANIM_AGENT_CROUCHWALK ("47f5f6fb-22e5-ae44-f871-73aaaf4a6022"); +LLUUID const ANIM_AGENT_CRY ("92624d3e-1068-f1aa-a5ec-8244585193ed"); +LLUUID const ANIM_AGENT_CUSTOMIZE ("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53"); +LLUUID const ANIM_AGENT_CUSTOMIZE_DONE ("6883a61a-b27b-5914-a61e-dda118a9ee2c"); +LLUUID const ANIM_AGENT_DANCE1 ("b68a3d7c-de9e-fc87-eec8-543d787e5b0d"); +LLUUID const ANIM_AGENT_DANCE2 ("928cae18-e31d-76fd-9cc9-2f55160ff818"); +LLUUID const ANIM_AGENT_DANCE3 ("30047778-10ea-1af7-6881-4db7a3a5a114"); +LLUUID const ANIM_AGENT_DANCE4 ("951469f4-c7b2-c818-9dee-ad7eea8c30b7"); +LLUUID const ANIM_AGENT_DANCE5 ("4bd69a1d-1114-a0b4-625f-84e0a5237155"); +LLUUID const ANIM_AGENT_DANCE6 ("cd28b69b-9c95-bb78-3f94-8d605ff1bb12"); +LLUUID const ANIM_AGENT_DANCE7 ("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6"); +LLUUID const ANIM_AGENT_DANCE8 ("b0dc417c-1f11-af36-2e80-7e7489fa7cdc"); +LLUUID const ANIM_AGENT_DEAD ("57abaae6-1d17-7b1b-5f98-6d11a6411276"); +LLUUID const ANIM_AGENT_DRINK ("0f86e355-dd31-a61c-fdb0-3a96b9aad05f"); +LLUUID const ANIM_AGENT_EMBARRASSED ("514af488-9051-044a-b3fc-d4dbf76377c6"); +LLUUID const ANIM_AGENT_EXPRESS_AFRAID ("aa2df84d-cf8f-7218-527b-424a52de766e"); +LLUUID const ANIM_AGENT_EXPRESS_ANGER ("1a03b575-9634-b62a-5767-3a679e81f4de"); +LLUUID const ANIM_AGENT_EXPRESS_BORED ("214aa6c1-ba6a-4578-f27c-ce7688f61d0d"); +LLUUID const ANIM_AGENT_EXPRESS_CRY ("d535471b-85bf-3b4d-a542-93bea4f59d33"); +LLUUID const ANIM_AGENT_EXPRESS_DISDAIN ("d4416ff1-09d3-300f-4183-1b68a19b9fc1"); +LLUUID const ANIM_AGENT_EXPRESS_EMBARRASSED ("0b8c8211-d78c-33e8-fa28-c51a9594e424"); +LLUUID const ANIM_AGENT_EXPRESS_FROWN ("fee3df48-fa3d-1015-1e26-a205810e3001"); +LLUUID const ANIM_AGENT_EXPRESS_KISS ("1e8d90cc-a84e-e135-884c-7c82c8b03a14"); +LLUUID const ANIM_AGENT_EXPRESS_LAUGH ("62570842-0950-96f8-341c-809e65110823"); +LLUUID const ANIM_AGENT_EXPRESS_OPEN_MOUTH ("d63bc1f9-fc81-9625-a0c6-007176d82eb7"); +LLUUID const ANIM_AGENT_EXPRESS_REPULSED ("f76cda94-41d4-a229-2872-e0296e58afe1"); +LLUUID const ANIM_AGENT_EXPRESS_SAD ("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7"); +LLUUID const ANIM_AGENT_EXPRESS_SHRUG ("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef"); +LLUUID const ANIM_AGENT_EXPRESS_SMILE ("b7c7c833-e3d3-c4e3-9fc0-131237446312"); +LLUUID const ANIM_AGENT_EXPRESS_SURPRISE ("728646d9-cc79-08b2-32d6-937f0a835c24"); +LLUUID const ANIM_AGENT_EXPRESS_TONGUE_OUT ("835965c6-7f2f-bda2-5deb-2478737f91bf"); +LLUUID const ANIM_AGENT_EXPRESS_TOOTHSMILE ("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e"); +LLUUID const ANIM_AGENT_EXPRESS_WINK ("da020525-4d94-59d6-23d7-81fdebf33148"); +LLUUID const ANIM_AGENT_EXPRESS_WORRY ("9c05e5c7-6f07-6ca4-ed5a-b230390c3950"); +LLUUID const ANIM_AGENT_FALLDOWN ("666307d9-a860-572d-6fd4-c3ab8865c094"); +LLUUID const ANIM_AGENT_FEMALE_RUN_NEW ("85995026-eade-5d78-d364-94a64512cb66"); +LLUUID const ANIM_AGENT_FEMALE_WALK ("f5fc7433-043d-e819-8298-f519a119b688"); +LLUUID const ANIM_AGENT_FEMALE_WALK_NEW ("d60c41d2-7c24-7074-d3fa-6101cea22a51"); +LLUUID const ANIM_AGENT_FINGER_WAG ("c1bc7f36-3ba0-d844-f93c-93be945d644f"); +LLUUID const ANIM_AGENT_FIST_PUMP ("7db00ccd-f380-f3ee-439d-61968ec69c8a"); +LLUUID const ANIM_AGENT_FLY ("aec4610c-757f-bc4e-c092-c6e9caf18daf"); +LLUUID const ANIM_AGENT_FLYSLOW ("2b5a38b2-5e00-3a97-a495-4c826bc443e6"); +LLUUID const ANIM_AGENT_HELLO ("9b29cd61-c45b-5689-ded2-91756b8d76a9"); +LLUUID const ANIM_AGENT_HOLD_BAZOOKA_R ("ef62d355-c815-4816-2474-b1acc21094a6"); +LLUUID const ANIM_AGENT_HOLD_BOW_L ("8b102617-bcba-037b-86c1-b76219f90c88"); +LLUUID const ANIM_AGENT_HOLD_HANDGUN_R ("efdc1727-8b8a-c800-4077-975fc27ee2f2"); +LLUUID const ANIM_AGENT_HOLD_RIFLE_R ("3d94bad0-c55b-7dcc-8763-033c59405d33"); +LLUUID const ANIM_AGENT_HOLD_THROW_R ("7570c7b5-1f22-56dd-56ef-a9168241bbb6"); +LLUUID const ANIM_AGENT_HOVER ("4ae8016b-31b9-03bb-c401-b1ea941db41d"); +LLUUID const ANIM_AGENT_HOVER_DOWN ("20f063ea-8306-2562-0b07-5c853b37b31e"); +LLUUID const ANIM_AGENT_HOVER_UP ("62c5de58-cb33-5743-3d07-9e4cd4352864"); +LLUUID const ANIM_AGENT_IMPATIENT ("5ea3991f-c293-392e-6860-91dfa01278a3"); +LLUUID const ANIM_AGENT_JUMP ("2305bd75-1ca9-b03b-1faa-b176b8a8c49e"); +LLUUID const ANIM_AGENT_JUMP_FOR_JOY ("709ea28e-1573-c023-8bf8-520c8bc637fa"); +LLUUID const ANIM_AGENT_KISS_MY_BUTT ("19999406-3a3a-d58c-a2ac-d72e555dcf51"); +LLUUID const ANIM_AGENT_LAND ("7a17b059-12b2-41b1-570a-186368b6aa6f"); +LLUUID const ANIM_AGENT_LAUGH_SHORT ("ca5b3f14-3194-7a2b-c894-aa699b718d1f"); +LLUUID const ANIM_AGENT_MEDIUM_LAND ("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57"); +LLUUID const ANIM_AGENT_MOTORCYCLE_SIT ("08464f78-3a8e-2944-cba5-0c94aff3af29"); +LLUUID const ANIM_AGENT_MUSCLE_BEACH ("315c3a41-a5f3-0ba4-27da-f893f769e69b"); +LLUUID const ANIM_AGENT_NO ("5a977ed9-7f72-44e9-4c4c-6e913df8ae74"); +LLUUID const ANIM_AGENT_NO_UNHAPPY ("d83fa0e5-97ed-7eb2-e798-7bd006215cb4"); +LLUUID const ANIM_AGENT_NYAH_NYAH ("f061723d-0a18-754f-66ee-29a44795a32f"); +LLUUID const ANIM_AGENT_ONETWO_PUNCH ("eefc79be-daae-a239-8c04-890f5d23654a"); +LLUUID const ANIM_AGENT_PEACE ("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9"); +LLUUID const ANIM_AGENT_POINT_ME ("17c024cc-eef2-f6a0-3527-9869876d7752"); +LLUUID const ANIM_AGENT_POINT_YOU ("ec952cca-61ef-aa3b-2789-4d1344f016de"); +LLUUID const ANIM_AGENT_PRE_JUMP ("7a4e87fe-de39-6fcb-6223-024b00893244"); +LLUUID const ANIM_AGENT_PUNCH_LEFT ("f3300ad9-3462-1d07-2044-0fef80062da0"); +LLUUID const ANIM_AGENT_PUNCH_RIGHT ("c8e42d32-7310-6906-c903-cab5d4a34656"); +LLUUID const ANIM_AGENT_REPULSED ("36f81a92-f076-5893-dc4b-7c3795e487cf"); +LLUUID const ANIM_AGENT_ROUNDHOUSE_KICK ("49aea43b-5ac3-8a44-b595-96100af0beda"); +LLUUID const ANIM_AGENT_RPS_COUNTDOWN ("35db4f7e-28c2-6679-cea9-3ee108f7fc7f"); +LLUUID const ANIM_AGENT_RPS_PAPER ("0836b67f-7f7b-f37b-c00a-460dc1521f5a"); +LLUUID const ANIM_AGENT_RPS_ROCK ("42dd95d5-0bc6-6392-f650-777304946c0f"); +LLUUID const ANIM_AGENT_RPS_SCISSORS ("16803a9f-5140-e042-4d7b-d28ba247c325"); +LLUUID const ANIM_AGENT_RUN ("05ddbff8-aaa9-92a1-2b74-8fe77a29b445"); +LLUUID const ANIM_AGENT_RUN_NEW ("1ab1b236-cd08-21e6-0cbc-0d923fc6eca2"); +LLUUID const ANIM_AGENT_SAD ("0eb702e2-cc5a-9a88-56a5-661a55c0676a"); +LLUUID const ANIM_AGENT_SALUTE ("cd7668a6-7011-d7e2-ead8-fc69eff1a104"); +LLUUID const ANIM_AGENT_SHOOT_BOW_L ("e04d450d-fdb5-0432-fd68-818aaf5935f8"); +LLUUID const ANIM_AGENT_SHOUT ("6bd01860-4ebd-127a-bb3d-d1427e8e0c42"); +LLUUID const ANIM_AGENT_SHRUG ("70ea714f-3a97-d742-1b01-590a8fcd1db5"); +LLUUID const ANIM_AGENT_SIT ("1a5fe8ac-a804-8a5d-7cbd-56bd83184568"); +LLUUID const ANIM_AGENT_SIT_FEMALE ("b1709c8d-ecd3-54a1-4f28-d55ac0840782"); +LLUUID const ANIM_AGENT_SIT_GENERIC ("245f3c54-f1c0-bf2e-811f-46d8eeb386e7"); +LLUUID const ANIM_AGENT_SIT_GROUND ("1c7600d6-661f-b87b-efe2-d7421eb93c86"); +LLUUID const ANIM_AGENT_SIT_GROUND_CONSTRAINED("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e"); +LLUUID const ANIM_AGENT_SIT_TO_STAND ("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e"); +LLUUID const ANIM_AGENT_SLEEP ("f2bed5f9-9d44-39af-b0cd-257b2a17fe40"); +LLUUID const ANIM_AGENT_SMOKE_IDLE ("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a"); +LLUUID const ANIM_AGENT_SMOKE_INHALE ("6802d553-49da-0778-9f85-1599a2266526"); +LLUUID const ANIM_AGENT_SMOKE_THROW_DOWN ("0a9fb970-8b44-9114-d3a9-bf69cfe804d6"); +LLUUID const ANIM_AGENT_SNAPSHOT ("eae8905b-271a-99e2-4c0e-31106afd100c"); +LLUUID const ANIM_AGENT_STAND ("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f"); +LLUUID const ANIM_AGENT_STANDUP ("3da1d753-028a-5446-24f3-9c9b856d9422"); +LLUUID const ANIM_AGENT_STAND_1 ("15468e00-3400-bb66-cecc-646d7c14458e"); +LLUUID const ANIM_AGENT_STAND_2 ("370f3a20-6ca6-9971-848c-9a01bc42ae3c"); +LLUUID const ANIM_AGENT_STAND_3 ("42b46214-4b44-79ae-deb8-0df61424ff4b"); +LLUUID const ANIM_AGENT_STAND_4 ("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f"); +LLUUID const ANIM_AGENT_STRETCH ("80700431-74ec-a008-14f8-77575e73693f"); +LLUUID const ANIM_AGENT_STRIDE ("1cb562b0-ba21-2202-efb3-30f82cdf9595"); +LLUUID const ANIM_AGENT_SURF ("41426836-7437-7e89-025d-0aa4d10f1d69"); +LLUUID const ANIM_AGENT_SURPRISE ("313b9881-4302-73c0-c7d0-0e7a36b6c224"); +LLUUID const ANIM_AGENT_SWORD_STRIKE ("85428680-6bf9-3e64-b489-6f81087c24bd"); +LLUUID const ANIM_AGENT_TALK ("5c682a95-6da4-a463-0bf6-0f5b7be129d1"); +LLUUID const ANIM_AGENT_TANTRUM ("11000694-3f41-adc2-606b-eee1d66f3724"); +LLUUID const ANIM_AGENT_THROW_R ("aa134404-7dac-7aca-2cba-435f9db875ca"); +LLUUID const ANIM_AGENT_TRYON_SHIRT ("83ff59fe-2346-f236-9009-4e3608af64c1"); +LLUUID const ANIM_AGENT_TURNLEFT ("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135"); +LLUUID const ANIM_AGENT_TURNRIGHT ("2d6daa51-3192-6794-8e2e-a15f8338ec30"); +LLUUID const ANIM_AGENT_TYPE ("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9"); +LLUUID const ANIM_AGENT_WALK ("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0"); +LLUUID const ANIM_AGENT_WALK_NEW ("33339176-7ddc-9397-94a4-bf3403cbc8f5"); +LLUUID const ANIM_AGENT_WHISPER ("7693f268-06c7-ea71-fa21-2b30d6533f8f"); +LLUUID const ANIM_AGENT_WHISTLE ("b1ed7982-c68e-a982-7561-52a88a5298c0"); +LLUUID const ANIM_AGENT_WINK ("869ecdad-a44b-671e-3266-56aef2e3ac2e"); +LLUUID const ANIM_AGENT_WINK_HOLLYWOOD ("c0c4030f-c02b-49de-24ba-2331f43fe41c"); +LLUUID const ANIM_AGENT_WORRY ("9f496bd2-589a-709f-16cc-69bf7df1d36c"); +LLUUID const ANIM_AGENT_YES ("15dd911d-be82-2856-26db-27659b142875"); +LLUUID const ANIM_AGENT_YES_HAPPY ("b8c8b2a3-9008-1771-3bfc-90924955ab2d"); +LLUUID const ANIM_AGENT_YOGA_FLOAT ("42ecd00b-9947-a97c-400a-bbc9174c7aeb"); + +LLUUID AGENT_WALK_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_CROUCHWALK, ANIM_AGENT_TURNLEFT, ANIM_AGENT_TURNRIGHT}; +S32 NUM_AGENT_WALK_ANIMS = LL_ARRAY_SIZE(AGENT_WALK_ANIMS); + +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}; +S32 NUM_AGENT_GUN_HOLD_ANIMS = LL_ARRAY_SIZE(AGENT_GUN_HOLD_ANIMS); + +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}; +S32 NUM_AGENT_GUN_AIM_ANIMS = LL_ARRAY_SIZE(AGENT_GUN_AIM_ANIMS); + +LLUUID AGENT_NO_ROTATE_ANIMS[] = {ANIM_AGENT_SIT_GROUND, ANIM_AGENT_SIT_GROUND_CONSTRAINED, ANIM_AGENT_STANDUP}; +S32 NUM_AGENT_NO_ROTATE_ANIMS = LL_ARRAY_SIZE(AGENT_NO_ROTATE_ANIMS); + +LLUUID AGENT_STAND_ANIMS[] = {ANIM_AGENT_STAND, ANIM_AGENT_STAND_1, ANIM_AGENT_STAND_2, ANIM_AGENT_STAND_3, ANIM_AGENT_STAND_4}; +S32 NUM_AGENT_STAND_ANIMS = LL_ARRAY_SIZE(AGENT_STAND_ANIMS); + + +LLAnimationLibrary gAnimLibrary; + +//----------------------------------------------------------------------------- +// LLAnimationLibrary() +//----------------------------------------------------------------------------- +LLAnimationLibrary::LLAnimationLibrary() : + mAnimStringTable(16384) +{ + //add animation names to animmap + mAnimMap[ANIM_AGENT_AFRAID]= mAnimStringTable.addString("express_afraid"); + mAnimMap[ANIM_AGENT_AIM_BAZOOKA_R]= mAnimStringTable.addString("aim_r_bazooka"); + mAnimMap[ANIM_AGENT_AIM_BOW_L]= mAnimStringTable.addString("aim_l_bow"); + mAnimMap[ANIM_AGENT_AIM_HANDGUN_R]= mAnimStringTable.addString("aim_r_handgun"); + mAnimMap[ANIM_AGENT_AIM_RIFLE_R]= mAnimStringTable.addString("aim_r_rifle"); + mAnimMap[ANIM_AGENT_ANGRY]= mAnimStringTable.addString("express_anger"); + mAnimMap[ANIM_AGENT_AWAY]= mAnimStringTable.addString("away"); + mAnimMap[ANIM_AGENT_BACKFLIP]= mAnimStringTable.addString("backflip"); + mAnimMap[ANIM_AGENT_BELLY_LAUGH]= mAnimStringTable.addString("express_laugh"); + mAnimMap[ANIM_AGENT_BLOW_KISS]= mAnimStringTable.addString("blowkiss"); + mAnimMap[ANIM_AGENT_BORED]= mAnimStringTable.addString("express_bored"); + mAnimMap[ANIM_AGENT_BOW]= mAnimStringTable.addString("bow"); + mAnimMap[ANIM_AGENT_BRUSH]= mAnimStringTable.addString("brush"); + mAnimMap[ANIM_AGENT_DO_NOT_DISTURB]= mAnimStringTable.addString("busy"); + mAnimMap[ANIM_AGENT_CLAP]= mAnimStringTable.addString("clap"); + mAnimMap[ANIM_AGENT_COURTBOW]= mAnimStringTable.addString("courtbow"); + mAnimMap[ANIM_AGENT_CROUCH]= mAnimStringTable.addString("crouch"); + mAnimMap[ANIM_AGENT_CROUCHWALK]= mAnimStringTable.addString("crouchwalk"); + mAnimMap[ANIM_AGENT_CRY]= mAnimStringTable.addString("express_cry"); + mAnimMap[ANIM_AGENT_CUSTOMIZE]= mAnimStringTable.addString("turn_180"); + mAnimMap[ANIM_AGENT_CUSTOMIZE_DONE]= mAnimStringTable.addString("turnback_180"); + mAnimMap[ANIM_AGENT_DANCE1]= mAnimStringTable.addString("dance1"); + mAnimMap[ANIM_AGENT_DANCE2]= mAnimStringTable.addString("dance2"); + mAnimMap[ANIM_AGENT_DANCE3]= mAnimStringTable.addString("dance3"); + mAnimMap[ANIM_AGENT_DANCE4]= mAnimStringTable.addString("dance4"); + mAnimMap[ANIM_AGENT_DANCE5]= mAnimStringTable.addString("dance5"); + mAnimMap[ANIM_AGENT_DANCE6]= mAnimStringTable.addString("dance6"); + mAnimMap[ANIM_AGENT_DANCE7]= mAnimStringTable.addString("dance7"); + mAnimMap[ANIM_AGENT_DANCE8]= mAnimStringTable.addString("dance8"); + mAnimMap[ANIM_AGENT_DEAD]= mAnimStringTable.addString("dead"); + mAnimMap[ANIM_AGENT_DRINK]= mAnimStringTable.addString("drink"); + mAnimMap[ANIM_AGENT_EMBARRASSED]= mAnimStringTable.addString("express_embarrased"); + mAnimMap[ANIM_AGENT_EXPRESS_AFRAID]= mAnimStringTable.addString("express_afraid_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_ANGER]= mAnimStringTable.addString("express_anger_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_BORED]= mAnimStringTable.addString("express_bored_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_CRY]= mAnimStringTable.addString("express_cry_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_DISDAIN]= mAnimStringTable.addString("express_disdain"); + mAnimMap[ANIM_AGENT_EXPRESS_EMBARRASSED]= mAnimStringTable.addString("express_embarrassed_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_FROWN]= mAnimStringTable.addString("express_frown"); + mAnimMap[ANIM_AGENT_EXPRESS_KISS]= mAnimStringTable.addString("express_kiss"); + mAnimMap[ANIM_AGENT_EXPRESS_LAUGH]= mAnimStringTable.addString("express_laugh_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_OPEN_MOUTH]= mAnimStringTable.addString("express_open_mouth"); + mAnimMap[ANIM_AGENT_EXPRESS_REPULSED]= mAnimStringTable.addString("express_repulsed_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_SAD]= mAnimStringTable.addString("express_sad_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_SHRUG]= mAnimStringTable.addString("express_shrug_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_SMILE]= mAnimStringTable.addString("express_smile"); + mAnimMap[ANIM_AGENT_EXPRESS_SURPRISE]= mAnimStringTable.addString("express_surprise_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_TONGUE_OUT]= mAnimStringTable.addString("express_tongue_out"); + mAnimMap[ANIM_AGENT_EXPRESS_TOOTHSMILE]= mAnimStringTable.addString("express_toothsmile"); + mAnimMap[ANIM_AGENT_EXPRESS_WINK]= mAnimStringTable.addString("express_wink_emote"); + mAnimMap[ANIM_AGENT_EXPRESS_WORRY]= mAnimStringTable.addString("express_worry_emote"); + mAnimMap[ANIM_AGENT_FALLDOWN]= mAnimStringTable.addString("falldown"); + mAnimMap[ANIM_AGENT_FEMALE_RUN_NEW]= mAnimStringTable.addString("female_run_new"); + mAnimMap[ANIM_AGENT_FEMALE_WALK]= mAnimStringTable.addString("female_walk"); + mAnimMap[ANIM_AGENT_FEMALE_WALK_NEW]= mAnimStringTable.addString("female_walk_new"); + mAnimMap[ANIM_AGENT_FINGER_WAG]= mAnimStringTable.addString("angry_fingerwag"); + mAnimMap[ANIM_AGENT_FIST_PUMP]= mAnimStringTable.addString("fist_pump"); + mAnimMap[ANIM_AGENT_FLY]= mAnimStringTable.addString("fly"); + mAnimMap[ANIM_AGENT_FLYSLOW]= mAnimStringTable.addString("flyslow"); + mAnimMap[ANIM_AGENT_HELLO]= mAnimStringTable.addString("hello"); + mAnimMap[ANIM_AGENT_HOLD_BAZOOKA_R]= mAnimStringTable.addString("hold_r_bazooka"); + mAnimMap[ANIM_AGENT_HOLD_BOW_L]= mAnimStringTable.addString("hold_l_bow"); + mAnimMap[ANIM_AGENT_HOLD_HANDGUN_R]= mAnimStringTable.addString("hold_r_handgun"); + mAnimMap[ANIM_AGENT_HOLD_RIFLE_R]= mAnimStringTable.addString("hold_r_rifle"); + mAnimMap[ANIM_AGENT_HOLD_THROW_R]= mAnimStringTable.addString("hold_throw_r"); + mAnimMap[ANIM_AGENT_HOVER]= mAnimStringTable.addString("hover"); + mAnimMap[ANIM_AGENT_HOVER_DOWN]= mAnimStringTable.addString("hover_down"); + mAnimMap[ANIM_AGENT_HOVER_UP]= mAnimStringTable.addString("hover_up"); + mAnimMap[ANIM_AGENT_IMPATIENT]= mAnimStringTable.addString("impatient"); + mAnimMap[ANIM_AGENT_JUMP]= mAnimStringTable.addString("jump"); + mAnimMap[ANIM_AGENT_JUMP_FOR_JOY]= mAnimStringTable.addString("jumpforjoy"); + mAnimMap[ANIM_AGENT_KISS_MY_BUTT]= mAnimStringTable.addString("kissmybutt"); + mAnimMap[ANIM_AGENT_LAND]= mAnimStringTable.addString("land"); + mAnimMap[ANIM_AGENT_LAUGH_SHORT]= mAnimStringTable.addString("laugh_short"); + mAnimMap[ANIM_AGENT_MEDIUM_LAND]= mAnimStringTable.addString("soft_land"); + mAnimMap[ANIM_AGENT_MOTORCYCLE_SIT]= mAnimStringTable.addString("motorcycle_sit"); + mAnimMap[ANIM_AGENT_MUSCLE_BEACH]= mAnimStringTable.addString("musclebeach"); + mAnimMap[ANIM_AGENT_NO]= mAnimStringTable.addString("no_head"); + mAnimMap[ANIM_AGENT_NO_UNHAPPY]= mAnimStringTable.addString("no_unhappy"); + mAnimMap[ANIM_AGENT_NYAH_NYAH]= mAnimStringTable.addString("nyanya"); + mAnimMap[ANIM_AGENT_ONETWO_PUNCH]= mAnimStringTable.addString("punch_onetwo"); + mAnimMap[ANIM_AGENT_PEACE]= mAnimStringTable.addString("peace"); + mAnimMap[ANIM_AGENT_POINT_ME]= mAnimStringTable.addString("point_me"); + mAnimMap[ANIM_AGENT_POINT_YOU]= mAnimStringTable.addString("point_you"); + mAnimMap[ANIM_AGENT_PRE_JUMP]= mAnimStringTable.addString("prejump"); + mAnimMap[ANIM_AGENT_PUNCH_LEFT]= mAnimStringTable.addString("punch_l"); + mAnimMap[ANIM_AGENT_PUNCH_RIGHT]= mAnimStringTable.addString("punch_r"); + mAnimMap[ANIM_AGENT_REPULSED]= mAnimStringTable.addString("express_repulsed"); + mAnimMap[ANIM_AGENT_ROUNDHOUSE_KICK]= mAnimStringTable.addString("kick_roundhouse_r"); + mAnimMap[ANIM_AGENT_RPS_COUNTDOWN]= mAnimStringTable.addString("rps_countdown"); + mAnimMap[ANIM_AGENT_RPS_PAPER]= mAnimStringTable.addString("rps_paper"); + mAnimMap[ANIM_AGENT_RPS_ROCK]= mAnimStringTable.addString("rps_rock"); + mAnimMap[ANIM_AGENT_RPS_SCISSORS]= mAnimStringTable.addString("rps_scissors"); + mAnimMap[ANIM_AGENT_RUN]= mAnimStringTable.addString("run"); + mAnimMap[ANIM_AGENT_RUN_NEW]= mAnimStringTable.addString("run_new"); + mAnimMap[ANIM_AGENT_SAD]= mAnimStringTable.addString("express_sad"); + mAnimMap[ANIM_AGENT_SALUTE]= mAnimStringTable.addString("salute"); + mAnimMap[ANIM_AGENT_SHOOT_BOW_L]= mAnimStringTable.addString("shoot_l_bow"); + mAnimMap[ANIM_AGENT_SHOUT]= mAnimStringTable.addString("shout"); + mAnimMap[ANIM_AGENT_SHRUG]= mAnimStringTable.addString("express_shrug"); + mAnimMap[ANIM_AGENT_SIT]= mAnimStringTable.addString("sit"); + mAnimMap[ANIM_AGENT_SIT_FEMALE]= mAnimStringTable.addString("sit_female"); + mAnimMap[ANIM_AGENT_SIT_GROUND]= mAnimStringTable.addString("sit_ground"); + mAnimMap[ANIM_AGENT_SIT_GROUND_CONSTRAINED]= mAnimStringTable.addString("sit_ground_constrained"); + mAnimMap[ANIM_AGENT_SIT_GENERIC]= mAnimStringTable.addString("sit_generic"); + mAnimMap[ANIM_AGENT_SIT_TO_STAND]= mAnimStringTable.addString("sit_to_stand"); + mAnimMap[ANIM_AGENT_SLEEP]= mAnimStringTable.addString("sleep"); + mAnimMap[ANIM_AGENT_SMOKE_IDLE]= mAnimStringTable.addString("smoke_idle"); + mAnimMap[ANIM_AGENT_SMOKE_INHALE]= mAnimStringTable.addString("smoke_inhale"); + mAnimMap[ANIM_AGENT_SMOKE_THROW_DOWN]= mAnimStringTable.addString("smoke_throw_down"); + mAnimMap[ANIM_AGENT_SNAPSHOT]= mAnimStringTable.addString("snapshot"); + mAnimMap[ANIM_AGENT_STAND]= mAnimStringTable.addString("stand"); + mAnimMap[ANIM_AGENT_STANDUP]= mAnimStringTable.addString("standup"); + mAnimMap[ANIM_AGENT_STAND_1]= mAnimStringTable.addString("stand_1"); + mAnimMap[ANIM_AGENT_STAND_2]= mAnimStringTable.addString("stand_2"); + mAnimMap[ANIM_AGENT_STAND_3]= mAnimStringTable.addString("stand_3"); + mAnimMap[ANIM_AGENT_STAND_4]= mAnimStringTable.addString("stand_4"); + mAnimMap[ANIM_AGENT_STRETCH]= mAnimStringTable.addString("stretch"); + mAnimMap[ANIM_AGENT_STRIDE]= mAnimStringTable.addString("stride"); + mAnimMap[ANIM_AGENT_SURF]= mAnimStringTable.addString("surf"); + mAnimMap[ANIM_AGENT_SURPRISE]= mAnimStringTable.addString("express_surprise"); + mAnimMap[ANIM_AGENT_SWORD_STRIKE]= mAnimStringTable.addString("sword_strike_r"); + mAnimMap[ANIM_AGENT_TALK]= mAnimStringTable.addString("talk"); + mAnimMap[ANIM_AGENT_TANTRUM]= mAnimStringTable.addString("angry_tantrum"); + mAnimMap[ANIM_AGENT_THROW_R]= mAnimStringTable.addString("throw_r"); + mAnimMap[ANIM_AGENT_TRYON_SHIRT]= mAnimStringTable.addString("tryon_shirt"); + mAnimMap[ANIM_AGENT_TURNLEFT]= mAnimStringTable.addString("turnleft"); + mAnimMap[ANIM_AGENT_TURNRIGHT]= mAnimStringTable.addString("turnright"); + mAnimMap[ANIM_AGENT_TYPE]= mAnimStringTable.addString("type"); + mAnimMap[ANIM_AGENT_WALK]= mAnimStringTable.addString("walk"); + mAnimMap[ANIM_AGENT_WALK_NEW]= mAnimStringTable.addString("walk_new"); + mAnimMap[ANIM_AGENT_WHISPER]= mAnimStringTable.addString("whisper"); + mAnimMap[ANIM_AGENT_WHISTLE]= mAnimStringTable.addString("whistle"); + mAnimMap[ANIM_AGENT_WINK]= mAnimStringTable.addString("express_wink"); + mAnimMap[ANIM_AGENT_WINK_HOLLYWOOD]= mAnimStringTable.addString("wink_hollywood"); + mAnimMap[ANIM_AGENT_WORRY]= mAnimStringTable.addString("express_worry"); + mAnimMap[ANIM_AGENT_YES]= mAnimStringTable.addString("yes_head"); + mAnimMap[ANIM_AGENT_YES_HAPPY]= mAnimStringTable.addString("yes_happy"); + mAnimMap[ANIM_AGENT_YOGA_FLOAT]= mAnimStringTable.addString("yoga_float"); +} + +//----------------------------------------------------------------------------- +// ~LLAnimationLibrary() +//----------------------------------------------------------------------------- +LLAnimationLibrary::~LLAnimationLibrary() +{ +} + +//----------------------------------------------------------------------------- +// Return the text name of an animation state +//----------------------------------------------------------------------------- +const char *LLAnimationLibrary::animStateToString( const LLUUID& state ) +{ + if (state.isNull()) + { + return NULL; + } + if (mAnimMap.count(state)) + { + return mAnimMap[state]; + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Return the animation state for a given name +//----------------------------------------------------------------------------- +LLUUID LLAnimationLibrary::stringToAnimState( const std::string& name, bool allow_ids ) +{ + std::string lower_case_name(name); + LLStringUtil::toLower(lower_case_name); + + char *true_name = mAnimStringTable.checkString(lower_case_name.c_str()); + + LLUUID id; + id.setNull(); + + if (true_name) + { + for (anim_map_t::value_type& anim_pair : mAnimMap) + { + if (anim_pair.second == true_name) + { + id = anim_pair.first; + break; + } + } + } + else if (allow_ids) + { + // try to convert string to LLUUID + id.set(name, false); + } + + return id; +} + +//----------------------------------------------------------------------------- +// Associate an anim state with a name +//----------------------------------------------------------------------------- +void LLAnimationLibrary::animStateSetString( const LLUUID& state, const std::string& name) +{ + mAnimMap[state] = mAnimStringTable.addString(name); +} + +std::string LLAnimationLibrary::animationName( const LLUUID& id ) const +{ + const char *cptr = gAnimLibrary.animStateToString(id); + if (cptr) + return std::string(cptr); + else + return std::string("[") + id.asString() + std::string("]"); +} + +// Animation states that the user can trigger as part of a gesture +// See struct LLAnimStateEntry in header for label location information +const LLAnimStateEntry gUserAnimStates[] = { + LLAnimStateEntry("express_afraid", ANIM_AGENT_AFRAID), + LLAnimStateEntry("express_anger", ANIM_AGENT_ANGRY), + LLAnimStateEntry("away", ANIM_AGENT_AWAY), + LLAnimStateEntry("backflip", ANIM_AGENT_BACKFLIP), + LLAnimStateEntry("express_laugh", ANIM_AGENT_BELLY_LAUGH), + LLAnimStateEntry("express_toothsmile", ANIM_AGENT_EXPRESS_TOOTHSMILE), + LLAnimStateEntry("blowkiss", ANIM_AGENT_BLOW_KISS), + LLAnimStateEntry("express_bored", ANIM_AGENT_BORED), + LLAnimStateEntry("bow", ANIM_AGENT_BOW), + LLAnimStateEntry("clap", ANIM_AGENT_CLAP), + LLAnimStateEntry("courtbow", ANIM_AGENT_COURTBOW), + LLAnimStateEntry("express_cry", ANIM_AGENT_CRY), + LLAnimStateEntry("dance1", ANIM_AGENT_DANCE1), + LLAnimStateEntry("dance2", ANIM_AGENT_DANCE2), + LLAnimStateEntry("dance3", ANIM_AGENT_DANCE3), + LLAnimStateEntry("dance4", ANIM_AGENT_DANCE4), + LLAnimStateEntry("dance5", ANIM_AGENT_DANCE5), + LLAnimStateEntry("dance6", ANIM_AGENT_DANCE6), + LLAnimStateEntry("dance7", ANIM_AGENT_DANCE7), + LLAnimStateEntry("dance8", ANIM_AGENT_DANCE8), + LLAnimStateEntry("express_disdain", ANIM_AGENT_EXPRESS_DISDAIN), + LLAnimStateEntry("drink", ANIM_AGENT_DRINK), + LLAnimStateEntry("express_embarrased", ANIM_AGENT_EMBARRASSED), + LLAnimStateEntry("angry_fingerwag", ANIM_AGENT_FINGER_WAG), + LLAnimStateEntry("fist_pump", ANIM_AGENT_FIST_PUMP), + LLAnimStateEntry("yoga_float", ANIM_AGENT_YOGA_FLOAT), + LLAnimStateEntry("express_frown", ANIM_AGENT_EXPRESS_FROWN), + LLAnimStateEntry("impatient", ANIM_AGENT_IMPATIENT), + LLAnimStateEntry("jumpforjoy", ANIM_AGENT_JUMP_FOR_JOY), + LLAnimStateEntry("kissmybutt", ANIM_AGENT_KISS_MY_BUTT), + LLAnimStateEntry("express_kiss", ANIM_AGENT_EXPRESS_KISS), + LLAnimStateEntry("laugh_short", ANIM_AGENT_LAUGH_SHORT), + LLAnimStateEntry("musclebeach", ANIM_AGENT_MUSCLE_BEACH), + LLAnimStateEntry("no_unhappy", ANIM_AGENT_NO_UNHAPPY), + LLAnimStateEntry("no_head", ANIM_AGENT_NO), + LLAnimStateEntry("nyanya", ANIM_AGENT_NYAH_NYAH), + LLAnimStateEntry("punch_onetwo", ANIM_AGENT_ONETWO_PUNCH), + LLAnimStateEntry("express_open_mouth", ANIM_AGENT_EXPRESS_OPEN_MOUTH), + LLAnimStateEntry("peace", ANIM_AGENT_PEACE), + LLAnimStateEntry("point_you", ANIM_AGENT_POINT_YOU), + LLAnimStateEntry("point_me", ANIM_AGENT_POINT_ME), + LLAnimStateEntry("punch_l", ANIM_AGENT_PUNCH_LEFT), + LLAnimStateEntry("punch_r", ANIM_AGENT_PUNCH_RIGHT), + LLAnimStateEntry("rps_countdown", ANIM_AGENT_RPS_COUNTDOWN), + LLAnimStateEntry("rps_paper", ANIM_AGENT_RPS_PAPER), + LLAnimStateEntry("rps_rock", ANIM_AGENT_RPS_ROCK), + LLAnimStateEntry("rps_scissors", ANIM_AGENT_RPS_SCISSORS), + LLAnimStateEntry("express_repulsed", ANIM_AGENT_EXPRESS_REPULSED), + LLAnimStateEntry("kick_roundhouse_r", ANIM_AGENT_ROUNDHOUSE_KICK), + LLAnimStateEntry("express_sad", ANIM_AGENT_SAD), + LLAnimStateEntry("salute", ANIM_AGENT_SALUTE), + LLAnimStateEntry("shout", ANIM_AGENT_SHOUT), + LLAnimStateEntry("express_shrug", ANIM_AGENT_SHRUG), + LLAnimStateEntry("express_smile", ANIM_AGENT_EXPRESS_SMILE), + LLAnimStateEntry("smoke_idle", ANIM_AGENT_SMOKE_IDLE), + LLAnimStateEntry("smoke_inhale", ANIM_AGENT_SMOKE_INHALE), + LLAnimStateEntry("smoke_throw_down", ANIM_AGENT_SMOKE_THROW_DOWN), + LLAnimStateEntry("express_surprise", ANIM_AGENT_SURPRISE), + LLAnimStateEntry("sword_strike_r", ANIM_AGENT_SWORD_STRIKE), + LLAnimStateEntry("angry_tantrum", ANIM_AGENT_TANTRUM), + LLAnimStateEntry("express_tongue_out", ANIM_AGENT_EXPRESS_TONGUE_OUT), + LLAnimStateEntry("hello", ANIM_AGENT_HELLO), + LLAnimStateEntry("whisper", ANIM_AGENT_WHISPER), + LLAnimStateEntry("whistle", ANIM_AGENT_WHISTLE), + LLAnimStateEntry("express_wink", ANIM_AGENT_WINK), + LLAnimStateEntry("wink_hollywood", ANIM_AGENT_WINK_HOLLYWOOD), + LLAnimStateEntry("express_worry", ANIM_AGENT_EXPRESS_WORRY), + LLAnimStateEntry("yes_happy", ANIM_AGENT_YES_HAPPY), + LLAnimStateEntry("yes_head", ANIM_AGENT_YES), +}; + +const S32 gUserAnimStatesCount = LL_ARRAY_SIZE(gUserAnimStates); + + +// End + diff --git a/indra/llcharacter/llanimationstates.h b/indra/llcharacter/llanimationstates.h index 9eea37a3c8..85232b6612 100644 --- a/indra/llcharacter/llanimationstates.h +++ b/indra/llcharacter/llanimationstates.h @@ -1,262 +1,262 @@ -/**
- * @file llanimationstates.h
- * @brief Implementation of animation state support.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLANIMATIONSTATES_H
-#define LL_LLANIMATIONSTATES_H
-
-#include <map>
-
-#include "llstringtable.h"
-#include "lluuid.h"
-
-//-----------------------------------------------------------------------------
-// These bit flags are generally used to track the animation state
-// of characters. The simulator and viewer share these flags to interpret
-// the Animation name/value attribute on agents.
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// Agent Animation State
-//-----------------------------------------------------------------------------
-const S32 MAX_CONCURRENT_ANIMS = 16;
-
-extern const LLUUID ANIM_AGENT_AFRAID;
-extern const LLUUID ANIM_AGENT_AIM_BAZOOKA_R;
-extern const LLUUID ANIM_AGENT_AIM_BOW_L;
-extern const LLUUID ANIM_AGENT_AIM_HANDGUN_R;
-extern const LLUUID ANIM_AGENT_AIM_RIFLE_R;
-extern const LLUUID ANIM_AGENT_ANGRY;
-extern const LLUUID ANIM_AGENT_AWAY;
-extern const LLUUID ANIM_AGENT_BACKFLIP;
-extern const LLUUID ANIM_AGENT_BELLY_LAUGH;
-extern const LLUUID ANIM_AGENT_BLOW_KISS;
-extern const LLUUID ANIM_AGENT_BORED;
-extern const LLUUID ANIM_AGENT_BOW;
-extern const LLUUID ANIM_AGENT_BRUSH;
-extern const LLUUID ANIM_AGENT_DO_NOT_DISTURB;
-extern const LLUUID ANIM_AGENT_CLAP;
-extern const LLUUID ANIM_AGENT_COURTBOW;
-extern const LLUUID ANIM_AGENT_CROUCH;
-extern const LLUUID ANIM_AGENT_CROUCHWALK;
-extern const LLUUID ANIM_AGENT_CRY;
-extern const LLUUID ANIM_AGENT_CUSTOMIZE;
-extern const LLUUID ANIM_AGENT_CUSTOMIZE_DONE;
-extern const LLUUID ANIM_AGENT_DANCE1;
-extern const LLUUID ANIM_AGENT_DANCE2;
-extern const LLUUID ANIM_AGENT_DANCE3;
-extern const LLUUID ANIM_AGENT_DANCE4;
-extern const LLUUID ANIM_AGENT_DANCE5;
-extern const LLUUID ANIM_AGENT_DANCE6;
-extern const LLUUID ANIM_AGENT_DANCE7;
-extern const LLUUID ANIM_AGENT_DANCE8;
-extern const LLUUID ANIM_AGENT_DEAD;
-extern const LLUUID ANIM_AGENT_DRINK;
-extern const LLUUID ANIM_AGENT_EMBARRASSED;
-extern const LLUUID ANIM_AGENT_EXPRESS_AFRAID;
-extern const LLUUID ANIM_AGENT_EXPRESS_ANGER;
-extern const LLUUID ANIM_AGENT_EXPRESS_BORED;
-extern const LLUUID ANIM_AGENT_EXPRESS_CRY;
-extern const LLUUID ANIM_AGENT_EXPRESS_DISDAIN;
-extern const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED;
-extern const LLUUID ANIM_AGENT_EXPRESS_FROWN;
-extern const LLUUID ANIM_AGENT_EXPRESS_KISS;
-extern const LLUUID ANIM_AGENT_EXPRESS_LAUGH;
-extern const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH;
-extern const LLUUID ANIM_AGENT_EXPRESS_REPULSED;
-extern const LLUUID ANIM_AGENT_EXPRESS_SAD;
-extern const LLUUID ANIM_AGENT_EXPRESS_SHRUG;
-extern const LLUUID ANIM_AGENT_EXPRESS_SMILE;
-extern const LLUUID ANIM_AGENT_EXPRESS_SURPRISE;
-extern const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT;
-extern const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE;
-extern const LLUUID ANIM_AGENT_EXPRESS_WINK;
-extern const LLUUID ANIM_AGENT_EXPRESS_WORRY;
-extern const LLUUID ANIM_AGENT_FALLDOWN;
-extern const LLUUID ANIM_AGENT_FEMALE_RUN_NEW;
-extern const LLUUID ANIM_AGENT_FEMALE_WALK;
-extern const LLUUID ANIM_AGENT_FEMALE_WALK_NEW;
-extern const LLUUID ANIM_AGENT_FINGER_WAG;
-extern const LLUUID ANIM_AGENT_FIST_PUMP;
-extern const LLUUID ANIM_AGENT_FLY;
-extern const LLUUID ANIM_AGENT_FLYSLOW;
-extern const LLUUID ANIM_AGENT_HELLO;
-extern const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R;
-extern const LLUUID ANIM_AGENT_HOLD_BOW_L;
-extern const LLUUID ANIM_AGENT_HOLD_HANDGUN_R;
-extern const LLUUID ANIM_AGENT_HOLD_RIFLE_R;
-extern const LLUUID ANIM_AGENT_HOLD_THROW_R;
-extern const LLUUID ANIM_AGENT_HOVER;
-extern const LLUUID ANIM_AGENT_HOVER_DOWN;
-extern const LLUUID ANIM_AGENT_HOVER_UP;
-extern const LLUUID ANIM_AGENT_IMPATIENT;
-extern const LLUUID ANIM_AGENT_JUMP;
-extern const LLUUID ANIM_AGENT_JUMP_FOR_JOY;
-extern const LLUUID ANIM_AGENT_KISS_MY_BUTT;
-extern const LLUUID ANIM_AGENT_LAND;
-extern const LLUUID ANIM_AGENT_LAUGH_SHORT;
-extern const LLUUID ANIM_AGENT_MEDIUM_LAND;
-extern const LLUUID ANIM_AGENT_MOTORCYCLE_SIT;
-extern const LLUUID ANIM_AGENT_MUSCLE_BEACH;
-extern const LLUUID ANIM_AGENT_NO;
-extern const LLUUID ANIM_AGENT_NO_UNHAPPY;
-extern const LLUUID ANIM_AGENT_NYAH_NYAH;
-extern const LLUUID ANIM_AGENT_ONETWO_PUNCH;
-extern const LLUUID ANIM_AGENT_PEACE;
-extern const LLUUID ANIM_AGENT_POINT_ME;
-extern const LLUUID ANIM_AGENT_POINT_YOU;
-extern const LLUUID ANIM_AGENT_PRE_JUMP;
-extern const LLUUID ANIM_AGENT_PUNCH_LEFT;
-extern const LLUUID ANIM_AGENT_PUNCH_RIGHT;
-extern const LLUUID ANIM_AGENT_REPULSED;
-extern const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK;
-extern const LLUUID ANIM_AGENT_RPS_COUNTDOWN;
-extern const LLUUID ANIM_AGENT_RPS_PAPER;
-extern const LLUUID ANIM_AGENT_RPS_ROCK;
-extern const LLUUID ANIM_AGENT_RPS_SCISSORS;
-extern const LLUUID ANIM_AGENT_RUN;
-extern const LLUUID ANIM_AGENT_RUN_NEW;
-extern const LLUUID ANIM_AGENT_SAD;
-extern const LLUUID ANIM_AGENT_SALUTE;
-extern const LLUUID ANIM_AGENT_SHOOT_BOW_L;
-extern const LLUUID ANIM_AGENT_SHOUT;
-extern const LLUUID ANIM_AGENT_SHRUG;
-extern const LLUUID ANIM_AGENT_SIT;
-extern const LLUUID ANIM_AGENT_SIT_FEMALE;
-extern const LLUUID ANIM_AGENT_SIT_GENERIC;
-extern const LLUUID ANIM_AGENT_SIT_GROUND;
-extern const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED;
-extern const LLUUID ANIM_AGENT_SIT_TO_STAND;
-extern const LLUUID ANIM_AGENT_SLEEP;
-extern const LLUUID ANIM_AGENT_SMOKE_IDLE;
-extern const LLUUID ANIM_AGENT_SMOKE_INHALE;
-extern const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN;
-extern const LLUUID ANIM_AGENT_SNAPSHOT;
-extern const LLUUID ANIM_AGENT_STAND;
-extern const LLUUID ANIM_AGENT_STANDUP;
-extern const LLUUID ANIM_AGENT_STAND_1;
-extern const LLUUID ANIM_AGENT_STAND_2;
-extern const LLUUID ANIM_AGENT_STAND_3;
-extern const LLUUID ANIM_AGENT_STAND_4;
-extern const LLUUID ANIM_AGENT_STRETCH;
-extern const LLUUID ANIM_AGENT_STRIDE;
-extern const LLUUID ANIM_AGENT_SURF;
-extern const LLUUID ANIM_AGENT_SURPRISE;
-extern const LLUUID ANIM_AGENT_SWORD_STRIKE;
-extern const LLUUID ANIM_AGENT_TALK;
-extern const LLUUID ANIM_AGENT_TANTRUM;
-extern const LLUUID ANIM_AGENT_THROW_R;
-extern const LLUUID ANIM_AGENT_TRYON_SHIRT;
-extern const LLUUID ANIM_AGENT_TURNLEFT;
-extern const LLUUID ANIM_AGENT_TURNRIGHT;
-extern const LLUUID ANIM_AGENT_TYPE;
-extern const LLUUID ANIM_AGENT_WALK;
-extern const LLUUID ANIM_AGENT_WALK_NEW;
-extern const LLUUID ANIM_AGENT_WHISPER;
-extern const LLUUID ANIM_AGENT_WHISTLE;
-extern const LLUUID ANIM_AGENT_WINK;
-extern const LLUUID ANIM_AGENT_WINK_HOLLYWOOD;
-extern const LLUUID ANIM_AGENT_WORRY;
-extern const LLUUID ANIM_AGENT_YES;
-extern const LLUUID ANIM_AGENT_YES_HAPPY;
-extern const LLUUID ANIM_AGENT_YOGA_FLOAT;
-
-extern LLUUID AGENT_WALK_ANIMS[];
-extern S32 NUM_AGENT_WALK_ANIMS;
-
-extern LLUUID AGENT_GUN_HOLD_ANIMS[];
-extern S32 NUM_AGENT_GUN_HOLD_ANIMS;
-
-extern LLUUID AGENT_GUN_AIM_ANIMS[];
-extern S32 NUM_AGENT_GUN_AIM_ANIMS;
-
-extern LLUUID AGENT_NO_ROTATE_ANIMS[];
-extern S32 NUM_AGENT_NO_ROTATE_ANIMS;
-
-extern LLUUID AGENT_STAND_ANIMS[];
-extern S32 NUM_AGENT_STAND_ANIMS;
-
-class LLAnimationLibrary
-{
-private:
- LLStringTable mAnimStringTable;
-
- typedef std::map<LLUUID, char *> anim_map_t;
- anim_map_t mAnimMap;
-
-public:
- LLAnimationLibrary();
- ~LLAnimationLibrary();
-
- //-----------------------------------------------------------------------------
- // Return the text name of a single animation state,
- // Return NULL if the state is invalid
- //-----------------------------------------------------------------------------
- const char *animStateToString( const LLUUID& state );
-
- //-----------------------------------------------------------------------------
- // Return the animation state for the given name.
- // Retun NULL if the name is invalid.
- //-----------------------------------------------------------------------------
- LLUUID stringToAnimState( const std::string& name, bool allow_ids = true );
-
- //-----------------------------------------------------------------------------
- // Associate an anim state with a name
- //-----------------------------------------------------------------------------
- void animStateSetString( const LLUUID& state, const std::string& name);
-
- //-----------------------------------------------------------------------------
- // Find the name for a given animation, or UUID string if none defined.
- //-----------------------------------------------------------------------------
- std::string animationName( const LLUUID& id ) const;
-};
-
-struct LLAnimStateEntry
-{
- LLAnimStateEntry(const char* name, const LLUUID& id) :
- mName(name),
- mID(id)
- {
- // LABELS:
- // Look to newview/LLAnimStateLabels.* for how to get the labels.
- // The labels should no longer be stored in this structure. The server
- // shouldn't care about the local friendly name of an animation, and
- // this is common code.
- }
-
-
- const char* mName;
- const LLUUID mID;
-};
-
-// Animation states that the user can trigger
-extern const LLAnimStateEntry gUserAnimStates[];
-extern const S32 gUserAnimStatesCount;
-extern LLAnimationLibrary gAnimLibrary;
-
-#endif // LL_LLANIMATIONSTATES_H
-
-
-
+/** + * @file llanimationstates.h + * @brief Implementation of animation state support. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLANIMATIONSTATES_H +#define LL_LLANIMATIONSTATES_H + +#include <map> + +#include "llstringtable.h" +#include "lluuid.h" + +//----------------------------------------------------------------------------- +// These bit flags are generally used to track the animation state +// of characters. The simulator and viewer share these flags to interpret +// the Animation name/value attribute on agents. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Agent Animation State +//----------------------------------------------------------------------------- +const S32 MAX_CONCURRENT_ANIMS = 16; + +extern const LLUUID ANIM_AGENT_AFRAID; +extern const LLUUID ANIM_AGENT_AIM_BAZOOKA_R; +extern const LLUUID ANIM_AGENT_AIM_BOW_L; +extern const LLUUID ANIM_AGENT_AIM_HANDGUN_R; +extern const LLUUID ANIM_AGENT_AIM_RIFLE_R; +extern const LLUUID ANIM_AGENT_ANGRY; +extern const LLUUID ANIM_AGENT_AWAY; +extern const LLUUID ANIM_AGENT_BACKFLIP; +extern const LLUUID ANIM_AGENT_BELLY_LAUGH; +extern const LLUUID ANIM_AGENT_BLOW_KISS; +extern const LLUUID ANIM_AGENT_BORED; +extern const LLUUID ANIM_AGENT_BOW; +extern const LLUUID ANIM_AGENT_BRUSH; +extern const LLUUID ANIM_AGENT_DO_NOT_DISTURB; +extern const LLUUID ANIM_AGENT_CLAP; +extern const LLUUID ANIM_AGENT_COURTBOW; +extern const LLUUID ANIM_AGENT_CROUCH; +extern const LLUUID ANIM_AGENT_CROUCHWALK; +extern const LLUUID ANIM_AGENT_CRY; +extern const LLUUID ANIM_AGENT_CUSTOMIZE; +extern const LLUUID ANIM_AGENT_CUSTOMIZE_DONE; +extern const LLUUID ANIM_AGENT_DANCE1; +extern const LLUUID ANIM_AGENT_DANCE2; +extern const LLUUID ANIM_AGENT_DANCE3; +extern const LLUUID ANIM_AGENT_DANCE4; +extern const LLUUID ANIM_AGENT_DANCE5; +extern const LLUUID ANIM_AGENT_DANCE6; +extern const LLUUID ANIM_AGENT_DANCE7; +extern const LLUUID ANIM_AGENT_DANCE8; +extern const LLUUID ANIM_AGENT_DEAD; +extern const LLUUID ANIM_AGENT_DRINK; +extern const LLUUID ANIM_AGENT_EMBARRASSED; +extern const LLUUID ANIM_AGENT_EXPRESS_AFRAID; +extern const LLUUID ANIM_AGENT_EXPRESS_ANGER; +extern const LLUUID ANIM_AGENT_EXPRESS_BORED; +extern const LLUUID ANIM_AGENT_EXPRESS_CRY; +extern const LLUUID ANIM_AGENT_EXPRESS_DISDAIN; +extern const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED; +extern const LLUUID ANIM_AGENT_EXPRESS_FROWN; +extern const LLUUID ANIM_AGENT_EXPRESS_KISS; +extern const LLUUID ANIM_AGENT_EXPRESS_LAUGH; +extern const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH; +extern const LLUUID ANIM_AGENT_EXPRESS_REPULSED; +extern const LLUUID ANIM_AGENT_EXPRESS_SAD; +extern const LLUUID ANIM_AGENT_EXPRESS_SHRUG; +extern const LLUUID ANIM_AGENT_EXPRESS_SMILE; +extern const LLUUID ANIM_AGENT_EXPRESS_SURPRISE; +extern const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT; +extern const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE; +extern const LLUUID ANIM_AGENT_EXPRESS_WINK; +extern const LLUUID ANIM_AGENT_EXPRESS_WORRY; +extern const LLUUID ANIM_AGENT_FALLDOWN; +extern const LLUUID ANIM_AGENT_FEMALE_RUN_NEW; +extern const LLUUID ANIM_AGENT_FEMALE_WALK; +extern const LLUUID ANIM_AGENT_FEMALE_WALK_NEW; +extern const LLUUID ANIM_AGENT_FINGER_WAG; +extern const LLUUID ANIM_AGENT_FIST_PUMP; +extern const LLUUID ANIM_AGENT_FLY; +extern const LLUUID ANIM_AGENT_FLYSLOW; +extern const LLUUID ANIM_AGENT_HELLO; +extern const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R; +extern const LLUUID ANIM_AGENT_HOLD_BOW_L; +extern const LLUUID ANIM_AGENT_HOLD_HANDGUN_R; +extern const LLUUID ANIM_AGENT_HOLD_RIFLE_R; +extern const LLUUID ANIM_AGENT_HOLD_THROW_R; +extern const LLUUID ANIM_AGENT_HOVER; +extern const LLUUID ANIM_AGENT_HOVER_DOWN; +extern const LLUUID ANIM_AGENT_HOVER_UP; +extern const LLUUID ANIM_AGENT_IMPATIENT; +extern const LLUUID ANIM_AGENT_JUMP; +extern const LLUUID ANIM_AGENT_JUMP_FOR_JOY; +extern const LLUUID ANIM_AGENT_KISS_MY_BUTT; +extern const LLUUID ANIM_AGENT_LAND; +extern const LLUUID ANIM_AGENT_LAUGH_SHORT; +extern const LLUUID ANIM_AGENT_MEDIUM_LAND; +extern const LLUUID ANIM_AGENT_MOTORCYCLE_SIT; +extern const LLUUID ANIM_AGENT_MUSCLE_BEACH; +extern const LLUUID ANIM_AGENT_NO; +extern const LLUUID ANIM_AGENT_NO_UNHAPPY; +extern const LLUUID ANIM_AGENT_NYAH_NYAH; +extern const LLUUID ANIM_AGENT_ONETWO_PUNCH; +extern const LLUUID ANIM_AGENT_PEACE; +extern const LLUUID ANIM_AGENT_POINT_ME; +extern const LLUUID ANIM_AGENT_POINT_YOU; +extern const LLUUID ANIM_AGENT_PRE_JUMP; +extern const LLUUID ANIM_AGENT_PUNCH_LEFT; +extern const LLUUID ANIM_AGENT_PUNCH_RIGHT; +extern const LLUUID ANIM_AGENT_REPULSED; +extern const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK; +extern const LLUUID ANIM_AGENT_RPS_COUNTDOWN; +extern const LLUUID ANIM_AGENT_RPS_PAPER; +extern const LLUUID ANIM_AGENT_RPS_ROCK; +extern const LLUUID ANIM_AGENT_RPS_SCISSORS; +extern const LLUUID ANIM_AGENT_RUN; +extern const LLUUID ANIM_AGENT_RUN_NEW; +extern const LLUUID ANIM_AGENT_SAD; +extern const LLUUID ANIM_AGENT_SALUTE; +extern const LLUUID ANIM_AGENT_SHOOT_BOW_L; +extern const LLUUID ANIM_AGENT_SHOUT; +extern const LLUUID ANIM_AGENT_SHRUG; +extern const LLUUID ANIM_AGENT_SIT; +extern const LLUUID ANIM_AGENT_SIT_FEMALE; +extern const LLUUID ANIM_AGENT_SIT_GENERIC; +extern const LLUUID ANIM_AGENT_SIT_GROUND; +extern const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED; +extern const LLUUID ANIM_AGENT_SIT_TO_STAND; +extern const LLUUID ANIM_AGENT_SLEEP; +extern const LLUUID ANIM_AGENT_SMOKE_IDLE; +extern const LLUUID ANIM_AGENT_SMOKE_INHALE; +extern const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN; +extern const LLUUID ANIM_AGENT_SNAPSHOT; +extern const LLUUID ANIM_AGENT_STAND; +extern const LLUUID ANIM_AGENT_STANDUP; +extern const LLUUID ANIM_AGENT_STAND_1; +extern const LLUUID ANIM_AGENT_STAND_2; +extern const LLUUID ANIM_AGENT_STAND_3; +extern const LLUUID ANIM_AGENT_STAND_4; +extern const LLUUID ANIM_AGENT_STRETCH; +extern const LLUUID ANIM_AGENT_STRIDE; +extern const LLUUID ANIM_AGENT_SURF; +extern const LLUUID ANIM_AGENT_SURPRISE; +extern const LLUUID ANIM_AGENT_SWORD_STRIKE; +extern const LLUUID ANIM_AGENT_TALK; +extern const LLUUID ANIM_AGENT_TANTRUM; +extern const LLUUID ANIM_AGENT_THROW_R; +extern const LLUUID ANIM_AGENT_TRYON_SHIRT; +extern const LLUUID ANIM_AGENT_TURNLEFT; +extern const LLUUID ANIM_AGENT_TURNRIGHT; +extern const LLUUID ANIM_AGENT_TYPE; +extern const LLUUID ANIM_AGENT_WALK; +extern const LLUUID ANIM_AGENT_WALK_NEW; +extern const LLUUID ANIM_AGENT_WHISPER; +extern const LLUUID ANIM_AGENT_WHISTLE; +extern const LLUUID ANIM_AGENT_WINK; +extern const LLUUID ANIM_AGENT_WINK_HOLLYWOOD; +extern const LLUUID ANIM_AGENT_WORRY; +extern const LLUUID ANIM_AGENT_YES; +extern const LLUUID ANIM_AGENT_YES_HAPPY; +extern const LLUUID ANIM_AGENT_YOGA_FLOAT; + +extern LLUUID AGENT_WALK_ANIMS[]; +extern S32 NUM_AGENT_WALK_ANIMS; + +extern LLUUID AGENT_GUN_HOLD_ANIMS[]; +extern S32 NUM_AGENT_GUN_HOLD_ANIMS; + +extern LLUUID AGENT_GUN_AIM_ANIMS[]; +extern S32 NUM_AGENT_GUN_AIM_ANIMS; + +extern LLUUID AGENT_NO_ROTATE_ANIMS[]; +extern S32 NUM_AGENT_NO_ROTATE_ANIMS; + +extern LLUUID AGENT_STAND_ANIMS[]; +extern S32 NUM_AGENT_STAND_ANIMS; + +class LLAnimationLibrary +{ +private: + LLStringTable mAnimStringTable; + + typedef std::map<LLUUID, char *> anim_map_t; + anim_map_t mAnimMap; + +public: + LLAnimationLibrary(); + ~LLAnimationLibrary(); + + //----------------------------------------------------------------------------- + // Return the text name of a single animation state, + // Return NULL if the state is invalid + //----------------------------------------------------------------------------- + const char *animStateToString( const LLUUID& state ); + + //----------------------------------------------------------------------------- + // Return the animation state for the given name. + // Retun NULL if the name is invalid. + //----------------------------------------------------------------------------- + LLUUID stringToAnimState( const std::string& name, bool allow_ids = true ); + + //----------------------------------------------------------------------------- + // Associate an anim state with a name + //----------------------------------------------------------------------------- + void animStateSetString( const LLUUID& state, const std::string& name); + + //----------------------------------------------------------------------------- + // Find the name for a given animation, or UUID string if none defined. + //----------------------------------------------------------------------------- + std::string animationName( const LLUUID& id ) const; +}; + +struct LLAnimStateEntry +{ + LLAnimStateEntry(const char* name, const LLUUID& id) : + mName(name), + mID(id) + { + // LABELS: + // Look to newview/LLAnimStateLabels.* for how to get the labels. + // The labels should no longer be stored in this structure. The server + // shouldn't care about the local friendly name of an animation, and + // this is common code. + } + + + const char* mName; + const LLUUID mID; +}; + +// Animation states that the user can trigger +extern const LLAnimStateEntry gUserAnimStates[]; +extern const S32 gUserAnimStatesCount; +extern LLAnimationLibrary gAnimLibrary; + +#endif // LL_LLANIMATIONSTATES_H + + + diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 988e352fdb..9dace08e6f 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -1,1500 +1,1500 @@ -/**
- * @file llbvhloader.cpp
- * @brief Translates a BVH files to LindenLabAnimation format.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,7
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llbvhloader.h"
-
-#include <boost/tokenizer.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include "lldatapacker.h"
-#include "lldir.h"
-#include "llkeyframemotion.h"
-#include "llquantize.h"
-#include "llstl.h"
-#include "llapr.h"
-#include "llsdserialize.h"
-
-
-using namespace std;
-
-#define INCHES_TO_METERS 0.02540005f
-
-/// The .bvh does not have a formal spec, and different readers interpret things in their own way.
-/// In OUR usage, frame 0 is used in optimization and is not considered to be part of the animation.
-const S32 NUMBER_OF_IGNORED_FRAMES_AT_START = 1;
-/// In our usage, the last frame is used only to indicate what the penultimate frame should be interpolated towards.
-/// I.e., the animation only plays up to the start of the last frame. There is no hold or exptrapolation past that point..
-/// Thus there are two frame of the total that do not contribute to the total running time of the animation.
-const S32 NUMBER_OF_UNPLAYED_FRAMES = NUMBER_OF_IGNORED_FRAMES_AT_START + 1;
-
-const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f;
-const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
-
-const F32 POSITION_MOTION_THRESHOLD_SQUARED = 0.001f * 0.001f;
-const F32 ROTATION_MOTION_THRESHOLD = 0.001f;
-
-char gInFile[1024]; /* Flawfinder: ignore */
-char gOutFile[1024]; /* Flawfinder: ignore */
-/*
-//------------------------------------------------------------------------
-// Status Codes
-//------------------------------------------------------------------------
-const char *LLBVHLoader::ST_OK = "Ok";
-const char *LLBVHLoader::ST_EOF = "Premature end of file.";
-const char *LLBVHLoader::ST_NO_CONSTRAINT = "Can't read constraint definition.";
-const char *LLBVHLoader::ST_NO_FILE = "Can't open BVH file.";
-const char *LLBVHLoader::ST_NO_HIER = "Invalid HIERARCHY header.";
-const char *LLBVHLoader::ST_NO_JOINT = "Can't find ROOT or JOINT.";
-const char *LLBVHLoader::ST_NO_NAME = "Can't get JOINT name.";
-const char *LLBVHLoader::ST_NO_OFFSET = "Can't find OFFSET.";
-const char *LLBVHLoader::ST_NO_CHANNELS = "Can't find CHANNELS.";
-const char *LLBVHLoader::ST_NO_ROTATION = "Can't get rotation order.";
-const char *LLBVHLoader::ST_NO_AXIS = "Can't get rotation axis.";
-const char *LLBVHLoader::ST_NO_MOTION = "Can't find MOTION.";
-const char *LLBVHLoader::ST_NO_FRAMES = "Can't get number of frames.";
-const char *LLBVHLoader::ST_NO_FRAME_TIME = "Can't get frame time.";
-const char *LLBVHLoader::ST_NO_POS = "Can't get position values.";
-const char *LLBVHLoader::ST_NO_ROT = "Can't get rotation values.";
-const char *LLBVHLoader::ST_NO_XLT_FILE = "Can't open translation file.";
-const char *LLBVHLoader::ST_NO_XLT_HEADER = "Can't read translation header.";
-const char *LLBVHLoader::ST_NO_XLT_NAME = "Can't read translation names.";
-const char *LLBVHLoader::ST_NO_XLT_IGNORE = "Can't read translation ignore value.";
-const char *LLBVHLoader::ST_NO_XLT_RELATIVE = "Can't read translation relative value.";
-const char *LLBVHLoader::ST_NO_XLT_OUTNAME = "Can't read translation outname value.";
-const char *LLBVHLoader::ST_NO_XLT_MATRIX = "Can't read translation matrix.";
-const char *LLBVHLoader::ST_NO_XLT_MERGECHILD = "Can't get mergechild name.";
-const char *LLBVHLoader::ST_NO_XLT_MERGEPARENT = "Can't get mergeparent name.";
-const char *LLBVHLoader::ST_NO_XLT_PRIORITY = "Can't get priority value.";
-const char *LLBVHLoader::ST_NO_XLT_LOOP = "Can't get loop value.";
-const char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values.";
-const char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values.";
-const char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value.";
-const char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name.";
-const char *LLBVHLoader::ST_BAD_ROOT = "Illegal ROOT joint.";
-*/
-
-//------------------------------------------------------------------------
-// find_next_whitespace()
-//------------------------------------------------------------------------
-const char *find_next_whitespace(const char *p)
-{
- while(*p && isspace(*p)) p++;
- while(*p && !isspace(*p)) p++;
- return p;
-}
-
-
-//------------------------------------------------------------------------
-// bvhStringToOrder()
-//
-// XYZ order in BVH files must be passed to mayaQ() as ZYX.
-// This function reverses the input string before passing it on
-// to StringToOrder().
-//------------------------------------------------------------------------
-LLQuaternion::Order bvhStringToOrder( char *str )
-{
- char order[4]; /* Flawfinder: ignore */
- order[0] = str[2];
- order[1] = str[1];
- order[2] = str[0];
- order[3] = 0;
- LLQuaternion::Order retVal = StringToOrder( order );
- return retVal;
-}
-
-//-----------------------------------------------------------------------------
-// LLBVHLoader()
-//-----------------------------------------------------------------------------
-
-LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map )
-{
- reset();
- errorLine = 0;
- mStatus = loadTranslationTable("anim.ini");
- loadStatus = mStatus;
- LL_INFOS("BVH") << "Load Status 00 : " << loadStatus << LL_ENDL;
- if (mStatus == E_ST_NO_XLT_FILE)
- {
- LL_WARNS("BVH") << "NOTE: No translation table found." << LL_ENDL;
- loadStatus = mStatus;
- return;
- }
- else
- {
- if (mStatus != E_ST_OK)
- {
- LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
- errorLine = getLineNumber();
- loadStatus = mStatus;
- return;
- }
- }
-
- // Recognize all names we've been told are legal.
- for (std::map<std::string, std::string>::value_type& alias_pair : joint_alias_map)
- {
- makeTranslation( alias_pair.first , alias_pair.second );
- }
-
- char error_text[128]; /* Flawfinder: ignore */
- S32 error_line;
- mStatus = loadBVHFile(buffer, error_text, error_line); //Reads all joints in BVH file.
-
- LL_DEBUGS("BVH") << "============================================================" << LL_ENDL;
- LL_DEBUGS("BVH") << "Raw data from file" << LL_ENDL;
- dumpBVHInfo();
-
- if (mStatus != E_ST_OK)
- {
- LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL;
- loadStatus = mStatus;
- errorLine = getLineNumber();
- return;
- }
-
- applyTranslations(); //Maps between joints found in file and the aliased names.
- optimize();
-
- LL_DEBUGS("BVH") << "============================================================" << LL_ENDL;
- LL_DEBUGS("BVH") << "After translations and optimize" << LL_ENDL;
- dumpBVHInfo();
-
- mInitialized = true;
-}
-
-
-LLBVHLoader::~LLBVHLoader()
-{
- std::for_each(mJoints.begin(),mJoints.end(),DeletePointer());
- mJoints.clear();
-}
-
-//------------------------------------------------------------------------
-// LLBVHLoader::loadTranslationTable()
-//------------------------------------------------------------------------
-ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
-{
- //--------------------------------------------------------------------
- // open file
- //--------------------------------------------------------------------
- std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
-
- LLAPRFile infile ;
- infile.open(path, LL_APR_R);
- apr_file_t *fp = infile.getFileHandle();
- if (!fp)
- return E_ST_NO_XLT_FILE;
-
- LL_INFOS("BVH") << "NOTE: Loading translation table: " << fileName << LL_ENDL;
-
- //--------------------------------------------------------------------
- // register file to be closed on function exit
- //--------------------------------------------------------------------
-
- //--------------------------------------------------------------------
- // load header
- //--------------------------------------------------------------------
- if ( ! getLine(fp) )
- return E_ST_EOF;
- if ( strncmp(mLine, "Translations 1.0", 16) )
- return E_ST_NO_XLT_HEADER;
-
- //--------------------------------------------------------------------
- // load data one line at a time
- //--------------------------------------------------------------------
- bool loadingGlobals = false;
- while ( getLine(fp) )
- {
- //----------------------------------------------------------------
- // check the 1st token on the line to determine if it's empty or a comment
- //----------------------------------------------------------------
- char token[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %127s", token) != 1 ) /* Flawfinder: ignore */
- continue;
-
- if (token[0] == '#')
- continue;
-
- //----------------------------------------------------------------
- // check if a [jointName] or [GLOBALS] was specified.
- //----------------------------------------------------------------
- if (token[0] == '[')
- {
- char name[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " [%127[^]]", name) != 1 )
- return E_ST_NO_XLT_NAME;
-
- if (strcmp(name, "GLOBALS")==0)
- {
- loadingGlobals = true;
- continue;
- }
- }
-
- //----------------------------------------------------------------
- // check for optional emote
- //----------------------------------------------------------------
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "emote")==0)
- {
- char emote_str[1024]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %1023s", emote_str) != 1 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_EMOTE;
-
- mEmoteName.assign( emote_str );
-// LL_INFOS() << "NOTE: Emote: " << mEmoteName.c_str() << LL_ENDL;
- continue;
- }
-
-
- //----------------------------------------------------------------
- // check for global priority setting
- //----------------------------------------------------------------
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "priority")==0)
- {
- S32 priority;
- if ( sscanf(mLine, " %*s = %d", &priority) != 1 )
- return E_ST_NO_XLT_PRIORITY;
-
- mPriority = priority;
-// LL_INFOS() << "NOTE: Priority: " << mPriority << LL_ENDL;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for global loop setting
- //----------------------------------------------------------------
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "loop")==0)
- {
- char trueFalse[128]; /* Flawfinder: ignore */
- trueFalse[0] = '\0';
-
- F32 loop_in = 0.f;
- F32 loop_out = 1.f;
-
- if ( sscanf(mLine, " %*s = %f %f", &loop_in, &loop_out) == 2 )
- {
- mLoop = true;
- }
- else if ( sscanf(mLine, " %*s = %127s", trueFalse) == 1 ) /* Flawfinder: ignore */
- {
- mLoop = (LLStringUtil::compareInsensitive(trueFalse, "true")==0);
- }
- else
- {
- return E_ST_NO_XLT_LOOP;
- }
-
- mLoopInPoint = loop_in * mDuration;
- mLoopOutPoint = loop_out * mDuration;
-
- continue;
- }
-
- //----------------------------------------------------------------
- // check for global easeIn setting
- //----------------------------------------------------------------
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "easein")==0)
- {
- F32 duration;
- char type[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_EASEIN;
-
- mEaseIn = duration;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for global easeOut setting
- //----------------------------------------------------------------
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "easeout")==0)
- {
- F32 duration;
- char type[128]; /* Flawfinder: ignore */
- if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 ) /* Flawfinder: ignore */
- return E_ST_NO_XLT_EASEOUT;
-
- mEaseOut = duration;
- continue;
- }
-
- //----------------------------------------------------------------
- // check for global handMorph setting
- //----------------------------------------------------------------
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "hand")==0)
- {
- S32 handMorph;
- if (sscanf(mLine, " %*s = %d", &handMorph) != 1)
- return E_ST_NO_XLT_HAND;
-
- mHand = handMorph;
- continue;
- }
-
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "constraint")==0)
- {
- Constraint constraint;
-
- // try reading optional target direction
- if(sscanf( /* Flawfinder: ignore */
- mLine,
- " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f",
- &constraint.mChainLength,
- &constraint.mEaseInStart,
- &constraint.mEaseInStop,
- &constraint.mEaseOutStart,
- &constraint.mEaseOutStop,
- constraint.mSourceJointName,
- &constraint.mSourceOffset.mV[VX],
- &constraint.mSourceOffset.mV[VY],
- &constraint.mSourceOffset.mV[VZ],
- constraint.mTargetJointName,
- &constraint.mTargetOffset.mV[VX],
- &constraint.mTargetOffset.mV[VY],
- &constraint.mTargetOffset.mV[VZ],
- &constraint.mTargetDir.mV[VX],
- &constraint.mTargetDir.mV[VY],
- &constraint.mTargetDir.mV[VZ]) != 16)
- {
- if(sscanf( /* Flawfinder: ignore */
- mLine,
- " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f",
- &constraint.mChainLength,
- &constraint.mEaseInStart,
- &constraint.mEaseInStop,
- &constraint.mEaseOutStart,
- &constraint.mEaseOutStop,
- constraint.mSourceJointName,
- &constraint.mSourceOffset.mV[VX],
- &constraint.mSourceOffset.mV[VY],
- &constraint.mSourceOffset.mV[VZ],
- constraint.mTargetJointName,
- &constraint.mTargetOffset.mV[VX],
- &constraint.mTargetOffset.mV[VY],
- &constraint.mTargetOffset.mV[VZ]) != 13)
- {
- return E_ST_NO_CONSTRAINT;
- }
- }
- else
- {
- // normalize direction
- if (!constraint.mTargetDir.isExactlyZero())
- {
- constraint.mTargetDir.normVec();
- }
-
- }
-
- constraint.mConstraintType = CONSTRAINT_TYPE_POINT;
- mConstraints.push_back(constraint);
- continue;
- }
-
- if (loadingGlobals && LLStringUtil::compareInsensitive(token, "planar_constraint")==0)
- {
- Constraint constraint;
-
- // try reading optional target direction
- if(sscanf( /* Flawfinder: ignore */
- mLine,
- " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f",
- &constraint.mChainLength,
- &constraint.mEaseInStart,
- &constraint.mEaseInStop,
- &constraint.mEaseOutStart,
- &constraint.mEaseOutStop,
- constraint.mSourceJointName,
- &constraint.mSourceOffset.mV[VX],
- &constraint.mSourceOffset.mV[VY],
- &constraint.mSourceOffset.mV[VZ],
- constraint.mTargetJointName,
- &constraint.mTargetOffset.mV[VX],
- &constraint.mTargetOffset.mV[VY],
- &constraint.mTargetOffset.mV[VZ],
- &constraint.mTargetDir.mV[VX],
- &constraint.mTargetDir.mV[VY],
- &constraint.mTargetDir.mV[VZ]) != 16)
- {
- if(sscanf( /* Flawfinder: ignore */
- mLine,
- " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f",
- &constraint.mChainLength,
- &constraint.mEaseInStart,
- &constraint.mEaseInStop,
- &constraint.mEaseOutStart,
- &constraint.mEaseOutStop,
- constraint.mSourceJointName,
- &constraint.mSourceOffset.mV[VX],
- &constraint.mSourceOffset.mV[VY],
- &constraint.mSourceOffset.mV[VZ],
- constraint.mTargetJointName,
- &constraint.mTargetOffset.mV[VX],
- &constraint.mTargetOffset.mV[VY],
- &constraint.mTargetOffset.mV[VZ]) != 13)
- {
- return E_ST_NO_CONSTRAINT;
- }
- }
- else
- {
- // normalize direction
- if (!constraint.mTargetDir.isExactlyZero())
- {
- constraint.mTargetDir.normVec();
- }
-
- }
-
- constraint.mConstraintType = CONSTRAINT_TYPE_PLANE;
- mConstraints.push_back(constraint);
- continue;
- }
- }
-
- infile.close() ;
- return E_ST_OK;
-}
-void LLBVHLoader::makeTranslation(std::string alias_name, std::string joint_name)
-{
- //Translation &newTrans = (foomap.insert(value_type(alias_name, Translation()))).first();
- Translation &newTrans = mTranslations[ alias_name ]; //Uses []'s implicit call to ctor.
-
- newTrans.mOutName = joint_name;
- LLMatrix3 fm;
- LLVector3 vect1(0, 1, 0);
- LLVector3 vect2(0, 0, 1);
- LLVector3 vect3(1, 0, 0);
- fm.setRows(vect1, vect2, vect3);
-
- newTrans.mFrameMatrix = fm;
-
-if (joint_name == "mPelvis")
- {
- newTrans.mRelativePositionKey = true;
- newTrans.mRelativeRotationKey = true;
- }
-
-}
-
-ELoadStatus LLBVHLoader::loadAliases(const char * filename)
-{
- LLSD aliases_sd;
-
- std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,filename);
-
- llifstream input_stream;
- input_stream.open(fullpath.c_str(), std::ios::in | std::ios::binary);
-
- if(input_stream.is_open())
- {
- if ( LLSDSerialize::fromXML(aliases_sd, input_stream) )
- {
- for(LLSD::map_iterator alias_iter = aliases_sd.beginMap();
- alias_iter != aliases_sd.endMap();
- ++alias_iter)
- {
- LLSD::String alias_name = alias_iter->first;
- LLSD::String joint_name = alias_iter->second;
- makeTranslation(alias_name, joint_name);
-
- }
- }
- else
- {
- return E_ST_NO_XLT_HEADER;
- }
- input_stream.close();
- }
- else
- {
- LL_WARNS("BVH") << "Can't open joint alias file " << fullpath << LL_ENDL;
- return E_ST_NO_XLT_FILE;
- }
-
- return E_ST_OK;
-}
-
-void LLBVHLoader::dumpBVHInfo()
-{
- for (U32 j=0; j<mJoints.size(); j++)
- {
- Joint *joint = mJoints[j];
- LL_DEBUGS("BVH") << joint->mName << LL_ENDL;
- for (S32 i=0; i<mNumFrames; i++)
- {
- if (i<joint->mKeys.size()) // Check this in case file load failed.
- {
- Key &prevkey = joint->mKeys[llmax(i-1,0)];
- Key &key = joint->mKeys[i];
- if ((i==0) ||
- (key.mPos[0] != prevkey.mPos[0]) ||
- (key.mPos[1] != prevkey.mPos[1]) ||
- (key.mPos[2] != prevkey.mPos[2]) ||
- (key.mRot[0] != prevkey.mRot[0]) ||
- (key.mRot[1] != prevkey.mRot[1]) ||
- (key.mRot[2] != prevkey.mRot[2])
- )
- {
- LL_DEBUGS("BVH") << "FRAME " << i
- << " POS " << key.mPos[0] << "," << key.mPos[1] << "," << key.mPos[2]
- << " ROT " << key.mRot[0] << "," << key.mRot[1] << "," << key.mRot[2] << LL_ENDL;
- }
- }
- }
- }
-
-}
-
-//------------------------------------------------------------------------
-// LLBVHLoader::loadBVHFile()
-//------------------------------------------------------------------------
-ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &err_line)
-{
- std::string line;
-
- err_line = 0;
- error_text[127] = '\0';
-
- std::string str(buffer);
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("\r\n");
- tokenizer tokens(str, sep);
- tokenizer::iterator iter = tokens.begin();
-
- mLineNumber = 0;
- mJoints.clear();
-
- std::vector<S32> parent_joints;
-
- //--------------------------------------------------------------------
- // consume hierarchy
- //--------------------------------------------------------------------
- if (iter == tokens.end())
- return E_ST_EOF;
- line = (*(iter++));
- err_line++;
-
- if ( !strstr(line.c_str(), "HIERARCHY") )
- {
-// LL_INFOS() << line << LL_ENDL;
- return E_ST_NO_HIER;
- }
-
- //--------------------------------------------------------------------
- // consume joints
- //--------------------------------------------------------------------
- while (true)
- {
- //----------------------------------------------------------------
- // get next line
- //----------------------------------------------------------------
- if (iter == tokens.end())
- return E_ST_EOF;
- line = (*(iter++));
- err_line++;
-
- //----------------------------------------------------------------
- // consume }
- //----------------------------------------------------------------
- if ( strstr(line.c_str(), "}") )
- {
- if (parent_joints.size() > 0)
- {
- parent_joints.pop_back();
- }
- continue;
- }
-
- //----------------------------------------------------------------
- // if MOTION, break out
- //----------------------------------------------------------------
- if ( strstr(line.c_str(), "MOTION") )
- break;
-
- //----------------------------------------------------------------
- // it must be either ROOT or JOINT or EndSite
- //----------------------------------------------------------------
- if ( strstr(line.c_str(), "ROOT") )
- {
- }
- else if ( strstr(line.c_str(), "JOINT") )
- {
- }
- else if ( strstr(line.c_str(), "End Site") )
- {
- iter++; // {
- iter++; // OFFSET
- iter++; // }
- S32 depth = 0;
- for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
- {
- Joint *joint = mJoints[parent_joints[j]];
- if (depth > joint->mChildTreeMaxDepth)
- {
- joint->mChildTreeMaxDepth = depth;
- }
- depth++;
- }
- continue;
- }
- else
- {
- strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
- return E_ST_NO_JOINT;
- }
-
- //----------------------------------------------------------------
- // get the joint name
- //----------------------------------------------------------------
- char jointName[80]; /* Flawfinder: ignore */
- if ( sscanf(line.c_str(), "%*s %79s", jointName) != 1 ) /* Flawfinder: ignore */
- {
- strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
- return E_ST_NO_NAME;
- }
-
- //---------------------------------------------------------------
- // we require the root joint be "hip" - DEV-26188
- //---------------------------------------------------------------
- if (mJoints.size() == 0 )
- {
- //The root joint of the BVH file must be hip (mPelvis) or an alias of mPelvis.
- const char* FORCED_ROOT_NAME = "hip";
-
- TranslationMap::iterator hip_joint = mTranslations.find( FORCED_ROOT_NAME );
- TranslationMap::iterator root_joint = mTranslations.find( jointName );
- if ( hip_joint == mTranslations.end() || root_joint == mTranslations.end() || root_joint->second.mOutName != hip_joint->second.mOutName )
- {
- strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */
- return E_ST_BAD_ROOT;
- }
- }
-
-
- //----------------------------------------------------------------
- // add a set of keyframes for this joint
- //----------------------------------------------------------------
- mJoints.push_back( new Joint( jointName ) );
- Joint *joint = mJoints.back();
- LL_DEBUGS("BVH") << "Created joint " << jointName << LL_ENDL;
- LL_DEBUGS("BVH") << "- index " << mJoints.size()-1 << LL_ENDL;
-
- S32 depth = 1;
- for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--)
- {
- Joint *pjoint = mJoints[parent_joints[j]];
- LL_DEBUGS("BVH") << "- ancestor " << pjoint->mName << LL_ENDL;
- if (depth > pjoint->mChildTreeMaxDepth)
- {
- pjoint->mChildTreeMaxDepth = depth;
- }
- depth++;
- }
-
- //----------------------------------------------------------------
- // get next line
- //----------------------------------------------------------------
- if (iter == tokens.end())
- {
- return E_ST_EOF;
- }
- line = (*(iter++));
- err_line++;
-
- //----------------------------------------------------------------
- // it must be {
- //----------------------------------------------------------------
- if ( !strstr(line.c_str(), "{") )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_OFFSET;
- }
- else
- {
- parent_joints.push_back((S32)mJoints.size() - 1);
- }
-
- //----------------------------------------------------------------
- // get next line
- //----------------------------------------------------------------
- if (iter == tokens.end())
- {
- return E_ST_EOF;
- }
- line = (*(iter++));
- err_line++;
-
- //----------------------------------------------------------------
- // it must be OFFSET
- //----------------------------------------------------------------
- if ( !strstr(line.c_str(), "OFFSET") )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_OFFSET;
- }
-
- //----------------------------------------------------------------
- // get next line
- //----------------------------------------------------------------
- if (iter == tokens.end())
- {
- return E_ST_EOF;
- }
- line = (*(iter++));
- err_line++;
-
- //----------------------------------------------------------------
- // it must be CHANNELS
- //----------------------------------------------------------------
- if ( !strstr(line.c_str(), "CHANNELS") )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_CHANNELS;
- }
-
- // Animating position (via mNumChannels = 6) is only supported for mPelvis.
- int res = sscanf(line.c_str(), " CHANNELS %d", &joint->mNumChannels);
- if ( res != 1 )
- {
- // Assume default if not otherwise specified.
- if (mJoints.size()==1)
- {
- joint->mNumChannels = 6;
- }
- else
- {
- joint->mNumChannels = 3;
- }
- }
-
- //----------------------------------------------------------------
- // get rotation order
- //----------------------------------------------------------------
- const char *p = line.c_str();
- for (S32 i=0; i<3; i++)
- {
- p = strstr(p, "rotation");
- if (!p)
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_ROTATION;
- }
-
- const char axis = *(p - 1);
- if ((axis != 'X') && (axis != 'Y') && (axis != 'Z'))
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_AXIS;
- }
-
- joint->mOrder[i] = axis;
-
- p++;
- }
- }
-
- //--------------------------------------------------------------------
- // consume motion
- //--------------------------------------------------------------------
- if ( !strstr(line.c_str(), "MOTION") )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_MOTION;
- }
-
- //--------------------------------------------------------------------
- // get number of frames
- //--------------------------------------------------------------------
- if (iter == tokens.end())
- {
- return E_ST_EOF;
- }
- line = (*(iter++));
- err_line++;
-
- if ( !strstr(line.c_str(), "Frames:") )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_FRAMES;
- }
-
- if ( sscanf(line.c_str(), "Frames: %d", &mNumFrames) != 1 )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_FRAMES;
- }
-
- //--------------------------------------------------------------------
- // get frame time
- //--------------------------------------------------------------------
- if (iter == tokens.end())
- {
- return E_ST_EOF;
- }
- line = (*(iter++));
- err_line++;
-
- if ( !strstr(line.c_str(), "Frame Time:") )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_FRAME_TIME;
- }
-
- if ( sscanf(line.c_str(), "Frame Time: %f", &mFrameTime) != 1 )
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_FRAME_TIME;
- }
-
- // If the user only supplies one animation frame (after the ignored reference frame 0), hold for mFrameTime.
- // If the user supples exactly one total frame, it isn't clear if that is a pose or reference frame, and the
- // behavior is not defined. In this case, retain historical undefined behavior.
- mDuration = llmax((F32)(mNumFrames - NUMBER_OF_UNPLAYED_FRAMES), 1.0f) * mFrameTime;
- if (!mLoop)
- {
- mLoopOutPoint = mDuration;
- }
-
- //--------------------------------------------------------------------
- // load frames
- //--------------------------------------------------------------------
- for (S32 i=0; i<mNumFrames; i++)
- {
- // get next line
- if (iter == tokens.end())
- {
- return E_ST_EOF;
- }
- line = (*(iter++));
- err_line++;
-
- // Split line into a collection of floats.
- std::deque<F32> floats;
- boost::char_separator<char> whitespace_sep("\t ");
- tokenizer float_tokens(line, whitespace_sep);
- tokenizer::iterator float_token_iter = float_tokens.begin();
- while (float_token_iter != float_tokens.end())
- {
- try
- {
- F32 val = boost::lexical_cast<float>(*float_token_iter);
- floats.push_back(val);
- }
- catch (const boost::bad_lexical_cast&)
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_POS;
- }
- float_token_iter++;
- }
- LL_DEBUGS("BVH") << "Got " << floats.size() << " floats " << LL_ENDL;
- for (U32 j=0; j<mJoints.size(); j++)
- {
- Joint *joint = mJoints[j];
- joint->mKeys.push_back( Key() );
- Key &key = joint->mKeys.back();
-
- if (floats.size() < joint->mNumChannels)
- {
- strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/
- return E_ST_NO_POS;
- }
-
- // assume either numChannels == 6, in which case we have pos + rot,
- // or numChannels == 3, in which case we have only rot.
- if (joint->mNumChannels == 6)
- {
- key.mPos[0] = floats.front(); floats.pop_front();
- key.mPos[1] = floats.front(); floats.pop_front();
- key.mPos[2] = floats.front(); floats.pop_front();
- }
- key.mRot[ joint->mOrder[0]-'X' ] = floats.front(); floats.pop_front();
- key.mRot[ joint->mOrder[1]-'X' ] = floats.front(); floats.pop_front();
- key.mRot[ joint->mOrder[2]-'X' ] = floats.front(); floats.pop_front();
- }
- }
-
- return E_ST_OK;
-}
-
-
-//------------------------------------------------------------------------
-// LLBVHLoader::applyTranslation()
-//------------------------------------------------------------------------
-void LLBVHLoader::applyTranslations()
-{
- for (Joint* joint : mJoints)
- {
- //----------------------------------------------------------------
- // Look for a translation for this joint.
- // If none, skip to next joint
- //----------------------------------------------------------------
- TranslationMap::iterator ti = mTranslations.find( joint->mName );
- if ( ti == mTranslations.end() )
- {
- continue;
- }
-
- Translation &trans = ti->second;
-
- //----------------------------------------------------------------
- // Set the ignore flag if necessary
- //----------------------------------------------------------------
- if ( trans.mIgnore )
- {
- //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL;
- joint->mIgnore = true;
- continue;
- }
-
- //----------------------------------------------------------------
- // Set the output name
- //----------------------------------------------------------------
- if ( ! trans.mOutName.empty() )
- {
- //LL_INFOS() << "NOTE: Changing " << joint->mName.c_str() << " to " << trans.mOutName.c_str() << LL_ENDL;
- joint->mOutName = trans.mOutName;
- }
-
- //Allow joint position changes as of SL-318
- joint->mIgnorePositions = false;
- if (joint->mNumChannels == 3)
- {
- joint->mIgnorePositions = true;
- }
-
- //----------------------------------------------------------------
- // Set the relativepos flags if necessary
- //----------------------------------------------------------------
- if ( trans.mRelativePositionKey )
- {
-// LL_INFOS() << "NOTE: Removing 1st position offset from all keys for " << joint->mOutName.c_str() << LL_ENDL;
- joint->mRelativePositionKey = true;
- }
-
- if ( trans.mRelativeRotationKey )
- {
-// LL_INFOS() << "NOTE: Removing 1st rotation from all keys for " << joint->mOutName.c_str() << LL_ENDL;
- joint->mRelativeRotationKey = true;
- }
-
- if ( trans.mRelativePosition.magVec() > 0.0f )
- {
- joint->mRelativePosition = trans.mRelativePosition;
-// LL_INFOS() << "NOTE: Removing " <<
-// joint->mRelativePosition.mV[0] << " " <<
-// joint->mRelativePosition.mV[1] << " " <<
-// joint->mRelativePosition.mV[2] <<
-// " from all position keys in " <<
-// joint->mOutName.c_str() << LL_ENDL;
- }
-
- //----------------------------------------------------------------
- // Set change of coordinate frame
- //----------------------------------------------------------------
- joint->mFrameMatrix = trans.mFrameMatrix;
- joint->mOffsetMatrix = trans.mOffsetMatrix;
-
- //----------------------------------------------------------------
- // Set mergeparent name
- //----------------------------------------------------------------
- if ( ! trans.mMergeParentName.empty() )
- {
-// LL_INFOS() << "NOTE: Merging " << joint->mOutName.c_str() <<
-// " with parent " <<
-// trans.mMergeParentName.c_str() << LL_ENDL;
- joint->mMergeParentName = trans.mMergeParentName;
- }
-
- //----------------------------------------------------------------
- // Set mergechild name
- //----------------------------------------------------------------
- if ( ! trans.mMergeChildName.empty() )
- {
-// LL_INFOS() << "NOTE: Merging " << joint->mName.c_str() <<
-// " with child " << trans.mMergeChildName.c_str() << LL_ENDL;
- joint->mMergeChildName = trans.mMergeChildName;
- }
-
- //----------------------------------------------------------------
- // Set joint priority
- //----------------------------------------------------------------
- joint->mPriority = mPriority + trans.mPriorityModifier;
-
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLBVHLoader::optimize()
-//-----------------------------------------------------------------------------
-void LLBVHLoader::optimize()
-{
- //RN: assumes motion blend, which is the default now
- if (!mLoop && mEaseIn + mEaseOut > mDuration && mDuration != 0.f)
- {
- F32 factor = mDuration / (mEaseIn + mEaseOut);
- mEaseIn *= factor;
- mEaseOut *= factor;
- }
-
- for (Joint* joint : mJoints)
- {
- bool pos_changed = false;
- bool rot_changed = false;
-
- if ( ! joint->mIgnore )
- {
- joint->mNumPosKeys = 0;
- joint->mNumRotKeys = 0;
- LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
-
- KeyVector::iterator first_key = joint->mKeys.begin();
-
- // no keys?
- if (first_key == joint->mKeys.end())
- {
- joint->mIgnore = true;
- continue;
- }
-
- LLVector3 first_frame_pos(first_key->mPos);
- LLQuaternion first_frame_rot = mayaQ( first_key->mRot[0], first_key->mRot[1], first_key->mRot[2], order);
-
- // skip first key
- KeyVector::iterator ki = joint->mKeys.begin();
- if (joint->mKeys.size() == 1)
- {
- // *FIX: use single frame to move pelvis
- // if only one keyframe force output for this joint
- rot_changed = true;
- }
- else
- {
- // if more than one keyframe, use first frame as reference and skip to second
- first_key->mIgnorePos = true;
- first_key->mIgnoreRot = true;
- ++ki;
- }
-
- KeyVector::iterator ki_prev = ki;
- KeyVector::iterator ki_last_good_pos = ki;
- KeyVector::iterator ki_last_good_rot = ki;
- S32 numPosFramesConsidered = 2;
- S32 numRotFramesConsidered = 2;
-
- F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)joint->mChildTreeMaxDepth * 0.33f, 1.f);
-
- double diff_max = 0;
- KeyVector::iterator ki_max = ki;
- for (; ki != joint->mKeys.end(); ++ki)
- {
- if (ki_prev == ki_last_good_pos)
- {
- joint->mNumPosKeys++;
- if (dist_vec_squared(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED)
- {
- pos_changed = true;
- }
- }
- else
- {
- //check position for noticeable effect
- LLVector3 test_pos(ki_prev->mPos);
- LLVector3 last_good_pos(ki_last_good_pos->mPos);
- LLVector3 current_pos(ki->mPos);
- LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered);
-
- if (dist_vec_squared(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED)
- {
- pos_changed = true;
- }
-
- if (dist_vec_squared(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD_SQUARED)
- {
- ki_prev->mIgnorePos = true;
- numPosFramesConsidered++;
- }
- else
- {
- numPosFramesConsidered = 2;
- ki_last_good_pos = ki_prev;
- joint->mNumPosKeys++;
- }
- }
-
- if (ki_prev == ki_last_good_rot)
- {
- joint->mNumRotKeys++;
- LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order);
- F32 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
- F32 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
- F32 rot_test = x_delta + y_delta;
-
- if (rot_test > ROTATION_MOTION_THRESHOLD)
- {
- rot_changed = true;
- }
- }
- else
- {
- //check rotation for noticeable effect
- LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order);
- LLQuaternion last_good_rot = mayaQ( ki_last_good_rot->mRot[0], ki_last_good_rot->mRot[1], ki_last_good_rot->mRot[2], order);
- LLQuaternion current_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order);
- LLQuaternion interp_rot = lerp(1.f / (F32)numRotFramesConsidered, current_rot, last_good_rot);
-
- F32 x_delta;
- F32 y_delta;
- F32 rot_test;
-
- // Test if the rotation has changed significantly since the very first frame. If false
- // for all frames, then we'll just throw out this joint's rotation entirely.
- x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot);
- y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot);
- rot_test = x_delta + y_delta;
- if (rot_test > ROTATION_MOTION_THRESHOLD)
- {
- rot_changed = true;
- }
- x_delta = dist_vec(LLVector3::x_axis * interp_rot, LLVector3::x_axis * test_rot);
- y_delta = dist_vec(LLVector3::y_axis * interp_rot, LLVector3::y_axis * test_rot);
- rot_test = x_delta + y_delta;
-
- // Draw a line between the last good keyframe and current. Test the distance between the last frame (current-1, i.e. ki_prev)
- // and the line. If it's greater than some threshold, then it represents a significant frame and we want to include it.
- if (rot_test >= rot_threshold ||
- (ki+1 == joint->mKeys.end() && numRotFramesConsidered > 2))
- {
- // Add the current test keyframe (which is technically the previous key, i.e. ki_prev).
- numRotFramesConsidered = 2;
- ki_last_good_rot = ki_prev;
- joint->mNumRotKeys++;
-
- // Add another keyframe between the last good keyframe and current, at whatever point was the most "significant" (i.e.
- // had the largest deviation from the earlier tests). Note that a more robust approach would be test all intermediate
- // keyframes against the line between the last good keyframe and current, but we're settling for this other method
- // because it's significantly faster.
- if (diff_max > 0)
- {
- if (ki_max->mIgnoreRot)
- {
- ki_max->mIgnoreRot = false;
- joint->mNumRotKeys++;
- }
- diff_max = 0;
- }
- }
- else
- {
- // This keyframe isn't significant enough, throw it away.
- ki_prev->mIgnoreRot = true;
- numRotFramesConsidered++;
- // Store away the keyframe that has the largest deviation from the interpolated line, for insertion later.
- if (rot_test > diff_max)
- {
- diff_max = rot_test;
- ki_max = ki;
- }
- }
- }
-
- ki_prev = ki;
- }
- }
-
- // don't output joints with no motion
- if (!(pos_changed || rot_changed))
- {
- //LL_INFOS() << "Ignoring joint " << joint->mName << LL_ENDL;
- joint->mIgnore = true;
- }
- }
-}
-
-void LLBVHLoader::reset()
-{
- mLineNumber = 0;
- mNumFrames = 0;
- mFrameTime = 0.0f;
- mDuration = 0.0f;
-
- mPriority = 2;
- mLoop = false;
- mLoopInPoint = 0.f;
- mLoopOutPoint = 0.f;
- mEaseIn = 0.3f;
- mEaseOut = 0.3f;
- mHand = 1;
- mInitialized = false;
-
- mEmoteName = "";
- mLineNumber = 0;
- mTranslations.clear();
- mConstraints.clear();
-}
-
-//------------------------------------------------------------------------
-// LLBVHLoader::getLine()
-//------------------------------------------------------------------------
-bool LLBVHLoader::getLine(apr_file_t* fp)
-{
- if (apr_file_eof(fp) == APR_EOF)
- {
- return false;
- }
- if ( apr_file_gets(mLine, BVH_PARSER_LINE_SIZE, fp) == APR_SUCCESS)
- {
- mLineNumber++;
- return true;
- }
-
- return false;
-}
-
-// returns required size of output buffer
-U32 LLBVHLoader::getOutputSize()
-{
- LLDataPackerBinaryBuffer dp;
- serialize(dp);
-
- return dp.getCurrentSize();
-}
-
-// writes contents to datapacker
-bool LLBVHLoader::serialize(LLDataPacker& dp)
-{
- F32 time;
-
- // count number of non-ignored joints
- S32 numJoints = 0;
- for (Joint* joint : mJoints)
- {
- if ( ! joint->mIgnore )
- numJoints++;
- }
-
- // print header
- dp.packU16(KEYFRAME_MOTION_VERSION, "version");
- dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
- dp.packS32(mPriority, "base_priority");
- dp.packF32(mDuration, "duration");
- dp.packString(mEmoteName, "emote_name");
- dp.packF32(mLoopInPoint, "loop_in_point");
- dp.packF32(mLoopOutPoint, "loop_out_point");
- dp.packS32(mLoop, "loop");
- dp.packF32(mEaseIn, "ease_in_duration");
- dp.packF32(mEaseOut, "ease_out_duration");
- dp.packU32(mHand, "hand_pose");
- dp.packU32(numJoints, "num_joints");
-
- for (Joint* joint : mJoints)
- {
- // if ignored, skip it
- if ( joint->mIgnore )
- continue;
-
- LLQuaternion first_frame_rot;
- LLQuaternion fixup_rot;
-
- dp.packString(joint->mOutName, "joint_name");
- dp.packS32(joint->mPriority, "joint_priority");
-
- // compute coordinate frame rotation
- LLQuaternion frameRot( joint->mFrameMatrix );
- LLQuaternion frameRotInv = ~frameRot;
-
- LLQuaternion offsetRot( joint->mOffsetMatrix );
-
- // find mergechild and mergeparent joints, if specified
- LLQuaternion mergeParentRot;
- LLQuaternion mergeChildRot;
- Joint *mergeParent = NULL;
- Joint *mergeChild = NULL;
-
- for (Joint* mjoint : mJoints)
- {
- if ( !joint->mMergeParentName.empty() && (mjoint->mName == joint->mMergeParentName) )
- {
- mergeParent = mjoint;
- }
- if ( !joint->mMergeChildName.empty() && (mjoint->mName == joint->mMergeChildName) )
- {
- mergeChild = mjoint;
- }
- }
-
- dp.packS32(joint->mNumRotKeys, "num_rot_keys");
-
- LLQuaternion::Order order = bvhStringToOrder( joint->mOrder );
- S32 frame = 0;
- for (Key& key : joint->mKeys)
- {
-
- if ((frame == 0) && joint->mRelativeRotationKey)
- {
- first_frame_rot = mayaQ( key.mRot[0], key.mRot[1], key.mRot[2], order);
-
- fixup_rot.shortestArc(LLVector3::z_axis * first_frame_rot * frameRot, LLVector3::z_axis);
- }
-
- if (key.mIgnoreRot)
- {
- frame++;
- continue;
- }
-
- time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
-
- if (mergeParent)
- {
- mergeParentRot = mayaQ( mergeParent->mKeys[frame-1].mRot[0],
- mergeParent->mKeys[frame-1].mRot[1],
- mergeParent->mKeys[frame-1].mRot[2],
- bvhStringToOrder(mergeParent->mOrder) );
- LLQuaternion parentFrameRot( mergeParent->mFrameMatrix );
- LLQuaternion parentOffsetRot( mergeParent->mOffsetMatrix );
- mergeParentRot = ~parentFrameRot * mergeParentRot * parentFrameRot * parentOffsetRot;
- }
- else
- {
- mergeParentRot.loadIdentity();
- }
-
- if (mergeChild)
- {
- mergeChildRot = mayaQ( mergeChild->mKeys[frame-1].mRot[0],
- mergeChild->mKeys[frame-1].mRot[1],
- mergeChild->mKeys[frame-1].mRot[2],
- bvhStringToOrder(mergeChild->mOrder) );
- LLQuaternion childFrameRot( mergeChild->mFrameMatrix );
- LLQuaternion childOffsetRot( mergeChild->mOffsetMatrix );
- mergeChildRot = ~childFrameRot * mergeChildRot * childFrameRot * childOffsetRot;
-
- }
- else
- {
- mergeChildRot.loadIdentity();
- }
-
- LLQuaternion inRot = mayaQ( key.mRot[0], key.mRot[1], key.mRot[2], order);
-
- LLQuaternion outRot = frameRotInv* mergeChildRot * inRot * mergeParentRot * ~first_frame_rot * frameRot * offsetRot;
-
- U16 time_short = F32_to_U16(time, 0.f, mDuration);
- dp.packU16(time_short, "time");
- U16 x, y, z;
- LLVector3 rot_vec = outRot.packToVector3();
- rot_vec.quantize16(-1.f, 1.f, -1.f, 1.f);
- x = F32_to_U16(rot_vec.mV[VX], -1.f, 1.f);
- y = F32_to_U16(rot_vec.mV[VY], -1.f, 1.f);
- z = F32_to_U16(rot_vec.mV[VZ], -1.f, 1.f);
- dp.packU16(x, "rot_angle_x");
- dp.packU16(y, "rot_angle_y");
- dp.packU16(z, "rot_angle_z");
- frame++;
- }
-
- // output position keys if joint has motion.
- if ( !joint->mIgnorePositions )
- {
- dp.packS32(joint->mNumPosKeys, "num_pos_keys");
-
- LLVector3 relPos = joint->mRelativePosition;
- LLVector3 relKey;
-
- frame = 0;
- for (Key& key : joint->mKeys)
- {
- if ((frame == 0) && joint->mRelativePositionKey)
- {
- relKey.setVec(key.mPos);
- }
-
- if (key.mIgnorePos)
- {
- frame++;
- continue;
- }
-
- time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts.
-
- LLVector3 inPos = (LLVector3(key.mPos) - relKey) * ~first_frame_rot;// * fixup_rot;
- LLVector3 outPos = inPos * frameRot * offsetRot;
-
- outPos *= INCHES_TO_METERS;
-
- //SL-318 Pelvis position can only move 5m. Limiting all joint position offsets to this dist.
- outPos -= relPos;
- outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
-
- U16 time_short = F32_to_U16(time, 0.f, mDuration);
- dp.packU16(time_short, "time");
-
- U16 x, y, z;
- outPos.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- x = F32_to_U16(outPos.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- y = F32_to_U16(outPos.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- z = F32_to_U16(outPos.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- dp.packU16(x, "pos_x");
- dp.packU16(y, "pos_y");
- dp.packU16(z, "pos_z");
-
- frame++;
- }
- }
- else
- {
- dp.packS32(0, "num_pos_keys");
- }
- }
-
- S32 num_constraints = (S32)mConstraints.size();
- dp.packS32(num_constraints, "num_constraints");
-
- for (Constraint& constraint : mConstraints)
- {
- U8 byte = constraint.mChainLength;
- dp.packU8(byte, "chain_length");
-
- byte = constraint.mConstraintType;
- dp.packU8(byte, "constraint_type");
- dp.packBinaryDataFixed((U8*)constraint.mSourceJointName, 16, "source_volume");
- dp.packVector3(constraint.mSourceOffset, "source_offset");
- dp.packBinaryDataFixed((U8*)constraint.mTargetJointName, 16, "target_volume");
- dp.packVector3(constraint.mTargetOffset, "target_offset");
- dp.packVector3(constraint.mTargetDir, "target_dir");
- dp.packF32(constraint.mEaseInStart, "ease_in_start");
- dp.packF32(constraint.mEaseInStop, "ease_in_stop");
- dp.packF32(constraint.mEaseOutStart, "ease_out_start");
- dp.packF32(constraint.mEaseOutStop, "ease_out_stop");
- }
-
-
- return true;
-}
+/** + * @file llbvhloader.cpp + * @brief Translates a BVH files to LindenLabAnimation format. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful,7 + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llbvhloader.h" + +#include <boost/tokenizer.hpp> +#include <boost/lexical_cast.hpp> + +#include "lldatapacker.h" +#include "lldir.h" +#include "llkeyframemotion.h" +#include "llquantize.h" +#include "llstl.h" +#include "llapr.h" +#include "llsdserialize.h" + + +using namespace std; + +#define INCHES_TO_METERS 0.02540005f + +/// The .bvh does not have a formal spec, and different readers interpret things in their own way. +/// In OUR usage, frame 0 is used in optimization and is not considered to be part of the animation. +const S32 NUMBER_OF_IGNORED_FRAMES_AT_START = 1; +/// In our usage, the last frame is used only to indicate what the penultimate frame should be interpolated towards. +/// I.e., the animation only plays up to the start of the last frame. There is no hold or exptrapolation past that point.. +/// Thus there are two frame of the total that do not contribute to the total running time of the animation. +const S32 NUMBER_OF_UNPLAYED_FRAMES = NUMBER_OF_IGNORED_FRAMES_AT_START + 1; + +const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f; +const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f; + +const F32 POSITION_MOTION_THRESHOLD_SQUARED = 0.001f * 0.001f; +const F32 ROTATION_MOTION_THRESHOLD = 0.001f; + +char gInFile[1024]; /* Flawfinder: ignore */ +char gOutFile[1024]; /* Flawfinder: ignore */ +/* +//------------------------------------------------------------------------ +// Status Codes +//------------------------------------------------------------------------ +const char *LLBVHLoader::ST_OK = "Ok"; +const char *LLBVHLoader::ST_EOF = "Premature end of file."; +const char *LLBVHLoader::ST_NO_CONSTRAINT = "Can't read constraint definition."; +const char *LLBVHLoader::ST_NO_FILE = "Can't open BVH file."; +const char *LLBVHLoader::ST_NO_HIER = "Invalid HIERARCHY header."; +const char *LLBVHLoader::ST_NO_JOINT = "Can't find ROOT or JOINT."; +const char *LLBVHLoader::ST_NO_NAME = "Can't get JOINT name."; +const char *LLBVHLoader::ST_NO_OFFSET = "Can't find OFFSET."; +const char *LLBVHLoader::ST_NO_CHANNELS = "Can't find CHANNELS."; +const char *LLBVHLoader::ST_NO_ROTATION = "Can't get rotation order."; +const char *LLBVHLoader::ST_NO_AXIS = "Can't get rotation axis."; +const char *LLBVHLoader::ST_NO_MOTION = "Can't find MOTION."; +const char *LLBVHLoader::ST_NO_FRAMES = "Can't get number of frames."; +const char *LLBVHLoader::ST_NO_FRAME_TIME = "Can't get frame time."; +const char *LLBVHLoader::ST_NO_POS = "Can't get position values."; +const char *LLBVHLoader::ST_NO_ROT = "Can't get rotation values."; +const char *LLBVHLoader::ST_NO_XLT_FILE = "Can't open translation file."; +const char *LLBVHLoader::ST_NO_XLT_HEADER = "Can't read translation header."; +const char *LLBVHLoader::ST_NO_XLT_NAME = "Can't read translation names."; +const char *LLBVHLoader::ST_NO_XLT_IGNORE = "Can't read translation ignore value."; +const char *LLBVHLoader::ST_NO_XLT_RELATIVE = "Can't read translation relative value."; +const char *LLBVHLoader::ST_NO_XLT_OUTNAME = "Can't read translation outname value."; +const char *LLBVHLoader::ST_NO_XLT_MATRIX = "Can't read translation matrix."; +const char *LLBVHLoader::ST_NO_XLT_MERGECHILD = "Can't get mergechild name."; +const char *LLBVHLoader::ST_NO_XLT_MERGEPARENT = "Can't get mergeparent name."; +const char *LLBVHLoader::ST_NO_XLT_PRIORITY = "Can't get priority value."; +const char *LLBVHLoader::ST_NO_XLT_LOOP = "Can't get loop value."; +const char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values."; +const char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values."; +const char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value."; +const char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name."; +const char *LLBVHLoader::ST_BAD_ROOT = "Illegal ROOT joint."; +*/ + +//------------------------------------------------------------------------ +// find_next_whitespace() +//------------------------------------------------------------------------ +const char *find_next_whitespace(const char *p) +{ + while(*p && isspace(*p)) p++; + while(*p && !isspace(*p)) p++; + return p; +} + + +//------------------------------------------------------------------------ +// bvhStringToOrder() +// +// XYZ order in BVH files must be passed to mayaQ() as ZYX. +// This function reverses the input string before passing it on +// to StringToOrder(). +//------------------------------------------------------------------------ +LLQuaternion::Order bvhStringToOrder( char *str ) +{ + char order[4]; /* Flawfinder: ignore */ + order[0] = str[2]; + order[1] = str[1]; + order[2] = str[0]; + order[3] = 0; + LLQuaternion::Order retVal = StringToOrder( order ); + return retVal; +} + +//----------------------------------------------------------------------------- +// LLBVHLoader() +//----------------------------------------------------------------------------- + +LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map ) +{ + reset(); + errorLine = 0; + mStatus = loadTranslationTable("anim.ini"); + loadStatus = mStatus; + LL_INFOS("BVH") << "Load Status 00 : " << loadStatus << LL_ENDL; + if (mStatus == E_ST_NO_XLT_FILE) + { + LL_WARNS("BVH") << "NOTE: No translation table found." << LL_ENDL; + loadStatus = mStatus; + return; + } + else + { + if (mStatus != E_ST_OK) + { + LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; + errorLine = getLineNumber(); + loadStatus = mStatus; + return; + } + } + + // Recognize all names we've been told are legal. + for (std::map<std::string, std::string>::value_type& alias_pair : joint_alias_map) + { + makeTranslation( alias_pair.first , alias_pair.second ); + } + + char error_text[128]; /* Flawfinder: ignore */ + S32 error_line; + mStatus = loadBVHFile(buffer, error_text, error_line); //Reads all joints in BVH file. + + LL_DEBUGS("BVH") << "============================================================" << LL_ENDL; + LL_DEBUGS("BVH") << "Raw data from file" << LL_ENDL; + dumpBVHInfo(); + + if (mStatus != E_ST_OK) + { + LL_WARNS("BVH") << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; + loadStatus = mStatus; + errorLine = getLineNumber(); + return; + } + + applyTranslations(); //Maps between joints found in file and the aliased names. + optimize(); + + LL_DEBUGS("BVH") << "============================================================" << LL_ENDL; + LL_DEBUGS("BVH") << "After translations and optimize" << LL_ENDL; + dumpBVHInfo(); + + mInitialized = true; +} + + +LLBVHLoader::~LLBVHLoader() +{ + std::for_each(mJoints.begin(),mJoints.end(),DeletePointer()); + mJoints.clear(); +} + +//------------------------------------------------------------------------ +// LLBVHLoader::loadTranslationTable() +//------------------------------------------------------------------------ +ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) +{ + //-------------------------------------------------------------------- + // open file + //-------------------------------------------------------------------- + std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName); + + LLAPRFile infile ; + infile.open(path, LL_APR_R); + apr_file_t *fp = infile.getFileHandle(); + if (!fp) + return E_ST_NO_XLT_FILE; + + LL_INFOS("BVH") << "NOTE: Loading translation table: " << fileName << LL_ENDL; + + //-------------------------------------------------------------------- + // register file to be closed on function exit + //-------------------------------------------------------------------- + + //-------------------------------------------------------------------- + // load header + //-------------------------------------------------------------------- + if ( ! getLine(fp) ) + return E_ST_EOF; + if ( strncmp(mLine, "Translations 1.0", 16) ) + return E_ST_NO_XLT_HEADER; + + //-------------------------------------------------------------------- + // load data one line at a time + //-------------------------------------------------------------------- + bool loadingGlobals = false; + while ( getLine(fp) ) + { + //---------------------------------------------------------------- + // check the 1st token on the line to determine if it's empty or a comment + //---------------------------------------------------------------- + char token[128]; /* Flawfinder: ignore */ + if ( sscanf(mLine, " %127s", token) != 1 ) /* Flawfinder: ignore */ + continue; + + if (token[0] == '#') + continue; + + //---------------------------------------------------------------- + // check if a [jointName] or [GLOBALS] was specified. + //---------------------------------------------------------------- + if (token[0] == '[') + { + char name[128]; /* Flawfinder: ignore */ + if ( sscanf(mLine, " [%127[^]]", name) != 1 ) + return E_ST_NO_XLT_NAME; + + if (strcmp(name, "GLOBALS")==0) + { + loadingGlobals = true; + continue; + } + } + + //---------------------------------------------------------------- + // check for optional emote + //---------------------------------------------------------------- + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "emote")==0) + { + char emote_str[1024]; /* Flawfinder: ignore */ + if ( sscanf(mLine, " %*s = %1023s", emote_str) != 1 ) /* Flawfinder: ignore */ + return E_ST_NO_XLT_EMOTE; + + mEmoteName.assign( emote_str ); +// LL_INFOS() << "NOTE: Emote: " << mEmoteName.c_str() << LL_ENDL; + continue; + } + + + //---------------------------------------------------------------- + // check for global priority setting + //---------------------------------------------------------------- + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "priority")==0) + { + S32 priority; + if ( sscanf(mLine, " %*s = %d", &priority) != 1 ) + return E_ST_NO_XLT_PRIORITY; + + mPriority = priority; +// LL_INFOS() << "NOTE: Priority: " << mPriority << LL_ENDL; + continue; + } + + //---------------------------------------------------------------- + // check for global loop setting + //---------------------------------------------------------------- + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "loop")==0) + { + char trueFalse[128]; /* Flawfinder: ignore */ + trueFalse[0] = '\0'; + + F32 loop_in = 0.f; + F32 loop_out = 1.f; + + if ( sscanf(mLine, " %*s = %f %f", &loop_in, &loop_out) == 2 ) + { + mLoop = true; + } + else if ( sscanf(mLine, " %*s = %127s", trueFalse) == 1 ) /* Flawfinder: ignore */ + { + mLoop = (LLStringUtil::compareInsensitive(trueFalse, "true")==0); + } + else + { + return E_ST_NO_XLT_LOOP; + } + + mLoopInPoint = loop_in * mDuration; + mLoopOutPoint = loop_out * mDuration; + + continue; + } + + //---------------------------------------------------------------- + // check for global easeIn setting + //---------------------------------------------------------------- + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "easein")==0) + { + F32 duration; + char type[128]; /* Flawfinder: ignore */ + if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 ) /* Flawfinder: ignore */ + return E_ST_NO_XLT_EASEIN; + + mEaseIn = duration; + continue; + } + + //---------------------------------------------------------------- + // check for global easeOut setting + //---------------------------------------------------------------- + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "easeout")==0) + { + F32 duration; + char type[128]; /* Flawfinder: ignore */ + if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 ) /* Flawfinder: ignore */ + return E_ST_NO_XLT_EASEOUT; + + mEaseOut = duration; + continue; + } + + //---------------------------------------------------------------- + // check for global handMorph setting + //---------------------------------------------------------------- + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "hand")==0) + { + S32 handMorph; + if (sscanf(mLine, " %*s = %d", &handMorph) != 1) + return E_ST_NO_XLT_HAND; + + mHand = handMorph; + continue; + } + + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "constraint")==0) + { + Constraint constraint; + + // try reading optional target direction + if(sscanf( /* Flawfinder: ignore */ + mLine, + " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f", + &constraint.mChainLength, + &constraint.mEaseInStart, + &constraint.mEaseInStop, + &constraint.mEaseOutStart, + &constraint.mEaseOutStop, + constraint.mSourceJointName, + &constraint.mSourceOffset.mV[VX], + &constraint.mSourceOffset.mV[VY], + &constraint.mSourceOffset.mV[VZ], + constraint.mTargetJointName, + &constraint.mTargetOffset.mV[VX], + &constraint.mTargetOffset.mV[VY], + &constraint.mTargetOffset.mV[VZ], + &constraint.mTargetDir.mV[VX], + &constraint.mTargetDir.mV[VY], + &constraint.mTargetDir.mV[VZ]) != 16) + { + if(sscanf( /* Flawfinder: ignore */ + mLine, + " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f", + &constraint.mChainLength, + &constraint.mEaseInStart, + &constraint.mEaseInStop, + &constraint.mEaseOutStart, + &constraint.mEaseOutStop, + constraint.mSourceJointName, + &constraint.mSourceOffset.mV[VX], + &constraint.mSourceOffset.mV[VY], + &constraint.mSourceOffset.mV[VZ], + constraint.mTargetJointName, + &constraint.mTargetOffset.mV[VX], + &constraint.mTargetOffset.mV[VY], + &constraint.mTargetOffset.mV[VZ]) != 13) + { + return E_ST_NO_CONSTRAINT; + } + } + else + { + // normalize direction + if (!constraint.mTargetDir.isExactlyZero()) + { + constraint.mTargetDir.normVec(); + } + + } + + constraint.mConstraintType = CONSTRAINT_TYPE_POINT; + mConstraints.push_back(constraint); + continue; + } + + if (loadingGlobals && LLStringUtil::compareInsensitive(token, "planar_constraint")==0) + { + Constraint constraint; + + // try reading optional target direction + if(sscanf( /* Flawfinder: ignore */ + mLine, + " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f %f %f %f", + &constraint.mChainLength, + &constraint.mEaseInStart, + &constraint.mEaseInStop, + &constraint.mEaseOutStart, + &constraint.mEaseOutStop, + constraint.mSourceJointName, + &constraint.mSourceOffset.mV[VX], + &constraint.mSourceOffset.mV[VY], + &constraint.mSourceOffset.mV[VZ], + constraint.mTargetJointName, + &constraint.mTargetOffset.mV[VX], + &constraint.mTargetOffset.mV[VY], + &constraint.mTargetOffset.mV[VZ], + &constraint.mTargetDir.mV[VX], + &constraint.mTargetDir.mV[VY], + &constraint.mTargetDir.mV[VZ]) != 16) + { + if(sscanf( /* Flawfinder: ignore */ + mLine, + " %*s = %d %f %f %f %f %15s %f %f %f %15s %f %f %f", + &constraint.mChainLength, + &constraint.mEaseInStart, + &constraint.mEaseInStop, + &constraint.mEaseOutStart, + &constraint.mEaseOutStop, + constraint.mSourceJointName, + &constraint.mSourceOffset.mV[VX], + &constraint.mSourceOffset.mV[VY], + &constraint.mSourceOffset.mV[VZ], + constraint.mTargetJointName, + &constraint.mTargetOffset.mV[VX], + &constraint.mTargetOffset.mV[VY], + &constraint.mTargetOffset.mV[VZ]) != 13) + { + return E_ST_NO_CONSTRAINT; + } + } + else + { + // normalize direction + if (!constraint.mTargetDir.isExactlyZero()) + { + constraint.mTargetDir.normVec(); + } + + } + + constraint.mConstraintType = CONSTRAINT_TYPE_PLANE; + mConstraints.push_back(constraint); + continue; + } + } + + infile.close() ; + return E_ST_OK; +} +void LLBVHLoader::makeTranslation(std::string alias_name, std::string joint_name) +{ + //Translation &newTrans = (foomap.insert(value_type(alias_name, Translation()))).first(); + Translation &newTrans = mTranslations[ alias_name ]; //Uses []'s implicit call to ctor. + + newTrans.mOutName = joint_name; + LLMatrix3 fm; + LLVector3 vect1(0, 1, 0); + LLVector3 vect2(0, 0, 1); + LLVector3 vect3(1, 0, 0); + fm.setRows(vect1, vect2, vect3); + + newTrans.mFrameMatrix = fm; + +if (joint_name == "mPelvis") + { + newTrans.mRelativePositionKey = true; + newTrans.mRelativeRotationKey = true; + } + +} + +ELoadStatus LLBVHLoader::loadAliases(const char * filename) +{ + LLSD aliases_sd; + + std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,filename); + + llifstream input_stream; + input_stream.open(fullpath.c_str(), std::ios::in | std::ios::binary); + + if(input_stream.is_open()) + { + if ( LLSDSerialize::fromXML(aliases_sd, input_stream) ) + { + for(LLSD::map_iterator alias_iter = aliases_sd.beginMap(); + alias_iter != aliases_sd.endMap(); + ++alias_iter) + { + LLSD::String alias_name = alias_iter->first; + LLSD::String joint_name = alias_iter->second; + makeTranslation(alias_name, joint_name); + + } + } + else + { + return E_ST_NO_XLT_HEADER; + } + input_stream.close(); + } + else + { + LL_WARNS("BVH") << "Can't open joint alias file " << fullpath << LL_ENDL; + return E_ST_NO_XLT_FILE; + } + + return E_ST_OK; +} + +void LLBVHLoader::dumpBVHInfo() +{ + for (U32 j=0; j<mJoints.size(); j++) + { + Joint *joint = mJoints[j]; + LL_DEBUGS("BVH") << joint->mName << LL_ENDL; + for (S32 i=0; i<mNumFrames; i++) + { + if (i<joint->mKeys.size()) // Check this in case file load failed. + { + Key &prevkey = joint->mKeys[llmax(i-1,0)]; + Key &key = joint->mKeys[i]; + if ((i==0) || + (key.mPos[0] != prevkey.mPos[0]) || + (key.mPos[1] != prevkey.mPos[1]) || + (key.mPos[2] != prevkey.mPos[2]) || + (key.mRot[0] != prevkey.mRot[0]) || + (key.mRot[1] != prevkey.mRot[1]) || + (key.mRot[2] != prevkey.mRot[2]) + ) + { + LL_DEBUGS("BVH") << "FRAME " << i + << " POS " << key.mPos[0] << "," << key.mPos[1] << "," << key.mPos[2] + << " ROT " << key.mRot[0] << "," << key.mRot[1] << "," << key.mRot[2] << LL_ENDL; + } + } + } + } + +} + +//------------------------------------------------------------------------ +// LLBVHLoader::loadBVHFile() +//------------------------------------------------------------------------ +ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &err_line) +{ + std::string line; + + err_line = 0; + error_text[127] = '\0'; + + std::string str(buffer); + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("\r\n"); + tokenizer tokens(str, sep); + tokenizer::iterator iter = tokens.begin(); + + mLineNumber = 0; + mJoints.clear(); + + std::vector<S32> parent_joints; + + //-------------------------------------------------------------------- + // consume hierarchy + //-------------------------------------------------------------------- + if (iter == tokens.end()) + return E_ST_EOF; + line = (*(iter++)); + err_line++; + + if ( !strstr(line.c_str(), "HIERARCHY") ) + { +// LL_INFOS() << line << LL_ENDL; + return E_ST_NO_HIER; + } + + //-------------------------------------------------------------------- + // consume joints + //-------------------------------------------------------------------- + while (true) + { + //---------------------------------------------------------------- + // get next line + //---------------------------------------------------------------- + if (iter == tokens.end()) + return E_ST_EOF; + line = (*(iter++)); + err_line++; + + //---------------------------------------------------------------- + // consume } + //---------------------------------------------------------------- + if ( strstr(line.c_str(), "}") ) + { + if (parent_joints.size() > 0) + { + parent_joints.pop_back(); + } + continue; + } + + //---------------------------------------------------------------- + // if MOTION, break out + //---------------------------------------------------------------- + if ( strstr(line.c_str(), "MOTION") ) + break; + + //---------------------------------------------------------------- + // it must be either ROOT or JOINT or EndSite + //---------------------------------------------------------------- + if ( strstr(line.c_str(), "ROOT") ) + { + } + else if ( strstr(line.c_str(), "JOINT") ) + { + } + else if ( strstr(line.c_str(), "End Site") ) + { + iter++; // { + iter++; // OFFSET + iter++; // } + S32 depth = 0; + for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--) + { + Joint *joint = mJoints[parent_joints[j]]; + if (depth > joint->mChildTreeMaxDepth) + { + joint->mChildTreeMaxDepth = depth; + } + depth++; + } + continue; + } + else + { + strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ + return E_ST_NO_JOINT; + } + + //---------------------------------------------------------------- + // get the joint name + //---------------------------------------------------------------- + char jointName[80]; /* Flawfinder: ignore */ + if ( sscanf(line.c_str(), "%*s %79s", jointName) != 1 ) /* Flawfinder: ignore */ + { + strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ + return E_ST_NO_NAME; + } + + //--------------------------------------------------------------- + // we require the root joint be "hip" - DEV-26188 + //--------------------------------------------------------------- + if (mJoints.size() == 0 ) + { + //The root joint of the BVH file must be hip (mPelvis) or an alias of mPelvis. + const char* FORCED_ROOT_NAME = "hip"; + + TranslationMap::iterator hip_joint = mTranslations.find( FORCED_ROOT_NAME ); + TranslationMap::iterator root_joint = mTranslations.find( jointName ); + if ( hip_joint == mTranslations.end() || root_joint == mTranslations.end() || root_joint->second.mOutName != hip_joint->second.mOutName ) + { + strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ + return E_ST_BAD_ROOT; + } + } + + + //---------------------------------------------------------------- + // add a set of keyframes for this joint + //---------------------------------------------------------------- + mJoints.push_back( new Joint( jointName ) ); + Joint *joint = mJoints.back(); + LL_DEBUGS("BVH") << "Created joint " << jointName << LL_ENDL; + LL_DEBUGS("BVH") << "- index " << mJoints.size()-1 << LL_ENDL; + + S32 depth = 1; + for (S32 j = (S32)parent_joints.size() - 1; j >= 0; j--) + { + Joint *pjoint = mJoints[parent_joints[j]]; + LL_DEBUGS("BVH") << "- ancestor " << pjoint->mName << LL_ENDL; + if (depth > pjoint->mChildTreeMaxDepth) + { + pjoint->mChildTreeMaxDepth = depth; + } + depth++; + } + + //---------------------------------------------------------------- + // get next line + //---------------------------------------------------------------- + if (iter == tokens.end()) + { + return E_ST_EOF; + } + line = (*(iter++)); + err_line++; + + //---------------------------------------------------------------- + // it must be { + //---------------------------------------------------------------- + if ( !strstr(line.c_str(), "{") ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_OFFSET; + } + else + { + parent_joints.push_back((S32)mJoints.size() - 1); + } + + //---------------------------------------------------------------- + // get next line + //---------------------------------------------------------------- + if (iter == tokens.end()) + { + return E_ST_EOF; + } + line = (*(iter++)); + err_line++; + + //---------------------------------------------------------------- + // it must be OFFSET + //---------------------------------------------------------------- + if ( !strstr(line.c_str(), "OFFSET") ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_OFFSET; + } + + //---------------------------------------------------------------- + // get next line + //---------------------------------------------------------------- + if (iter == tokens.end()) + { + return E_ST_EOF; + } + line = (*(iter++)); + err_line++; + + //---------------------------------------------------------------- + // it must be CHANNELS + //---------------------------------------------------------------- + if ( !strstr(line.c_str(), "CHANNELS") ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_CHANNELS; + } + + // Animating position (via mNumChannels = 6) is only supported for mPelvis. + int res = sscanf(line.c_str(), " CHANNELS %d", &joint->mNumChannels); + if ( res != 1 ) + { + // Assume default if not otherwise specified. + if (mJoints.size()==1) + { + joint->mNumChannels = 6; + } + else + { + joint->mNumChannels = 3; + } + } + + //---------------------------------------------------------------- + // get rotation order + //---------------------------------------------------------------- + const char *p = line.c_str(); + for (S32 i=0; i<3; i++) + { + p = strstr(p, "rotation"); + if (!p) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_ROTATION; + } + + const char axis = *(p - 1); + if ((axis != 'X') && (axis != 'Y') && (axis != 'Z')) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_AXIS; + } + + joint->mOrder[i] = axis; + + p++; + } + } + + //-------------------------------------------------------------------- + // consume motion + //-------------------------------------------------------------------- + if ( !strstr(line.c_str(), "MOTION") ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_MOTION; + } + + //-------------------------------------------------------------------- + // get number of frames + //-------------------------------------------------------------------- + if (iter == tokens.end()) + { + return E_ST_EOF; + } + line = (*(iter++)); + err_line++; + + if ( !strstr(line.c_str(), "Frames:") ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_FRAMES; + } + + if ( sscanf(line.c_str(), "Frames: %d", &mNumFrames) != 1 ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_FRAMES; + } + + //-------------------------------------------------------------------- + // get frame time + //-------------------------------------------------------------------- + if (iter == tokens.end()) + { + return E_ST_EOF; + } + line = (*(iter++)); + err_line++; + + if ( !strstr(line.c_str(), "Frame Time:") ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_FRAME_TIME; + } + + if ( sscanf(line.c_str(), "Frame Time: %f", &mFrameTime) != 1 ) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_FRAME_TIME; + } + + // If the user only supplies one animation frame (after the ignored reference frame 0), hold for mFrameTime. + // If the user supples exactly one total frame, it isn't clear if that is a pose or reference frame, and the + // behavior is not defined. In this case, retain historical undefined behavior. + mDuration = llmax((F32)(mNumFrames - NUMBER_OF_UNPLAYED_FRAMES), 1.0f) * mFrameTime; + if (!mLoop) + { + mLoopOutPoint = mDuration; + } + + //-------------------------------------------------------------------- + // load frames + //-------------------------------------------------------------------- + for (S32 i=0; i<mNumFrames; i++) + { + // get next line + if (iter == tokens.end()) + { + return E_ST_EOF; + } + line = (*(iter++)); + err_line++; + + // Split line into a collection of floats. + std::deque<F32> floats; + boost::char_separator<char> whitespace_sep("\t "); + tokenizer float_tokens(line, whitespace_sep); + tokenizer::iterator float_token_iter = float_tokens.begin(); + while (float_token_iter != float_tokens.end()) + { + try + { + F32 val = boost::lexical_cast<float>(*float_token_iter); + floats.push_back(val); + } + catch (const boost::bad_lexical_cast&) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_POS; + } + float_token_iter++; + } + LL_DEBUGS("BVH") << "Got " << floats.size() << " floats " << LL_ENDL; + for (U32 j=0; j<mJoints.size(); j++) + { + Joint *joint = mJoints[j]; + joint->mKeys.push_back( Key() ); + Key &key = joint->mKeys.back(); + + if (floats.size() < joint->mNumChannels) + { + strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ + return E_ST_NO_POS; + } + + // assume either numChannels == 6, in which case we have pos + rot, + // or numChannels == 3, in which case we have only rot. + if (joint->mNumChannels == 6) + { + key.mPos[0] = floats.front(); floats.pop_front(); + key.mPos[1] = floats.front(); floats.pop_front(); + key.mPos[2] = floats.front(); floats.pop_front(); + } + key.mRot[ joint->mOrder[0]-'X' ] = floats.front(); floats.pop_front(); + key.mRot[ joint->mOrder[1]-'X' ] = floats.front(); floats.pop_front(); + key.mRot[ joint->mOrder[2]-'X' ] = floats.front(); floats.pop_front(); + } + } + + return E_ST_OK; +} + + +//------------------------------------------------------------------------ +// LLBVHLoader::applyTranslation() +//------------------------------------------------------------------------ +void LLBVHLoader::applyTranslations() +{ + for (Joint* joint : mJoints) + { + //---------------------------------------------------------------- + // Look for a translation for this joint. + // If none, skip to next joint + //---------------------------------------------------------------- + TranslationMap::iterator ti = mTranslations.find( joint->mName ); + if ( ti == mTranslations.end() ) + { + continue; + } + + Translation &trans = ti->second; + + //---------------------------------------------------------------- + // Set the ignore flag if necessary + //---------------------------------------------------------------- + if ( trans.mIgnore ) + { + //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL; + joint->mIgnore = true; + continue; + } + + //---------------------------------------------------------------- + // Set the output name + //---------------------------------------------------------------- + if ( ! trans.mOutName.empty() ) + { + //LL_INFOS() << "NOTE: Changing " << joint->mName.c_str() << " to " << trans.mOutName.c_str() << LL_ENDL; + joint->mOutName = trans.mOutName; + } + + //Allow joint position changes as of SL-318 + joint->mIgnorePositions = false; + if (joint->mNumChannels == 3) + { + joint->mIgnorePositions = true; + } + + //---------------------------------------------------------------- + // Set the relativepos flags if necessary + //---------------------------------------------------------------- + if ( trans.mRelativePositionKey ) + { +// LL_INFOS() << "NOTE: Removing 1st position offset from all keys for " << joint->mOutName.c_str() << LL_ENDL; + joint->mRelativePositionKey = true; + } + + if ( trans.mRelativeRotationKey ) + { +// LL_INFOS() << "NOTE: Removing 1st rotation from all keys for " << joint->mOutName.c_str() << LL_ENDL; + joint->mRelativeRotationKey = true; + } + + if ( trans.mRelativePosition.magVec() > 0.0f ) + { + joint->mRelativePosition = trans.mRelativePosition; +// LL_INFOS() << "NOTE: Removing " << +// joint->mRelativePosition.mV[0] << " " << +// joint->mRelativePosition.mV[1] << " " << +// joint->mRelativePosition.mV[2] << +// " from all position keys in " << +// joint->mOutName.c_str() << LL_ENDL; + } + + //---------------------------------------------------------------- + // Set change of coordinate frame + //---------------------------------------------------------------- + joint->mFrameMatrix = trans.mFrameMatrix; + joint->mOffsetMatrix = trans.mOffsetMatrix; + + //---------------------------------------------------------------- + // Set mergeparent name + //---------------------------------------------------------------- + if ( ! trans.mMergeParentName.empty() ) + { +// LL_INFOS() << "NOTE: Merging " << joint->mOutName.c_str() << +// " with parent " << +// trans.mMergeParentName.c_str() << LL_ENDL; + joint->mMergeParentName = trans.mMergeParentName; + } + + //---------------------------------------------------------------- + // Set mergechild name + //---------------------------------------------------------------- + if ( ! trans.mMergeChildName.empty() ) + { +// LL_INFOS() << "NOTE: Merging " << joint->mName.c_str() << +// " with child " << trans.mMergeChildName.c_str() << LL_ENDL; + joint->mMergeChildName = trans.mMergeChildName; + } + + //---------------------------------------------------------------- + // Set joint priority + //---------------------------------------------------------------- + joint->mPriority = mPriority + trans.mPriorityModifier; + + } +} + +//----------------------------------------------------------------------------- +// LLBVHLoader::optimize() +//----------------------------------------------------------------------------- +void LLBVHLoader::optimize() +{ + //RN: assumes motion blend, which is the default now + if (!mLoop && mEaseIn + mEaseOut > mDuration && mDuration != 0.f) + { + F32 factor = mDuration / (mEaseIn + mEaseOut); + mEaseIn *= factor; + mEaseOut *= factor; + } + + for (Joint* joint : mJoints) + { + bool pos_changed = false; + bool rot_changed = false; + + if ( ! joint->mIgnore ) + { + joint->mNumPosKeys = 0; + joint->mNumRotKeys = 0; + LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); + + KeyVector::iterator first_key = joint->mKeys.begin(); + + // no keys? + if (first_key == joint->mKeys.end()) + { + joint->mIgnore = true; + continue; + } + + LLVector3 first_frame_pos(first_key->mPos); + LLQuaternion first_frame_rot = mayaQ( first_key->mRot[0], first_key->mRot[1], first_key->mRot[2], order); + + // skip first key + KeyVector::iterator ki = joint->mKeys.begin(); + if (joint->mKeys.size() == 1) + { + // *FIX: use single frame to move pelvis + // if only one keyframe force output for this joint + rot_changed = true; + } + else + { + // if more than one keyframe, use first frame as reference and skip to second + first_key->mIgnorePos = true; + first_key->mIgnoreRot = true; + ++ki; + } + + KeyVector::iterator ki_prev = ki; + KeyVector::iterator ki_last_good_pos = ki; + KeyVector::iterator ki_last_good_rot = ki; + S32 numPosFramesConsidered = 2; + S32 numRotFramesConsidered = 2; + + F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)joint->mChildTreeMaxDepth * 0.33f, 1.f); + + double diff_max = 0; + KeyVector::iterator ki_max = ki; + for (; ki != joint->mKeys.end(); ++ki) + { + if (ki_prev == ki_last_good_pos) + { + joint->mNumPosKeys++; + if (dist_vec_squared(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED) + { + pos_changed = true; + } + } + else + { + //check position for noticeable effect + LLVector3 test_pos(ki_prev->mPos); + LLVector3 last_good_pos(ki_last_good_pos->mPos); + LLVector3 current_pos(ki->mPos); + LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered); + + if (dist_vec_squared(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED) + { + pos_changed = true; + } + + if (dist_vec_squared(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD_SQUARED) + { + ki_prev->mIgnorePos = true; + numPosFramesConsidered++; + } + else + { + numPosFramesConsidered = 2; + ki_last_good_pos = ki_prev; + joint->mNumPosKeys++; + } + } + + if (ki_prev == ki_last_good_rot) + { + joint->mNumRotKeys++; + LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order); + F32 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot); + F32 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot); + F32 rot_test = x_delta + y_delta; + + if (rot_test > ROTATION_MOTION_THRESHOLD) + { + rot_changed = true; + } + } + else + { + //check rotation for noticeable effect + LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order); + LLQuaternion last_good_rot = mayaQ( ki_last_good_rot->mRot[0], ki_last_good_rot->mRot[1], ki_last_good_rot->mRot[2], order); + LLQuaternion current_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order); + LLQuaternion interp_rot = lerp(1.f / (F32)numRotFramesConsidered, current_rot, last_good_rot); + + F32 x_delta; + F32 y_delta; + F32 rot_test; + + // Test if the rotation has changed significantly since the very first frame. If false + // for all frames, then we'll just throw out this joint's rotation entirely. + x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot); + y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot); + rot_test = x_delta + y_delta; + if (rot_test > ROTATION_MOTION_THRESHOLD) + { + rot_changed = true; + } + x_delta = dist_vec(LLVector3::x_axis * interp_rot, LLVector3::x_axis * test_rot); + y_delta = dist_vec(LLVector3::y_axis * interp_rot, LLVector3::y_axis * test_rot); + rot_test = x_delta + y_delta; + + // Draw a line between the last good keyframe and current. Test the distance between the last frame (current-1, i.e. ki_prev) + // and the line. If it's greater than some threshold, then it represents a significant frame and we want to include it. + if (rot_test >= rot_threshold || + (ki+1 == joint->mKeys.end() && numRotFramesConsidered > 2)) + { + // Add the current test keyframe (which is technically the previous key, i.e. ki_prev). + numRotFramesConsidered = 2; + ki_last_good_rot = ki_prev; + joint->mNumRotKeys++; + + // Add another keyframe between the last good keyframe and current, at whatever point was the most "significant" (i.e. + // had the largest deviation from the earlier tests). Note that a more robust approach would be test all intermediate + // keyframes against the line between the last good keyframe and current, but we're settling for this other method + // because it's significantly faster. + if (diff_max > 0) + { + if (ki_max->mIgnoreRot) + { + ki_max->mIgnoreRot = false; + joint->mNumRotKeys++; + } + diff_max = 0; + } + } + else + { + // This keyframe isn't significant enough, throw it away. + ki_prev->mIgnoreRot = true; + numRotFramesConsidered++; + // Store away the keyframe that has the largest deviation from the interpolated line, for insertion later. + if (rot_test > diff_max) + { + diff_max = rot_test; + ki_max = ki; + } + } + } + + ki_prev = ki; + } + } + + // don't output joints with no motion + if (!(pos_changed || rot_changed)) + { + //LL_INFOS() << "Ignoring joint " << joint->mName << LL_ENDL; + joint->mIgnore = true; + } + } +} + +void LLBVHLoader::reset() +{ + mLineNumber = 0; + mNumFrames = 0; + mFrameTime = 0.0f; + mDuration = 0.0f; + + mPriority = 2; + mLoop = false; + mLoopInPoint = 0.f; + mLoopOutPoint = 0.f; + mEaseIn = 0.3f; + mEaseOut = 0.3f; + mHand = 1; + mInitialized = false; + + mEmoteName = ""; + mLineNumber = 0; + mTranslations.clear(); + mConstraints.clear(); +} + +//------------------------------------------------------------------------ +// LLBVHLoader::getLine() +//------------------------------------------------------------------------ +bool LLBVHLoader::getLine(apr_file_t* fp) +{ + if (apr_file_eof(fp) == APR_EOF) + { + return false; + } + if ( apr_file_gets(mLine, BVH_PARSER_LINE_SIZE, fp) == APR_SUCCESS) + { + mLineNumber++; + return true; + } + + return false; +} + +// returns required size of output buffer +U32 LLBVHLoader::getOutputSize() +{ + LLDataPackerBinaryBuffer dp; + serialize(dp); + + return dp.getCurrentSize(); +} + +// writes contents to datapacker +bool LLBVHLoader::serialize(LLDataPacker& dp) +{ + F32 time; + + // count number of non-ignored joints + S32 numJoints = 0; + for (Joint* joint : mJoints) + { + if ( ! joint->mIgnore ) + numJoints++; + } + + // print header + dp.packU16(KEYFRAME_MOTION_VERSION, "version"); + dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version"); + dp.packS32(mPriority, "base_priority"); + dp.packF32(mDuration, "duration"); + dp.packString(mEmoteName, "emote_name"); + dp.packF32(mLoopInPoint, "loop_in_point"); + dp.packF32(mLoopOutPoint, "loop_out_point"); + dp.packS32(mLoop, "loop"); + dp.packF32(mEaseIn, "ease_in_duration"); + dp.packF32(mEaseOut, "ease_out_duration"); + dp.packU32(mHand, "hand_pose"); + dp.packU32(numJoints, "num_joints"); + + for (Joint* joint : mJoints) + { + // if ignored, skip it + if ( joint->mIgnore ) + continue; + + LLQuaternion first_frame_rot; + LLQuaternion fixup_rot; + + dp.packString(joint->mOutName, "joint_name"); + dp.packS32(joint->mPriority, "joint_priority"); + + // compute coordinate frame rotation + LLQuaternion frameRot( joint->mFrameMatrix ); + LLQuaternion frameRotInv = ~frameRot; + + LLQuaternion offsetRot( joint->mOffsetMatrix ); + + // find mergechild and mergeparent joints, if specified + LLQuaternion mergeParentRot; + LLQuaternion mergeChildRot; + Joint *mergeParent = NULL; + Joint *mergeChild = NULL; + + for (Joint* mjoint : mJoints) + { + if ( !joint->mMergeParentName.empty() && (mjoint->mName == joint->mMergeParentName) ) + { + mergeParent = mjoint; + } + if ( !joint->mMergeChildName.empty() && (mjoint->mName == joint->mMergeChildName) ) + { + mergeChild = mjoint; + } + } + + dp.packS32(joint->mNumRotKeys, "num_rot_keys"); + + LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); + S32 frame = 0; + for (Key& key : joint->mKeys) + { + + if ((frame == 0) && joint->mRelativeRotationKey) + { + first_frame_rot = mayaQ( key.mRot[0], key.mRot[1], key.mRot[2], order); + + fixup_rot.shortestArc(LLVector3::z_axis * first_frame_rot * frameRot, LLVector3::z_axis); + } + + if (key.mIgnoreRot) + { + frame++; + continue; + } + + time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts. + + if (mergeParent) + { + mergeParentRot = mayaQ( mergeParent->mKeys[frame-1].mRot[0], + mergeParent->mKeys[frame-1].mRot[1], + mergeParent->mKeys[frame-1].mRot[2], + bvhStringToOrder(mergeParent->mOrder) ); + LLQuaternion parentFrameRot( mergeParent->mFrameMatrix ); + LLQuaternion parentOffsetRot( mergeParent->mOffsetMatrix ); + mergeParentRot = ~parentFrameRot * mergeParentRot * parentFrameRot * parentOffsetRot; + } + else + { + mergeParentRot.loadIdentity(); + } + + if (mergeChild) + { + mergeChildRot = mayaQ( mergeChild->mKeys[frame-1].mRot[0], + mergeChild->mKeys[frame-1].mRot[1], + mergeChild->mKeys[frame-1].mRot[2], + bvhStringToOrder(mergeChild->mOrder) ); + LLQuaternion childFrameRot( mergeChild->mFrameMatrix ); + LLQuaternion childOffsetRot( mergeChild->mOffsetMatrix ); + mergeChildRot = ~childFrameRot * mergeChildRot * childFrameRot * childOffsetRot; + + } + else + { + mergeChildRot.loadIdentity(); + } + + LLQuaternion inRot = mayaQ( key.mRot[0], key.mRot[1], key.mRot[2], order); + + LLQuaternion outRot = frameRotInv* mergeChildRot * inRot * mergeParentRot * ~first_frame_rot * frameRot * offsetRot; + + U16 time_short = F32_to_U16(time, 0.f, mDuration); + dp.packU16(time_short, "time"); + U16 x, y, z; + LLVector3 rot_vec = outRot.packToVector3(); + rot_vec.quantize16(-1.f, 1.f, -1.f, 1.f); + x = F32_to_U16(rot_vec.mV[VX], -1.f, 1.f); + y = F32_to_U16(rot_vec.mV[VY], -1.f, 1.f); + z = F32_to_U16(rot_vec.mV[VZ], -1.f, 1.f); + dp.packU16(x, "rot_angle_x"); + dp.packU16(y, "rot_angle_y"); + dp.packU16(z, "rot_angle_z"); + frame++; + } + + // output position keys if joint has motion. + if ( !joint->mIgnorePositions ) + { + dp.packS32(joint->mNumPosKeys, "num_pos_keys"); + + LLVector3 relPos = joint->mRelativePosition; + LLVector3 relKey; + + frame = 0; + for (Key& key : joint->mKeys) + { + if ((frame == 0) && joint->mRelativePositionKey) + { + relKey.setVec(key.mPos); + } + + if (key.mIgnorePos) + { + frame++; + continue; + } + + time = llmax((F32)(frame - NUMBER_OF_IGNORED_FRAMES_AT_START), 0.0f) * mFrameTime; // Time elapsed before this frame starts. + + LLVector3 inPos = (LLVector3(key.mPos) - relKey) * ~first_frame_rot;// * fixup_rot; + LLVector3 outPos = inPos * frameRot * offsetRot; + + outPos *= INCHES_TO_METERS; + + //SL-318 Pelvis position can only move 5m. Limiting all joint position offsets to this dist. + outPos -= relPos; + outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + + U16 time_short = F32_to_U16(time, 0.f, mDuration); + dp.packU16(time_short, "time"); + + U16 x, y, z; + outPos.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + x = F32_to_U16(outPos.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + y = F32_to_U16(outPos.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + z = F32_to_U16(outPos.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + dp.packU16(x, "pos_x"); + dp.packU16(y, "pos_y"); + dp.packU16(z, "pos_z"); + + frame++; + } + } + else + { + dp.packS32(0, "num_pos_keys"); + } + } + + S32 num_constraints = (S32)mConstraints.size(); + dp.packS32(num_constraints, "num_constraints"); + + for (Constraint& constraint : mConstraints) + { + U8 byte = constraint.mChainLength; + dp.packU8(byte, "chain_length"); + + byte = constraint.mConstraintType; + dp.packU8(byte, "constraint_type"); + dp.packBinaryDataFixed((U8*)constraint.mSourceJointName, 16, "source_volume"); + dp.packVector3(constraint.mSourceOffset, "source_offset"); + dp.packBinaryDataFixed((U8*)constraint.mTargetJointName, 16, "target_volume"); + dp.packVector3(constraint.mTargetOffset, "target_offset"); + dp.packVector3(constraint.mTargetDir, "target_dir"); + dp.packF32(constraint.mEaseInStart, "ease_in_start"); + dp.packF32(constraint.mEaseInStop, "ease_in_stop"); + dp.packF32(constraint.mEaseOutStart, "ease_out_start"); + dp.packF32(constraint.mEaseOutStop, "ease_out_stop"); + } + + + return true; +} diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h index 472192d799..de31f76dd3 100644 --- a/indra/llcharacter/llbvhloader.h +++ b/indra/llcharacter/llbvhloader.h @@ -1,340 +1,340 @@ -/**
- * @file llbvhloader.h
- * @brief Translates a BVH files to LindenLabAnimation format.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLBVHLOADER_H
-#define LL_LLBVHLOADER_H
-
-#include "v3math.h"
-#include "m3math.h"
-#include "llmath.h"
-#include "llapr.h"
-#include "llbvhconsts.h"
-
-const S32 BVH_PARSER_LINE_SIZE = 2048;
-class LLDataPacker;
-
-//------------------------------------------------------------------------
-// FileCloser
-//------------------------------------------------------------------------
-class FileCloser
-{
-public:
- FileCloser( apr_file_t *file )
- {
- mFile = file;
- }
-
- ~FileCloser()
- {
- apr_file_close(mFile);
- }
-protected:
- apr_file_t* mFile;
-};
-
-
-//------------------------------------------------------------------------
-// Key
-//------------------------------------------------------------------------
-struct Key
-{
- Key()
- {
- mPos[0] = mPos[1] = mPos[2] = 0.0f;
- mRot[0] = mRot[1] = mRot[2] = 0.0f;
- mIgnorePos = false;
- mIgnoreRot = false;
- }
-
- F32 mPos[3];
- F32 mRot[3];
- bool mIgnorePos;
- bool mIgnoreRot;
-};
-
-
-//------------------------------------------------------------------------
-// KeyVector
-//------------------------------------------------------------------------
-typedef std::vector<Key> KeyVector;
-
-//------------------------------------------------------------------------
-// Joint
-//------------------------------------------------------------------------
-struct Joint
-{
- Joint(const char *name)
- {
- mName = name;
- mIgnore = false;
- mIgnorePositions = false;
- mRelativePositionKey = false;
- mRelativeRotationKey = false;
- mOutName = name;
- mOrder[0] = 'X';
- mOrder[1] = 'Y';
- mOrder[2] = 'Z';
- mOrder[3] = 0;
- mNumPosKeys = 0;
- mNumRotKeys = 0;
- mChildTreeMaxDepth = 0;
- mPriority = 0;
- mNumChannels = 3;
- }
-
- // Include aligned members first
- LLMatrix3 mFrameMatrix;
- LLMatrix3 mOffsetMatrix;
- LLVector3 mRelativePosition;
- //
- std::string mName;
- bool mIgnore;
- bool mIgnorePositions;
- bool mRelativePositionKey;
- bool mRelativeRotationKey;
- std::string mOutName;
- std::string mMergeParentName;
- std::string mMergeChildName;
- char mOrder[4]; /* Flawfinder: ignore */
- KeyVector mKeys;
- S32 mNumPosKeys;
- S32 mNumRotKeys;
- S32 mChildTreeMaxDepth;
- S32 mPriority;
- S32 mNumChannels;
-};
-
-
-struct Constraint
-{
- char mSourceJointName[16]; /* Flawfinder: ignore */
- char mTargetJointName[16]; /* Flawfinder: ignore */
- S32 mChainLength;
- LLVector3 mSourceOffset;
- LLVector3 mTargetOffset;
- LLVector3 mTargetDir;
- F32 mEaseInStart;
- F32 mEaseInStop;
- F32 mEaseOutStart;
- F32 mEaseOutStop;
- EConstraintType mConstraintType;
-};
-
-//------------------------------------------------------------------------
-// JointVector
-//------------------------------------------------------------------------
-typedef std::vector<Joint*> JointVector;
-
-//------------------------------------------------------------------------
-// ConstraintVector
-//------------------------------------------------------------------------
-typedef std::vector<Constraint> ConstraintVector;
-
-//------------------------------------------------------------------------
-// Translation
-//------------------------------------------------------------------------
-class Translation
-{
-public:
- Translation()
- {
- mIgnore = false;
- mIgnorePositions = false;
- mRelativePositionKey = false;
- mRelativeRotationKey = false;
- mPriorityModifier = 0;
- }
-
- std::string mOutName;
- bool mIgnore;
- bool mIgnorePositions;
- bool mRelativePositionKey;
- bool mRelativeRotationKey;
- LLMatrix3 mFrameMatrix;
- LLMatrix3 mOffsetMatrix;
- LLVector3 mRelativePosition;
- std::string mMergeParentName;
- std::string mMergeChildName;
- S32 mPriorityModifier;
-};
-
-typedef enum e_load_status
- {
- E_ST_OK,
- E_ST_EOF,
- E_ST_NO_CONSTRAINT,
- E_ST_NO_FILE,
- E_ST_NO_HIER,
- E_ST_NO_JOINT,
- E_ST_NO_NAME,
- E_ST_NO_OFFSET,
- E_ST_NO_CHANNELS,
- E_ST_NO_ROTATION,
- E_ST_NO_AXIS,
- E_ST_NO_MOTION,
- E_ST_NO_FRAMES,
- E_ST_NO_FRAME_TIME,
- E_ST_NO_POS,
- E_ST_NO_ROT,
- E_ST_NO_XLT_FILE,
- E_ST_NO_XLT_HEADER,
- E_ST_NO_XLT_NAME,
- E_ST_NO_XLT_IGNORE,
- E_ST_NO_XLT_RELATIVE,
- E_ST_NO_XLT_OUTNAME,
- E_ST_NO_XLT_MATRIX,
- E_ST_NO_XLT_MERGECHILD,
- E_ST_NO_XLT_MERGEPARENT,
- E_ST_NO_XLT_PRIORITY,
- E_ST_NO_XLT_LOOP,
- E_ST_NO_XLT_EASEIN,
- E_ST_NO_XLT_EASEOUT,
- E_ST_NO_XLT_HAND,
- E_ST_NO_XLT_EMOTE,
- E_ST_BAD_ROOT
- } ELoadStatus;
-
-//------------------------------------------------------------------------
-// TranslationMap
-//------------------------------------------------------------------------
-typedef std::map<std::string, Translation> TranslationMap;
-
-class LLBVHLoader
-{
- friend class LLKeyframeMotion;
-public:
- // Constructor
- LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map );
- ~LLBVHLoader();
-
-/*
- // Status Codes
- typedef const char *status_t;
- static const char *ST_OK;
- static const char *ST_EOF;
- static const char *ST_NO_CONSTRAINT;
- static const char *ST_NO_FILE;
- static const char *ST_NO_HIER;
- static const char *ST_NO_JOINT;
- static const char *ST_NO_NAME;
- static const char *ST_NO_OFFSET;
- static const char *ST_NO_CHANNELS;
- static const char *ST_NO_ROTATION;
- static const char *ST_NO_AXIS;
- static const char *ST_NO_MOTION;
- static const char *ST_NO_FRAMES;
- static const char *ST_NO_FRAME_TIME;
- static const char *ST_NO_POS;
- static const char *ST_NO_ROT;
- static const char *ST_NO_XLT_FILE;
- static const char *ST_NO_XLT_HEADER;
- static const char *ST_NO_XLT_NAME;
- static const char *ST_NO_XLT_IGNORE;
- static const char *ST_NO_XLT_RELATIVE;
- static const char *ST_NO_XLT_OUTNAME;
- static const char *ST_NO_XLT_MATRIX;
- static const char *ST_NO_XLT_MERGECHILD;
- static const char *ST_NO_XLT_MERGEPARENT;
- static const char *ST_NO_XLT_PRIORITY;
- static const char *ST_NO_XLT_LOOP;
- static const char *ST_NO_XLT_EASEIN;
- static const char *ST_NO_XLT_EASEOUT;
- static const char *ST_NO_XLT_HAND;
- static const char *ST_NO_XLT_EMOTE;
- static const char *ST_BAD_ROOT;
-*/
-
- // Loads the specified translation table.
- ELoadStatus loadTranslationTable(const char *fileName);
-
- //Create a new joint alias
- void makeTranslation(std::string key, std::string value);
-
- // Loads joint aliases from XML file.
- ELoadStatus loadAliases(const char * filename);
-
- // Load the specified BVH file.
- // Returns status code.
- ELoadStatus loadBVHFile(const char *buffer, char *error_text, S32 &error_line);
-
- void dumpBVHInfo();
-
- // Applies translations to BVH data loaded.
- void applyTranslations();
-
- // Returns the number of lines scanned.
- // Useful for error reporting.
- S32 getLineNumber() { return mLineNumber; }
-
- // returns required size of output buffer
- U32 getOutputSize();
-
- // writes contents to datapacker
- bool serialize(LLDataPacker& dp);
-
- // flags redundant keyframe data
- void optimize();
-
- void reset();
-
- F32 getDuration() { return mDuration; }
-
- bool isInitialized() { return mInitialized; }
-
- ELoadStatus getStatus() { return mStatus; }
-
-protected:
- // Consumes one line of input from file.
- bool getLine(apr_file_t *fp);
-
- // parser state
- char mLine[BVH_PARSER_LINE_SIZE]; /* Flawfinder: ignore */
- S32 mLineNumber;
-
- // parsed values
- S32 mNumFrames;
- F32 mFrameTime;
- JointVector mJoints;
- ConstraintVector mConstraints;
- TranslationMap mTranslations;
-
- S32 mPriority;
- bool mLoop;
- F32 mLoopInPoint;
- F32 mLoopOutPoint;
- F32 mEaseIn;
- F32 mEaseOut;
- S32 mHand;
- std::string mEmoteName;
-
- bool mInitialized;
- ELoadStatus mStatus;
-
- // computed values
- F32 mDuration;
-};
-
-#endif // LL_LLBVHLOADER_H
+/** + * @file llbvhloader.h + * @brief Translates a BVH files to LindenLabAnimation format. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLBVHLOADER_H +#define LL_LLBVHLOADER_H + +#include "v3math.h" +#include "m3math.h" +#include "llmath.h" +#include "llapr.h" +#include "llbvhconsts.h" + +const S32 BVH_PARSER_LINE_SIZE = 2048; +class LLDataPacker; + +//------------------------------------------------------------------------ +// FileCloser +//------------------------------------------------------------------------ +class FileCloser +{ +public: + FileCloser( apr_file_t *file ) + { + mFile = file; + } + + ~FileCloser() + { + apr_file_close(mFile); + } +protected: + apr_file_t* mFile; +}; + + +//------------------------------------------------------------------------ +// Key +//------------------------------------------------------------------------ +struct Key +{ + Key() + { + mPos[0] = mPos[1] = mPos[2] = 0.0f; + mRot[0] = mRot[1] = mRot[2] = 0.0f; + mIgnorePos = false; + mIgnoreRot = false; + } + + F32 mPos[3]; + F32 mRot[3]; + bool mIgnorePos; + bool mIgnoreRot; +}; + + +//------------------------------------------------------------------------ +// KeyVector +//------------------------------------------------------------------------ +typedef std::vector<Key> KeyVector; + +//------------------------------------------------------------------------ +// Joint +//------------------------------------------------------------------------ +struct Joint +{ + Joint(const char *name) + { + mName = name; + mIgnore = false; + mIgnorePositions = false; + mRelativePositionKey = false; + mRelativeRotationKey = false; + mOutName = name; + mOrder[0] = 'X'; + mOrder[1] = 'Y'; + mOrder[2] = 'Z'; + mOrder[3] = 0; + mNumPosKeys = 0; + mNumRotKeys = 0; + mChildTreeMaxDepth = 0; + mPriority = 0; + mNumChannels = 3; + } + + // Include aligned members first + LLMatrix3 mFrameMatrix; + LLMatrix3 mOffsetMatrix; + LLVector3 mRelativePosition; + // + std::string mName; + bool mIgnore; + bool mIgnorePositions; + bool mRelativePositionKey; + bool mRelativeRotationKey; + std::string mOutName; + std::string mMergeParentName; + std::string mMergeChildName; + char mOrder[4]; /* Flawfinder: ignore */ + KeyVector mKeys; + S32 mNumPosKeys; + S32 mNumRotKeys; + S32 mChildTreeMaxDepth; + S32 mPriority; + S32 mNumChannels; +}; + + +struct Constraint +{ + char mSourceJointName[16]; /* Flawfinder: ignore */ + char mTargetJointName[16]; /* Flawfinder: ignore */ + S32 mChainLength; + LLVector3 mSourceOffset; + LLVector3 mTargetOffset; + LLVector3 mTargetDir; + F32 mEaseInStart; + F32 mEaseInStop; + F32 mEaseOutStart; + F32 mEaseOutStop; + EConstraintType mConstraintType; +}; + +//------------------------------------------------------------------------ +// JointVector +//------------------------------------------------------------------------ +typedef std::vector<Joint*> JointVector; + +//------------------------------------------------------------------------ +// ConstraintVector +//------------------------------------------------------------------------ +typedef std::vector<Constraint> ConstraintVector; + +//------------------------------------------------------------------------ +// Translation +//------------------------------------------------------------------------ +class Translation +{ +public: + Translation() + { + mIgnore = false; + mIgnorePositions = false; + mRelativePositionKey = false; + mRelativeRotationKey = false; + mPriorityModifier = 0; + } + + std::string mOutName; + bool mIgnore; + bool mIgnorePositions; + bool mRelativePositionKey; + bool mRelativeRotationKey; + LLMatrix3 mFrameMatrix; + LLMatrix3 mOffsetMatrix; + LLVector3 mRelativePosition; + std::string mMergeParentName; + std::string mMergeChildName; + S32 mPriorityModifier; +}; + +typedef enum e_load_status + { + E_ST_OK, + E_ST_EOF, + E_ST_NO_CONSTRAINT, + E_ST_NO_FILE, + E_ST_NO_HIER, + E_ST_NO_JOINT, + E_ST_NO_NAME, + E_ST_NO_OFFSET, + E_ST_NO_CHANNELS, + E_ST_NO_ROTATION, + E_ST_NO_AXIS, + E_ST_NO_MOTION, + E_ST_NO_FRAMES, + E_ST_NO_FRAME_TIME, + E_ST_NO_POS, + E_ST_NO_ROT, + E_ST_NO_XLT_FILE, + E_ST_NO_XLT_HEADER, + E_ST_NO_XLT_NAME, + E_ST_NO_XLT_IGNORE, + E_ST_NO_XLT_RELATIVE, + E_ST_NO_XLT_OUTNAME, + E_ST_NO_XLT_MATRIX, + E_ST_NO_XLT_MERGECHILD, + E_ST_NO_XLT_MERGEPARENT, + E_ST_NO_XLT_PRIORITY, + E_ST_NO_XLT_LOOP, + E_ST_NO_XLT_EASEIN, + E_ST_NO_XLT_EASEOUT, + E_ST_NO_XLT_HAND, + E_ST_NO_XLT_EMOTE, + E_ST_BAD_ROOT + } ELoadStatus; + +//------------------------------------------------------------------------ +// TranslationMap +//------------------------------------------------------------------------ +typedef std::map<std::string, Translation> TranslationMap; + +class LLBVHLoader +{ + friend class LLKeyframeMotion; +public: + // Constructor + LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map<std::string, std::string>& joint_alias_map ); + ~LLBVHLoader(); + +/* + // Status Codes + typedef const char *status_t; + static const char *ST_OK; + static const char *ST_EOF; + static const char *ST_NO_CONSTRAINT; + static const char *ST_NO_FILE; + static const char *ST_NO_HIER; + static const char *ST_NO_JOINT; + static const char *ST_NO_NAME; + static const char *ST_NO_OFFSET; + static const char *ST_NO_CHANNELS; + static const char *ST_NO_ROTATION; + static const char *ST_NO_AXIS; + static const char *ST_NO_MOTION; + static const char *ST_NO_FRAMES; + static const char *ST_NO_FRAME_TIME; + static const char *ST_NO_POS; + static const char *ST_NO_ROT; + static const char *ST_NO_XLT_FILE; + static const char *ST_NO_XLT_HEADER; + static const char *ST_NO_XLT_NAME; + static const char *ST_NO_XLT_IGNORE; + static const char *ST_NO_XLT_RELATIVE; + static const char *ST_NO_XLT_OUTNAME; + static const char *ST_NO_XLT_MATRIX; + static const char *ST_NO_XLT_MERGECHILD; + static const char *ST_NO_XLT_MERGEPARENT; + static const char *ST_NO_XLT_PRIORITY; + static const char *ST_NO_XLT_LOOP; + static const char *ST_NO_XLT_EASEIN; + static const char *ST_NO_XLT_EASEOUT; + static const char *ST_NO_XLT_HAND; + static const char *ST_NO_XLT_EMOTE; + static const char *ST_BAD_ROOT; +*/ + + // Loads the specified translation table. + ELoadStatus loadTranslationTable(const char *fileName); + + //Create a new joint alias + void makeTranslation(std::string key, std::string value); + + // Loads joint aliases from XML file. + ELoadStatus loadAliases(const char * filename); + + // Load the specified BVH file. + // Returns status code. + ELoadStatus loadBVHFile(const char *buffer, char *error_text, S32 &error_line); + + void dumpBVHInfo(); + + // Applies translations to BVH data loaded. + void applyTranslations(); + + // Returns the number of lines scanned. + // Useful for error reporting. + S32 getLineNumber() { return mLineNumber; } + + // returns required size of output buffer + U32 getOutputSize(); + + // writes contents to datapacker + bool serialize(LLDataPacker& dp); + + // flags redundant keyframe data + void optimize(); + + void reset(); + + F32 getDuration() { return mDuration; } + + bool isInitialized() { return mInitialized; } + + ELoadStatus getStatus() { return mStatus; } + +protected: + // Consumes one line of input from file. + bool getLine(apr_file_t *fp); + + // parser state + char mLine[BVH_PARSER_LINE_SIZE]; /* Flawfinder: ignore */ + S32 mLineNumber; + + // parsed values + S32 mNumFrames; + F32 mFrameTime; + JointVector mJoints; + ConstraintVector mConstraints; + TranslationMap mTranslations; + + S32 mPriority; + bool mLoop; + F32 mLoopInPoint; + F32 mLoopOutPoint; + F32 mEaseIn; + F32 mEaseOut; + S32 mHand; + std::string mEmoteName; + + bool mInitialized; + ELoadStatus mStatus; + + // computed values + F32 mDuration; +}; + +#endif // LL_LLBVHLOADER_H diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 2c66d6f336..3fcef42a89 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -1,500 +1,500 @@ -/**
- * @file llcharacter.cpp
- * @brief Implementation of LLCharacter class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-
-#include "linden_common.h"
-
-#include "llcharacter.h"
-#include "llstring.h"
-#include "llfasttimer.h"
-
-#define SKEL_HEADER "Linden Skeleton 1.0"
-
-LLStringTable LLCharacter::sVisualParamNames(1024);
-
-std::vector< LLCharacter* > LLCharacter::sInstances;
-bool LLCharacter::sAllowInstancesChange = true ;
-
-//-----------------------------------------------------------------------------
-// LLCharacter()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLCharacter::LLCharacter()
- :
- mPreferredPelvisHeight( 0.f ),
- mSex( SEX_FEMALE ),
- mAppearanceSerialNum( 0 ),
- mSkeletonSerialNum( 0 )
-{
- llassert_always(sAllowInstancesChange) ;
- sInstances.push_back(this);
-
- mMotionController.setCharacter( this );
- mPauseRequest = new LLPauseRequestHandle();
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLCharacter()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLCharacter::~LLCharacter()
-{
- for (LLVisualParam *param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- delete param;
- }
-
- U32 i ;
- U32 size = sInstances.size() ;
- for(i = 0 ; i < size ; i++)
- {
- if(sInstances[i] == this)
- {
- break ;
- }
- }
-
- llassert_always(i < size) ;
-
- llassert_always(sAllowInstancesChange) ;
- sInstances[i] = sInstances[size - 1] ;
- sInstances.pop_back() ;
-}
-
-
-//-----------------------------------------------------------------------------
-// getJoint()
-//-----------------------------------------------------------------------------
-LLJoint *LLCharacter::getJoint( const std::string &name )
-{
- LLJoint* joint = NULL;
-
- LLJoint *root = getRootJoint();
- if (root)
- {
- joint = root->findJoint(name);
- }
-
- if (!joint)
- {
- LL_WARNS() << "Failed to find joint." << LL_ENDL;
- }
- return joint;
-}
-
-//-----------------------------------------------------------------------------
-// registerMotion()
-//-----------------------------------------------------------------------------
-bool LLCharacter::registerMotion( const LLUUID& id, LLMotionConstructor create )
-{
- return mMotionController.registerMotion(id, create);
-}
-
-//-----------------------------------------------------------------------------
-// removeMotion()
-//-----------------------------------------------------------------------------
-void LLCharacter::removeMotion( const LLUUID& id )
-{
- mMotionController.removeMotion(id);
-}
-
-//-----------------------------------------------------------------------------
-// findMotion()
-//-----------------------------------------------------------------------------
-LLMotion* LLCharacter::findMotion( const LLUUID &id )
-{
- return mMotionController.findMotion( id );
-}
-
-//-----------------------------------------------------------------------------
-// createMotion()
-// NOTE: Always assign the result to a LLPointer!
-//-----------------------------------------------------------------------------
-LLMotion* LLCharacter::createMotion( const LLUUID &id )
-{
- return mMotionController.createMotion( id );
-}
-
-//-----------------------------------------------------------------------------
-// startMotion()
-//-----------------------------------------------------------------------------
-bool LLCharacter::startMotion(const LLUUID &id, F32 start_offset)
-{
- return mMotionController.startMotion(id, start_offset);
-}
-
-
-//-----------------------------------------------------------------------------
-// stopMotion()
-//-----------------------------------------------------------------------------
-bool LLCharacter::stopMotion(const LLUUID& id, bool stop_immediate)
-{
- return mMotionController.stopMotionLocally(id, stop_immediate);
-}
-
-//-----------------------------------------------------------------------------
-// isMotionActive()
-//-----------------------------------------------------------------------------
-bool LLCharacter::isMotionActive(const LLUUID& id)
-{
- LLMotion *motionp = mMotionController.findMotion(id);
- if (motionp)
- {
- return mMotionController.isMotionActive(motionp);
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-// onDeactivateMotion()
-//-----------------------------------------------------------------------------
-void LLCharacter::requestStopMotion( LLMotion* motion)
-{
-// LL_INFOS() << "DEBUG: Char::onDeactivateMotion( " << motionName << " )" << LL_ENDL;
-}
-
-
-//-----------------------------------------------------------------------------
-// updateMotions()
-//-----------------------------------------------------------------------------
-void LLCharacter::updateMotions(e_update_t update_type)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- if (update_type == HIDDEN_UPDATE)
- {
- mMotionController.updateMotionsMinimal();
- }
- else
- {
- // unpause if the number of outstanding pause requests has dropped to the initial one
- if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
- {
- mMotionController.unpauseAllMotions();
- }
- bool force_update = (update_type == FORCE_UPDATE);
- {
- mMotionController.updateMotions(force_update);
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// deactivateAllMotions()
-//-----------------------------------------------------------------------------
-void LLCharacter::deactivateAllMotions()
-{
- mMotionController.deactivateAllMotions();
-}
-
-
-//-----------------------------------------------------------------------------
-// flushAllMotions()
-//-----------------------------------------------------------------------------
-void LLCharacter::flushAllMotions()
-{
- mMotionController.flushAllMotions();
-}
-
-
-//-----------------------------------------------------------------------------
-// dumpCharacter()
-//-----------------------------------------------------------------------------
-void LLCharacter::dumpCharacter( LLJoint* joint )
-{
- // handle top level entry into recursion
- if (joint == NULL)
- {
- LL_INFOS() << "DEBUG: Dumping Character @" << this << LL_ENDL;
- dumpCharacter( getRootJoint() );
- LL_INFOS() << "DEBUG: Done." << LL_ENDL;
- return;
- }
-
- // print joint info
- LL_INFOS() << "DEBUG: " << joint->getName() << " (" << (joint->getParent()?joint->getParent()->getName():std::string("ROOT")) << ")" << LL_ENDL;
-
- // recurse
- for (LLJoint* child_joint : joint->mChildren)
- {
- dumpCharacter(child_joint);
- }
-}
-
-//-----------------------------------------------------------------------------
-// setAnimationData()
-//-----------------------------------------------------------------------------
-void LLCharacter::setAnimationData(std::string name, void *data)
-{
- mAnimationData[name] = data;
-}
-
-//-----------------------------------------------------------------------------
-// getAnimationData()
-//-----------------------------------------------------------------------------
-void* LLCharacter::getAnimationData(std::string name)
-{
- return get_if_there(mAnimationData, name, (void*)NULL);
-}
-
-//-----------------------------------------------------------------------------
-// removeAnimationData()
-//-----------------------------------------------------------------------------
-void LLCharacter::removeAnimationData(std::string name)
-{
- mAnimationData.erase(name);
-}
-
-//-----------------------------------------------------------------------------
-// setVisualParamWeight()
-//-----------------------------------------------------------------------------
-bool LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight)
-{
- S32 index = which_param->getID();
- visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
- if (index_iter != mVisualParamIndexMap.end())
- {
- index_iter->second->setWeight(weight);
- return true;
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// setVisualParamWeight()
-//-----------------------------------------------------------------------------
-bool LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
-{
- std::string tname(param_name);
- LLStringUtil::toLower(tname);
- char *tableptr = sVisualParamNames.checkString(tname);
- visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
- if (name_iter != mVisualParamNameMap.end())
- {
- name_iter->second->setWeight(weight);
- return true;
- }
- LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL;
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// setVisualParamWeight()
-//-----------------------------------------------------------------------------
-bool LLCharacter::setVisualParamWeight(S32 index, F32 weight)
-{
- visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
- if (index_iter != mVisualParamIndexMap.end())
- {
- index_iter->second->setWeight(weight);
- return true;
- }
- LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL;
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// getVisualParamWeight()
-//-----------------------------------------------------------------------------
-F32 LLCharacter::getVisualParamWeight(LLVisualParam *which_param)
-{
- S32 index = which_param->getID();
- visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
- if (index_iter != mVisualParamIndexMap.end())
- {
- return index_iter->second->getWeight();
- }
- else
- {
- LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter*, index= " << index << LL_ENDL;
- return 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// getVisualParamWeight()
-//-----------------------------------------------------------------------------
-F32 LLCharacter::getVisualParamWeight(const char* param_name)
-{
- std::string tname(param_name);
- LLStringUtil::toLower(tname);
- char *tableptr = sVisualParamNames.checkString(tname);
- visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
- if (name_iter != mVisualParamNameMap.end())
- {
- return name_iter->second->getWeight();
- }
- LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL;
- return 0.f;
-}
-
-//-----------------------------------------------------------------------------
-// getVisualParamWeight()
-//-----------------------------------------------------------------------------
-F32 LLCharacter::getVisualParamWeight(S32 index)
-{
- visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
- if (index_iter != mVisualParamIndexMap.end())
- {
- return index_iter->second->getWeight();
- }
- else
- {
- LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL;
- return 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// clearVisualParamWeights()
-//-----------------------------------------------------------------------------
-void LLCharacter::clearVisualParamWeights()
-{
- for (LLVisualParam *param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- if (param->isTweakable())
- {
- param->setWeight( param->getDefaultWeight());
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// getVisualParam()
-//-----------------------------------------------------------------------------
-LLVisualParam* LLCharacter::getVisualParam(const char *param_name)
-{
- std::string tname(param_name);
- LLStringUtil::toLower(tname);
- char *tableptr = sVisualParamNames.checkString(tname);
- visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
- if (name_iter != mVisualParamNameMap.end())
- {
- return name_iter->second;
- }
- LL_WARNS() << "LLCharacter::getVisualParam() Invalid visual parameter: " << param_name << LL_ENDL;
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// addSharedVisualParam()
-//-----------------------------------------------------------------------------
-void LLCharacter::addSharedVisualParam(LLVisualParam *param)
-{
- S32 index = param->getID();
- visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
- LLVisualParam* current_param = 0;
- if (index_iter != mVisualParamIndexMap.end())
- current_param = index_iter->second;
- if( current_param )
- {
- LLVisualParam* next_param = current_param;
- while(next_param->getNextParam())
- {
- next_param = next_param->getNextParam();
- }
- next_param->setNextParam(param);
- }
- else
- {
- LL_WARNS() << "Shared visual parameter " << param->getName() << " does not already exist with ID " <<
- param->getID() << LL_ENDL;
- }
-}
-
-//-----------------------------------------------------------------------------
-// addVisualParam()
-//-----------------------------------------------------------------------------
-void LLCharacter::addVisualParam(LLVisualParam *param)
-{
- S32 index = param->getID();
- // Add Index map
- std::pair<visual_param_index_map_t::iterator, bool> idxres;
- idxres = mVisualParamIndexMap.insert(visual_param_index_map_t::value_type(index, param));
- if (!idxres.second)
- {
- LL_WARNS() << "Visual parameter " << param->getName() << " already exists with same ID as " <<
- param->getName() << LL_ENDL;
- visual_param_index_map_t::iterator index_iter = idxres.first;
- index_iter->second = param;
- }
-
- if (param->getInfo())
- {
- // Add name map
- std::string tname(param->getName());
- LLStringUtil::toLower(tname);
- char *tableptr = sVisualParamNames.addString(tname);
- std::pair<visual_param_name_map_t::iterator, bool> nameres;
- nameres = mVisualParamNameMap.insert(visual_param_name_map_t::value_type(tableptr, param));
- if (!nameres.second)
- {
- // Already exists, copy param
- visual_param_name_map_t::iterator name_iter = nameres.first;
- name_iter->second = param;
- }
- }
- //LL_INFOS() << "Adding Visual Param '" << param->getName() << "' ( " << index << " )" << LL_ENDL;
-}
-
-//-----------------------------------------------------------------------------
-// updateVisualParams()
-//-----------------------------------------------------------------------------
-void LLCharacter::updateVisualParams()
-{
- for (LLVisualParam *param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- if (param->isAnimating())
- {
- continue;
- }
- // only apply parameters whose effective weight has changed
- F32 effective_weight = ( param->getSex() & mSex ) ? param->getWeight() : param->getDefaultWeight();
- if (effective_weight != param->getLastWeight())
- {
- param->apply( mSex );
- }
- }
-}
-
-LLAnimPauseRequest LLCharacter::requestPause()
-{
- mMotionController.pauseAllMotions();
- return mPauseRequest;
-}
-
+/** + * @file llcharacter.cpp + * @brief Implementation of LLCharacter class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- + +#include "linden_common.h" + +#include "llcharacter.h" +#include "llstring.h" +#include "llfasttimer.h" + +#define SKEL_HEADER "Linden Skeleton 1.0" + +LLStringTable LLCharacter::sVisualParamNames(1024); + +std::vector< LLCharacter* > LLCharacter::sInstances; +bool LLCharacter::sAllowInstancesChange = true ; + +//----------------------------------------------------------------------------- +// LLCharacter() +// Class Constructor +//----------------------------------------------------------------------------- +LLCharacter::LLCharacter() + : + mPreferredPelvisHeight( 0.f ), + mSex( SEX_FEMALE ), + mAppearanceSerialNum( 0 ), + mSkeletonSerialNum( 0 ) +{ + llassert_always(sAllowInstancesChange) ; + sInstances.push_back(this); + + mMotionController.setCharacter( this ); + mPauseRequest = new LLPauseRequestHandle(); +} + + +//----------------------------------------------------------------------------- +// ~LLCharacter() +// Class Destructor +//----------------------------------------------------------------------------- +LLCharacter::~LLCharacter() +{ + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + delete param; + } + + U32 i ; + U32 size = sInstances.size() ; + for(i = 0 ; i < size ; i++) + { + if(sInstances[i] == this) + { + break ; + } + } + + llassert_always(i < size) ; + + llassert_always(sAllowInstancesChange) ; + sInstances[i] = sInstances[size - 1] ; + sInstances.pop_back() ; +} + + +//----------------------------------------------------------------------------- +// getJoint() +//----------------------------------------------------------------------------- +LLJoint *LLCharacter::getJoint( const std::string &name ) +{ + LLJoint* joint = NULL; + + LLJoint *root = getRootJoint(); + if (root) + { + joint = root->findJoint(name); + } + + if (!joint) + { + LL_WARNS() << "Failed to find joint." << LL_ENDL; + } + return joint; +} + +//----------------------------------------------------------------------------- +// registerMotion() +//----------------------------------------------------------------------------- +bool LLCharacter::registerMotion( const LLUUID& id, LLMotionConstructor create ) +{ + return mMotionController.registerMotion(id, create); +} + +//----------------------------------------------------------------------------- +// removeMotion() +//----------------------------------------------------------------------------- +void LLCharacter::removeMotion( const LLUUID& id ) +{ + mMotionController.removeMotion(id); +} + +//----------------------------------------------------------------------------- +// findMotion() +//----------------------------------------------------------------------------- +LLMotion* LLCharacter::findMotion( const LLUUID &id ) +{ + return mMotionController.findMotion( id ); +} + +//----------------------------------------------------------------------------- +// createMotion() +// NOTE: Always assign the result to a LLPointer! +//----------------------------------------------------------------------------- +LLMotion* LLCharacter::createMotion( const LLUUID &id ) +{ + return mMotionController.createMotion( id ); +} + +//----------------------------------------------------------------------------- +// startMotion() +//----------------------------------------------------------------------------- +bool LLCharacter::startMotion(const LLUUID &id, F32 start_offset) +{ + return mMotionController.startMotion(id, start_offset); +} + + +//----------------------------------------------------------------------------- +// stopMotion() +//----------------------------------------------------------------------------- +bool LLCharacter::stopMotion(const LLUUID& id, bool stop_immediate) +{ + return mMotionController.stopMotionLocally(id, stop_immediate); +} + +//----------------------------------------------------------------------------- +// isMotionActive() +//----------------------------------------------------------------------------- +bool LLCharacter::isMotionActive(const LLUUID& id) +{ + LLMotion *motionp = mMotionController.findMotion(id); + if (motionp) + { + return mMotionController.isMotionActive(motionp); + } + + return false; +} + + +//----------------------------------------------------------------------------- +// onDeactivateMotion() +//----------------------------------------------------------------------------- +void LLCharacter::requestStopMotion( LLMotion* motion) +{ +// LL_INFOS() << "DEBUG: Char::onDeactivateMotion( " << motionName << " )" << LL_ENDL; +} + + +//----------------------------------------------------------------------------- +// updateMotions() +//----------------------------------------------------------------------------- +void LLCharacter::updateMotions(e_update_t update_type) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + if (update_type == HIDDEN_UPDATE) + { + mMotionController.updateMotionsMinimal(); + } + else + { + // unpause if the number of outstanding pause requests has dropped to the initial one + if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) + { + mMotionController.unpauseAllMotions(); + } + bool force_update = (update_type == FORCE_UPDATE); + { + mMotionController.updateMotions(force_update); + } + } +} + + +//----------------------------------------------------------------------------- +// deactivateAllMotions() +//----------------------------------------------------------------------------- +void LLCharacter::deactivateAllMotions() +{ + mMotionController.deactivateAllMotions(); +} + + +//----------------------------------------------------------------------------- +// flushAllMotions() +//----------------------------------------------------------------------------- +void LLCharacter::flushAllMotions() +{ + mMotionController.flushAllMotions(); +} + + +//----------------------------------------------------------------------------- +// dumpCharacter() +//----------------------------------------------------------------------------- +void LLCharacter::dumpCharacter( LLJoint* joint ) +{ + // handle top level entry into recursion + if (joint == NULL) + { + LL_INFOS() << "DEBUG: Dumping Character @" << this << LL_ENDL; + dumpCharacter( getRootJoint() ); + LL_INFOS() << "DEBUG: Done." << LL_ENDL; + return; + } + + // print joint info + LL_INFOS() << "DEBUG: " << joint->getName() << " (" << (joint->getParent()?joint->getParent()->getName():std::string("ROOT")) << ")" << LL_ENDL; + + // recurse + for (LLJoint* child_joint : joint->mChildren) + { + dumpCharacter(child_joint); + } +} + +//----------------------------------------------------------------------------- +// setAnimationData() +//----------------------------------------------------------------------------- +void LLCharacter::setAnimationData(std::string name, void *data) +{ + mAnimationData[name] = data; +} + +//----------------------------------------------------------------------------- +// getAnimationData() +//----------------------------------------------------------------------------- +void* LLCharacter::getAnimationData(std::string name) +{ + return get_if_there(mAnimationData, name, (void*)NULL); +} + +//----------------------------------------------------------------------------- +// removeAnimationData() +//----------------------------------------------------------------------------- +void LLCharacter::removeAnimationData(std::string name) +{ + mAnimationData.erase(name); +} + +//----------------------------------------------------------------------------- +// setVisualParamWeight() +//----------------------------------------------------------------------------- +bool LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight) +{ + S32 index = which_param->getID(); + visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); + if (index_iter != mVisualParamIndexMap.end()) + { + index_iter->second->setWeight(weight); + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// setVisualParamWeight() +//----------------------------------------------------------------------------- +bool LLCharacter::setVisualParamWeight(const char* param_name, F32 weight) +{ + std::string tname(param_name); + LLStringUtil::toLower(tname); + char *tableptr = sVisualParamNames.checkString(tname); + visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr); + if (name_iter != mVisualParamNameMap.end()) + { + name_iter->second->setWeight(weight); + return true; + } + LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL; + return false; +} + +//----------------------------------------------------------------------------- +// setVisualParamWeight() +//----------------------------------------------------------------------------- +bool LLCharacter::setVisualParamWeight(S32 index, F32 weight) +{ + visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); + if (index_iter != mVisualParamIndexMap.end()) + { + index_iter->second->setWeight(weight); + return true; + } + LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL; + return false; +} + +//----------------------------------------------------------------------------- +// getVisualParamWeight() +//----------------------------------------------------------------------------- +F32 LLCharacter::getVisualParamWeight(LLVisualParam *which_param) +{ + S32 index = which_param->getID(); + visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); + if (index_iter != mVisualParamIndexMap.end()) + { + return index_iter->second->getWeight(); + } + else + { + LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter*, index= " << index << LL_ENDL; + return 0.f; + } +} + +//----------------------------------------------------------------------------- +// getVisualParamWeight() +//----------------------------------------------------------------------------- +F32 LLCharacter::getVisualParamWeight(const char* param_name) +{ + std::string tname(param_name); + LLStringUtil::toLower(tname); + char *tableptr = sVisualParamNames.checkString(tname); + visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr); + if (name_iter != mVisualParamNameMap.end()) + { + return name_iter->second->getWeight(); + } + LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL; + return 0.f; +} + +//----------------------------------------------------------------------------- +// getVisualParamWeight() +//----------------------------------------------------------------------------- +F32 LLCharacter::getVisualParamWeight(S32 index) +{ + visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); + if (index_iter != mVisualParamIndexMap.end()) + { + return index_iter->second->getWeight(); + } + else + { + LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL; + return 0.f; + } +} + +//----------------------------------------------------------------------------- +// clearVisualParamWeights() +//----------------------------------------------------------------------------- +void LLCharacter::clearVisualParamWeights() +{ + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isTweakable()) + { + param->setWeight( param->getDefaultWeight()); + } + } +} + +//----------------------------------------------------------------------------- +// getVisualParam() +//----------------------------------------------------------------------------- +LLVisualParam* LLCharacter::getVisualParam(const char *param_name) +{ + std::string tname(param_name); + LLStringUtil::toLower(tname); + char *tableptr = sVisualParamNames.checkString(tname); + visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr); + if (name_iter != mVisualParamNameMap.end()) + { + return name_iter->second; + } + LL_WARNS() << "LLCharacter::getVisualParam() Invalid visual parameter: " << param_name << LL_ENDL; + return NULL; +} + +//----------------------------------------------------------------------------- +// addSharedVisualParam() +//----------------------------------------------------------------------------- +void LLCharacter::addSharedVisualParam(LLVisualParam *param) +{ + S32 index = param->getID(); + visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); + LLVisualParam* current_param = 0; + if (index_iter != mVisualParamIndexMap.end()) + current_param = index_iter->second; + if( current_param ) + { + LLVisualParam* next_param = current_param; + while(next_param->getNextParam()) + { + next_param = next_param->getNextParam(); + } + next_param->setNextParam(param); + } + else + { + LL_WARNS() << "Shared visual parameter " << param->getName() << " does not already exist with ID " << + param->getID() << LL_ENDL; + } +} + +//----------------------------------------------------------------------------- +// addVisualParam() +//----------------------------------------------------------------------------- +void LLCharacter::addVisualParam(LLVisualParam *param) +{ + S32 index = param->getID(); + // Add Index map + std::pair<visual_param_index_map_t::iterator, bool> idxres; + idxres = mVisualParamIndexMap.insert(visual_param_index_map_t::value_type(index, param)); + if (!idxres.second) + { + LL_WARNS() << "Visual parameter " << param->getName() << " already exists with same ID as " << + param->getName() << LL_ENDL; + visual_param_index_map_t::iterator index_iter = idxres.first; + index_iter->second = param; + } + + if (param->getInfo()) + { + // Add name map + std::string tname(param->getName()); + LLStringUtil::toLower(tname); + char *tableptr = sVisualParamNames.addString(tname); + std::pair<visual_param_name_map_t::iterator, bool> nameres; + nameres = mVisualParamNameMap.insert(visual_param_name_map_t::value_type(tableptr, param)); + if (!nameres.second) + { + // Already exists, copy param + visual_param_name_map_t::iterator name_iter = nameres.first; + name_iter->second = param; + } + } + //LL_INFOS() << "Adding Visual Param '" << param->getName() << "' ( " << index << " )" << LL_ENDL; +} + +//----------------------------------------------------------------------------- +// updateVisualParams() +//----------------------------------------------------------------------------- +void LLCharacter::updateVisualParams() +{ + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isAnimating()) + { + continue; + } + // only apply parameters whose effective weight has changed + F32 effective_weight = ( param->getSex() & mSex ) ? param->getWeight() : param->getDefaultWeight(); + if (effective_weight != param->getLastWeight()) + { + param->apply( mSex ); + } + } +} + +LLAnimPauseRequest LLCharacter::requestPause() +{ + mMotionController.pauseAllMotions(); + return mPauseRequest; +} + diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index d845ead44d..b390960a75 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -1,291 +1,291 @@ -/**
- * @file llcharacter.h
- * @brief Implementation of LLCharacter class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLCHARACTER_H
-#define LL_LLCHARACTER_H
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include <string>
-
-#include "lljoint.h"
-#include "llmotioncontroller.h"
-#include "llvisualparam.h"
-#include "llstringtable.h"
-#include "llpointer.h"
-#include "llrefcount.h"
-
-class LLPolyMesh;
-
-class LLPauseRequestHandle : public LLThreadSafeRefCount
-{
-public:
- LLPauseRequestHandle() {};
-};
-
-typedef LLPointer<LLPauseRequestHandle> LLAnimPauseRequest;
-
-//-----------------------------------------------------------------------------
-// class LLCharacter
-//-----------------------------------------------------------------------------
-class LLCharacter
-{
-public:
- // Constructor
- LLCharacter();
-
- // Destructor
- virtual ~LLCharacter();
-
- //-------------------------------------------------------------------------
- // LLCharacter Interface
- // These functions must be implemented by subclasses.
- //-------------------------------------------------------------------------
-
- // get the prefix to be used to lookup motion data files
- // from the viewer data directory
- virtual const char *getAnimationPrefix() = 0;
-
- // get the root joint of the character
- virtual LLJoint *getRootJoint() = 0;
-
- // get the specified joint
- // default implementation does recursive search,
- // subclasses may optimize/cache results.
- virtual LLJoint *getJoint( const std::string &name );
-
- // get the position of the character
- virtual LLVector3 getCharacterPosition() = 0;
-
- // get the rotation of the character
- virtual LLQuaternion getCharacterRotation() = 0;
-
- // get the velocity of the character
- virtual LLVector3 getCharacterVelocity() = 0;
-
- // get the angular velocity of the character
- virtual LLVector3 getCharacterAngularVelocity() = 0;
-
- // get the height & normal of the ground under a point
- virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm) = 0;
-
- // skeleton joint accessor to support joint subclasses
- virtual LLJoint *getCharacterJoint( U32 i ) = 0;
-
- // get the physics time dilation for the simulator
- virtual F32 getTimeDilation() = 0;
-
- // gets current pixel area of this character
- virtual F32 getPixelArea() const = 0;
-
- // gets the head mesh of the character
- virtual LLPolyMesh* getHeadMesh() = 0;
-
- // gets the upper body mesh of the character
- virtual LLPolyMesh* getUpperBodyMesh() = 0;
-
- // gets global coordinates from agent local coordinates
- virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position) = 0;
-
- // gets agent local coordinates from global coordinates
- virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position) = 0;
-
- // updates all visual parameters for this character
- virtual void updateVisualParams();
-
- virtual void addDebugText( const std::string& text ) = 0;
-
- virtual const LLUUID& getID() const = 0;
- //-------------------------------------------------------------------------
- // End Interface
- //-------------------------------------------------------------------------
- // registers a motion with the character
- // returns true if successfull
- bool registerMotion( const LLUUID& id, LLMotionConstructor create );
-
- void removeMotion( const LLUUID& id );
-
- // returns an instance of a registered motion, creating one if necessary
- LLMotion* createMotion( const LLUUID &id );
-
- // returns an existing instance of a registered motion
- LLMotion* findMotion( const LLUUID &id );
-
- // start a motion
- // returns true if successful, false if an error occurred
- virtual bool startMotion( const LLUUID& id, F32 start_offset = 0.f);
-
- // stop a motion
- virtual bool stopMotion( const LLUUID& id, bool stop_immediate = false );
-
- // is this motion active?
- bool isMotionActive( const LLUUID& id );
-
- // Event handler for motion deactivation.
- // Called when a motion has completely stopped and has been deactivated.
- // Subclasses may optionally override this.
- // The default implementation does nothing.
- virtual void requestStopMotion( LLMotion* motion );
-
- // periodic update function, steps the motion controller
- enum e_update_t { NORMAL_UPDATE, HIDDEN_UPDATE, FORCE_UPDATE };
- void updateMotions(e_update_t update_type);
-
- LLAnimPauseRequest requestPause();
- bool areAnimationsPaused() const { return mMotionController.isPaused(); }
- void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); }
- void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); }
-
- LLMotionController& getMotionController() { return mMotionController; }
-
- // Releases all motion instances which should result in
- // no cached references to character joint data. This is
- // useful if a character wants to rebuild it's skeleton.
- virtual void flushAllMotions();
-
- // Flush only wipes active animations.
- virtual void deactivateAllMotions();
-
- // dumps information for debugging
- virtual void dumpCharacter( LLJoint *joint = NULL );
-
- virtual F32 getPreferredPelvisHeight() { return mPreferredPelvisHeight; }
-
- virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) { return LLVector3::zero; }
-
- virtual LLJoint* findCollisionVolume(S32 volume_id) { return NULL; }
-
- virtual S32 getCollisionVolumeID(std::string &name) { return -1; }
-
- void setAnimationData(std::string name, void *data);
-
- void *getAnimationData(std::string name);
-
- void removeAnimationData(std::string name);
-
- void addVisualParam(LLVisualParam *param);
- void addSharedVisualParam(LLVisualParam *param);
-
- virtual bool setVisualParamWeight(const LLVisualParam *which_param, F32 weight);
- virtual bool setVisualParamWeight(const char* param_name, F32 weight);
- virtual bool setVisualParamWeight(S32 index, F32 weight);
-
- // get visual param weight by param or name
- F32 getVisualParamWeight(LLVisualParam *distortion);
- F32 getVisualParamWeight(const char* param_name);
- F32 getVisualParamWeight(S32 index);
-
- // set all morph weights to defaults
- void clearVisualParamWeights();
-
- // visual parameter accessors
- LLVisualParam* getFirstVisualParam()
- {
- mCurIterator = mVisualParamIndexMap.begin();
- return getNextVisualParam();
- }
- LLVisualParam* getNextVisualParam()
- {
- if (mCurIterator == mVisualParamIndexMap.end())
- return 0;
- return (mCurIterator++)->second;
- }
-
- S32 getVisualParamCountInGroup(const EVisualParamGroup group) const
- {
- S32 rtn = 0;
- for (const visual_param_index_map_t::value_type& index_pair : mVisualParamIndexMap)
- {
- if (index_pair.second->getGroup() == group)
- {
- ++rtn;
- }
- }
- return rtn;
- }
-
- LLVisualParam* getVisualParam(S32 id) const
- {
- visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(id);
- return (iter == mVisualParamIndexMap.end()) ? 0 : iter->second;
- }
- S32 getVisualParamID(LLVisualParam *id)
- {
- for (visual_param_index_map_t::value_type& index_pair : mVisualParamIndexMap)
- {
- if (index_pair.second == id)
- return index_pair.first;
- }
- return 0;
- }
- S32 getVisualParamCount() const { return (S32)mVisualParamIndexMap.size(); }
- LLVisualParam* getVisualParam(const char *name);
-
-
- ESex getSex() const { return mSex; }
- void setSex( ESex sex ) { mSex = sex; }
-
- U32 getAppearanceSerialNum() const { return mAppearanceSerialNum; }
- void setAppearanceSerialNum( U32 num ) { mAppearanceSerialNum = num; }
-
- U32 getSkeletonSerialNum() const { return mSkeletonSerialNum; }
- void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
-
- static std::vector< LLCharacter* > sInstances;
- static bool sAllowInstancesChange ; //debug use
-
- virtual void setHoverOffset(const LLVector3& hover_offset, bool send_update=true) { mHoverOffset = hover_offset; }
- const LLVector3& getHoverOffset() const { return mHoverOffset; }
-
-protected:
- LLMotionController mMotionController;
-
- typedef std::map<std::string, void *> animation_data_map_t;
- animation_data_map_t mAnimationData;
-
- F32 mPreferredPelvisHeight;
- ESex mSex;
- U32 mAppearanceSerialNum;
- U32 mSkeletonSerialNum;
- LLAnimPauseRequest mPauseRequest;
-
-private:
- // visual parameter stuff
- typedef std::map<S32, LLVisualParam *> visual_param_index_map_t;
- typedef std::map<char *, LLVisualParam *> visual_param_name_map_t;
-
- visual_param_index_map_t::iterator mCurIterator;
- visual_param_index_map_t mVisualParamIndexMap;
- visual_param_name_map_t mVisualParamNameMap;
-
- static LLStringTable sVisualParamNames;
-
- LLVector3 mHoverOffset;
-};
-
-#endif // LL_LLCHARACTER_H
-
+/** + * @file llcharacter.h + * @brief Implementation of LLCharacter class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLCHARACTER_H +#define LL_LLCHARACTER_H + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include <string> + +#include "lljoint.h" +#include "llmotioncontroller.h" +#include "llvisualparam.h" +#include "llstringtable.h" +#include "llpointer.h" +#include "llrefcount.h" + +class LLPolyMesh; + +class LLPauseRequestHandle : public LLThreadSafeRefCount +{ +public: + LLPauseRequestHandle() {}; +}; + +typedef LLPointer<LLPauseRequestHandle> LLAnimPauseRequest; + +//----------------------------------------------------------------------------- +// class LLCharacter +//----------------------------------------------------------------------------- +class LLCharacter +{ +public: + // Constructor + LLCharacter(); + + // Destructor + virtual ~LLCharacter(); + + //------------------------------------------------------------------------- + // LLCharacter Interface + // These functions must be implemented by subclasses. + //------------------------------------------------------------------------- + + // get the prefix to be used to lookup motion data files + // from the viewer data directory + virtual const char *getAnimationPrefix() = 0; + + // get the root joint of the character + virtual LLJoint *getRootJoint() = 0; + + // get the specified joint + // default implementation does recursive search, + // subclasses may optimize/cache results. + virtual LLJoint *getJoint( const std::string &name ); + + // get the position of the character + virtual LLVector3 getCharacterPosition() = 0; + + // get the rotation of the character + virtual LLQuaternion getCharacterRotation() = 0; + + // get the velocity of the character + virtual LLVector3 getCharacterVelocity() = 0; + + // get the angular velocity of the character + virtual LLVector3 getCharacterAngularVelocity() = 0; + + // get the height & normal of the ground under a point + virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm) = 0; + + // skeleton joint accessor to support joint subclasses + virtual LLJoint *getCharacterJoint( U32 i ) = 0; + + // get the physics time dilation for the simulator + virtual F32 getTimeDilation() = 0; + + // gets current pixel area of this character + virtual F32 getPixelArea() const = 0; + + // gets the head mesh of the character + virtual LLPolyMesh* getHeadMesh() = 0; + + // gets the upper body mesh of the character + virtual LLPolyMesh* getUpperBodyMesh() = 0; + + // gets global coordinates from agent local coordinates + virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position) = 0; + + // gets agent local coordinates from global coordinates + virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position) = 0; + + // updates all visual parameters for this character + virtual void updateVisualParams(); + + virtual void addDebugText( const std::string& text ) = 0; + + virtual const LLUUID& getID() const = 0; + //------------------------------------------------------------------------- + // End Interface + //------------------------------------------------------------------------- + // registers a motion with the character + // returns true if successfull + bool registerMotion( const LLUUID& id, LLMotionConstructor create ); + + void removeMotion( const LLUUID& id ); + + // returns an instance of a registered motion, creating one if necessary + LLMotion* createMotion( const LLUUID &id ); + + // returns an existing instance of a registered motion + LLMotion* findMotion( const LLUUID &id ); + + // start a motion + // returns true if successful, false if an error occurred + virtual bool startMotion( const LLUUID& id, F32 start_offset = 0.f); + + // stop a motion + virtual bool stopMotion( const LLUUID& id, bool stop_immediate = false ); + + // is this motion active? + bool isMotionActive( const LLUUID& id ); + + // Event handler for motion deactivation. + // Called when a motion has completely stopped and has been deactivated. + // Subclasses may optionally override this. + // The default implementation does nothing. + virtual void requestStopMotion( LLMotion* motion ); + + // periodic update function, steps the motion controller + enum e_update_t { NORMAL_UPDATE, HIDDEN_UPDATE, FORCE_UPDATE }; + void updateMotions(e_update_t update_type); + + LLAnimPauseRequest requestPause(); + bool areAnimationsPaused() const { return mMotionController.isPaused(); } + void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); } + void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); } + + LLMotionController& getMotionController() { return mMotionController; } + + // Releases all motion instances which should result in + // no cached references to character joint data. This is + // useful if a character wants to rebuild it's skeleton. + virtual void flushAllMotions(); + + // Flush only wipes active animations. + virtual void deactivateAllMotions(); + + // dumps information for debugging + virtual void dumpCharacter( LLJoint *joint = NULL ); + + virtual F32 getPreferredPelvisHeight() { return mPreferredPelvisHeight; } + + virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) { return LLVector3::zero; } + + virtual LLJoint* findCollisionVolume(S32 volume_id) { return NULL; } + + virtual S32 getCollisionVolumeID(std::string &name) { return -1; } + + void setAnimationData(std::string name, void *data); + + void *getAnimationData(std::string name); + + void removeAnimationData(std::string name); + + void addVisualParam(LLVisualParam *param); + void addSharedVisualParam(LLVisualParam *param); + + virtual bool setVisualParamWeight(const LLVisualParam *which_param, F32 weight); + virtual bool setVisualParamWeight(const char* param_name, F32 weight); + virtual bool setVisualParamWeight(S32 index, F32 weight); + + // get visual param weight by param or name + F32 getVisualParamWeight(LLVisualParam *distortion); + F32 getVisualParamWeight(const char* param_name); + F32 getVisualParamWeight(S32 index); + + // set all morph weights to defaults + void clearVisualParamWeights(); + + // visual parameter accessors + LLVisualParam* getFirstVisualParam() + { + mCurIterator = mVisualParamIndexMap.begin(); + return getNextVisualParam(); + } + LLVisualParam* getNextVisualParam() + { + if (mCurIterator == mVisualParamIndexMap.end()) + return 0; + return (mCurIterator++)->second; + } + + S32 getVisualParamCountInGroup(const EVisualParamGroup group) const + { + S32 rtn = 0; + for (const visual_param_index_map_t::value_type& index_pair : mVisualParamIndexMap) + { + if (index_pair.second->getGroup() == group) + { + ++rtn; + } + } + return rtn; + } + + LLVisualParam* getVisualParam(S32 id) const + { + visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(id); + return (iter == mVisualParamIndexMap.end()) ? 0 : iter->second; + } + S32 getVisualParamID(LLVisualParam *id) + { + for (visual_param_index_map_t::value_type& index_pair : mVisualParamIndexMap) + { + if (index_pair.second == id) + return index_pair.first; + } + return 0; + } + S32 getVisualParamCount() const { return (S32)mVisualParamIndexMap.size(); } + LLVisualParam* getVisualParam(const char *name); + + + ESex getSex() const { return mSex; } + void setSex( ESex sex ) { mSex = sex; } + + U32 getAppearanceSerialNum() const { return mAppearanceSerialNum; } + void setAppearanceSerialNum( U32 num ) { mAppearanceSerialNum = num; } + + U32 getSkeletonSerialNum() const { return mSkeletonSerialNum; } + void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; } + + static std::vector< LLCharacter* > sInstances; + static bool sAllowInstancesChange ; //debug use + + virtual void setHoverOffset(const LLVector3& hover_offset, bool send_update=true) { mHoverOffset = hover_offset; } + const LLVector3& getHoverOffset() const { return mHoverOffset; } + +protected: + LLMotionController mMotionController; + + typedef std::map<std::string, void *> animation_data_map_t; + animation_data_map_t mAnimationData; + + F32 mPreferredPelvisHeight; + ESex mSex; + U32 mAppearanceSerialNum; + U32 mSkeletonSerialNum; + LLAnimPauseRequest mPauseRequest; + +private: + // visual parameter stuff + typedef std::map<S32, LLVisualParam *> visual_param_index_map_t; + typedef std::map<char *, LLVisualParam *> visual_param_name_map_t; + + visual_param_index_map_t::iterator mCurIterator; + visual_param_index_map_t mVisualParamIndexMap; + visual_param_name_map_t mVisualParamNameMap; + + static LLStringTable sVisualParamNames; + + LLVector3 mHoverOffset; +}; + +#endif // LL_LLCHARACTER_H + diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp index 7ad0aefa6a..9fb2a931f9 100644 --- a/indra/llcharacter/lleditingmotion.cpp +++ b/indra/llcharacter/lleditingmotion.cpp @@ -1,264 +1,264 @@ -/**
- * @file lleditingmotion.cpp
- * @brief Implementation of LLEditingMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "lleditingmotion.h"
-#include "llcharacter.h"
-#include "llhandmotion.h"
-#include "llcriticaldamp.h"
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-const LLQuaternion EDIT_MOTION_WRIST_ROTATION(F_PI_BY_TWO * 0.7f, LLVector3(1.0f, 0.0f, 0.0f));
-const F32 TARGET_LAG_HALF_LIFE = 0.1f; // half-life of IK targeting
-
-S32 LLEditingMotion::sHandPose = LLHandMotion::HAND_POSE_RELAXED_R;
-S32 LLEditingMotion::sHandPosePriority = 3;
-
-//-----------------------------------------------------------------------------
-// LLEditingMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id)
-{
- mCharacter = NULL;
-
- // create kinematic chain
- mParentJoint.addChild( &mShoulderJoint );
- mShoulderJoint.addChild( &mElbowJoint );
- mElbowJoint.addChild( &mWristJoint );
-
- mName = "editing";
-
- mParentState = new LLJointState;
- mShoulderState = new LLJointState;
- mElbowState = new LLJointState;
- mWristState = new LLJointState;
- mTorsoState = new LLJointState;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLEditingMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLEditingMotion::~LLEditingMotion()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLEditingMotion::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *character)
-{
- // save character for future use
- mCharacter = character;
-
- // make sure character skeleton is copacetic
- if (!mCharacter->getJoint("mShoulderLeft") ||
- !mCharacter->getJoint("mElbowLeft") ||
- !mCharacter->getJoint("mWristLeft"))
- {
- LL_WARNS() << "Invalid skeleton for editing motion!" << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- // get the shoulder, elbow, wrist joints from the character
- mParentState->setJoint( mCharacter->getJoint("mShoulderLeft")->getParent() );
- mShoulderState->setJoint( mCharacter->getJoint("mShoulderLeft") );
- mElbowState->setJoint( mCharacter->getJoint("mElbowLeft") );
- mWristState->setJoint( mCharacter->getJoint("mWristLeft") );
- mTorsoState->setJoint( mCharacter->getJoint("mTorso"));
-
- if ( ! mParentState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get parent joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mWristOffset = LLVector3(0.0f, 0.2f, 0.0f);
-
- // add joint states to the pose
- mShoulderState->setUsage(LLJointState::ROT);
- mElbowState->setUsage(LLJointState::ROT);
- mTorsoState->setUsage(LLJointState::ROT);
- mWristState->setUsage(LLJointState::ROT);
- addJointState( mShoulderState );
- addJointState( mElbowState );
- addJointState( mTorsoState );
- addJointState( mWristState );
-
- // propagate joint positions to kinematic chain
- // SL-315
- mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() );
- mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() );
- mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() );
- mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset );
-
- // propagate current joint rotations to kinematic chain
- mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() );
- mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() );
- mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() );
-
- // connect the ikSolver to the chain
- mIKSolver.setPoleVector( LLVector3( -1.0f, 1.0f, 0.0f ) );
- // specifying the elbow's axis will prevent bad IK for the more
- // singular configurations, but the axis is limb-specific -- Leviathan
- mIKSolver.setBAxis( LLVector3( -0.682683f, 0.0f, -0.730714f ) );
- mIKSolver.setupJoints( &mShoulderJoint, &mElbowJoint, &mWristJoint, &mTarget );
-
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// LLEditingMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLEditingMotion::onActivate()
-{
- // propagate joint positions to kinematic chain
- // SL-315
- mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() );
- mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() );
- mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() );
- mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset );
-
- // propagate current joint rotations to kinematic chain
- mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() );
- mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() );
- mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() );
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLEditingMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLVector3 focus_pt;
- LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint");
-
-
- bool result = true;
-
- if (!pointAtPt)
- {
- focus_pt = mLastSelectPt;
- result = false;
- }
- else
- {
- focus_pt = *pointAtPt;
- mLastSelectPt = focus_pt;
- }
-
- focus_pt += mCharacter->getCharacterPosition();
-
- // propagate joint positions to kinematic chain
- // SL-315
- mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() );
- mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() );
- mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() );
- mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset );
-
- // propagate current joint rotations to kinematic chain
- mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() );
- mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() );
- mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() );
-
- // update target position from character
- LLVector3 target = focus_pt - mParentJoint.getPosition();
- F32 target_dist = target.normVec();
-
- LLVector3 edit_plane_normal(1.f / F_SQRT2, 1.f / F_SQRT2, 0.f);
- edit_plane_normal.normVec();
-
- edit_plane_normal.rotVec(mTorsoState->getJoint()->getWorldRotation());
-
- F32 dot = edit_plane_normal * target;
-
- if (dot < 0.f)
- {
- target = target + (edit_plane_normal * (dot * 2.f));
- target.mV[VZ] += clamp_rescale(dot, 0.f, -1.f, 0.f, 5.f);
- target.normVec();
- }
-
- target = target * target_dist;
- if (!target.isFinite())
- {
- // Don't error out here, set a fail-safe target vector
- LL_WARNS() << "Non finite target in editing motion with target distance of " << target_dist <<
- " and focus point " << focus_pt << LL_ENDL;
- target.setVec(1.f, 1.f, 1.f);
- }
-
- // SL-315
- mTarget.setPosition( target + mParentJoint.getPosition());
-
-// LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL;
-
- // update the ikSolver
- if (!mTarget.getPosition().isExactlyZero())
- {
- LLQuaternion shoulderRot = mShoulderJoint.getRotation();
- LLQuaternion elbowRot = mElbowJoint.getRotation();
- mIKSolver.solve();
-
- // use blending...
- F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TARGET_LAG_HALF_LIFE);
- shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot);
- elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot);
-
- // now put blended values back into joints
- llassert(shoulderRot.isFinite());
- llassert(elbowRot.isFinite());
- mShoulderState->setRotation(shoulderRot);
- mElbowState->setRotation(elbowRot);
- mWristState->setRotation(LLQuaternion::DEFAULT);
- }
-
- mCharacter->setAnimationData("Hand Pose", &sHandPose);
- mCharacter->setAnimationData("Hand Pose Priority", &sHandPosePriority);
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// LLEditingMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLEditingMotion::onDeactivate()
-{
-}
-
-
-// End
-
+/** + * @file lleditingmotion.cpp + * @brief Implementation of LLEditingMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "lleditingmotion.h" +#include "llcharacter.h" +#include "llhandmotion.h" +#include "llcriticaldamp.h" + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- +const LLQuaternion EDIT_MOTION_WRIST_ROTATION(F_PI_BY_TWO * 0.7f, LLVector3(1.0f, 0.0f, 0.0f)); +const F32 TARGET_LAG_HALF_LIFE = 0.1f; // half-life of IK targeting + +S32 LLEditingMotion::sHandPose = LLHandMotion::HAND_POSE_RELAXED_R; +S32 LLEditingMotion::sHandPosePriority = 3; + +//----------------------------------------------------------------------------- +// LLEditingMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id) +{ + mCharacter = NULL; + + // create kinematic chain + mParentJoint.addChild( &mShoulderJoint ); + mShoulderJoint.addChild( &mElbowJoint ); + mElbowJoint.addChild( &mWristJoint ); + + mName = "editing"; + + mParentState = new LLJointState; + mShoulderState = new LLJointState; + mElbowState = new LLJointState; + mWristState = new LLJointState; + mTorsoState = new LLJointState; +} + + +//----------------------------------------------------------------------------- +// ~LLEditingMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLEditingMotion::~LLEditingMotion() +{ +} + +//----------------------------------------------------------------------------- +// LLEditingMotion::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *character) +{ + // save character for future use + mCharacter = character; + + // make sure character skeleton is copacetic + if (!mCharacter->getJoint("mShoulderLeft") || + !mCharacter->getJoint("mElbowLeft") || + !mCharacter->getJoint("mWristLeft")) + { + LL_WARNS() << "Invalid skeleton for editing motion!" << LL_ENDL; + return STATUS_FAILURE; + } + + // get the shoulder, elbow, wrist joints from the character + mParentState->setJoint( mCharacter->getJoint("mShoulderLeft")->getParent() ); + mShoulderState->setJoint( mCharacter->getJoint("mShoulderLeft") ); + mElbowState->setJoint( mCharacter->getJoint("mElbowLeft") ); + mWristState->setJoint( mCharacter->getJoint("mWristLeft") ); + mTorsoState->setJoint( mCharacter->getJoint("mTorso")); + + if ( ! mParentState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get parent joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mWristOffset = LLVector3(0.0f, 0.2f, 0.0f); + + // add joint states to the pose + mShoulderState->setUsage(LLJointState::ROT); + mElbowState->setUsage(LLJointState::ROT); + mTorsoState->setUsage(LLJointState::ROT); + mWristState->setUsage(LLJointState::ROT); + addJointState( mShoulderState ); + addJointState( mElbowState ); + addJointState( mTorsoState ); + addJointState( mWristState ); + + // propagate joint positions to kinematic chain + // SL-315 + mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); + mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); + mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); + mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset ); + + // propagate current joint rotations to kinematic chain + mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() ); + mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() ); + mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() ); + + // connect the ikSolver to the chain + mIKSolver.setPoleVector( LLVector3( -1.0f, 1.0f, 0.0f ) ); + // specifying the elbow's axis will prevent bad IK for the more + // singular configurations, but the axis is limb-specific -- Leviathan + mIKSolver.setBAxis( LLVector3( -0.682683f, 0.0f, -0.730714f ) ); + mIKSolver.setupJoints( &mShoulderJoint, &mElbowJoint, &mWristJoint, &mTarget ); + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLEditingMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLEditingMotion::onActivate() +{ + // propagate joint positions to kinematic chain + // SL-315 + mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); + mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); + mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); + mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset ); + + // propagate current joint rotations to kinematic chain + mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() ); + mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() ); + mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() ); + + return true; +} + +//----------------------------------------------------------------------------- +// LLEditingMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLEditingMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + LLVector3 focus_pt; + LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint"); + + + bool result = true; + + if (!pointAtPt) + { + focus_pt = mLastSelectPt; + result = false; + } + else + { + focus_pt = *pointAtPt; + mLastSelectPt = focus_pt; + } + + focus_pt += mCharacter->getCharacterPosition(); + + // propagate joint positions to kinematic chain + // SL-315 + mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); + mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); + mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); + mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset ); + + // propagate current joint rotations to kinematic chain + mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() ); + mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() ); + mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() ); + + // update target position from character + LLVector3 target = focus_pt - mParentJoint.getPosition(); + F32 target_dist = target.normVec(); + + LLVector3 edit_plane_normal(1.f / F_SQRT2, 1.f / F_SQRT2, 0.f); + edit_plane_normal.normVec(); + + edit_plane_normal.rotVec(mTorsoState->getJoint()->getWorldRotation()); + + F32 dot = edit_plane_normal * target; + + if (dot < 0.f) + { + target = target + (edit_plane_normal * (dot * 2.f)); + target.mV[VZ] += clamp_rescale(dot, 0.f, -1.f, 0.f, 5.f); + target.normVec(); + } + + target = target * target_dist; + if (!target.isFinite()) + { + // Don't error out here, set a fail-safe target vector + LL_WARNS() << "Non finite target in editing motion with target distance of " << target_dist << + " and focus point " << focus_pt << LL_ENDL; + target.setVec(1.f, 1.f, 1.f); + } + + // SL-315 + mTarget.setPosition( target + mParentJoint.getPosition()); + +// LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL; + + // update the ikSolver + if (!mTarget.getPosition().isExactlyZero()) + { + LLQuaternion shoulderRot = mShoulderJoint.getRotation(); + LLQuaternion elbowRot = mElbowJoint.getRotation(); + mIKSolver.solve(); + + // use blending... + F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TARGET_LAG_HALF_LIFE); + shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot); + elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot); + + // now put blended values back into joints + llassert(shoulderRot.isFinite()); + llassert(elbowRot.isFinite()); + mShoulderState->setRotation(shoulderRot); + mElbowState->setRotation(elbowRot); + mWristState->setRotation(LLQuaternion::DEFAULT); + } + + mCharacter->setAnimationData("Hand Pose", &sHandPose); + mCharacter->setAnimationData("Hand Pose Priority", &sHandPosePriority); + return result; +} + +//----------------------------------------------------------------------------- +// LLEditingMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLEditingMotion::onDeactivate() +{ +} + + +// End + diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h index 0f350af20c..f94756d43d 100644 --- a/indra/llcharacter/lleditingmotion.h +++ b/indra/llcharacter/lleditingmotion.h @@ -1,135 +1,135 @@ -/**
- * @file lleditingmotion.h
- * @brief Implementation of LLEditingMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLEDITINGMOTION_H
-#define LL_LLEDITINGMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llmotion.h"
-#include "lljointsolverrp3.h"
-#include "v3dmath.h"
-
-#define EDITING_EASEIN_DURATION 0.0f
-#define EDITING_EASEOUT_DURATION 0.5f
-#define EDITING_PRIORITY LLJoint::HIGH_PRIORITY
-#define MIN_REQUIRED_PIXEL_AREA_EDITING 500.f
-
-//-----------------------------------------------------------------------------
-// class LLEditingMotion
-//-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLEditingMotion :
- public LLMotion
-{
- LL_ALIGN_NEW
-public:
- // Constructor
- LLEditingMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLEditingMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() { return true; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return EDITING_EASEIN_DURATION; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return EDITING_EASEOUT_DURATION; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return EDITING_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_EDITING; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
-public:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
- LL_ALIGN_16(LLJoint mParentJoint);
- LL_ALIGN_16(LLJoint mShoulderJoint);
- LL_ALIGN_16(LLJoint mElbowJoint);
- LL_ALIGN_16(LLJoint mWristJoint);
- LL_ALIGN_16(LLJoint mTarget);
- LLJointSolverRP3 mIKSolver;
-
- LLCharacter *mCharacter;
- LLVector3 mWristOffset;
-
- LLPointer<LLJointState> mParentState;
- LLPointer<LLJointState> mShoulderState;
- LLPointer<LLJointState> mElbowState;
- LLPointer<LLJointState> mWristState;
- LLPointer<LLJointState> mTorsoState;
-
- static S32 sHandPose;
- static S32 sHandPosePriority;
- LLVector3 mLastSelectPt;
-} LL_ALIGN_POSTFIX(16);
-
-#endif // LL_LLKEYFRAMEMOTION_H
-
+/** + * @file lleditingmotion.h + * @brief Implementation of LLEditingMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLEDITINGMOTION_H +#define LL_LLEDITINGMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" +#include "lljointsolverrp3.h" +#include "v3dmath.h" + +#define EDITING_EASEIN_DURATION 0.0f +#define EDITING_EASEOUT_DURATION 0.5f +#define EDITING_PRIORITY LLJoint::HIGH_PRIORITY +#define MIN_REQUIRED_PIXEL_AREA_EDITING 500.f + +//----------------------------------------------------------------------------- +// class LLEditingMotion +//----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) +class LLEditingMotion : + public LLMotion +{ + LL_ALIGN_NEW +public: + // Constructor + LLEditingMotion(const LLUUID &id); + + // Destructor + virtual ~LLEditingMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { return true; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return EDITING_EASEIN_DURATION; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return EDITING_EASEOUT_DURATION; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return EDITING_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_EDITING; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + +public: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LL_ALIGN_16(LLJoint mParentJoint); + LL_ALIGN_16(LLJoint mShoulderJoint); + LL_ALIGN_16(LLJoint mElbowJoint); + LL_ALIGN_16(LLJoint mWristJoint); + LL_ALIGN_16(LLJoint mTarget); + LLJointSolverRP3 mIKSolver; + + LLCharacter *mCharacter; + LLVector3 mWristOffset; + + LLPointer<LLJointState> mParentState; + LLPointer<LLJointState> mShoulderState; + LLPointer<LLJointState> mElbowState; + LLPointer<LLJointState> mWristState; + LLPointer<LLJointState> mTorsoState; + + static S32 sHandPose; + static S32 sHandPosePriority; + LLVector3 mLastSelectPt; +} LL_ALIGN_POSTFIX(16); + +#endif // LL_LLKEYFRAMEMOTION_H + diff --git a/indra/llcharacter/llgesture.cpp b/indra/llcharacter/llgesture.cpp index 9dee01c1ee..151bac7920 100644 --- a/indra/llcharacter/llgesture.cpp +++ b/indra/llcharacter/llgesture.cpp @@ -1,348 +1,348 @@ -/**
- * @file llgesture.cpp
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "indra_constants.h"
-
-#include "llgesture.h"
-#include "llendianswizzle.h"
-#include "message.h"
-#include <boost/tokenizer.hpp>
-
-// for allocating serialization buffers - these need to be updated when members change
-const S32 LLGestureList::SERIAL_HEADER_SIZE = sizeof(S32);
-const S32 LLGesture::MAX_SERIAL_SIZE = sizeof(KEY) + sizeof(MASK) + 16 + 26 + 41 + 41;
-
-LLGesture::LLGesture()
-: mKey(KEY_NONE),
- mMask(MASK_NONE),
- mTrigger(),
- mTriggerLower(),
- mSoundItemID(),
- mAnimation(),
- mOutputString()
-{ }
-
-LLGesture::LLGesture(KEY key, MASK mask, const std::string &trigger,
- const LLUUID &sound_item_id,
- const std::string &animation,
- const std::string &output_string)
-:
- mKey(key),
- mMask(mask),
- mTrigger(trigger),
- mTriggerLower(trigger),
- mSoundItemID(sound_item_id),
- mAnimation(animation),
- mOutputString(output_string)
-{
- mTriggerLower = utf8str_tolower(mTriggerLower);
-}
-
-LLGesture::LLGesture(U8 **buffer, S32 max_size)
-{
- *buffer = deserialize(*buffer, max_size);
-}
-
-LLGesture::LLGesture(const LLGesture &rhs)
-{
- mKey = rhs.mKey;
- mMask = rhs.mMask;
- mTrigger = rhs.mTrigger;
- mTriggerLower = rhs.mTriggerLower;
- mSoundItemID = rhs.mSoundItemID;
- mAnimation = rhs.mAnimation;
- mOutputString = rhs.mOutputString;
-}
-
-const LLGesture &LLGesture::operator =(const LLGesture &rhs)
-{
- mKey = rhs.mKey;
- mMask = rhs.mMask;
- mTrigger = rhs.mTrigger;
- mTriggerLower = rhs.mTriggerLower;
- mSoundItemID = rhs.mSoundItemID;
- mAnimation = rhs.mAnimation;
- mOutputString = rhs.mOutputString;
- return (*this);
-}
-
-
-bool LLGesture::trigger(KEY key, MASK mask)
-{
- LL_WARNS() << "Parent class trigger called: you probably didn't mean this." << LL_ENDL;
- return false;
-}
-
-
-bool LLGesture::trigger(const std::string& trigger_string)
-{
- LL_WARNS() << "Parent class trigger called: you probably didn't mean this." << LL_ENDL;
- return false;
-}
-
-// NOT endian-neutral
-U8 *LLGesture::serialize(U8 *buffer) const
-{
- htolememcpy(buffer, &mKey, MVT_S8, 1);
- buffer += sizeof(mKey);
- htolememcpy(buffer, &mMask, MVT_U32, 4);
- buffer += sizeof(mMask);
- htolememcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16);
- buffer += 16;
-
- memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1); /* Flawfinder: ignore */
- buffer += mTrigger.length() + 1;
- memcpy(buffer, mAnimation.c_str(), mAnimation.length() + 1); /* Flawfinder: ignore */
- buffer += mAnimation.length() + 1;
- memcpy(buffer, mOutputString.c_str(), mOutputString.length() + 1); /* Flawfinder: ignore */
- buffer += mOutputString.length() + 1;
-
- return buffer;
-}
-
-U8 *LLGesture::deserialize(U8 *buffer, S32 max_size)
-{
- U8 *tmp = buffer;
-
- if (tmp + sizeof(mKey) + sizeof(mMask) + 16 > buffer + max_size)
- {
- LL_WARNS() << "Attempt to read past end of buffer, bad data!!!!" << LL_ENDL;
- return buffer;
- }
-
- htolememcpy(&mKey, tmp, MVT_S8, 1);
- tmp += sizeof(mKey);
- htolememcpy(&mMask, tmp, MVT_U32, 4);
- tmp += sizeof(mMask);
- htolememcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16);
- tmp += 16;
-
- mTrigger.assign((char *)tmp);
- mTriggerLower = mTrigger;
- mTriggerLower = utf8str_tolower(mTriggerLower);
- tmp += mTrigger.length() + 1;
- mAnimation.assign((char *)tmp);
- //RN: force animation names to lower case
- // must do this for backwards compatibility
- mAnimation = utf8str_tolower(mAnimation);
- tmp += mAnimation.length() + 1;
- mOutputString.assign((char *)tmp);
- tmp += mOutputString.length() + 1;
-
- if (tmp > buffer + max_size)
- {
- LL_WARNS() << "Read past end of buffer, bad data!!!!" << LL_ENDL;
- return tmp;
- }
-
- return tmp;
-}
-
-S32 LLGesture::getMaxSerialSize()
-{
- return MAX_SERIAL_SIZE;
-}
-
-//---------------------------------------------------------------------
-// LLGestureList
-//---------------------------------------------------------------------
-
-LLGestureList::LLGestureList()
-: mList(0)
-{}
-
-LLGestureList::~LLGestureList()
-{
- deleteAll();
-}
-
-
-void LLGestureList::deleteAll()
-{
- delete_and_clear(mList);
-}
-
-// Iterates through space delimited tokens in string, triggering any gestures found.
-// Generates a revised string that has the found tokens replaced by their replacement strings
-// and (as a minor side effect) has multiple spaces in a row replaced by single spaces.
-bool LLGestureList::triggerAndReviseString(const std::string &string, std::string* revised_string)
-{
- std::string tokenized = string;
-
- bool found_gestures = false;
- bool first_token = true;
-
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep(" ");
- tokenizer tokens(string, sep);
-
- for(const std::string& cur_token : tokens)
- {
- LLGesture* gesture = NULL;
-
- if( !found_gestures ) // Only pay attention to the first gesture in the string.
- {
- std::string cur_token_lower = cur_token;
- LLStringUtil::toLower(cur_token_lower);
-
- for (U32 i = 0; i < mList.size(); i++)
- {
- gesture = mList.at(i);
- if (gesture->trigger(cur_token_lower))
- {
- if( !gesture->getOutputString().empty() )
- {
- if( !first_token )
- {
- revised_string->append( " " );
- }
-
- // Don't muck with the user's capitalization if we don't have to.
- const std::string& output = gesture->getOutputString();
- std::string output_lower = std::string(output.c_str());
- LLStringUtil::toLower(output_lower);
- if( cur_token_lower == output_lower )
- {
- revised_string->append(cur_token);
- }
- else
- {
- revised_string->append(output);
- }
-
- }
- found_gestures = true;
- break;
- }
- gesture = NULL;
- }
- }
-
- if( !gesture )
- {
- if( !first_token )
- {
- revised_string->append( " " );
- }
- revised_string->append( cur_token );
- }
-
- first_token = false;
- }
- return found_gestures;
-}
-
-
-
-bool LLGestureList::trigger(KEY key, MASK mask)
-{
- for (U32 i = 0; i < mList.size(); i++)
- {
- LLGesture* gesture = mList.at(i);
- if( gesture )
- {
- if (gesture->trigger(key, mask))
- {
- return true;
- }
- }
- else
- {
- LL_WARNS() << "NULL gesture in gesture list (" << i << ")" << LL_ENDL;
- }
- }
- return false;
-}
-
-// NOT endian-neutral
-U8 *LLGestureList::serialize(U8 *buffer) const
-{
- // a single S32 serves as the header that tells us how many to read
- U32 count = mList.size();
- htolememcpy(buffer, &count, MVT_S32, 4);
- buffer += sizeof(count);
-
- for (S32 i = 0; i < count; i++)
- {
- buffer = mList[i]->serialize(buffer);
- }
-
- return buffer;
-}
-
-const S32 MAX_GESTURES = 4096;
-
-U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size)
-{
- deleteAll();
-
- S32 count;
- U8 *tmp = buffer;
-
- if (tmp + sizeof(count) > buffer + max_size)
- {
- LL_WARNS() << "Invalid max_size" << LL_ENDL;
- return buffer;
- }
-
- htolememcpy(&count, tmp, MVT_S32, 4);
-
- if (count > MAX_GESTURES)
- {
- LL_WARNS() << "Unreasonably large gesture list count in deserialize: " << count << LL_ENDL;
- return tmp;
- }
-
- tmp += sizeof(count);
-
- mList.resize(count);
-
- for (S32 i = 0; i < count; i++)
- {
- mList[i] = create_gesture(&tmp, max_size - (S32)(tmp - buffer));
- if (tmp - buffer > max_size)
- {
- LL_WARNS() << "Deserialization read past end of buffer, bad data!!!!" << LL_ENDL;
- return tmp;
- }
- }
-
- return tmp;
-}
-
-// this is a helper for deserialize
-// it gets overridden by LLViewerGestureList to create LLViewerGestures
-// overridden by child class to use local LLGesture implementation
-LLGesture *LLGestureList::create_gesture(U8 **buffer, S32 max_size)
-{
- return new LLGesture(buffer, max_size);
-}
-
-S32 LLGestureList::getMaxSerialSize()
-{
- return SERIAL_HEADER_SIZE + (count() * LLGesture::getMaxSerialSize());
-}
+/** + * @file llgesture.cpp + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "indra_constants.h" + +#include "llgesture.h" +#include "llendianswizzle.h" +#include "message.h" +#include <boost/tokenizer.hpp> + +// for allocating serialization buffers - these need to be updated when members change +const S32 LLGestureList::SERIAL_HEADER_SIZE = sizeof(S32); +const S32 LLGesture::MAX_SERIAL_SIZE = sizeof(KEY) + sizeof(MASK) + 16 + 26 + 41 + 41; + +LLGesture::LLGesture() +: mKey(KEY_NONE), + mMask(MASK_NONE), + mTrigger(), + mTriggerLower(), + mSoundItemID(), + mAnimation(), + mOutputString() +{ } + +LLGesture::LLGesture(KEY key, MASK mask, const std::string &trigger, + const LLUUID &sound_item_id, + const std::string &animation, + const std::string &output_string) +: + mKey(key), + mMask(mask), + mTrigger(trigger), + mTriggerLower(trigger), + mSoundItemID(sound_item_id), + mAnimation(animation), + mOutputString(output_string) +{ + mTriggerLower = utf8str_tolower(mTriggerLower); +} + +LLGesture::LLGesture(U8 **buffer, S32 max_size) +{ + *buffer = deserialize(*buffer, max_size); +} + +LLGesture::LLGesture(const LLGesture &rhs) +{ + mKey = rhs.mKey; + mMask = rhs.mMask; + mTrigger = rhs.mTrigger; + mTriggerLower = rhs.mTriggerLower; + mSoundItemID = rhs.mSoundItemID; + mAnimation = rhs.mAnimation; + mOutputString = rhs.mOutputString; +} + +const LLGesture &LLGesture::operator =(const LLGesture &rhs) +{ + mKey = rhs.mKey; + mMask = rhs.mMask; + mTrigger = rhs.mTrigger; + mTriggerLower = rhs.mTriggerLower; + mSoundItemID = rhs.mSoundItemID; + mAnimation = rhs.mAnimation; + mOutputString = rhs.mOutputString; + return (*this); +} + + +bool LLGesture::trigger(KEY key, MASK mask) +{ + LL_WARNS() << "Parent class trigger called: you probably didn't mean this." << LL_ENDL; + return false; +} + + +bool LLGesture::trigger(const std::string& trigger_string) +{ + LL_WARNS() << "Parent class trigger called: you probably didn't mean this." << LL_ENDL; + return false; +} + +// NOT endian-neutral +U8 *LLGesture::serialize(U8 *buffer) const +{ + htolememcpy(buffer, &mKey, MVT_S8, 1); + buffer += sizeof(mKey); + htolememcpy(buffer, &mMask, MVT_U32, 4); + buffer += sizeof(mMask); + htolememcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16); + buffer += 16; + + memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1); /* Flawfinder: ignore */ + buffer += mTrigger.length() + 1; + memcpy(buffer, mAnimation.c_str(), mAnimation.length() + 1); /* Flawfinder: ignore */ + buffer += mAnimation.length() + 1; + memcpy(buffer, mOutputString.c_str(), mOutputString.length() + 1); /* Flawfinder: ignore */ + buffer += mOutputString.length() + 1; + + return buffer; +} + +U8 *LLGesture::deserialize(U8 *buffer, S32 max_size) +{ + U8 *tmp = buffer; + + if (tmp + sizeof(mKey) + sizeof(mMask) + 16 > buffer + max_size) + { + LL_WARNS() << "Attempt to read past end of buffer, bad data!!!!" << LL_ENDL; + return buffer; + } + + htolememcpy(&mKey, tmp, MVT_S8, 1); + tmp += sizeof(mKey); + htolememcpy(&mMask, tmp, MVT_U32, 4); + tmp += sizeof(mMask); + htolememcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16); + tmp += 16; + + mTrigger.assign((char *)tmp); + mTriggerLower = mTrigger; + mTriggerLower = utf8str_tolower(mTriggerLower); + tmp += mTrigger.length() + 1; + mAnimation.assign((char *)tmp); + //RN: force animation names to lower case + // must do this for backwards compatibility + mAnimation = utf8str_tolower(mAnimation); + tmp += mAnimation.length() + 1; + mOutputString.assign((char *)tmp); + tmp += mOutputString.length() + 1; + + if (tmp > buffer + max_size) + { + LL_WARNS() << "Read past end of buffer, bad data!!!!" << LL_ENDL; + return tmp; + } + + return tmp; +} + +S32 LLGesture::getMaxSerialSize() +{ + return MAX_SERIAL_SIZE; +} + +//--------------------------------------------------------------------- +// LLGestureList +//--------------------------------------------------------------------- + +LLGestureList::LLGestureList() +: mList(0) +{} + +LLGestureList::~LLGestureList() +{ + deleteAll(); +} + + +void LLGestureList::deleteAll() +{ + delete_and_clear(mList); +} + +// Iterates through space delimited tokens in string, triggering any gestures found. +// Generates a revised string that has the found tokens replaced by their replacement strings +// and (as a minor side effect) has multiple spaces in a row replaced by single spaces. +bool LLGestureList::triggerAndReviseString(const std::string &string, std::string* revised_string) +{ + std::string tokenized = string; + + bool found_gestures = false; + bool first_token = true; + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + tokenizer tokens(string, sep); + + for(const std::string& cur_token : tokens) + { + LLGesture* gesture = NULL; + + if( !found_gestures ) // Only pay attention to the first gesture in the string. + { + std::string cur_token_lower = cur_token; + LLStringUtil::toLower(cur_token_lower); + + for (U32 i = 0; i < mList.size(); i++) + { + gesture = mList.at(i); + if (gesture->trigger(cur_token_lower)) + { + if( !gesture->getOutputString().empty() ) + { + if( !first_token ) + { + revised_string->append( " " ); + } + + // Don't muck with the user's capitalization if we don't have to. + const std::string& output = gesture->getOutputString(); + std::string output_lower = std::string(output.c_str()); + LLStringUtil::toLower(output_lower); + if( cur_token_lower == output_lower ) + { + revised_string->append(cur_token); + } + else + { + revised_string->append(output); + } + + } + found_gestures = true; + break; + } + gesture = NULL; + } + } + + if( !gesture ) + { + if( !first_token ) + { + revised_string->append( " " ); + } + revised_string->append( cur_token ); + } + + first_token = false; + } + return found_gestures; +} + + + +bool LLGestureList::trigger(KEY key, MASK mask) +{ + for (U32 i = 0; i < mList.size(); i++) + { + LLGesture* gesture = mList.at(i); + if( gesture ) + { + if (gesture->trigger(key, mask)) + { + return true; + } + } + else + { + LL_WARNS() << "NULL gesture in gesture list (" << i << ")" << LL_ENDL; + } + } + return false; +} + +// NOT endian-neutral +U8 *LLGestureList::serialize(U8 *buffer) const +{ + // a single S32 serves as the header that tells us how many to read + U32 count = mList.size(); + htolememcpy(buffer, &count, MVT_S32, 4); + buffer += sizeof(count); + + for (S32 i = 0; i < count; i++) + { + buffer = mList[i]->serialize(buffer); + } + + return buffer; +} + +const S32 MAX_GESTURES = 4096; + +U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size) +{ + deleteAll(); + + S32 count; + U8 *tmp = buffer; + + if (tmp + sizeof(count) > buffer + max_size) + { + LL_WARNS() << "Invalid max_size" << LL_ENDL; + return buffer; + } + + htolememcpy(&count, tmp, MVT_S32, 4); + + if (count > MAX_GESTURES) + { + LL_WARNS() << "Unreasonably large gesture list count in deserialize: " << count << LL_ENDL; + return tmp; + } + + tmp += sizeof(count); + + mList.resize(count); + + for (S32 i = 0; i < count; i++) + { + mList[i] = create_gesture(&tmp, max_size - (S32)(tmp - buffer)); + if (tmp - buffer > max_size) + { + LL_WARNS() << "Deserialization read past end of buffer, bad data!!!!" << LL_ENDL; + return tmp; + } + } + + return tmp; +} + +// this is a helper for deserialize +// it gets overridden by LLViewerGestureList to create LLViewerGestures +// overridden by child class to use local LLGesture implementation +LLGesture *LLGestureList::create_gesture(U8 **buffer, S32 max_size) +{ + return new LLGesture(buffer, max_size); +} + +S32 LLGestureList::getMaxSerialSize() +{ + return SERIAL_HEADER_SIZE + (count() * LLGesture::getMaxSerialSize()); +} diff --git a/indra/llcharacter/llgesture.h b/indra/llcharacter/llgesture.h index 69b2946866..f1b83a4b50 100644 --- a/indra/llcharacter/llgesture.h +++ b/indra/llcharacter/llgesture.h @@ -1,113 +1,113 @@ -/**
- * @file llgesture.h
- * @brief A gesture is a combination of a triggering chat phrase or
- * key, a sound, an animation, and a chat string.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLGESTURE_H
-#define LL_LLGESTURE_H
-
-#include "llanimationstates.h"
-#include "lluuid.h"
-#include "llstring.h"
-
-class LLGesture
-{
-public:
- LLGesture();
- LLGesture(KEY key, MASK mask, const std::string &trigger,
- const LLUUID &sound_item_id, const std::string &animation,
- const std::string &output_string);
-
- LLGesture(U8 **buffer, S32 max_size); // deserializes, advances buffer
- LLGesture(const LLGesture &gesture);
- const LLGesture &operator=(const LLGesture &rhs);
-
- virtual ~LLGesture() {};
-
- // Accessors
- KEY getKey() const { return mKey; }
- MASK getMask() const { return mMask; }
- const std::string& getTrigger() const { return mTrigger; }
- const LLUUID& getSound() const { return mSoundItemID; }
- const std::string& getAnimation() const { return mAnimation; }
- const std::string& getOutputString() const { return mOutputString; }
-
- // Triggers if a key/mask matches it
- virtual bool trigger(KEY key, MASK mask);
-
- // Triggers if case-insensitive substring matches (assumes string is lowercase)
- virtual bool trigger(const std::string &string);
-
- // non-endian-neutral serialization
- U8 *serialize(U8 *buffer) const;
- U8 *deserialize(U8 *buffer, S32 max_size);
- static S32 getMaxSerialSize();
-
-protected:
- KEY mKey; // usually a function key
- MASK mMask; // usually MASK_NONE, or MASK_SHIFT
- std::string mTrigger; // string, no whitespace allowed
- std::string mTriggerLower; // lowercase version of mTrigger
- LLUUID mSoundItemID; // ItemID of sound to play, LLUUID::null if none
- std::string mAnimation; // canonical name of animation or face animation
- std::string mOutputString; // string to say
-
- static const S32 MAX_SERIAL_SIZE;
-};
-
-class LLGestureList
-{
-public:
- LLGestureList();
- virtual ~LLGestureList();
-
- // Triggers if a key/mask matches one in the list
- bool trigger(KEY key, MASK mask);
-
- // Triggers if substring matches and generates revised string.
- bool triggerAndReviseString(const std::string &string, std::string* revised_string);
-
- // Used for construction from UI
- S32 count() const { return mList.size(); }
- virtual LLGesture* get(S32 i) const { return mList.at(i); }
- virtual void put(LLGesture* gesture) { mList.push_back( gesture ); }
- void deleteAll();
-
- // non-endian-neutral serialization
- U8 *serialize(U8 *buffer) const;
- U8 *deserialize(U8 *buffer, S32 max_size);
- S32 getMaxSerialSize();
-
-protected:
- // overridden by child class to use local LLGesture implementation
- virtual LLGesture *create_gesture(U8 **buffer, S32 max_size);
-
-protected:
- std::vector<LLGesture*> mList;
-
- static const S32 SERIAL_HEADER_SIZE;
-};
-
-#endif
+/** + * @file llgesture.h + * @brief A gesture is a combination of a triggering chat phrase or + * key, a sound, an animation, and a chat string. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLGESTURE_H +#define LL_LLGESTURE_H + +#include "llanimationstates.h" +#include "lluuid.h" +#include "llstring.h" + +class LLGesture +{ +public: + LLGesture(); + LLGesture(KEY key, MASK mask, const std::string &trigger, + const LLUUID &sound_item_id, const std::string &animation, + const std::string &output_string); + + LLGesture(U8 **buffer, S32 max_size); // deserializes, advances buffer + LLGesture(const LLGesture &gesture); + const LLGesture &operator=(const LLGesture &rhs); + + virtual ~LLGesture() {}; + + // Accessors + KEY getKey() const { return mKey; } + MASK getMask() const { return mMask; } + const std::string& getTrigger() const { return mTrigger; } + const LLUUID& getSound() const { return mSoundItemID; } + const std::string& getAnimation() const { return mAnimation; } + const std::string& getOutputString() const { return mOutputString; } + + // Triggers if a key/mask matches it + virtual bool trigger(KEY key, MASK mask); + + // Triggers if case-insensitive substring matches (assumes string is lowercase) + virtual bool trigger(const std::string &string); + + // non-endian-neutral serialization + U8 *serialize(U8 *buffer) const; + U8 *deserialize(U8 *buffer, S32 max_size); + static S32 getMaxSerialSize(); + +protected: + KEY mKey; // usually a function key + MASK mMask; // usually MASK_NONE, or MASK_SHIFT + std::string mTrigger; // string, no whitespace allowed + std::string mTriggerLower; // lowercase version of mTrigger + LLUUID mSoundItemID; // ItemID of sound to play, LLUUID::null if none + std::string mAnimation; // canonical name of animation or face animation + std::string mOutputString; // string to say + + static const S32 MAX_SERIAL_SIZE; +}; + +class LLGestureList +{ +public: + LLGestureList(); + virtual ~LLGestureList(); + + // Triggers if a key/mask matches one in the list + bool trigger(KEY key, MASK mask); + + // Triggers if substring matches and generates revised string. + bool triggerAndReviseString(const std::string &string, std::string* revised_string); + + // Used for construction from UI + S32 count() const { return mList.size(); } + virtual LLGesture* get(S32 i) const { return mList.at(i); } + virtual void put(LLGesture* gesture) { mList.push_back( gesture ); } + void deleteAll(); + + // non-endian-neutral serialization + U8 *serialize(U8 *buffer) const; + U8 *deserialize(U8 *buffer, S32 max_size); + S32 getMaxSerialSize(); + +protected: + // overridden by child class to use local LLGesture implementation + virtual LLGesture *create_gesture(U8 **buffer, S32 max_size); + +protected: + std::vector<LLGesture*> mList; + + static const S32 SERIAL_HEADER_SIZE; +}; + +#endif diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp index f52530db33..2c03ded841 100644 --- a/indra/llcharacter/llhandmotion.cpp +++ b/indra/llcharacter/llhandmotion.cpp @@ -1,271 +1,271 @@ -/**
- * @file llhandmotion.cpp
- * @brief Implementation of LLHandMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llhandmotion.h"
-#include "llcharacter.h"
-#include "m3math.h"
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
-const char *gHandPoseNames[LLHandMotion::NUM_HAND_POSES] = /* Flawfinder: ignore */
-{
- "",
- "Hands_Relaxed",
- "Hands_Point",
- "Hands_Fist",
- "Hands_Relaxed_L",
- "Hands_Point_L",
- "Hands_Fist_L",
- "Hands_Relaxed_R",
- "Hands_Point_R",
- "Hands_Fist_R",
- "Hands_Salute_R",
- "Hands_Typing",
- "Hands_Peace_R",
- "Hands_Spread_R"
-};
-
-const F32 HAND_MORPH_BLEND_TIME = 0.2f;
-
-//-----------------------------------------------------------------------------
-// LLHandMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id)
-{
- mCharacter = NULL;
- mLastTime = 0.f;
- mCurrentPose = HAND_POSE_RELAXED;
- mNewPose = HAND_POSE_RELAXED;
- mName = "hand_motion";
-
- //RN: flag hand joint as highest priority for now, until we implement a proper animation track
- mJointSignature[0][LL_HAND_JOINT_NUM] = 0xff;
- mJointSignature[1][LL_HAND_JOINT_NUM] = 0xff;
- mJointSignature[2][LL_HAND_JOINT_NUM] = 0xff;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLHandMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLHandMotion::~LLHandMotion()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLHandMotion::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLHandMotion::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- return STATUS_SUCCESS;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLHandMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLHandMotion::onActivate()
-{
- LLPolyMesh *upperBodyMesh = mCharacter->getUpperBodyMesh();
-
- if (upperBodyMesh)
- {
- // Note: 0 is the default
- for (S32 i = 1; i < LLHandMotion::NUM_HAND_POSES; i++)
- {
- mCharacter->setVisualParamWeight(gHandPoseNames[i], 0.f);
- }
- mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
- mCharacter->updateVisualParams();
- }
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLHandMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLHandMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- eHandPose *requestedHandPose;
-
- F32 timeDelta = time - mLastTime;
- mLastTime = time;
-
- requestedHandPose = (eHandPose *)mCharacter->getAnimationData("Hand Pose");
- // check to see if requested pose has changed
- if (!requestedHandPose)
- {
- if (mNewPose != HAND_POSE_RELAXED && mNewPose != mCurrentPose)
- {
- // Only set param weight for poses other than
- // default (HAND_POSE_SPREAD); HAND_POSE_SPREAD
- // is not an animatable morph!
- if (mNewPose != HAND_POSE_SPREAD)
- {
- mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
- }
-
- // Reset morph weight for current pose back to its
- // full extend or it might be stuck somewhere in the middle if a
- // pose is requested and the old pose is requested again shortly
- // after while still blending to the other pose!
- if (mCurrentPose != HAND_POSE_SPREAD)
- {
- mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
- }
-
- // Update visual params now if we won't blend
- if (mCurrentPose == HAND_POSE_RELAXED)
- {
- mCharacter->updateVisualParams();
- }
- }
- mNewPose = HAND_POSE_RELAXED;
- }
- else
- {
- // Sometimes we seem to get garbage here, with poses that are out of bounds.
- // So check for a valid pose first.
- if (*requestedHandPose >= 0 && *requestedHandPose < NUM_HAND_POSES)
- {
- // This is a new morph we didn't know about before:
- // Reset morph weight for both current and new pose
- // back their starting values while still blending.
- if (*requestedHandPose != mNewPose && mNewPose != mCurrentPose)
- {
- if (mNewPose != HAND_POSE_SPREAD)
- {
- mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
- }
-
- // Reset morph weight for current pose back to its full extend
- // or it might be stuck somewhere in the middle if a pose is
- // requested and the old pose is requested again shortly after
- // while still blending to the other pose!
- if (mCurrentPose != HAND_POSE_SPREAD)
- {
- mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
- }
-
- // Update visual params now if we won't blend
- if (mCurrentPose == *requestedHandPose)
- {
- mCharacter->updateVisualParams();
- }
- }
- mNewPose = *requestedHandPose;
- }
- else
- {
- LL_WARNS() << "Requested hand pose out of range. Ignoring requested pose." << LL_ENDL;
- }
- }
-
- mCharacter->removeAnimationData("Hand Pose");
- mCharacter->removeAnimationData("Hand Pose Priority");
-
-// if (requestedHandPose)
-// LL_INFOS() << "Hand Pose " << *requestedHandPose << LL_ENDL;
-
- // if we are still blending...
- if (mCurrentPose != mNewPose)
- {
- F32 incomingWeight = 1.f;
- F32 outgoingWeight = 0.f;
-
- if (mNewPose != HAND_POSE_SPREAD)
- {
- incomingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mNewPose]);
- incomingWeight += (timeDelta / HAND_MORPH_BLEND_TIME);
- incomingWeight = llclamp(incomingWeight, 0.f, 1.f);
- mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], incomingWeight);
- }
-
- if (mCurrentPose != HAND_POSE_SPREAD)
- {
- outgoingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mCurrentPose]);
- outgoingWeight -= (timeDelta / HAND_MORPH_BLEND_TIME);
- outgoingWeight = llclamp(outgoingWeight, 0.f, 1.f);
- mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], outgoingWeight);
- }
-
- mCharacter->updateVisualParams();
-
- if (incomingWeight == 1.f && outgoingWeight == 0.f)
- {
- mCurrentPose = mNewPose;
- }
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLHandMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLHandMotion::onDeactivate()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLHandMotion::getHandPoseName()
-//-----------------------------------------------------------------------------
-std::string LLHandMotion::getHandPoseName(eHandPose pose)
-{
- if ((S32)pose < LLHandMotion::NUM_HAND_POSES && (S32)pose >= 0)
- {
- return std::string(gHandPoseNames[pose]);
- }
- return LLStringUtil::null;
-}
-
-LLHandMotion::eHandPose LLHandMotion::getHandPose(std::string posename)
-{
- for (S32 pose = 0; pose < LLHandMotion::NUM_HAND_POSES; ++pose)
- {
- if (gHandPoseNames[pose] == posename)
- {
- return (eHandPose)pose;
- }
- }
- return (eHandPose)0;
-}
-
-// End
+/** + * @file llhandmotion.cpp + * @brief Implementation of LLHandMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llhandmotion.h" +#include "llcharacter.h" +#include "m3math.h" + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +const char *gHandPoseNames[LLHandMotion::NUM_HAND_POSES] = /* Flawfinder: ignore */ +{ + "", + "Hands_Relaxed", + "Hands_Point", + "Hands_Fist", + "Hands_Relaxed_L", + "Hands_Point_L", + "Hands_Fist_L", + "Hands_Relaxed_R", + "Hands_Point_R", + "Hands_Fist_R", + "Hands_Salute_R", + "Hands_Typing", + "Hands_Peace_R", + "Hands_Spread_R" +}; + +const F32 HAND_MORPH_BLEND_TIME = 0.2f; + +//----------------------------------------------------------------------------- +// LLHandMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id) +{ + mCharacter = NULL; + mLastTime = 0.f; + mCurrentPose = HAND_POSE_RELAXED; + mNewPose = HAND_POSE_RELAXED; + mName = "hand_motion"; + + //RN: flag hand joint as highest priority for now, until we implement a proper animation track + mJointSignature[0][LL_HAND_JOINT_NUM] = 0xff; + mJointSignature[1][LL_HAND_JOINT_NUM] = 0xff; + mJointSignature[2][LL_HAND_JOINT_NUM] = 0xff; +} + + +//----------------------------------------------------------------------------- +// ~LLHandMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLHandMotion::~LLHandMotion() +{ +} + +//----------------------------------------------------------------------------- +// LLHandMotion::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLHandMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + return STATUS_SUCCESS; +} + + +//----------------------------------------------------------------------------- +// LLHandMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLHandMotion::onActivate() +{ + LLPolyMesh *upperBodyMesh = mCharacter->getUpperBodyMesh(); + + if (upperBodyMesh) + { + // Note: 0 is the default + for (S32 i = 1; i < LLHandMotion::NUM_HAND_POSES; i++) + { + mCharacter->setVisualParamWeight(gHandPoseNames[i], 0.f); + } + mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f); + mCharacter->updateVisualParams(); + } + return true; +} + + +//----------------------------------------------------------------------------- +// LLHandMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLHandMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + eHandPose *requestedHandPose; + + F32 timeDelta = time - mLastTime; + mLastTime = time; + + requestedHandPose = (eHandPose *)mCharacter->getAnimationData("Hand Pose"); + // check to see if requested pose has changed + if (!requestedHandPose) + { + if (mNewPose != HAND_POSE_RELAXED && mNewPose != mCurrentPose) + { + // Only set param weight for poses other than + // default (HAND_POSE_SPREAD); HAND_POSE_SPREAD + // is not an animatable morph! + if (mNewPose != HAND_POSE_SPREAD) + { + mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f); + } + + // Reset morph weight for current pose back to its + // full extend or it might be stuck somewhere in the middle if a + // pose is requested and the old pose is requested again shortly + // after while still blending to the other pose! + if (mCurrentPose != HAND_POSE_SPREAD) + { + mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f); + } + + // Update visual params now if we won't blend + if (mCurrentPose == HAND_POSE_RELAXED) + { + mCharacter->updateVisualParams(); + } + } + mNewPose = HAND_POSE_RELAXED; + } + else + { + // Sometimes we seem to get garbage here, with poses that are out of bounds. + // So check for a valid pose first. + if (*requestedHandPose >= 0 && *requestedHandPose < NUM_HAND_POSES) + { + // This is a new morph we didn't know about before: + // Reset morph weight for both current and new pose + // back their starting values while still blending. + if (*requestedHandPose != mNewPose && mNewPose != mCurrentPose) + { + if (mNewPose != HAND_POSE_SPREAD) + { + mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f); + } + + // Reset morph weight for current pose back to its full extend + // or it might be stuck somewhere in the middle if a pose is + // requested and the old pose is requested again shortly after + // while still blending to the other pose! + if (mCurrentPose != HAND_POSE_SPREAD) + { + mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f); + } + + // Update visual params now if we won't blend + if (mCurrentPose == *requestedHandPose) + { + mCharacter->updateVisualParams(); + } + } + mNewPose = *requestedHandPose; + } + else + { + LL_WARNS() << "Requested hand pose out of range. Ignoring requested pose." << LL_ENDL; + } + } + + mCharacter->removeAnimationData("Hand Pose"); + mCharacter->removeAnimationData("Hand Pose Priority"); + +// if (requestedHandPose) +// LL_INFOS() << "Hand Pose " << *requestedHandPose << LL_ENDL; + + // if we are still blending... + if (mCurrentPose != mNewPose) + { + F32 incomingWeight = 1.f; + F32 outgoingWeight = 0.f; + + if (mNewPose != HAND_POSE_SPREAD) + { + incomingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mNewPose]); + incomingWeight += (timeDelta / HAND_MORPH_BLEND_TIME); + incomingWeight = llclamp(incomingWeight, 0.f, 1.f); + mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], incomingWeight); + } + + if (mCurrentPose != HAND_POSE_SPREAD) + { + outgoingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mCurrentPose]); + outgoingWeight -= (timeDelta / HAND_MORPH_BLEND_TIME); + outgoingWeight = llclamp(outgoingWeight, 0.f, 1.f); + mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], outgoingWeight); + } + + mCharacter->updateVisualParams(); + + if (incomingWeight == 1.f && outgoingWeight == 0.f) + { + mCurrentPose = mNewPose; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// LLHandMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLHandMotion::onDeactivate() +{ +} + +//----------------------------------------------------------------------------- +// LLHandMotion::getHandPoseName() +//----------------------------------------------------------------------------- +std::string LLHandMotion::getHandPoseName(eHandPose pose) +{ + if ((S32)pose < LLHandMotion::NUM_HAND_POSES && (S32)pose >= 0) + { + return std::string(gHandPoseNames[pose]); + } + return LLStringUtil::null; +} + +LLHandMotion::eHandPose LLHandMotion::getHandPose(std::string posename) +{ + for (S32 pose = 0; pose < LLHandMotion::NUM_HAND_POSES; ++pose) + { + if (gHandPoseNames[pose] == posename) + { + return (eHandPose)pose; + } + } + return (eHandPose)0; +} + +// End diff --git a/indra/llcharacter/llhandmotion.h b/indra/llcharacter/llhandmotion.h index 7f1b65d48b..42f3411148 100644 --- a/indra/llcharacter/llhandmotion.h +++ b/indra/llcharacter/llhandmotion.h @@ -1,139 +1,139 @@ -/**
- * @file llhandmotion.h
- * @brief Implementation of LLHandMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLHANDMOTION_H
-#define LL_LLHANDMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llmotion.h"
-#include "lltimer.h"
-
-#define MIN_REQUIRED_PIXEL_AREA_HAND 10000.f;
-
-//-----------------------------------------------------------------------------
-// class LLHandMotion
-//-----------------------------------------------------------------------------
-class LLHandMotion :
- public LLMotion
-{
-public:
- typedef enum e_hand_pose
- {
- HAND_POSE_SPREAD,
- HAND_POSE_RELAXED,
- HAND_POSE_POINT,
- HAND_POSE_FIST,
- HAND_POSE_RELAXED_L,
- HAND_POSE_POINT_L,
- HAND_POSE_FIST_L,
- HAND_POSE_RELAXED_R,
- HAND_POSE_POINT_R,
- HAND_POSE_FIST_R,
- HAND_POSE_SALUTE_R,
- HAND_POSE_TYPING,
- HAND_POSE_PEACE_R,
- HAND_POSE_PALM_R,
- NUM_HAND_POSES
- } eHandPose;
-
- // Constructor
- LLHandMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLHandMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() { return true; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return 0.0; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return 0.0; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_HAND; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
- virtual bool canDeprecate() { return false; }
-
- static std::string getHandPoseName(eHandPose pose);
- static eHandPose getHandPose(std::string posename);
-
-public:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
-
- LLCharacter *mCharacter;
-
- F32 mLastTime;
- eHandPose mCurrentPose;
- eHandPose mNewPose;
-};
-#endif // LL_LLHANDMOTION_H
-
+/** + * @file llhandmotion.h + * @brief Implementation of LLHandMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLHANDMOTION_H +#define LL_LLHANDMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" +#include "lltimer.h" + +#define MIN_REQUIRED_PIXEL_AREA_HAND 10000.f; + +//----------------------------------------------------------------------------- +// class LLHandMotion +//----------------------------------------------------------------------------- +class LLHandMotion : + public LLMotion +{ +public: + typedef enum e_hand_pose + { + HAND_POSE_SPREAD, + HAND_POSE_RELAXED, + HAND_POSE_POINT, + HAND_POSE_FIST, + HAND_POSE_RELAXED_L, + HAND_POSE_POINT_L, + HAND_POSE_FIST_L, + HAND_POSE_RELAXED_R, + HAND_POSE_POINT_R, + HAND_POSE_FIST_R, + HAND_POSE_SALUTE_R, + HAND_POSE_TYPING, + HAND_POSE_PEACE_R, + HAND_POSE_PALM_R, + NUM_HAND_POSES + } eHandPose; + + // Constructor + LLHandMotion(const LLUUID &id); + + // Destructor + virtual ~LLHandMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { return true; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return 0.0; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return 0.0; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_HAND; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + + virtual bool canDeprecate() { return false; } + + static std::string getHandPoseName(eHandPose pose); + static eHandPose getHandPose(std::string posename); + +public: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + + LLCharacter *mCharacter; + + F32 mLastTime; + eHandPose mCurrentPose; + eHandPose mNewPose; +}; +#endif // LL_LLHANDMOTION_H + diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 989c47b847..6169647423 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -1,575 +1,575 @@ -/**
- * @file llheadrotmotion.cpp
- * @brief Implementation of LLHeadRotMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llheadrotmotion.h"
-#include "llcharacter.h"
-#include "llrand.h"
-#include "m3math.h"
-#include "v3dmath.h"
-#include "llcriticaldamp.h"
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-const F32 TORSO_LAG = 0.35f; // torso rotation factor
-const F32 NECK_LAG = 0.5f; // neck rotation factor
-const F32 HEAD_LOOKAT_LAG_HALF_LIFE = 0.15f; // half-life of lookat targeting for head
-const F32 TORSO_LOOKAT_LAG_HALF_LIFE = 0.27f; // half-life of lookat targeting for torso
-const F32 HEAD_ROTATION_CONSTRAINT = F_PI_BY_TWO * 0.8f; // limit angle for head rotation
-const F32 MIN_HEAD_LOOKAT_DISTANCE = 0.3f; // minimum distance from head before we turn to look at it
-const F32 EYE_JITTER_MIN_TIME = 0.3f; // min amount of time between eye "jitter" motions
-const F32 EYE_JITTER_MAX_TIME = 2.5f; // max amount of time between eye "jitter" motions
-const F32 EYE_JITTER_MAX_YAW = 0.08f; // max yaw of eye jitter motion
-const F32 EYE_JITTER_MAX_PITCH = 0.015f; // max pitch of eye jitter motion
-const F32 EYE_LOOK_AWAY_MIN_TIME = 5.f; // min amount of time between eye "look away" motions
-const F32 EYE_LOOK_AWAY_MAX_TIME = 15.f; // max amount of time between eye "look away" motions
-const F32 EYE_LOOK_BACK_MIN_TIME = 1.f; // min amount of time before looking back after looking away
-const F32 EYE_LOOK_BACK_MAX_TIME = 5.f; // max amount of time before looking back after looking away
-const F32 EYE_LOOK_AWAY_MAX_YAW = 0.15f; // max yaw of eye look away motion
-const F32 EYE_LOOK_AWAY_MAX_PITCH = 0.12f; // max pitch of look away motion
-const F32 EYE_ROT_LIMIT_ANGLE = F_PI_BY_TWO * 0.3f; //max angle in radians for eye rotation
-
-const F32 EYE_BLINK_MIN_TIME = 0.5f; // minimum amount of time between blinks
-const F32 EYE_BLINK_MAX_TIME = 8.f; // maximum amount of time between blinks
-const F32 EYE_BLINK_CLOSE_TIME = 0.03f; // how long the eye stays closed in a blink
-const F32 EYE_BLINK_SPEED = 0.015f; // seconds it takes for a eye open/close movement
-const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blink and the other following
-
-//-----------------------------------------------------------------------------
-// LLHeadRotMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) :
- LLMotion(id),
- mCharacter(NULL),
- mTorsoJoint(NULL),
- mHeadJoint(NULL)
-{
- mName = "head_rot";
-
- mTorsoState = new LLJointState;
- mNeckState = new LLJointState;
- mHeadState = new LLJointState;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLHeadRotMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLHeadRotMotion::~LLHeadRotMotion()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLHeadRotMotion::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character)
-{
- if (!character)
- return STATUS_FAILURE;
- mCharacter = character;
-
- mPelvisJoint = character->getJoint("mPelvis");
- if ( ! mPelvisJoint )
- {
- LL_INFOS() << getName() << ": Can't get pelvis joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mRootJoint = character->getJoint("mRoot");
- if ( ! mRootJoint )
- {
- LL_INFOS() << getName() << ": Can't get root joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mTorsoJoint = character->getJoint("mTorso");
- if ( ! mTorsoJoint )
- {
- LL_INFOS() << getName() << ": Can't get torso joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mHeadJoint = character->getJoint("mHead");
- if ( ! mHeadJoint )
- {
- LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mTorsoState->setJoint( character->getJoint("mTorso") );
- if ( ! mTorsoState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get torso joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mNeckState->setJoint( character->getJoint("mNeck") );
- if ( ! mNeckState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get neck joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mHeadState->setJoint( character->getJoint("mHead") );
- if ( ! mHeadState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mTorsoState->setUsage(LLJointState::ROT);
- mNeckState->setUsage(LLJointState::ROT);
- mHeadState->setUsage(LLJointState::ROT);
-
- addJointState( mTorsoState );
- addJointState( mNeckState );
- addJointState( mHeadState );
-
- mLastHeadRot.loadIdentity();
-
- return STATUS_SUCCESS;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLHeadRotMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLHeadRotMotion::onActivate()
-{
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLHeadRotMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- LLQuaternion targetHeadRotWorld;
- LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation();
- LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld;
-
- F32 head_slerp_amt = LLSmoothInterpolation::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE);
- F32 torso_slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE);
-
- LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
-
- if (targetPos)
- {
- LLVector3 headLookAt = *targetPos;
-
-// LL_INFOS() << "Look At: " << headLookAt + mHeadJoint->getWorldPosition() << LL_ENDL;
-
- F32 lookatDistance = headLookAt.normVec();
-
- if (lookatDistance < MIN_HEAD_LOOKAT_DISTANCE)
- {
- targetHeadRotWorld = mPelvisJoint->getWorldRotation();
- }
- else
- {
- LLVector3 root_up = LLVector3(0.f, 0.f, 1.f) * currentRootRotWorld;
- LLVector3 left(root_up % headLookAt);
- // if look_at has zero length, fail
- // if look_at and skyward are parallel, fail
- //
- // Test both of these conditions with a cross product.
-
- if (left.magVecSquared() < 0.15f)
- {
- LLVector3 root_at = LLVector3(1.f, 0.f, 0.f) * currentRootRotWorld;
- root_at.mV[VZ] = 0.f;
- root_at.normVec();
-
- headLookAt = lerp(headLookAt, root_at, 0.4f);
- headLookAt.normVec();
-
- left = root_up % headLookAt;
- }
-
- // Make sure look_at and skyward and not parallel
- // and neither are zero length
- LLVector3 up(headLookAt % left);
-
- targetHeadRotWorld = LLQuaternion(headLookAt, left, up);
- }
- }
- else
- {
- targetHeadRotWorld = currentRootRotWorld;
- }
-
- LLQuaternion head_rot_local = targetHeadRotWorld * currentInvRootRotWorld;
- head_rot_local.constrain(HEAD_ROTATION_CONSTRAINT);
-
- // set final torso rotation
- // Set torso target rotation such that it lags behind the head rotation
- // by a fixed amount.
- LLQuaternion torso_rot_local = nlerp(TORSO_LAG, LLQuaternion::DEFAULT, head_rot_local );
- mTorsoState->setRotation( nlerp(torso_slerp_amt, mTorsoState->getRotation(), torso_rot_local) );
-
- head_rot_local = nlerp(head_slerp_amt, mLastHeadRot, head_rot_local);
- mLastHeadRot = head_rot_local;
-
- // Set the head rotation.
- if(mNeckState->getJoint() && mNeckState->getJoint()->getParent())
- {
- LLQuaternion torsoRotLocal = mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
- head_rot_local = head_rot_local * ~torsoRotLocal;
- mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
- mHeadState->setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local));
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLHeadRotMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLHeadRotMotion::onDeactivate()
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// LLEyeMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id)
-{
- mCharacter = NULL;
- mEyeJitterTime = 0.f;
- mEyeJitterYaw = 0.f;
- mEyeJitterPitch = 0.f;
-
- mEyeLookAwayTime = 0.f;
- mEyeLookAwayYaw = 0.f;
- mEyeLookAwayPitch = 0.f;
-
- mEyeBlinkTime = 0.f;
- mEyesClosed = false;
-
- mHeadJoint = NULL;
-
- mName = "eye_rot";
-
- mLeftEyeState = new LLJointState;
- mAltLeftEyeState = new LLJointState;
-
- mRightEyeState = new LLJointState;
- mAltRightEyeState = new LLJointState;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLEyeMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLEyeMotion::~LLEyeMotion()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLEyeMotion::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- mHeadJoint = character->getJoint("mHead");
- if ( ! mHeadJoint )
- {
- LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mLeftEyeState->setJoint( character->getJoint("mEyeLeft") );
- if ( ! mLeftEyeState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get left eyeball joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mAltLeftEyeState->setJoint( character->getJoint("mFaceEyeAltLeft") );
- if ( ! mAltLeftEyeState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get alt left eyeball joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mRightEyeState->setJoint( character->getJoint("mEyeRight") );
- if ( ! mRightEyeState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get right eyeball joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mAltRightEyeState->setJoint( character->getJoint("mFaceEyeAltRight") );
- if ( ! mAltRightEyeState->getJoint() )
- {
- LL_INFOS() << getName() << ": Can't get alt right eyeball joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mLeftEyeState->setUsage(LLJointState::ROT);
- mAltLeftEyeState->setUsage(LLJointState::ROT);
-
- mRightEyeState->setUsage(LLJointState::ROT);
- mAltRightEyeState->setUsage(LLJointState::ROT);
-
- addJointState( mLeftEyeState );
- addJointState( mAltLeftEyeState );
-
- addJointState( mRightEyeState );
- addJointState( mAltRightEyeState );
-
- return STATUS_SUCCESS;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLEyeMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLEyeMotion::onActivate()
-{
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLEyeMotion::adjustEyeTarget()
-//-----------------------------------------------------------------------------
-void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state)
-{
- // Compute eye rotation.
- bool has_eye_target = false;
- LLQuaternion target_eye_rot;
- LLVector3 eye_look_at;
- F32 vergence;
-
- if (targetPos)
- {
- LLVector3 skyward(0.f, 0.f, 1.f);
- LLVector3 left;
- LLVector3 up;
-
- eye_look_at = *targetPos;
- has_eye_target = true;
- F32 lookAtDistance = eye_look_at.normVec();
-
- left.setVec(skyward % eye_look_at);
- up.setVec(eye_look_at % left);
-
- target_eye_rot = LLQuaternion(eye_look_at, left, up);
- // convert target rotation to head-local coordinates
- target_eye_rot *= ~mHeadJoint->getWorldRotation();
- // eliminate any Euler roll - we're lucky that roll is applied last.
- F32 roll, pitch, yaw;
- target_eye_rot.getEulerAngles(&roll, &pitch, &yaw);
- target_eye_rot.setQuat(0.0f, pitch, yaw);
- // constrain target orientation to be in front of avatar's face
- target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE);
-
- // calculate vergence
- F32 interocular_dist = (left_eye_state.getJoint()->getWorldPosition() - right_eye_state.getJoint()->getWorldPosition()).magVec();
- vergence = -atan2((interocular_dist / 2.f), lookAtDistance);
- llclamp(vergence, -F_PI_BY_TWO, 0.f);
- }
- else
- {
- target_eye_rot = LLQuaternion::DEFAULT;
- vergence = 0.f;
- }
-
- //RN: subtract 4 degrees to account for foveal angular offset relative to pupil
- vergence += 4.f * DEG_TO_RAD;
-
- // calculate eye jitter
- LLQuaternion eye_jitter_rot;
-
- // vergence not too high...
- if (vergence > -0.05f)
- {
- //...go ahead and jitter
- eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw);
- }
- else
- {
- //...or don't
- eye_jitter_rot.loadIdentity();
- }
-
- // calculate vergence of eyes as an object gets closer to the avatar's head
- LLQuaternion vergence_quat;
-
- if (has_eye_target)
- {
- vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f));
- }
- else
- {
- vergence_quat.loadIdentity();
- }
-
- // calculate eye rotations
- LLQuaternion left_eye_rot = target_eye_rot;
- left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot;
-
- LLQuaternion right_eye_rot = target_eye_rot;
- vergence_quat.transQuat();
- right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot;
-
- left_eye_state.setRotation( left_eye_rot );
- right_eye_state.setRotation( right_eye_rot );
-}
-
-//-----------------------------------------------------------------------------
-// LLEyeMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- //calculate jitter
- if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
- {
- mEyeJitterTime = EYE_JITTER_MIN_TIME + ll_frand(EYE_JITTER_MAX_TIME - EYE_JITTER_MIN_TIME);
- mEyeJitterYaw = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_YAW;
- mEyeJitterPitch = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_PITCH;
- // make sure lookaway time count gets updated, because we're resetting the timer
- mEyeLookAwayTime -= llmax(0.f, mEyeJitterTimer.getElapsedTimeF32());
- mEyeJitterTimer.reset();
- }
- else if (mEyeJitterTimer.getElapsedTimeF32() > mEyeLookAwayTime)
- {
- if (ll_frand() > 0.1f)
- {
- // blink while moving eyes some percentage of the time
- mEyeBlinkTime = mEyeBlinkTimer.getElapsedTimeF32();
- }
- if (mEyeLookAwayYaw == 0.f && mEyeLookAwayPitch == 0.f)
- {
- mEyeLookAwayYaw = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_YAW;
- mEyeLookAwayPitch = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_PITCH;
- mEyeLookAwayTime = EYE_LOOK_BACK_MIN_TIME + ll_frand(EYE_LOOK_BACK_MAX_TIME - EYE_LOOK_BACK_MIN_TIME);
- }
- else
- {
- mEyeLookAwayYaw = 0.f;
- mEyeLookAwayPitch = 0.f;
- mEyeLookAwayTime = EYE_LOOK_AWAY_MIN_TIME + ll_frand(EYE_LOOK_AWAY_MAX_TIME - EYE_LOOK_AWAY_MIN_TIME);
- }
- }
-
- // do blinking
- if (!mEyesClosed && mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime)
- {
- F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime;
- F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA;
-
- leftEyeBlinkMorph = llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
- rightEyeBlinkMorph = llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
- mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph);
- mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph);
- mCharacter->updateVisualParams();
-
- if (rightEyeBlinkMorph == 1.f)
- {
- mEyesClosed = true;
- mEyeBlinkTime = EYE_BLINK_CLOSE_TIME;
- mEyeBlinkTimer.reset();
- }
- }
- else if (mEyesClosed)
- {
- if (mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime)
- {
- F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime;
- F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA;
-
- leftEyeBlinkMorph = 1.f - llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
- rightEyeBlinkMorph = 1.f - llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
- mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph);
- mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph);
- mCharacter->updateVisualParams();
-
- if (rightEyeBlinkMorph == 0.f)
- {
- mEyesClosed = false;
- mEyeBlinkTime = EYE_BLINK_MIN_TIME + ll_frand(EYE_BLINK_MAX_TIME - EYE_BLINK_MIN_TIME);
- mEyeBlinkTimer.reset();
- }
- }
- }
-
- LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
-
- adjustEyeTarget(targetPos, *mLeftEyeState, *mRightEyeState);
- adjustEyeTarget(targetPos, *mAltLeftEyeState, *mAltRightEyeState);
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLEyeMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLEyeMotion::onDeactivate()
-{
- LLJoint* joint = mLeftEyeState->getJoint();
- if (joint)
- {
- joint->setRotation(LLQuaternion::DEFAULT);
- }
-
- joint = mAltLeftEyeState->getJoint();
- if (joint)
- {
- joint->setRotation(LLQuaternion::DEFAULT);
- }
-
- joint = mRightEyeState->getJoint();
- if (joint)
- {
- joint->setRotation(LLQuaternion::DEFAULT);
- }
-
- joint = mAltRightEyeState->getJoint();
- if (joint)
- {
- joint->setRotation(LLQuaternion::DEFAULT);
- }
-}
-
-// End
-
+/** + * @file llheadrotmotion.cpp + * @brief Implementation of LLHeadRotMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llheadrotmotion.h" +#include "llcharacter.h" +#include "llrand.h" +#include "m3math.h" +#include "v3dmath.h" +#include "llcriticaldamp.h" + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- +const F32 TORSO_LAG = 0.35f; // torso rotation factor +const F32 NECK_LAG = 0.5f; // neck rotation factor +const F32 HEAD_LOOKAT_LAG_HALF_LIFE = 0.15f; // half-life of lookat targeting for head +const F32 TORSO_LOOKAT_LAG_HALF_LIFE = 0.27f; // half-life of lookat targeting for torso +const F32 HEAD_ROTATION_CONSTRAINT = F_PI_BY_TWO * 0.8f; // limit angle for head rotation +const F32 MIN_HEAD_LOOKAT_DISTANCE = 0.3f; // minimum distance from head before we turn to look at it +const F32 EYE_JITTER_MIN_TIME = 0.3f; // min amount of time between eye "jitter" motions +const F32 EYE_JITTER_MAX_TIME = 2.5f; // max amount of time between eye "jitter" motions +const F32 EYE_JITTER_MAX_YAW = 0.08f; // max yaw of eye jitter motion +const F32 EYE_JITTER_MAX_PITCH = 0.015f; // max pitch of eye jitter motion +const F32 EYE_LOOK_AWAY_MIN_TIME = 5.f; // min amount of time between eye "look away" motions +const F32 EYE_LOOK_AWAY_MAX_TIME = 15.f; // max amount of time between eye "look away" motions +const F32 EYE_LOOK_BACK_MIN_TIME = 1.f; // min amount of time before looking back after looking away +const F32 EYE_LOOK_BACK_MAX_TIME = 5.f; // max amount of time before looking back after looking away +const F32 EYE_LOOK_AWAY_MAX_YAW = 0.15f; // max yaw of eye look away motion +const F32 EYE_LOOK_AWAY_MAX_PITCH = 0.12f; // max pitch of look away motion +const F32 EYE_ROT_LIMIT_ANGLE = F_PI_BY_TWO * 0.3f; //max angle in radians for eye rotation + +const F32 EYE_BLINK_MIN_TIME = 0.5f; // minimum amount of time between blinks +const F32 EYE_BLINK_MAX_TIME = 8.f; // maximum amount of time between blinks +const F32 EYE_BLINK_CLOSE_TIME = 0.03f; // how long the eye stays closed in a blink +const F32 EYE_BLINK_SPEED = 0.015f; // seconds it takes for a eye open/close movement +const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blink and the other following + +//----------------------------------------------------------------------------- +// LLHeadRotMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) : + LLMotion(id), + mCharacter(NULL), + mTorsoJoint(NULL), + mHeadJoint(NULL) +{ + mName = "head_rot"; + + mTorsoState = new LLJointState; + mNeckState = new LLJointState; + mHeadState = new LLJointState; +} + + +//----------------------------------------------------------------------------- +// ~LLHeadRotMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLHeadRotMotion::~LLHeadRotMotion() +{ +} + +//----------------------------------------------------------------------------- +// LLHeadRotMotion::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character) +{ + if (!character) + return STATUS_FAILURE; + mCharacter = character; + + mPelvisJoint = character->getJoint("mPelvis"); + if ( ! mPelvisJoint ) + { + LL_INFOS() << getName() << ": Can't get pelvis joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mRootJoint = character->getJoint("mRoot"); + if ( ! mRootJoint ) + { + LL_INFOS() << getName() << ": Can't get root joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mTorsoJoint = character->getJoint("mTorso"); + if ( ! mTorsoJoint ) + { + LL_INFOS() << getName() << ": Can't get torso joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mHeadJoint = character->getJoint("mHead"); + if ( ! mHeadJoint ) + { + LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mTorsoState->setJoint( character->getJoint("mTorso") ); + if ( ! mTorsoState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get torso joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mNeckState->setJoint( character->getJoint("mNeck") ); + if ( ! mNeckState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get neck joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mHeadState->setJoint( character->getJoint("mHead") ); + if ( ! mHeadState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mTorsoState->setUsage(LLJointState::ROT); + mNeckState->setUsage(LLJointState::ROT); + mHeadState->setUsage(LLJointState::ROT); + + addJointState( mTorsoState ); + addJointState( mNeckState ); + addJointState( mHeadState ); + + mLastHeadRot.loadIdentity(); + + return STATUS_SUCCESS; +} + + +//----------------------------------------------------------------------------- +// LLHeadRotMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLHeadRotMotion::onActivate() +{ + return true; +} + + +//----------------------------------------------------------------------------- +// LLHeadRotMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + LLQuaternion targetHeadRotWorld; + LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation(); + LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld; + + F32 head_slerp_amt = LLSmoothInterpolation::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE); + F32 torso_slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE); + + LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); + + if (targetPos) + { + LLVector3 headLookAt = *targetPos; + +// LL_INFOS() << "Look At: " << headLookAt + mHeadJoint->getWorldPosition() << LL_ENDL; + + F32 lookatDistance = headLookAt.normVec(); + + if (lookatDistance < MIN_HEAD_LOOKAT_DISTANCE) + { + targetHeadRotWorld = mPelvisJoint->getWorldRotation(); + } + else + { + LLVector3 root_up = LLVector3(0.f, 0.f, 1.f) * currentRootRotWorld; + LLVector3 left(root_up % headLookAt); + // if look_at has zero length, fail + // if look_at and skyward are parallel, fail + // + // Test both of these conditions with a cross product. + + if (left.magVecSquared() < 0.15f) + { + LLVector3 root_at = LLVector3(1.f, 0.f, 0.f) * currentRootRotWorld; + root_at.mV[VZ] = 0.f; + root_at.normVec(); + + headLookAt = lerp(headLookAt, root_at, 0.4f); + headLookAt.normVec(); + + left = root_up % headLookAt; + } + + // Make sure look_at and skyward and not parallel + // and neither are zero length + LLVector3 up(headLookAt % left); + + targetHeadRotWorld = LLQuaternion(headLookAt, left, up); + } + } + else + { + targetHeadRotWorld = currentRootRotWorld; + } + + LLQuaternion head_rot_local = targetHeadRotWorld * currentInvRootRotWorld; + head_rot_local.constrain(HEAD_ROTATION_CONSTRAINT); + + // set final torso rotation + // Set torso target rotation such that it lags behind the head rotation + // by a fixed amount. + LLQuaternion torso_rot_local = nlerp(TORSO_LAG, LLQuaternion::DEFAULT, head_rot_local ); + mTorsoState->setRotation( nlerp(torso_slerp_amt, mTorsoState->getRotation(), torso_rot_local) ); + + head_rot_local = nlerp(head_slerp_amt, mLastHeadRot, head_rot_local); + mLastHeadRot = head_rot_local; + + // Set the head rotation. + if(mNeckState->getJoint() && mNeckState->getJoint()->getParent()) + { + LLQuaternion torsoRotLocal = mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld; + head_rot_local = head_rot_local * ~torsoRotLocal; + mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) ); + mHeadState->setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local)); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// LLHeadRotMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLHeadRotMotion::onDeactivate() +{ +} + + +//----------------------------------------------------------------------------- +// LLEyeMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id) +{ + mCharacter = NULL; + mEyeJitterTime = 0.f; + mEyeJitterYaw = 0.f; + mEyeJitterPitch = 0.f; + + mEyeLookAwayTime = 0.f; + mEyeLookAwayYaw = 0.f; + mEyeLookAwayPitch = 0.f; + + mEyeBlinkTime = 0.f; + mEyesClosed = false; + + mHeadJoint = NULL; + + mName = "eye_rot"; + + mLeftEyeState = new LLJointState; + mAltLeftEyeState = new LLJointState; + + mRightEyeState = new LLJointState; + mAltRightEyeState = new LLJointState; +} + + +//----------------------------------------------------------------------------- +// ~LLEyeMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLEyeMotion::~LLEyeMotion() +{ +} + +//----------------------------------------------------------------------------- +// LLEyeMotion::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + mHeadJoint = character->getJoint("mHead"); + if ( ! mHeadJoint ) + { + LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mLeftEyeState->setJoint( character->getJoint("mEyeLeft") ); + if ( ! mLeftEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get left eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mAltLeftEyeState->setJoint( character->getJoint("mFaceEyeAltLeft") ); + if ( ! mAltLeftEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get alt left eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mRightEyeState->setJoint( character->getJoint("mEyeRight") ); + if ( ! mRightEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get right eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mAltRightEyeState->setJoint( character->getJoint("mFaceEyeAltRight") ); + if ( ! mAltRightEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get alt right eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mLeftEyeState->setUsage(LLJointState::ROT); + mAltLeftEyeState->setUsage(LLJointState::ROT); + + mRightEyeState->setUsage(LLJointState::ROT); + mAltRightEyeState->setUsage(LLJointState::ROT); + + addJointState( mLeftEyeState ); + addJointState( mAltLeftEyeState ); + + addJointState( mRightEyeState ); + addJointState( mAltRightEyeState ); + + return STATUS_SUCCESS; +} + + +//----------------------------------------------------------------------------- +// LLEyeMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLEyeMotion::onActivate() +{ + return true; +} + +//----------------------------------------------------------------------------- +// LLEyeMotion::adjustEyeTarget() +//----------------------------------------------------------------------------- +void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state) +{ + // Compute eye rotation. + bool has_eye_target = false; + LLQuaternion target_eye_rot; + LLVector3 eye_look_at; + F32 vergence; + + if (targetPos) + { + LLVector3 skyward(0.f, 0.f, 1.f); + LLVector3 left; + LLVector3 up; + + eye_look_at = *targetPos; + has_eye_target = true; + F32 lookAtDistance = eye_look_at.normVec(); + + left.setVec(skyward % eye_look_at); + up.setVec(eye_look_at % left); + + target_eye_rot = LLQuaternion(eye_look_at, left, up); + // convert target rotation to head-local coordinates + target_eye_rot *= ~mHeadJoint->getWorldRotation(); + // eliminate any Euler roll - we're lucky that roll is applied last. + F32 roll, pitch, yaw; + target_eye_rot.getEulerAngles(&roll, &pitch, &yaw); + target_eye_rot.setQuat(0.0f, pitch, yaw); + // constrain target orientation to be in front of avatar's face + target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE); + + // calculate vergence + F32 interocular_dist = (left_eye_state.getJoint()->getWorldPosition() - right_eye_state.getJoint()->getWorldPosition()).magVec(); + vergence = -atan2((interocular_dist / 2.f), lookAtDistance); + llclamp(vergence, -F_PI_BY_TWO, 0.f); + } + else + { + target_eye_rot = LLQuaternion::DEFAULT; + vergence = 0.f; + } + + //RN: subtract 4 degrees to account for foveal angular offset relative to pupil + vergence += 4.f * DEG_TO_RAD; + + // calculate eye jitter + LLQuaternion eye_jitter_rot; + + // vergence not too high... + if (vergence > -0.05f) + { + //...go ahead and jitter + eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); + } + else + { + //...or don't + eye_jitter_rot.loadIdentity(); + } + + // calculate vergence of eyes as an object gets closer to the avatar's head + LLQuaternion vergence_quat; + + if (has_eye_target) + { + vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); + } + else + { + vergence_quat.loadIdentity(); + } + + // calculate eye rotations + LLQuaternion left_eye_rot = target_eye_rot; + left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; + + LLQuaternion right_eye_rot = target_eye_rot; + vergence_quat.transQuat(); + right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; + + left_eye_state.setRotation( left_eye_rot ); + right_eye_state.setRotation( right_eye_rot ); +} + +//----------------------------------------------------------------------------- +// LLEyeMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLEyeMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + //calculate jitter + if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime) + { + mEyeJitterTime = EYE_JITTER_MIN_TIME + ll_frand(EYE_JITTER_MAX_TIME - EYE_JITTER_MIN_TIME); + mEyeJitterYaw = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_YAW; + mEyeJitterPitch = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_PITCH; + // make sure lookaway time count gets updated, because we're resetting the timer + mEyeLookAwayTime -= llmax(0.f, mEyeJitterTimer.getElapsedTimeF32()); + mEyeJitterTimer.reset(); + } + else if (mEyeJitterTimer.getElapsedTimeF32() > mEyeLookAwayTime) + { + if (ll_frand() > 0.1f) + { + // blink while moving eyes some percentage of the time + mEyeBlinkTime = mEyeBlinkTimer.getElapsedTimeF32(); + } + if (mEyeLookAwayYaw == 0.f && mEyeLookAwayPitch == 0.f) + { + mEyeLookAwayYaw = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_YAW; + mEyeLookAwayPitch = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_PITCH; + mEyeLookAwayTime = EYE_LOOK_BACK_MIN_TIME + ll_frand(EYE_LOOK_BACK_MAX_TIME - EYE_LOOK_BACK_MIN_TIME); + } + else + { + mEyeLookAwayYaw = 0.f; + mEyeLookAwayPitch = 0.f; + mEyeLookAwayTime = EYE_LOOK_AWAY_MIN_TIME + ll_frand(EYE_LOOK_AWAY_MAX_TIME - EYE_LOOK_AWAY_MIN_TIME); + } + } + + // do blinking + if (!mEyesClosed && mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime) + { + F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime; + F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA; + + leftEyeBlinkMorph = llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); + rightEyeBlinkMorph = llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); + mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph); + mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph); + mCharacter->updateVisualParams(); + + if (rightEyeBlinkMorph == 1.f) + { + mEyesClosed = true; + mEyeBlinkTime = EYE_BLINK_CLOSE_TIME; + mEyeBlinkTimer.reset(); + } + } + else if (mEyesClosed) + { + if (mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime) + { + F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime; + F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA; + + leftEyeBlinkMorph = 1.f - llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); + rightEyeBlinkMorph = 1.f - llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); + mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph); + mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph); + mCharacter->updateVisualParams(); + + if (rightEyeBlinkMorph == 0.f) + { + mEyesClosed = false; + mEyeBlinkTime = EYE_BLINK_MIN_TIME + ll_frand(EYE_BLINK_MAX_TIME - EYE_BLINK_MIN_TIME); + mEyeBlinkTimer.reset(); + } + } + } + + LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); + + adjustEyeTarget(targetPos, *mLeftEyeState, *mRightEyeState); + adjustEyeTarget(targetPos, *mAltLeftEyeState, *mAltRightEyeState); + + return true; +} + + +//----------------------------------------------------------------------------- +// LLEyeMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLEyeMotion::onDeactivate() +{ + LLJoint* joint = mLeftEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } + + joint = mAltLeftEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } + + joint = mRightEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } + + joint = mAltRightEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } +} + +// End + diff --git a/indra/llcharacter/llheadrotmotion.h b/indra/llcharacter/llheadrotmotion.h index 602bcb96ad..50de4ffa26 100644 --- a/indra/llcharacter/llheadrotmotion.h +++ b/indra/llcharacter/llheadrotmotion.h @@ -1,216 +1,216 @@ -/**
- * @file llheadrotmotion.h
- * @brief Implementation of LLHeadRotMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLHEADROTMOTION_H
-#define LL_LLHEADROTMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llmotion.h"
-#include "llframetimer.h"
-
-#define MIN_REQUIRED_PIXEL_AREA_HEAD_ROT 500.f;
-#define MIN_REQUIRED_PIXEL_AREA_EYE 25000.f;
-
-//-----------------------------------------------------------------------------
-// class LLHeadRotMotion
-//-----------------------------------------------------------------------------
-class LLHeadRotMotion :
- public LLMotion
-{
-public:
- // Constructor
- LLHeadRotMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLHeadRotMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() { return true; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return 1.f; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return 1.f; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_HEAD_ROT; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
-public:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
- LLCharacter *mCharacter;
-
- LLJoint *mTorsoJoint;
- LLJoint *mHeadJoint;
- LLJoint *mRootJoint;
- LLJoint *mPelvisJoint;
-
- LLPointer<LLJointState> mTorsoState;
- LLPointer<LLJointState> mNeckState;
- LLPointer<LLJointState> mHeadState;
-
- LLQuaternion mLastHeadRot;
-};
-
-//-----------------------------------------------------------------------------
-// class LLEyeMotion
-//-----------------------------------------------------------------------------
-class LLEyeMotion :
- public LLMotion
-{
-public:
- // Constructor
- LLEyeMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLEyeMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() { return true; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return 0.5f; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return 0.5f; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_EYE; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- void adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state);
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
-public:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
- LLCharacter *mCharacter;
-
- LLJoint *mHeadJoint;
- LLPointer<LLJointState> mLeftEyeState;
- LLPointer<LLJointState> mRightEyeState;
- LLPointer<LLJointState> mAltLeftEyeState;
- LLPointer<LLJointState> mAltRightEyeState;
-
- LLFrameTimer mEyeJitterTimer;
- F32 mEyeJitterTime;
- F32 mEyeJitterYaw;
- F32 mEyeJitterPitch;
- F32 mEyeLookAwayTime;
- F32 mEyeLookAwayYaw;
- F32 mEyeLookAwayPitch;
-
- // eye blinking
- LLFrameTimer mEyeBlinkTimer;
- F32 mEyeBlinkTime;
- bool mEyesClosed;
-};
-
-#endif // LL_LLHEADROTMOTION_H
-
+/** + * @file llheadrotmotion.h + * @brief Implementation of LLHeadRotMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLHEADROTMOTION_H +#define LL_LLHEADROTMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" +#include "llframetimer.h" + +#define MIN_REQUIRED_PIXEL_AREA_HEAD_ROT 500.f; +#define MIN_REQUIRED_PIXEL_AREA_EYE 25000.f; + +//----------------------------------------------------------------------------- +// class LLHeadRotMotion +//----------------------------------------------------------------------------- +class LLHeadRotMotion : + public LLMotion +{ +public: + // Constructor + LLHeadRotMotion(const LLUUID &id); + + // Destructor + virtual ~LLHeadRotMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { return true; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return 1.f; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return 1.f; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_HEAD_ROT; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + +public: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LLCharacter *mCharacter; + + LLJoint *mTorsoJoint; + LLJoint *mHeadJoint; + LLJoint *mRootJoint; + LLJoint *mPelvisJoint; + + LLPointer<LLJointState> mTorsoState; + LLPointer<LLJointState> mNeckState; + LLPointer<LLJointState> mHeadState; + + LLQuaternion mLastHeadRot; +}; + +//----------------------------------------------------------------------------- +// class LLEyeMotion +//----------------------------------------------------------------------------- +class LLEyeMotion : + public LLMotion +{ +public: + // Constructor + LLEyeMotion(const LLUUID &id); + + // Destructor + virtual ~LLEyeMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { return true; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return 0.5f; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return 0.5f; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_EYE; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + void adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state); + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + +public: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LLCharacter *mCharacter; + + LLJoint *mHeadJoint; + LLPointer<LLJointState> mLeftEyeState; + LLPointer<LLJointState> mRightEyeState; + LLPointer<LLJointState> mAltLeftEyeState; + LLPointer<LLJointState> mAltRightEyeState; + + LLFrameTimer mEyeJitterTimer; + F32 mEyeJitterTime; + F32 mEyeJitterYaw; + F32 mEyeJitterPitch; + F32 mEyeLookAwayTime; + F32 mEyeLookAwayYaw; + F32 mEyeLookAwayPitch; + + // eye blinking + LLFrameTimer mEyeBlinkTimer; + F32 mEyeBlinkTime; + bool mEyesClosed; +}; + +#endif // LL_LLHEADROTMOTION_H + diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 888980ac11..34aea19d6c 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -1,1043 +1,1043 @@ -/**
- * @file lljoint.cpp
- * @brief Implementation of LLJoint class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "lljoint.h"
-
-#include "llmath.h"
-#include "llcallstack.h"
-#include <boost/algorithm/string.hpp>
-
-S32 LLJoint::sNumUpdates = 0;
-S32 LLJoint::sNumTouches = 0;
-
-template <class T>
-bool attachment_map_iter_compare_key(const T& a, const T& b)
-{
- return a.first < b.first;
-}
-
-bool LLVector3OverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const
-{
- pos = LLVector3(0,0,0);
- mesh_id = LLUUID();
- bool found = false;
-
- map_type::const_iterator it = std::max_element(m_map.begin(),
- m_map.end(),
- attachment_map_iter_compare_key<map_type::value_type>);
- if (it != m_map.end())
- {
- found = true;
- pos = it->second;
- mesh_id = it->first;
- }
- return found;
-}
-
-void LLVector3OverrideMap::showJointVector3Overrides( std::ostringstream& os ) const
-{
- map_type::const_iterator max_it = std::max_element(m_map.begin(),
- m_map.end(),
- attachment_map_iter_compare_key<map_type::value_type>);
- for (const map_type::value_type& pos_pair : m_map)
- {
- const LLVector3& pos = pos_pair.second;
- os << " " << "[" << pos_pair.first <<": " << pos << "]" << ((pos_pair==(*max_it)) ? "*" : "");
- }
-}
-
-U32 LLVector3OverrideMap::count() const
-{
- return m_map.size();
-}
-
-void LLVector3OverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos)
-{
- m_map[mesh_id] = pos;
-}
-
-bool LLVector3OverrideMap::remove(const LLUUID& mesh_id)
-{
- U32 remove_count = m_map.erase(mesh_id);
- return (remove_count > 0);
-}
-
-void LLVector3OverrideMap::clear()
-{
- m_map.clear();
-}
-
-//-----------------------------------------------------------------------------
-// LLJoint()
-// Class Constructor
-//-----------------------------------------------------------------------------
-
-
-void LLJoint::init()
-{
- mName = "unnamed";
- mParent = NULL;
- mXform.setScaleChildOffset(true);
- mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
- mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;
- mUpdateXform = true;
- mSupport = SUPPORT_BASE;
- mEnd = LLVector3(0.0f, 0.0f, 0.0f);
-}
-
-LLJoint::LLJoint() :
- mJointNum(-1)
-{
- init();
- touch();
-}
-
-LLJoint::LLJoint(S32 joint_num) :
- mJointNum(joint_num)
-{
- init();
- touch();
-}
-
-//-----------------------------------------------------------------------------
-// LLJoint()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLJoint::LLJoint(const std::string &name, LLJoint *parent) :
- mJointNum(-2)
-{
- init();
- mUpdateXform = false;
-
- setName(name);
- if (parent)
- {
- parent->addChild( this );
- }
- touch();
-}
-
-//-----------------------------------------------------------------------------
-// ~LLJoint()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLJoint::~LLJoint()
-{
- if (mParent)
- {
- mParent->removeChild( this );
- }
- removeAllChildren();
-}
-
-
-//-----------------------------------------------------------------------------
-// setup()
-//-----------------------------------------------------------------------------
-void LLJoint::setup(const std::string &name, LLJoint *parent)
-{
- setName(name);
- if (parent)
- {
- parent->addChild( this );
- }
-}
-
-//-----------------------------------------------------------------------------
-// setSupport()
-//-----------------------------------------------------------------------------
-void LLJoint::setSupport(const std::string& support_name)
-{
- if (support_name == "extended")
- {
- setSupport(SUPPORT_EXTENDED);
- }
- else if (support_name == "base")
- {
- setSupport(SUPPORT_BASE);
- }
- else
- {
- LL_WARNS() << "unknown support string " << support_name << LL_ENDL;
- setSupport(SUPPORT_BASE);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// touch()
-// Sets all dirty flags for all children, recursively.
-//-----------------------------------------------------------------------------
-void LLJoint::touch(U32 flags)
-{
- if ((flags | mDirtyFlags) != mDirtyFlags)
- {
- sNumTouches++;
- mDirtyFlags |= flags;
- U32 child_flags = flags;
- if (flags & ROTATION_DIRTY)
- {
- child_flags |= POSITION_DIRTY;
- }
-
- for (LLJoint* joint : mChildren)
- {
- joint->touch(child_flags);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// setJointNum()
-//-----------------------------------------------------------------------------
-void LLJoint::setJointNum(S32 joint_num)
-{
- mJointNum = joint_num;
- if (mJointNum + 2 >= LL_CHARACTER_MAX_ANIMATED_JOINTS)
- {
- LL_INFOS() << "LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be increased" << LL_ENDL;
- LL_ERRS() << "joint_num " << joint_num << " + 2 is too large for " << LL_CHARACTER_MAX_ANIMATED_JOINTS << LL_ENDL;
- }
-}
-//-----------------------------------------------------------------------------
-// getRoot()
-//-----------------------------------------------------------------------------
-LLJoint *LLJoint::getRoot()
-{
- if ( getParent() == NULL )
- {
- return this;
- }
- return getParent()->getRoot();
-}
-
-
-//-----------------------------------------------------------------------------
-// findJoint()
-//-----------------------------------------------------------------------------
-LLJoint *LLJoint::findJoint( const std::string &name )
-{
- if (name == getName())
- return this;
-
- for (LLJoint* joint : mChildren)
- {
- LLJoint *found = joint->findJoint(name);
- if (found)
- {
- return found;
- }
- }
-
- return NULL;
-}
-
-
-//--------------------------------------------------------------------
-// addChild()
-//--------------------------------------------------------------------
-void LLJoint::addChild(LLJoint* joint)
-{
- if (joint->mParent)
- joint->mParent->removeChild(joint);
-
- mChildren.push_back(joint);
- joint->mXform.setParent(&mXform);
- joint->mParent = this;
- joint->touch();
-}
-
-
-//--------------------------------------------------------------------
-// removeChild()
-//--------------------------------------------------------------------
-void LLJoint::removeChild(LLJoint* joint)
-{
- joints_t::iterator iter = std::find(mChildren.begin(), mChildren.end(), joint);
- if (iter != mChildren.end())
- {
- mChildren.erase(iter);
-
- joint->mXform.setParent(NULL);
- joint->mParent = NULL;
- joint->touch();
- }
-}
-
-
-//--------------------------------------------------------------------
-// removeAllChildren()
-//--------------------------------------------------------------------
-void LLJoint::removeAllChildren()
-{
- for (LLJoint* joint : mChildren)
- {
- if (joint)
- {
- joint->mXform.setParent(NULL);
- joint->mParent = NULL;
- joint->touch();
- //delete joint;
- }
- }
- mChildren.clear();
-}
-
-
-//--------------------------------------------------------------------
-// getPosition()
-//--------------------------------------------------------------------
-const LLVector3& LLJoint::getPosition()
-{
- return mXform.getPosition();
-}
-
-bool do_debug_joint(const std::string& name)
-{
- if (std::find(LLJoint::s_debugJointNames.begin(), LLJoint::s_debugJointNames.end(),name) != LLJoint::s_debugJointNames.end())
- {
- return true;
- }
- return false;
-}
-
-//--------------------------------------------------------------------
-// setPosition()
-//--------------------------------------------------------------------
-void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment_overrides )
-{
- LLVector3 pos(requested_pos);
-
- LLVector3 active_override;
- LLUUID mesh_id;
- if (apply_attachment_overrides && m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override))
- {
- if (pos != active_override && do_debug_joint(getName()))
- {
- LLScopedContextString str("setPosition");
- LL_DEBUGS("Avatar") << " joint " << getName() << " requested_pos " << requested_pos
- << " overriden by attachment " << active_override << LL_ENDL;
- }
- pos = active_override;
- }
- if ((pos != getPosition()) && do_debug_joint(getName()))
- {
- LLScopedContextString str("setPosition");
- LLCallStack cs;
- LLContextStatus con_status;
- LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL;
- LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << "====================" << LL_ENDL;
- LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL;
- }
- if (pos != getPosition())
- {
- mXform.setPosition(pos);
- touch(MATRIX_DIRTY | POSITION_DIRTY);
- }
-}
-
-void LLJoint::setDefaultPosition( const LLVector3& pos )
-{
- mDefaultPosition = pos;
-}
-
-const LLVector3& LLJoint::getDefaultPosition() const
-{
- return mDefaultPosition;
-}
-
-void LLJoint::setDefaultScale( const LLVector3& scale )
-{
- mDefaultScale = scale;
-}
-
-const LLVector3& LLJoint::getDefaultScale() const
-{
- return mDefaultScale;
-}
-
-void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info )
-{
- std::ostringstream os;
- os << joint.m_posBeforeOverrides;
- joint.m_attachmentPosOverrides.showJointVector3Overrides(os);
- LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL;
-}
-
-void showJointScaleOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info )
-{
- std::ostringstream os;
- os << joint.m_scaleBeforeOverrides;
- joint.m_attachmentScaleOverrides.showJointVector3Overrides(os);
- LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL;
-}
-
-bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const
-{
- LLVector3 diff = pos - getDefaultPosition();
- const F32 max_joint_pos_offset = LL_JOINT_TRESHOLD_POS_OFFSET; // 0.1 mm
- return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset;
-}
-
-bool LLJoint::aboveJointScaleThreshold(const LLVector3& scale) const
-{
- LLVector3 diff = scale - getDefaultScale();
- const F32 max_joint_scale_offset = 0.0001f; // 0.1 mm
- return diff.lengthSquared() > max_joint_scale_offset * max_joint_scale_offset;
-}
-
-//--------------------------------------------------------------------
-// addAttachmentPosOverride()
-//--------------------------------------------------------------------
-void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed )
-{
- active_override_changed = false;
- if (mesh_id.isNull())
- {
- return;
- }
- LLVector3 before_pos;
- LLUUID before_mesh_id;
- bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id );
- if (!m_attachmentPosOverrides.count())
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_posBeforeOverrides " << getPosition() << LL_ENDL;
- }
- m_posBeforeOverrides = getPosition();
- }
- m_attachmentPosOverrides.add(mesh_id,pos);
- LLVector3 after_pos;
- LLUUID after_mesh_id;
- hasAttachmentPosOverride(after_pos, after_mesh_id);
- if (!has_active_override_before || (after_pos != before_pos))
- {
- active_override_changed = true;
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL;
- }
- updatePos(av_info);
- }
-}
-
-//--------------------------------------------------------------------
-// removeAttachmentPosOverride()
-//--------------------------------------------------------------------
-void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed )
-{
- active_override_changed = false;
- if (mesh_id.isNull())
- {
- return;
- }
- LLVector3 before_pos;
- LLUUID before_mesh_id;
- hasAttachmentPosOverride( before_pos, before_mesh_id );
- if (m_attachmentPosOverrides.remove(mesh_id))
- {
- LLVector3 after_pos;
- LLUUID after_mesh_id;
- bool has_active_override_after = hasAttachmentPosOverride(after_pos, after_mesh_id);
- if (!has_active_override_after || (after_pos != before_pos))
- {
- active_override_changed = true;
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
- << " removeAttachmentPosOverride for " << mesh_id << LL_ENDL;
- showJointPosOverrides(*this, "remove", av_info);
- }
- updatePos(av_info);
- }
- }
-}
-
-//--------------------------------------------------------------------
- // hasAttachmentPosOverride()
- //--------------------------------------------------------------------
-bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const
-{
- return m_attachmentPosOverrides.findActiveOverride(mesh_id,pos);
-}
-
-//--------------------------------------------------------------------
-// clearAttachmentPosOverrides()
-//--------------------------------------------------------------------
-void LLJoint::clearAttachmentPosOverrides()
-{
- if (m_attachmentPosOverrides.count())
- {
- m_attachmentPosOverrides.clear();
- setPosition(m_posBeforeOverrides);
- }
-}
-
-//--------------------------------------------------------------------
-// getAllAttachmentPosOverrides()
-//--------------------------------------------------------------------
-void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides,
- std::set<LLVector3>& distinct_pos_overrides) const
-{
- num_pos_overrides = m_attachmentPosOverrides.count();
- for (const LLVector3OverrideMap::map_type::value_type& pos_override_pair : m_attachmentPosOverrides.getMap())
- {
- distinct_pos_overrides.insert(pos_override_pair.second);
- }
-}
-
-//--------------------------------------------------------------------
-// getAllAttachmentScaleOverrides()
-//--------------------------------------------------------------------
-void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides,
- std::set<LLVector3>& distinct_scale_overrides) const
-{
- num_scale_overrides = m_attachmentScaleOverrides.count();
- for (const LLVector3OverrideMap::map_type::value_type& scale_override_pair : m_attachmentScaleOverrides.getMap())
- {
- distinct_scale_overrides.insert(scale_override_pair.second);
- }
-}
-
-//--------------------------------------------------------------------
-// showAttachmentPosOverrides()
-//--------------------------------------------------------------------
-void LLJoint::showAttachmentPosOverrides(const std::string& av_info) const
-{
- LLVector3 active_override;
- bool has_active_override;
- LLUUID mesh_id;
- has_active_override = m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override);
- U32 count = m_attachmentPosOverrides.count();
- if (count==1)
- {
- LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin();
- std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : "";
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
- << " has single attachment pos override " << highlight << "" << it->second << " default " << mDefaultPosition << LL_ENDL;
- }
- else if (count>1)
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment pos overrides" << LL_ENDL;
- std::set<LLVector3> distinct_offsets;
- for (const LLVector3OverrideMap::map_type::value_type& pos_override_pair : m_attachmentPosOverrides.getMap())
- {
- distinct_offsets.insert(pos_override_pair.second);
- }
- if (distinct_offsets.size()>1)
- {
- LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL;
- }
- for (const LLVector3& offset : distinct_offsets)
- {
- std::string highlight = (has_active_override && offset == active_override) ? "*" : "";
- LL_DEBUGS("Avatar") << " POS " << highlight << "" << offset << " default " << mDefaultPosition << LL_ENDL;
- }
- }
-}
-
-//--------------------------------------------------------------------
-// updatePos()
-//--------------------------------------------------------------------
-void LLJoint::updatePos(const std::string& av_info)
-{
- LLVector3 pos, found_pos;
- LLUUID mesh_id;
- if (m_attachmentPosOverrides.findActiveOverride(mesh_id,found_pos))
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentPosOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL;
- }
- pos = found_pos;
- }
- else
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL;
- }
- pos = m_posBeforeOverrides;
- }
- setPosition(pos);
-}
-
-//--------------------------------------------------------------------
-// updateScale()
-//--------------------------------------------------------------------
-void LLJoint::updateScale(const std::string& av_info)
-{
- LLVector3 scale, found_scale;
- LLUUID mesh_id;
- if (m_attachmentScaleOverrides.findActiveOverride(mesh_id,found_scale))
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner of " << m_attachmentScaleOverrides.count() << " is mesh " << mesh_id << " scale " << found_scale << LL_ENDL;
- }
- scale = found_scale;
- }
- else
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner is scaleBeforeOverrides " << m_scaleBeforeOverrides << LL_ENDL;
- }
- scale = m_scaleBeforeOverrides;
- }
- setScale(scale);
-}
-
-//--------------------------------------------------------------------
-// addAttachmentScaleOverride()
-//--------------------------------------------------------------------
-void LLJoint::addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info )
-{
- if (mesh_id.isNull())
- {
- return;
- }
- if (!m_attachmentScaleOverrides.count())
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_scaleBeforeOverrides " << getScale() << LL_ENDL;
- }
- m_scaleBeforeOverrides = getScale();
- }
- m_attachmentScaleOverrides.add(mesh_id,scale);
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentScaleOverride for mesh " << mesh_id << " scale " << scale << LL_ENDL;
- }
- updateScale(av_info);
-}
-
-//--------------------------------------------------------------------
-// removeAttachmentScaleOverride()
-//--------------------------------------------------------------------
-void LLJoint::removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info )
-{
- if (mesh_id.isNull())
- {
- return;
- }
- if (m_attachmentScaleOverrides.remove(mesh_id))
- {
- if (do_debug_joint(getName()))
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
- << " removeAttachmentScaleOverride for " << mesh_id << LL_ENDL;
- showJointScaleOverrides(*this, "remove", av_info);
- }
- updateScale(av_info);
- }
-}
-
-//--------------------------------------------------------------------
- // hasAttachmentScaleOverride()
- //--------------------------------------------------------------------
-bool LLJoint::hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const
-{
- return m_attachmentScaleOverrides.findActiveOverride(mesh_id,scale);
-}
-
-//--------------------------------------------------------------------
-// clearAttachmentScaleOverrides()
-//--------------------------------------------------------------------
-void LLJoint::clearAttachmentScaleOverrides()
-{
- if (m_attachmentScaleOverrides.count())
- {
- m_attachmentScaleOverrides.clear();
- setScale(m_scaleBeforeOverrides);
- }
-}
-
-//--------------------------------------------------------------------
-// showAttachmentScaleOverrides()
-//--------------------------------------------------------------------
-void LLJoint::showAttachmentScaleOverrides(const std::string& av_info) const
-{
- LLVector3 active_override;
- bool has_active_override;
- LLUUID mesh_id;
- has_active_override = m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override);
- U32 count = m_attachmentScaleOverrides.count();
- if (count==1)
- {
- LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin();
- std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : "";
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
- << " has single attachment scale override " << highlight << "" << it->second << " default " << mDefaultScale << LL_ENDL;
- }
- else if (count>1)
- {
- LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment scale overrides" << LL_ENDL;
- std::set<LLVector3> distinct_offsets;
- for (const LLVector3OverrideMap::map_type::value_type& scale_override_pair : m_attachmentScaleOverrides.getMap())
- {
- distinct_offsets.insert(scale_override_pair.second);
- }
- if (distinct_offsets.size()>1)
- {
- LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL;
- }
- for (const LLVector3& offset : distinct_offsets)
- {
- std::string highlight = (has_active_override && offset == active_override) ? "*" : "";
- LL_DEBUGS("Avatar") << " POS " << highlight << "" << offset << " default " << mDefaultScale << LL_ENDL;
- }
- }
-}
-
-// init static
-LLJoint::debug_joint_name_t LLJoint::s_debugJointNames = debug_joint_name_t();
-
-//--------------------------------------------------------------------
-// setDebugJointNames
-//--------------------------------------------------------------------
-void LLJoint::setDebugJointNames(const debug_joint_name_t& names)
-{
- s_debugJointNames = names;
-}
-void LLJoint::setDebugJointNames(const std::string& names_string)
-{
- debug_joint_name_t names;
- boost::split(names, names_string, boost::is_any_of(" :,"));
- setDebugJointNames(names);
-}
-
-//--------------------------------------------------------------------
-// getWorldPosition()
-//--------------------------------------------------------------------
-LLVector3 LLJoint::getWorldPosition()
-{
- updateWorldPRSParent();
- return mXform.getWorldPosition();
-}
-
-//-----------------------------------------------------------------------------
-// getLastWorldPosition()
-//-----------------------------------------------------------------------------
-LLVector3 LLJoint::getLastWorldPosition()
-{
- return mXform.getWorldPosition();
-}
-//--------------------------------------------------------------------
-// setWorldPosition()
-//--------------------------------------------------------------------
-void LLJoint::setWorldPosition( const LLVector3& pos )
-{
- if (mParent == NULL)
- {
- this->setPosition( pos );
- return;
- }
-
- LLMatrix4 temp_matrix = getWorldMatrix();
- temp_matrix.mMatrix[VW][VX] = pos.mV[VX];
- temp_matrix.mMatrix[VW][VY] = pos.mV[VY];
- temp_matrix.mMatrix[VW][VZ] = pos.mV[VZ];
-
- LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix();
- LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert();
-
- temp_matrix *= invParentWorldMatrix;
-
- LLVector3 localPos( temp_matrix.mMatrix[VW][VX],
- temp_matrix.mMatrix[VW][VY],
- temp_matrix.mMatrix[VW][VZ] );
-
- setPosition( localPos );
-}
-
-
-//--------------------------------------------------------------------
-// getRotation()
-//--------------------------------------------------------------------
-const LLQuaternion& LLJoint::getRotation()
-{
- return mXform.getRotation();
-}
-
-
-//--------------------------------------------------------------------
-// setRotation()
-//--------------------------------------------------------------------
-void LLJoint::setRotation( const LLQuaternion& rot )
-{
- if (rot.isFinite())
- {
- // if (mXform.getRotation() != rot)
- {
- mXform.setRotation(rot);
- touch(MATRIX_DIRTY | ROTATION_DIRTY);
- }
- }
-}
-
-
-//--------------------------------------------------------------------
-// getWorldRotation()
-//--------------------------------------------------------------------
-LLQuaternion LLJoint::getWorldRotation()
-{
- updateWorldPRSParent();
-
- return mXform.getWorldRotation();
-}
-
-//-----------------------------------------------------------------------------
-// getLastWorldRotation()
-//-----------------------------------------------------------------------------
-LLQuaternion LLJoint::getLastWorldRotation()
-{
- return mXform.getWorldRotation();
-}
-
-//--------------------------------------------------------------------
-// setWorldRotation()
-//--------------------------------------------------------------------
-void LLJoint::setWorldRotation( const LLQuaternion& rot )
-{
- if (mParent == NULL)
- {
- this->setRotation( rot );
- return;
- }
-
- LLMatrix4 temp_mat(rot);
-
- LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix();
- parentWorldMatrix.mMatrix[VW][VX] = 0;
- parentWorldMatrix.mMatrix[VW][VY] = 0;
- parentWorldMatrix.mMatrix[VW][VZ] = 0;
-
- LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert();
-
- temp_mat *= invParentWorldMatrix;
-
- setRotation(LLQuaternion(temp_mat));
-}
-
-
-//--------------------------------------------------------------------
-// getScale()
-//--------------------------------------------------------------------
-const LLVector3& LLJoint::getScale()
-{
- return mXform.getScale();
-}
-
-//--------------------------------------------------------------------
-// setScale()
-//--------------------------------------------------------------------
-void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_overrides )
-{
- LLVector3 scale(requested_scale);
- LLUUID mesh_id;
- LLVector3 active_override;
- if (apply_attachment_overrides && m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override))
- {
- if (scale != active_override && do_debug_joint(getName()))
- {
- LLScopedContextString str("setScale");
- LL_DEBUGS("Avatar") << " joint " << getName() << " requested_scale " << requested_scale
- << " overriden by attachment " << active_override << LL_ENDL;
- }
- scale = active_override;
- }
- if ((mXform.getScale() != scale) && do_debug_joint(getName()))
- {
- LLScopedContextString str("setScale");
- LLCallStack cs;
- LLContextStatus con_status;
- LL_DEBUGS("Avatar") << " joint " << getName() << " set scale " << scale << LL_ENDL;
- LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << LL_ENDL;
- LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL;
- }
- mXform.setScale(scale);
- touch();
-
-}
-
-
-
-//--------------------------------------------------------------------
-// getWorldMatrix()
-//--------------------------------------------------------------------
-const LLMatrix4 &LLJoint::getWorldMatrix()
-{
- updateWorldMatrixParent();
-
- return mXform.getWorldMatrix();
-}
-
-const LLMatrix4a& LLJoint::getWorldMatrix4a()
-{
- updateWorldMatrixParent();
-
- return mWorldMatrix;
-}
-
-
-//--------------------------------------------------------------------
-// setWorldMatrix()
-//--------------------------------------------------------------------
-void LLJoint::setWorldMatrix( const LLMatrix4& mat )
-{
- LL_INFOS() << "WARNING: LLJoint::setWorldMatrix() not correctly implemented yet" << LL_ENDL;
- // extract global translation
- LLVector3 trans( mat.mMatrix[VW][VX],
- mat.mMatrix[VW][VY],
- mat.mMatrix[VW][VZ] );
-
- // extract global rotation
- LLQuaternion rot( mat );
-
- setWorldPosition( trans );
- setWorldRotation( rot );
-}
-
-//-----------------------------------------------------------------------------
-// updateWorldMatrixParent()
-//-----------------------------------------------------------------------------
-void LLJoint::updateWorldMatrixParent()
-{
- if (mDirtyFlags & MATRIX_DIRTY)
- {
- LLJoint *parent = getParent();
- if (parent)
- {
- parent->updateWorldMatrixParent();
- }
- updateWorldMatrix();
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateWorldPRSParent()
-//-----------------------------------------------------------------------------
-void LLJoint::updateWorldPRSParent()
-{
- if (mDirtyFlags & (ROTATION_DIRTY | POSITION_DIRTY))
- {
- LLJoint *parent = getParent();
- if (parent)
- {
- parent->updateWorldPRSParent();
- }
-
- mXform.update();
- mDirtyFlags &= ~(ROTATION_DIRTY | POSITION_DIRTY);
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateWorldMatrixChildren()
-//-----------------------------------------------------------------------------
-void LLJoint::updateWorldMatrixChildren()
-{
- if (!this->mUpdateXform) return;
-
- if (mDirtyFlags & MATRIX_DIRTY)
- {
- updateWorldMatrix();
- }
- for (LLJoint* joint : mChildren)
- {
- joint->updateWorldMatrixChildren();
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateWorldMatrix()
-//-----------------------------------------------------------------------------
-void LLJoint::updateWorldMatrix()
-{
- if (mDirtyFlags & MATRIX_DIRTY)
- {
- sNumUpdates++;
- mXform.updateMatrix(false);
- mWorldMatrix.loadu(mXform.getWorldMatrix());
- mDirtyFlags = 0x0;
- }
-}
-
-//--------------------------------------------------------------------
-// getSkinOffset()
-//--------------------------------------------------------------------
-const LLVector3 &LLJoint::getSkinOffset()
-{
- return mSkinOffset;
-}
-
-
-//--------------------------------------------------------------------
-// setSkinOffset()
-//--------------------------------------------------------------------
-void LLJoint::setSkinOffset( const LLVector3& offset )
-{
- mSkinOffset = offset;
-}
-
-
-//-----------------------------------------------------------------------------
-// clampRotation()
-//-----------------------------------------------------------------------------
-void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot)
-{
- LLVector3 main_axis(1.f, 0.f, 0.f);
-
- for (LLJoint* joint : mChildren)
- {
- if (joint->isAnimatable())
- {
- main_axis = joint->getPosition();
- main_axis.normVec();
- // only care about first animatable child
- break;
- }
- }
-}
-
-// End
-
+/** + * @file lljoint.cpp + * @brief Implementation of LLJoint class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "lljoint.h" + +#include "llmath.h" +#include "llcallstack.h" +#include <boost/algorithm/string.hpp> + +S32 LLJoint::sNumUpdates = 0; +S32 LLJoint::sNumTouches = 0; + +template <class T> +bool attachment_map_iter_compare_key(const T& a, const T& b) +{ + return a.first < b.first; +} + +bool LLVector3OverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const +{ + pos = LLVector3(0,0,0); + mesh_id = LLUUID(); + bool found = false; + + map_type::const_iterator it = std::max_element(m_map.begin(), + m_map.end(), + attachment_map_iter_compare_key<map_type::value_type>); + if (it != m_map.end()) + { + found = true; + pos = it->second; + mesh_id = it->first; + } + return found; +} + +void LLVector3OverrideMap::showJointVector3Overrides( std::ostringstream& os ) const +{ + map_type::const_iterator max_it = std::max_element(m_map.begin(), + m_map.end(), + attachment_map_iter_compare_key<map_type::value_type>); + for (const map_type::value_type& pos_pair : m_map) + { + const LLVector3& pos = pos_pair.second; + os << " " << "[" << pos_pair.first <<": " << pos << "]" << ((pos_pair==(*max_it)) ? "*" : ""); + } +} + +U32 LLVector3OverrideMap::count() const +{ + return m_map.size(); +} + +void LLVector3OverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos) +{ + m_map[mesh_id] = pos; +} + +bool LLVector3OverrideMap::remove(const LLUUID& mesh_id) +{ + U32 remove_count = m_map.erase(mesh_id); + return (remove_count > 0); +} + +void LLVector3OverrideMap::clear() +{ + m_map.clear(); +} + +//----------------------------------------------------------------------------- +// LLJoint() +// Class Constructor +//----------------------------------------------------------------------------- + + +void LLJoint::init() +{ + mName = "unnamed"; + mParent = NULL; + mXform.setScaleChildOffset(true); + mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f)); + mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY; + mUpdateXform = true; + mSupport = SUPPORT_BASE; + mEnd = LLVector3(0.0f, 0.0f, 0.0f); +} + +LLJoint::LLJoint() : + mJointNum(-1) +{ + init(); + touch(); +} + +LLJoint::LLJoint(S32 joint_num) : + mJointNum(joint_num) +{ + init(); + touch(); +} + +//----------------------------------------------------------------------------- +// LLJoint() +// Class Constructor +//----------------------------------------------------------------------------- +LLJoint::LLJoint(const std::string &name, LLJoint *parent) : + mJointNum(-2) +{ + init(); + mUpdateXform = false; + + setName(name); + if (parent) + { + parent->addChild( this ); + } + touch(); +} + +//----------------------------------------------------------------------------- +// ~LLJoint() +// Class Destructor +//----------------------------------------------------------------------------- +LLJoint::~LLJoint() +{ + if (mParent) + { + mParent->removeChild( this ); + } + removeAllChildren(); +} + + +//----------------------------------------------------------------------------- +// setup() +//----------------------------------------------------------------------------- +void LLJoint::setup(const std::string &name, LLJoint *parent) +{ + setName(name); + if (parent) + { + parent->addChild( this ); + } +} + +//----------------------------------------------------------------------------- +// setSupport() +//----------------------------------------------------------------------------- +void LLJoint::setSupport(const std::string& support_name) +{ + if (support_name == "extended") + { + setSupport(SUPPORT_EXTENDED); + } + else if (support_name == "base") + { + setSupport(SUPPORT_BASE); + } + else + { + LL_WARNS() << "unknown support string " << support_name << LL_ENDL; + setSupport(SUPPORT_BASE); + } +} + + +//----------------------------------------------------------------------------- +// touch() +// Sets all dirty flags for all children, recursively. +//----------------------------------------------------------------------------- +void LLJoint::touch(U32 flags) +{ + if ((flags | mDirtyFlags) != mDirtyFlags) + { + sNumTouches++; + mDirtyFlags |= flags; + U32 child_flags = flags; + if (flags & ROTATION_DIRTY) + { + child_flags |= POSITION_DIRTY; + } + + for (LLJoint* joint : mChildren) + { + joint->touch(child_flags); + } + } +} + +//----------------------------------------------------------------------------- +// setJointNum() +//----------------------------------------------------------------------------- +void LLJoint::setJointNum(S32 joint_num) +{ + mJointNum = joint_num; + if (mJointNum + 2 >= LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + LL_INFOS() << "LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be increased" << LL_ENDL; + LL_ERRS() << "joint_num " << joint_num << " + 2 is too large for " << LL_CHARACTER_MAX_ANIMATED_JOINTS << LL_ENDL; + } +} +//----------------------------------------------------------------------------- +// getRoot() +//----------------------------------------------------------------------------- +LLJoint *LLJoint::getRoot() +{ + if ( getParent() == NULL ) + { + return this; + } + return getParent()->getRoot(); +} + + +//----------------------------------------------------------------------------- +// findJoint() +//----------------------------------------------------------------------------- +LLJoint *LLJoint::findJoint( const std::string &name ) +{ + if (name == getName()) + return this; + + for (LLJoint* joint : mChildren) + { + LLJoint *found = joint->findJoint(name); + if (found) + { + return found; + } + } + + return NULL; +} + + +//-------------------------------------------------------------------- +// addChild() +//-------------------------------------------------------------------- +void LLJoint::addChild(LLJoint* joint) +{ + if (joint->mParent) + joint->mParent->removeChild(joint); + + mChildren.push_back(joint); + joint->mXform.setParent(&mXform); + joint->mParent = this; + joint->touch(); +} + + +//-------------------------------------------------------------------- +// removeChild() +//-------------------------------------------------------------------- +void LLJoint::removeChild(LLJoint* joint) +{ + joints_t::iterator iter = std::find(mChildren.begin(), mChildren.end(), joint); + if (iter != mChildren.end()) + { + mChildren.erase(iter); + + joint->mXform.setParent(NULL); + joint->mParent = NULL; + joint->touch(); + } +} + + +//-------------------------------------------------------------------- +// removeAllChildren() +//-------------------------------------------------------------------- +void LLJoint::removeAllChildren() +{ + for (LLJoint* joint : mChildren) + { + if (joint) + { + joint->mXform.setParent(NULL); + joint->mParent = NULL; + joint->touch(); + //delete joint; + } + } + mChildren.clear(); +} + + +//-------------------------------------------------------------------- +// getPosition() +//-------------------------------------------------------------------- +const LLVector3& LLJoint::getPosition() +{ + return mXform.getPosition(); +} + +bool do_debug_joint(const std::string& name) +{ + if (std::find(LLJoint::s_debugJointNames.begin(), LLJoint::s_debugJointNames.end(),name) != LLJoint::s_debugJointNames.end()) + { + return true; + } + return false; +} + +//-------------------------------------------------------------------- +// setPosition() +//-------------------------------------------------------------------- +void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment_overrides ) +{ + LLVector3 pos(requested_pos); + + LLVector3 active_override; + LLUUID mesh_id; + if (apply_attachment_overrides && m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override)) + { + if (pos != active_override && do_debug_joint(getName())) + { + LLScopedContextString str("setPosition"); + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_pos " << requested_pos + << " overriden by attachment " << active_override << LL_ENDL; + } + pos = active_override; + } + if ((pos != getPosition()) && do_debug_joint(getName())) + { + LLScopedContextString str("setPosition"); + LLCallStack cs; + LLContextStatus con_status; + LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL; + LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << "====================" << LL_ENDL; + LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; + } + if (pos != getPosition()) + { + mXform.setPosition(pos); + touch(MATRIX_DIRTY | POSITION_DIRTY); + } +} + +void LLJoint::setDefaultPosition( const LLVector3& pos ) +{ + mDefaultPosition = pos; +} + +const LLVector3& LLJoint::getDefaultPosition() const +{ + return mDefaultPosition; +} + +void LLJoint::setDefaultScale( const LLVector3& scale ) +{ + mDefaultScale = scale; +} + +const LLVector3& LLJoint::getDefaultScale() const +{ + return mDefaultScale; +} + +void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) +{ + std::ostringstream os; + os << joint.m_posBeforeOverrides; + joint.m_attachmentPosOverrides.showJointVector3Overrides(os); + LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; +} + +void showJointScaleOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) +{ + std::ostringstream os; + os << joint.m_scaleBeforeOverrides; + joint.m_attachmentScaleOverrides.showJointVector3Overrides(os); + LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; +} + +bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const +{ + LLVector3 diff = pos - getDefaultPosition(); + const F32 max_joint_pos_offset = LL_JOINT_TRESHOLD_POS_OFFSET; // 0.1 mm + return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset; +} + +bool LLJoint::aboveJointScaleThreshold(const LLVector3& scale) const +{ + LLVector3 diff = scale - getDefaultScale(); + const F32 max_joint_scale_offset = 0.0001f; // 0.1 mm + return diff.lengthSquared() > max_joint_scale_offset * max_joint_scale_offset; +} + +//-------------------------------------------------------------------- +// addAttachmentPosOverride() +//-------------------------------------------------------------------- +void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ) +{ + active_override_changed = false; + if (mesh_id.isNull()) + { + return; + } + LLVector3 before_pos; + LLUUID before_mesh_id; + bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id ); + if (!m_attachmentPosOverrides.count()) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_posBeforeOverrides " << getPosition() << LL_ENDL; + } + m_posBeforeOverrides = getPosition(); + } + m_attachmentPosOverrides.add(mesh_id,pos); + LLVector3 after_pos; + LLUUID after_mesh_id; + hasAttachmentPosOverride(after_pos, after_mesh_id); + if (!has_active_override_before || (after_pos != before_pos)) + { + active_override_changed = true; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL; + } + updatePos(av_info); + } +} + +//-------------------------------------------------------------------- +// removeAttachmentPosOverride() +//-------------------------------------------------------------------- +void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ) +{ + active_override_changed = false; + if (mesh_id.isNull()) + { + return; + } + LLVector3 before_pos; + LLUUID before_mesh_id; + hasAttachmentPosOverride( before_pos, before_mesh_id ); + if (m_attachmentPosOverrides.remove(mesh_id)) + { + LLVector3 after_pos; + LLUUID after_mesh_id; + bool has_active_override_after = hasAttachmentPosOverride(after_pos, after_mesh_id); + if (!has_active_override_after || (after_pos != before_pos)) + { + active_override_changed = true; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " removeAttachmentPosOverride for " << mesh_id << LL_ENDL; + showJointPosOverrides(*this, "remove", av_info); + } + updatePos(av_info); + } + } +} + +//-------------------------------------------------------------------- + // hasAttachmentPosOverride() + //-------------------------------------------------------------------- +bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const +{ + return m_attachmentPosOverrides.findActiveOverride(mesh_id,pos); +} + +//-------------------------------------------------------------------- +// clearAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::clearAttachmentPosOverrides() +{ + if (m_attachmentPosOverrides.count()) + { + m_attachmentPosOverrides.clear(); + setPosition(m_posBeforeOverrides); + } +} + +//-------------------------------------------------------------------- +// getAllAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, + std::set<LLVector3>& distinct_pos_overrides) const +{ + num_pos_overrides = m_attachmentPosOverrides.count(); + for (const LLVector3OverrideMap::map_type::value_type& pos_override_pair : m_attachmentPosOverrides.getMap()) + { + distinct_pos_overrides.insert(pos_override_pair.second); + } +} + +//-------------------------------------------------------------------- +// getAllAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides, + std::set<LLVector3>& distinct_scale_overrides) const +{ + num_scale_overrides = m_attachmentScaleOverrides.count(); + for (const LLVector3OverrideMap::map_type::value_type& scale_override_pair : m_attachmentScaleOverrides.getMap()) + { + distinct_scale_overrides.insert(scale_override_pair.second); + } +} + +//-------------------------------------------------------------------- +// showAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentPosOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentPosOverrides.count(); + if (count==1) + { + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment pos override " << highlight << "" << it->second << " default " << mDefaultPosition << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment pos overrides" << LL_ENDL; + std::set<LLVector3> distinct_offsets; + for (const LLVector3OverrideMap::map_type::value_type& pos_override_pair : m_attachmentPosOverrides.getMap()) + { + distinct_offsets.insert(pos_override_pair.second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + for (const LLVector3& offset : distinct_offsets) + { + std::string highlight = (has_active_override && offset == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << offset << " default " << mDefaultPosition << LL_ENDL; + } + } +} + +//-------------------------------------------------------------------- +// updatePos() +//-------------------------------------------------------------------- +void LLJoint::updatePos(const std::string& av_info) +{ + LLVector3 pos, found_pos; + LLUUID mesh_id; + if (m_attachmentPosOverrides.findActiveOverride(mesh_id,found_pos)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentPosOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL; + } + pos = found_pos; + } + else + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL; + } + pos = m_posBeforeOverrides; + } + setPosition(pos); +} + +//-------------------------------------------------------------------- +// updateScale() +//-------------------------------------------------------------------- +void LLJoint::updateScale(const std::string& av_info) +{ + LLVector3 scale, found_scale; + LLUUID mesh_id; + if (m_attachmentScaleOverrides.findActiveOverride(mesh_id,found_scale)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner of " << m_attachmentScaleOverrides.count() << " is mesh " << mesh_id << " scale " << found_scale << LL_ENDL; + } + scale = found_scale; + } + else + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner is scaleBeforeOverrides " << m_scaleBeforeOverrides << LL_ENDL; + } + scale = m_scaleBeforeOverrides; + } + setScale(scale); +} + +//-------------------------------------------------------------------- +// addAttachmentScaleOverride() +//-------------------------------------------------------------------- +void LLJoint::addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info ) +{ + if (mesh_id.isNull()) + { + return; + } + if (!m_attachmentScaleOverrides.count()) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_scaleBeforeOverrides " << getScale() << LL_ENDL; + } + m_scaleBeforeOverrides = getScale(); + } + m_attachmentScaleOverrides.add(mesh_id,scale); + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentScaleOverride for mesh " << mesh_id << " scale " << scale << LL_ENDL; + } + updateScale(av_info); +} + +//-------------------------------------------------------------------- +// removeAttachmentScaleOverride() +//-------------------------------------------------------------------- +void LLJoint::removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info ) +{ + if (mesh_id.isNull()) + { + return; + } + if (m_attachmentScaleOverrides.remove(mesh_id)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " removeAttachmentScaleOverride for " << mesh_id << LL_ENDL; + showJointScaleOverrides(*this, "remove", av_info); + } + updateScale(av_info); + } +} + +//-------------------------------------------------------------------- + // hasAttachmentScaleOverride() + //-------------------------------------------------------------------- +bool LLJoint::hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const +{ + return m_attachmentScaleOverrides.findActiveOverride(mesh_id,scale); +} + +//-------------------------------------------------------------------- +// clearAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::clearAttachmentScaleOverrides() +{ + if (m_attachmentScaleOverrides.count()) + { + m_attachmentScaleOverrides.clear(); + setScale(m_scaleBeforeOverrides); + } +} + +//-------------------------------------------------------------------- +// showAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentScaleOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentScaleOverrides.count(); + if (count==1) + { + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment scale override " << highlight << "" << it->second << " default " << mDefaultScale << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment scale overrides" << LL_ENDL; + std::set<LLVector3> distinct_offsets; + for (const LLVector3OverrideMap::map_type::value_type& scale_override_pair : m_attachmentScaleOverrides.getMap()) + { + distinct_offsets.insert(scale_override_pair.second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + for (const LLVector3& offset : distinct_offsets) + { + std::string highlight = (has_active_override && offset == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << offset << " default " << mDefaultScale << LL_ENDL; + } + } +} + +// init static +LLJoint::debug_joint_name_t LLJoint::s_debugJointNames = debug_joint_name_t(); + +//-------------------------------------------------------------------- +// setDebugJointNames +//-------------------------------------------------------------------- +void LLJoint::setDebugJointNames(const debug_joint_name_t& names) +{ + s_debugJointNames = names; +} +void LLJoint::setDebugJointNames(const std::string& names_string) +{ + debug_joint_name_t names; + boost::split(names, names_string, boost::is_any_of(" :,")); + setDebugJointNames(names); +} + +//-------------------------------------------------------------------- +// getWorldPosition() +//-------------------------------------------------------------------- +LLVector3 LLJoint::getWorldPosition() +{ + updateWorldPRSParent(); + return mXform.getWorldPosition(); +} + +//----------------------------------------------------------------------------- +// getLastWorldPosition() +//----------------------------------------------------------------------------- +LLVector3 LLJoint::getLastWorldPosition() +{ + return mXform.getWorldPosition(); +} +//-------------------------------------------------------------------- +// setWorldPosition() +//-------------------------------------------------------------------- +void LLJoint::setWorldPosition( const LLVector3& pos ) +{ + if (mParent == NULL) + { + this->setPosition( pos ); + return; + } + + LLMatrix4 temp_matrix = getWorldMatrix(); + temp_matrix.mMatrix[VW][VX] = pos.mV[VX]; + temp_matrix.mMatrix[VW][VY] = pos.mV[VY]; + temp_matrix.mMatrix[VW][VZ] = pos.mV[VZ]; + + LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix(); + LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert(); + + temp_matrix *= invParentWorldMatrix; + + LLVector3 localPos( temp_matrix.mMatrix[VW][VX], + temp_matrix.mMatrix[VW][VY], + temp_matrix.mMatrix[VW][VZ] ); + + setPosition( localPos ); +} + + +//-------------------------------------------------------------------- +// getRotation() +//-------------------------------------------------------------------- +const LLQuaternion& LLJoint::getRotation() +{ + return mXform.getRotation(); +} + + +//-------------------------------------------------------------------- +// setRotation() +//-------------------------------------------------------------------- +void LLJoint::setRotation( const LLQuaternion& rot ) +{ + if (rot.isFinite()) + { + // if (mXform.getRotation() != rot) + { + mXform.setRotation(rot); + touch(MATRIX_DIRTY | ROTATION_DIRTY); + } + } +} + + +//-------------------------------------------------------------------- +// getWorldRotation() +//-------------------------------------------------------------------- +LLQuaternion LLJoint::getWorldRotation() +{ + updateWorldPRSParent(); + + return mXform.getWorldRotation(); +} + +//----------------------------------------------------------------------------- +// getLastWorldRotation() +//----------------------------------------------------------------------------- +LLQuaternion LLJoint::getLastWorldRotation() +{ + return mXform.getWorldRotation(); +} + +//-------------------------------------------------------------------- +// setWorldRotation() +//-------------------------------------------------------------------- +void LLJoint::setWorldRotation( const LLQuaternion& rot ) +{ + if (mParent == NULL) + { + this->setRotation( rot ); + return; + } + + LLMatrix4 temp_mat(rot); + + LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix(); + parentWorldMatrix.mMatrix[VW][VX] = 0; + parentWorldMatrix.mMatrix[VW][VY] = 0; + parentWorldMatrix.mMatrix[VW][VZ] = 0; + + LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert(); + + temp_mat *= invParentWorldMatrix; + + setRotation(LLQuaternion(temp_mat)); +} + + +//-------------------------------------------------------------------- +// getScale() +//-------------------------------------------------------------------- +const LLVector3& LLJoint::getScale() +{ + return mXform.getScale(); +} + +//-------------------------------------------------------------------- +// setScale() +//-------------------------------------------------------------------- +void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_overrides ) +{ + LLVector3 scale(requested_scale); + LLUUID mesh_id; + LLVector3 active_override; + if (apply_attachment_overrides && m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override)) + { + if (scale != active_override && do_debug_joint(getName())) + { + LLScopedContextString str("setScale"); + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_scale " << requested_scale + << " overriden by attachment " << active_override << LL_ENDL; + } + scale = active_override; + } + if ((mXform.getScale() != scale) && do_debug_joint(getName())) + { + LLScopedContextString str("setScale"); + LLCallStack cs; + LLContextStatus con_status; + LL_DEBUGS("Avatar") << " joint " << getName() << " set scale " << scale << LL_ENDL; + LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << LL_ENDL; + LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; + } + mXform.setScale(scale); + touch(); + +} + + + +//-------------------------------------------------------------------- +// getWorldMatrix() +//-------------------------------------------------------------------- +const LLMatrix4 &LLJoint::getWorldMatrix() +{ + updateWorldMatrixParent(); + + return mXform.getWorldMatrix(); +} + +const LLMatrix4a& LLJoint::getWorldMatrix4a() +{ + updateWorldMatrixParent(); + + return mWorldMatrix; +} + + +//-------------------------------------------------------------------- +// setWorldMatrix() +//-------------------------------------------------------------------- +void LLJoint::setWorldMatrix( const LLMatrix4& mat ) +{ + LL_INFOS() << "WARNING: LLJoint::setWorldMatrix() not correctly implemented yet" << LL_ENDL; + // extract global translation + LLVector3 trans( mat.mMatrix[VW][VX], + mat.mMatrix[VW][VY], + mat.mMatrix[VW][VZ] ); + + // extract global rotation + LLQuaternion rot( mat ); + + setWorldPosition( trans ); + setWorldRotation( rot ); +} + +//----------------------------------------------------------------------------- +// updateWorldMatrixParent() +//----------------------------------------------------------------------------- +void LLJoint::updateWorldMatrixParent() +{ + if (mDirtyFlags & MATRIX_DIRTY) + { + LLJoint *parent = getParent(); + if (parent) + { + parent->updateWorldMatrixParent(); + } + updateWorldMatrix(); + } +} + +//----------------------------------------------------------------------------- +// updateWorldPRSParent() +//----------------------------------------------------------------------------- +void LLJoint::updateWorldPRSParent() +{ + if (mDirtyFlags & (ROTATION_DIRTY | POSITION_DIRTY)) + { + LLJoint *parent = getParent(); + if (parent) + { + parent->updateWorldPRSParent(); + } + + mXform.update(); + mDirtyFlags &= ~(ROTATION_DIRTY | POSITION_DIRTY); + } +} + +//----------------------------------------------------------------------------- +// updateWorldMatrixChildren() +//----------------------------------------------------------------------------- +void LLJoint::updateWorldMatrixChildren() +{ + if (!this->mUpdateXform) return; + + if (mDirtyFlags & MATRIX_DIRTY) + { + updateWorldMatrix(); + } + for (LLJoint* joint : mChildren) + { + joint->updateWorldMatrixChildren(); + } +} + +//----------------------------------------------------------------------------- +// updateWorldMatrix() +//----------------------------------------------------------------------------- +void LLJoint::updateWorldMatrix() +{ + if (mDirtyFlags & MATRIX_DIRTY) + { + sNumUpdates++; + mXform.updateMatrix(false); + mWorldMatrix.loadu(mXform.getWorldMatrix()); + mDirtyFlags = 0x0; + } +} + +//-------------------------------------------------------------------- +// getSkinOffset() +//-------------------------------------------------------------------- +const LLVector3 &LLJoint::getSkinOffset() +{ + return mSkinOffset; +} + + +//-------------------------------------------------------------------- +// setSkinOffset() +//-------------------------------------------------------------------- +void LLJoint::setSkinOffset( const LLVector3& offset ) +{ + mSkinOffset = offset; +} + + +//----------------------------------------------------------------------------- +// clampRotation() +//----------------------------------------------------------------------------- +void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) +{ + LLVector3 main_axis(1.f, 0.f, 0.f); + + for (LLJoint* joint : mChildren) + { + if (joint->isAnimatable()) + { + main_axis = joint->getPosition(); + main_axis.normVec(); + // only care about first animatable child + break; + } + } +} + +// End + diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 101121c7cb..763c1e3865 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -1,307 +1,307 @@ -/**
- * @file lljoint.h
- * @brief Implementation of LLJoint class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLJOINT_H
-#define LL_LLJOINT_H
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include <string>
-#include <list>
-
-#include "v3math.h"
-#include "v4math.h"
-#include "m4math.h"
-#include "llquaternion.h"
-#include "xform.h"
-#include "llmatrix4a.h"
-
-constexpr S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15;
-// Need to set this to count of animate-able joints,
-// currently = #bones + #collision_volumes + #attachments + 2,
-// rounded to next multiple of 4.
-constexpr U32 LL_CHARACTER_MAX_ANIMATED_JOINTS = 216; // must be divisible by 4!
-constexpr U32 LL_MAX_JOINTS_PER_MESH_OBJECT = 110;
-
-// These should be higher than the joint_num of any
-// other joint, to avoid conflicts in updateMotionsByType()
-constexpr U32 LL_HAND_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-1);
-constexpr U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2);
-constexpr S32 LL_CHARACTER_MAX_PRIORITY = 7;
-constexpr F32 LL_MAX_PELVIS_OFFSET = 5.f;
-
-constexpr F32 LL_JOINT_TRESHOLD_POS_OFFSET = 0.0001f; //0.1 mm
-
-class LLVector3OverrideMap
-{
-public:
- LLVector3OverrideMap() {}
- bool findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const;
- void showJointVector3Overrides(std::ostringstream& os) const;
- U32 count() const;
- void add(const LLUUID& mesh_id, const LLVector3& pos);
- bool remove(const LLUUID& mesh_id);
- void clear();
-
- typedef std::map<LLUUID,LLVector3> map_type;
- const map_type& getMap() const { return m_map; }
-private:
- map_type m_map;
-};
-
-inline bool operator==(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b)
-{
- return a.getMap() == b.getMap();
-}
-
-inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b)
-{
- return !(a == b);
-}
-
-//-----------------------------------------------------------------------------
-// class LLJoint
-//-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLJoint
-{
- LL_ALIGN_NEW
-public:
- // priority levels, from highest to lowest
- enum JointPriority
- {
- USE_MOTION_PRIORITY = -1,
- LOW_PRIORITY = 0,
- MEDIUM_PRIORITY,
- HIGH_PRIORITY,
- HIGHER_PRIORITY,
- HIGHEST_PRIORITY,
- ADDITIVE_PRIORITY = LL_CHARACTER_MAX_PRIORITY
- };
-
- enum DirtyFlags
- {
- MATRIX_DIRTY = 0x1 << 0,
- ROTATION_DIRTY = 0x1 << 1,
- POSITION_DIRTY = 0x1 << 2,
- ALL_DIRTY = 0x7
- };
-public:
- enum SupportCategory
- {
- SUPPORT_BASE,
- SUPPORT_EXTENDED
- };
-protected:
- // explicit transformation members
- LL_ALIGN_16(LLMatrix4a mWorldMatrix);
- LLXformMatrix mXform;
-
- std::string mName;
-
- SupportCategory mSupport;
-
- // parent joint
- LLJoint *mParent;
-
- LLVector3 mDefaultPosition;
- LLVector3 mDefaultScale;
-
-public:
- U32 mDirtyFlags;
- bool mUpdateXform;
-
- // describes the skin binding pose
- LLVector3 mSkinOffset;
-
- // Endpoint of the bone, if applicable. This is only relevant for
- // external programs like Blender, and for diagnostic display.
- LLVector3 mEnd;
-
- S32 mJointNum;
-
- // child joints
- typedef std::vector<LLJoint*> joints_t;
- joints_t mChildren;
-
- // debug statics
- static S32 sNumTouches;
- static S32 sNumUpdates;
- typedef std::set<std::string> debug_joint_name_t;
- static debug_joint_name_t s_debugJointNames;
- static void setDebugJointNames(const debug_joint_name_t& names);
- static void setDebugJointNames(const std::string& names_string);
-
- // Position overrides
- LLVector3OverrideMap m_attachmentPosOverrides;
- LLVector3 m_posBeforeOverrides;
-
- // Scale overrides
- LLVector3OverrideMap m_attachmentScaleOverrides;
- LLVector3 m_scaleBeforeOverrides;
-
- void updatePos(const std::string& av_info);
- void updateScale(const std::string& av_info);
-
-public:
- LLJoint();
-
- // Note: these joint_num constructors are a bad idea because there
- // are only a couple of places in the code where it is useful to
- // have a joint num for a joint (for joints that are used in
- // animations), and including them as part of the constructor then
- // forces us to maintain an alternate path through the entire
- // large-ish class hierarchy of joint types. The only reason they
- // are still here now is to avoid breaking the baking service
- // (appearanceutility) builds; these constructors are not used in
- // the viewer. Once the appearance utility is updated to remove
- // these joint num references, which it shouldn't ever need, from
- // its own classes, we can also remove all the joint_num
- // constructors from LLJoint, LLViewerJoint, LLAvatarJoint, and
- // createAvatarJoint.
- LLJoint(S32 joint_num);
-
- // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform*
- LLJoint( const std::string &name, LLJoint *parent=NULL );
- virtual ~LLJoint();
-
-private:
- void init();
-
-public:
- // set name and parent
- void setup( const std::string &name, LLJoint *parent=NULL );
-
- void touch(U32 flags = ALL_DIRTY);
-
- // get/set name
- const std::string& getName() const { return mName; }
- void setName( const std::string &name ) { mName = name; }
-
- // joint num
- S32 getJointNum() const { return mJointNum; }
- void setJointNum(S32 joint_num);
-
- // get/set support
- SupportCategory getSupport() const { return mSupport; }
- void setSupport( const SupportCategory& support) { mSupport = support; }
- void setSupport( const std::string& support_string);
-
- // get/set end point
- void setEnd( const LLVector3& end) { mEnd = end; }
- const LLVector3& getEnd() const { return mEnd; }
-
- // getParent
- LLJoint *getParent() { return mParent; }
-
- // getRoot
- LLJoint *getRoot();
-
- // search for child joints by name
- LLJoint *findJoint( const std::string &name );
-
- // add/remove children
- void addChild( LLJoint *joint );
- void removeChild( LLJoint *joint );
- void removeAllChildren();
-
- // get/set local position
- const LLVector3& getPosition();
- void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false );
-
- // Tracks the default position defined by the skeleton
- void setDefaultPosition( const LLVector3& pos );
- const LLVector3& getDefaultPosition() const;
-
- // Tracks the default scale defined by the skeleton
- void setDefaultScale( const LLVector3& scale );
- const LLVector3& getDefaultScale() const;
-
- // get/set world position
- LLVector3 getWorldPosition();
- LLVector3 getLastWorldPosition();
- void setWorldPosition( const LLVector3& pos );
-
- // get/set local rotation
- const LLQuaternion& getRotation();
- void setRotation( const LLQuaternion& rot );
-
- // get/set world rotation
- LLQuaternion getWorldRotation();
- LLQuaternion getLastWorldRotation();
- void setWorldRotation( const LLQuaternion& rot );
-
- // get/set local scale
- const LLVector3& getScale();
- void setScale( const LLVector3& scale, bool apply_attachment_overrides = false );
-
- // get/set world matrix
- const LLMatrix4 &getWorldMatrix();
- void setWorldMatrix( const LLMatrix4& mat );
-
- const LLMatrix4a& getWorldMatrix4a();
-
- void updateWorldMatrixChildren();
- void updateWorldMatrixParent();
-
- void updateWorldPRSParent();
-
- void updateWorldMatrix();
-
- // get/set skin offset
- const LLVector3 &getSkinOffset();
- void setSkinOffset( const LLVector3 &offset);
-
- LLXformMatrix *getXform() { return &mXform; }
-
- void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot);
-
- virtual bool isAnimatable() const { return true; }
-
- void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed );
- void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed );
- bool hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const;
- void clearAttachmentPosOverrides();
- void showAttachmentPosOverrides(const std::string& av_info) const;
-
- void addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info );
- void removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info );
- bool hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const;
- void clearAttachmentScaleOverrides();
- void showAttachmentScaleOverrides(const std::string& av_info) const;
-
- void getAllAttachmentPosOverrides(S32& num_pos_overrides,
- std::set<LLVector3>& distinct_pos_overrides) const;
- void getAllAttachmentScaleOverrides(S32& num_scale_overrides,
- std::set<LLVector3>& distinct_scale_overrides) const;
-
- // These are used in checks of whether a pos/scale override is considered significant.
- bool aboveJointPosThreshold(const LLVector3& pos) const;
- bool aboveJointScaleThreshold(const LLVector3& scale) const;
-} LL_ALIGN_POSTFIX(16);
-#endif // LL_LLJOINT_H
-
+/** + * @file lljoint.h + * @brief Implementation of LLJoint class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLJOINT_H +#define LL_LLJOINT_H + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include <string> +#include <list> + +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "llquaternion.h" +#include "xform.h" +#include "llmatrix4a.h" + +constexpr S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; +// Need to set this to count of animate-able joints, +// currently = #bones + #collision_volumes + #attachments + 2, +// rounded to next multiple of 4. +constexpr U32 LL_CHARACTER_MAX_ANIMATED_JOINTS = 216; // must be divisible by 4! +constexpr U32 LL_MAX_JOINTS_PER_MESH_OBJECT = 110; + +// These should be higher than the joint_num of any +// other joint, to avoid conflicts in updateMotionsByType() +constexpr U32 LL_HAND_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-1); +constexpr U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2); +constexpr S32 LL_CHARACTER_MAX_PRIORITY = 7; +constexpr F32 LL_MAX_PELVIS_OFFSET = 5.f; + +constexpr F32 LL_JOINT_TRESHOLD_POS_OFFSET = 0.0001f; //0.1 mm + +class LLVector3OverrideMap +{ +public: + LLVector3OverrideMap() {} + bool findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const; + void showJointVector3Overrides(std::ostringstream& os) const; + U32 count() const; + void add(const LLUUID& mesh_id, const LLVector3& pos); + bool remove(const LLUUID& mesh_id); + void clear(); + + typedef std::map<LLUUID,LLVector3> map_type; + const map_type& getMap() const { return m_map; } +private: + map_type m_map; +}; + +inline bool operator==(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ + return a.getMap() == b.getMap(); +} + +inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ + return !(a == b); +} + +//----------------------------------------------------------------------------- +// class LLJoint +//----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) +class LLJoint +{ + LL_ALIGN_NEW +public: + // priority levels, from highest to lowest + enum JointPriority + { + USE_MOTION_PRIORITY = -1, + LOW_PRIORITY = 0, + MEDIUM_PRIORITY, + HIGH_PRIORITY, + HIGHER_PRIORITY, + HIGHEST_PRIORITY, + ADDITIVE_PRIORITY = LL_CHARACTER_MAX_PRIORITY + }; + + enum DirtyFlags + { + MATRIX_DIRTY = 0x1 << 0, + ROTATION_DIRTY = 0x1 << 1, + POSITION_DIRTY = 0x1 << 2, + ALL_DIRTY = 0x7 + }; +public: + enum SupportCategory + { + SUPPORT_BASE, + SUPPORT_EXTENDED + }; +protected: + // explicit transformation members + LL_ALIGN_16(LLMatrix4a mWorldMatrix); + LLXformMatrix mXform; + + std::string mName; + + SupportCategory mSupport; + + // parent joint + LLJoint *mParent; + + LLVector3 mDefaultPosition; + LLVector3 mDefaultScale; + +public: + U32 mDirtyFlags; + bool mUpdateXform; + + // describes the skin binding pose + LLVector3 mSkinOffset; + + // Endpoint of the bone, if applicable. This is only relevant for + // external programs like Blender, and for diagnostic display. + LLVector3 mEnd; + + S32 mJointNum; + + // child joints + typedef std::vector<LLJoint*> joints_t; + joints_t mChildren; + + // debug statics + static S32 sNumTouches; + static S32 sNumUpdates; + typedef std::set<std::string> debug_joint_name_t; + static debug_joint_name_t s_debugJointNames; + static void setDebugJointNames(const debug_joint_name_t& names); + static void setDebugJointNames(const std::string& names_string); + + // Position overrides + LLVector3OverrideMap m_attachmentPosOverrides; + LLVector3 m_posBeforeOverrides; + + // Scale overrides + LLVector3OverrideMap m_attachmentScaleOverrides; + LLVector3 m_scaleBeforeOverrides; + + void updatePos(const std::string& av_info); + void updateScale(const std::string& av_info); + +public: + LLJoint(); + + // Note: these joint_num constructors are a bad idea because there + // are only a couple of places in the code where it is useful to + // have a joint num for a joint (for joints that are used in + // animations), and including them as part of the constructor then + // forces us to maintain an alternate path through the entire + // large-ish class hierarchy of joint types. The only reason they + // are still here now is to avoid breaking the baking service + // (appearanceutility) builds; these constructors are not used in + // the viewer. Once the appearance utility is updated to remove + // these joint num references, which it shouldn't ever need, from + // its own classes, we can also remove all the joint_num + // constructors from LLJoint, LLViewerJoint, LLAvatarJoint, and + // createAvatarJoint. + LLJoint(S32 joint_num); + + // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform* + LLJoint( const std::string &name, LLJoint *parent=NULL ); + virtual ~LLJoint(); + +private: + void init(); + +public: + // set name and parent + void setup( const std::string &name, LLJoint *parent=NULL ); + + void touch(U32 flags = ALL_DIRTY); + + // get/set name + const std::string& getName() const { return mName; } + void setName( const std::string &name ) { mName = name; } + + // joint num + S32 getJointNum() const { return mJointNum; } + void setJointNum(S32 joint_num); + + // get/set support + SupportCategory getSupport() const { return mSupport; } + void setSupport( const SupportCategory& support) { mSupport = support; } + void setSupport( const std::string& support_string); + + // get/set end point + void setEnd( const LLVector3& end) { mEnd = end; } + const LLVector3& getEnd() const { return mEnd; } + + // getParent + LLJoint *getParent() { return mParent; } + + // getRoot + LLJoint *getRoot(); + + // search for child joints by name + LLJoint *findJoint( const std::string &name ); + + // add/remove children + void addChild( LLJoint *joint ); + void removeChild( LLJoint *joint ); + void removeAllChildren(); + + // get/set local position + const LLVector3& getPosition(); + void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false ); + + // Tracks the default position defined by the skeleton + void setDefaultPosition( const LLVector3& pos ); + const LLVector3& getDefaultPosition() const; + + // Tracks the default scale defined by the skeleton + void setDefaultScale( const LLVector3& scale ); + const LLVector3& getDefaultScale() const; + + // get/set world position + LLVector3 getWorldPosition(); + LLVector3 getLastWorldPosition(); + void setWorldPosition( const LLVector3& pos ); + + // get/set local rotation + const LLQuaternion& getRotation(); + void setRotation( const LLQuaternion& rot ); + + // get/set world rotation + LLQuaternion getWorldRotation(); + LLQuaternion getLastWorldRotation(); + void setWorldRotation( const LLQuaternion& rot ); + + // get/set local scale + const LLVector3& getScale(); + void setScale( const LLVector3& scale, bool apply_attachment_overrides = false ); + + // get/set world matrix + const LLMatrix4 &getWorldMatrix(); + void setWorldMatrix( const LLMatrix4& mat ); + + const LLMatrix4a& getWorldMatrix4a(); + + void updateWorldMatrixChildren(); + void updateWorldMatrixParent(); + + void updateWorldPRSParent(); + + void updateWorldMatrix(); + + // get/set skin offset + const LLVector3 &getSkinOffset(); + void setSkinOffset( const LLVector3 &offset); + + LLXformMatrix *getXform() { return &mXform; } + + void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot); + + virtual bool isAnimatable() const { return true; } + + void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); + void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); + bool hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const; + void clearAttachmentPosOverrides(); + void showAttachmentPosOverrides(const std::string& av_info) const; + + void addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info ); + void removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info ); + bool hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const; + void clearAttachmentScaleOverrides(); + void showAttachmentScaleOverrides(const std::string& av_info) const; + + void getAllAttachmentPosOverrides(S32& num_pos_overrides, + std::set<LLVector3>& distinct_pos_overrides) const; + void getAllAttachmentScaleOverrides(S32& num_scale_overrides, + std::set<LLVector3>& distinct_scale_overrides) const; + + // These are used in checks of whether a pos/scale override is considered significant. + bool aboveJointPosThreshold(const LLVector3& pos) const; + bool aboveJointScaleThreshold(const LLVector3& scale) const; +} LL_ALIGN_POSTFIX(16); +#endif // LL_LLJOINT_H + diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp index c22e3cb70b..626029059e 100644 --- a/indra/llcharacter/lljointsolverrp3.cpp +++ b/indra/llcharacter/lljointsolverrp3.cpp @@ -1,395 +1,395 @@ -/**
- * @file lljointsolverrp3.cpp
- * @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "lljointsolverrp3.h"
-
-#include "llmath.h"
-
-#define F_EPSILON 0.00001f
-
-#if LL_RELEASE
- #define DEBUG_JOINT_SOLVER 0
-#else
- #define DEBUG_JOINT_SOLVER 1
-#endif
-
-//-----------------------------------------------------------------------------
-// Constructor
-//-----------------------------------------------------------------------------
-LLJointSolverRP3::LLJointSolverRP3()
-{
- mJointA = NULL;
- mJointB = NULL;
- mJointC = NULL;
- mJointGoal = NULL;
- mLengthAB = 1.0f;
- mLengthBC = 1.0f;
- mPoleVector.setVec( 1.0f, 0.0f, 0.0f );
- mbUseBAxis = false;
- mTwist = 0.0f;
- mFirstTime = true;
-}
-
-
-//-----------------------------------------------------------------------------
-// Destructor
-//-----------------------------------------------------------------------------
-/*virtual*/ LLJointSolverRP3::~LLJointSolverRP3()
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// setupJoints()
-//-----------------------------------------------------------------------------
-void LLJointSolverRP3::setupJoints( LLJoint* jointA,
- LLJoint* jointB,
- LLJoint* jointC,
- LLJoint* jointGoal )
-{
- mJointA = jointA;
- mJointB = jointB;
- mJointC = jointC;
- mJointGoal = jointGoal;
-
- mLengthAB = mJointB->getPosition().magVec();
- mLengthBC = mJointC->getPosition().magVec();
-
- mJointABaseRotation = jointA->getRotation();
- mJointBBaseRotation = jointB->getRotation();
-}
-
-
-//-----------------------------------------------------------------------------
-// getPoleVector()
-//-----------------------------------------------------------------------------
-const LLVector3& LLJointSolverRP3::getPoleVector()
-{
- return mPoleVector;
-}
-
-
-//-----------------------------------------------------------------------------
-// setPoleVector()
-//-----------------------------------------------------------------------------
-void LLJointSolverRP3::setPoleVector( const LLVector3& poleVector )
-{
- mPoleVector = poleVector;
- mPoleVector.normVec();
-}
-
-
-//-----------------------------------------------------------------------------
-// setPoleVector()
-//-----------------------------------------------------------------------------
-void LLJointSolverRP3::setBAxis( const LLVector3& bAxis )
-{
- mBAxis = bAxis;
- mBAxis.normVec();
- mbUseBAxis = true;
-}
-
-//-----------------------------------------------------------------------------
-// getTwist()
-//-----------------------------------------------------------------------------
-F32 LLJointSolverRP3::getTwist()
-{
- return mTwist;
-}
-
-
-//-----------------------------------------------------------------------------
-// setTwist()
-//-----------------------------------------------------------------------------
-void LLJointSolverRP3::setTwist( F32 twist )
-{
- mTwist = twist;
-}
-
-
-//-----------------------------------------------------------------------------
-// solve()
-//-----------------------------------------------------------------------------
-void LLJointSolverRP3::solve()
-{
-
- //-------------------------------------------------------------------------
- // setup joints in their base rotations
- //-------------------------------------------------------------------------
- mJointA->setRotation( mJointABaseRotation );
- mJointB->setRotation( mJointBBaseRotation );
-
- //-------------------------------------------------------------------------
- // get joint positions in world space
- //-------------------------------------------------------------------------
- LLVector3 aPos = mJointA->getWorldPosition();
- LLVector3 bPos = mJointB->getWorldPosition();
- LLVector3 cPos = mJointC->getWorldPosition();
- LLVector3 gPos = mJointGoal->getWorldPosition();
-
-#if DEBUG_JOINT_SOLVER
- LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE
- << "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE
- << "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE
- << "bRotLocal = " << mJointB->getRotation() << LL_NEWLINE
- << "cRotLocal = " << mJointC->getRotation() << LL_NEWLINE
- << "aPos : " << aPos << LL_NEWLINE
- << "bPos : " << bPos << LL_NEWLINE
- << "cPos : " << cPos << LL_NEWLINE
- << "gPos : " << gPos << LL_ENDL;
-#endif
-
- //-------------------------------------------------------------------------
- // get the poleVector in world space
- //-------------------------------------------------------------------------
- LLMatrix4 worldJointAParentMat;
- if ( mJointA->getParent() )
- {
- worldJointAParentMat = mJointA->getParent()->getWorldMatrix();
- }
- LLVector3 poleVec = rotate_vector( mPoleVector, worldJointAParentMat );
-
- //-------------------------------------------------------------------------
- // compute the following:
- // vector from A to B
- // vector from B to C
- // vector from A to C
- // vector from A to G (goal)
- //-------------------------------------------------------------------------
- LLVector3 abVec = bPos - aPos;
- LLVector3 bcVec = cPos - bPos;
- LLVector3 acVec = cPos - aPos;
- LLVector3 agVec = gPos - aPos;
-
- //-------------------------------------------------------------------------
- // compute needed lengths of those vectors
- //-------------------------------------------------------------------------
- F32 abLen = abVec.magVec();
- F32 bcLen = bcVec.magVec();
- F32 agLen = agVec.magVec();
-
- //-------------------------------------------------------------------------
- // compute component vector of (A->B) orthogonal to (A->C)
- //-------------------------------------------------------------------------
- LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
-
-#if DEBUG_JOINT_SOLVER
- LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE
- << "bcVec : " << bcVec << LL_NEWLINE
- << "acVec : " << acVec << LL_NEWLINE
- << "agVec : " << agVec << LL_NEWLINE
- << "abLen : " << abLen << LL_NEWLINE
- << "bcLen : " << bcLen << LL_NEWLINE
- << "agLen : " << agLen << LL_NEWLINE
- << "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL;
-#endif
-
- //-------------------------------------------------------------------------
- // compute the normal of the original ABC plane (and store for later)
- //-------------------------------------------------------------------------
- LLVector3 abcNorm;
- if (!mbUseBAxis)
- {
- if( are_parallel(abVec, bcVec, 0.001f) )
- {
- // the current solution is maxed out, so we use the axis that is
- // orthogonal to both poleVec and A->B
- if ( are_parallel(poleVec, abVec, 0.001f) )
- {
- // ACK! the problem is singular
- if ( are_parallel(poleVec, agVec, 0.001f) )
- {
- // the solutions is also singular
- return;
- }
- else
- {
- abcNorm = poleVec % agVec;
- }
- }
- else
- {
- abcNorm = poleVec % abVec;
- }
- }
- else
- {
- abcNorm = abVec % bcVec;
- }
- }
- else
- {
- abcNorm = mBAxis * mJointB->getWorldRotation();
- }
-
- //-------------------------------------------------------------------------
- // compute rotation of B
- //-------------------------------------------------------------------------
- // angle between A->B and B->C
- F32 abbcAng = angle_between(abVec, bcVec);
-
- // vector orthogonal to A->B and B->C
- LLVector3 abbcOrthoVec = abVec % bcVec;
- if (abbcOrthoVec.magVecSquared() < 0.001f)
- {
- abbcOrthoVec = poleVec % abVec;
- abacCompOrthoVec = poleVec;
- }
- abbcOrthoVec.normVec();
-
- F32 agLenSq = agLen * agLen;
-
- // angle arm for extension
- F32 cosTheta = (agLenSq - abLen*abLen - bcLen*bcLen) / (2.0f * abLen * bcLen);
- if (cosTheta > 1.0f)
- cosTheta = 1.0f;
- else if (cosTheta < -1.0f)
- cosTheta = -1.0f;
-
- F32 theta = acos(cosTheta);
-
- LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
-
-#if DEBUG_JOINT_SOLVER
- LL_DEBUGS("JointSolver") << "abbcAng : " << abbcAng << LL_NEWLINE
- << "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE
- << "agLenSq : " << agLenSq << LL_NEWLINE
- << "cosTheta : " << cosTheta << LL_NEWLINE
- << "theta : " << theta << LL_NEWLINE
- << "bRot : " << bRot << LL_NEWLINE
- << "theta abbcAng theta-abbcAng: "
- << theta*180.0/F_PI << " "
- << abbcAng*180.0f/F_PI << " "
- << (theta - abbcAng)*180.0f/F_PI
- << LL_ENDL;
-#endif
-
- //-------------------------------------------------------------------------
- // compute rotation that rotates new A->C to A->G
- //-------------------------------------------------------------------------
- // rotate B->C by bRot
- bcVec = bcVec * bRot;
-
- // update A->C
- acVec = abVec + bcVec;
-
- LLQuaternion cgRot;
- cgRot.shortestArc( acVec, agVec );
-
-#if DEBUG_JOINT_SOLVER
- LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE
- << "acVec : " << acVec << LL_NEWLINE
- << "cgRot : " << cgRot << LL_ENDL;
-#endif
-
- // update A->B and B->C with rotation from C to G
- abVec = abVec * cgRot;
- bcVec = bcVec * cgRot;
- abcNorm = abcNorm * cgRot;
- acVec = abVec + bcVec;
-
- //-------------------------------------------------------------------------
- // compute the normal of the APG plane
- //-------------------------------------------------------------------------
- if (are_parallel(agVec, poleVec, 0.001f))
- {
- // the solution plane is undefined ==> we're done
- return;
- }
- LLVector3 apgNorm = poleVec % agVec;
- apgNorm.normVec();
-
- if (!mbUseBAxis)
- {
- //---------------------------------------------------------------------
- // compute the normal of the new ABC plane
- // (only necessary if we're NOT using mBAxis)
- //---------------------------------------------------------------------
- if( are_parallel(abVec, bcVec, 0.001f) )
- {
- // G is either too close or too far away
- // we'll use the old ABCnormal
- }
- else
- {
- abcNorm = abVec % bcVec;
- }
- abcNorm.normVec();
- }
-
- //-------------------------------------------------------------------------
- // calcuate plane rotation
- //-------------------------------------------------------------------------
- LLQuaternion pRot;
- if ( are_parallel( abcNorm, apgNorm, 0.001f) )
- {
- if (abcNorm * apgNorm < 0.0f)
- {
- // we must be PI radians off ==> rotate by PI around agVec
- pRot.setQuat(F_PI, agVec);
- }
- else
- {
- // we're done
- }
- }
- else
- {
- pRot.shortestArc( abcNorm, apgNorm );
- }
-
- //-------------------------------------------------------------------------
- // compute twist rotation
- //-------------------------------------------------------------------------
- LLQuaternion twistRot( mTwist, agVec );
-
-#if DEBUG_JOINT_SOLVER
- LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE
- << "apgNorm = " << apgNorm << LL_NEWLINE
- << "pRot = " << pRot << LL_NEWLINE
- << "twist : " << mTwist*180.0/F_PI << LL_NEWLINE
- << "twistRot : " << twistRot << LL_ENDL;
-#endif
-
- //-------------------------------------------------------------------------
- // compute rotation of A
- //-------------------------------------------------------------------------
- LLQuaternion aRot = cgRot * pRot * twistRot;
-
- //-------------------------------------------------------------------------
- // apply the rotations
- //-------------------------------------------------------------------------
- mJointB->setWorldRotation( mJointB->getWorldRotation() * bRot );
- mJointA->setWorldRotation( mJointA->getWorldRotation() * aRot );
-}
-
-
-// End
+/** + * @file lljointsolverrp3.cpp + * @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "lljointsolverrp3.h" + +#include "llmath.h" + +#define F_EPSILON 0.00001f + +#if LL_RELEASE + #define DEBUG_JOINT_SOLVER 0 +#else + #define DEBUG_JOINT_SOLVER 1 +#endif + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +LLJointSolverRP3::LLJointSolverRP3() +{ + mJointA = NULL; + mJointB = NULL; + mJointC = NULL; + mJointGoal = NULL; + mLengthAB = 1.0f; + mLengthBC = 1.0f; + mPoleVector.setVec( 1.0f, 0.0f, 0.0f ); + mbUseBAxis = false; + mTwist = 0.0f; + mFirstTime = true; +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +/*virtual*/ LLJointSolverRP3::~LLJointSolverRP3() +{ +} + + +//----------------------------------------------------------------------------- +// setupJoints() +//----------------------------------------------------------------------------- +void LLJointSolverRP3::setupJoints( LLJoint* jointA, + LLJoint* jointB, + LLJoint* jointC, + LLJoint* jointGoal ) +{ + mJointA = jointA; + mJointB = jointB; + mJointC = jointC; + mJointGoal = jointGoal; + + mLengthAB = mJointB->getPosition().magVec(); + mLengthBC = mJointC->getPosition().magVec(); + + mJointABaseRotation = jointA->getRotation(); + mJointBBaseRotation = jointB->getRotation(); +} + + +//----------------------------------------------------------------------------- +// getPoleVector() +//----------------------------------------------------------------------------- +const LLVector3& LLJointSolverRP3::getPoleVector() +{ + return mPoleVector; +} + + +//----------------------------------------------------------------------------- +// setPoleVector() +//----------------------------------------------------------------------------- +void LLJointSolverRP3::setPoleVector( const LLVector3& poleVector ) +{ + mPoleVector = poleVector; + mPoleVector.normVec(); +} + + +//----------------------------------------------------------------------------- +// setPoleVector() +//----------------------------------------------------------------------------- +void LLJointSolverRP3::setBAxis( const LLVector3& bAxis ) +{ + mBAxis = bAxis; + mBAxis.normVec(); + mbUseBAxis = true; +} + +//----------------------------------------------------------------------------- +// getTwist() +//----------------------------------------------------------------------------- +F32 LLJointSolverRP3::getTwist() +{ + return mTwist; +} + + +//----------------------------------------------------------------------------- +// setTwist() +//----------------------------------------------------------------------------- +void LLJointSolverRP3::setTwist( F32 twist ) +{ + mTwist = twist; +} + + +//----------------------------------------------------------------------------- +// solve() +//----------------------------------------------------------------------------- +void LLJointSolverRP3::solve() +{ + + //------------------------------------------------------------------------- + // setup joints in their base rotations + //------------------------------------------------------------------------- + mJointA->setRotation( mJointABaseRotation ); + mJointB->setRotation( mJointBBaseRotation ); + + //------------------------------------------------------------------------- + // get joint positions in world space + //------------------------------------------------------------------------- + LLVector3 aPos = mJointA->getWorldPosition(); + LLVector3 bPos = mJointB->getWorldPosition(); + LLVector3 cPos = mJointC->getWorldPosition(); + LLVector3 gPos = mJointGoal->getWorldPosition(); + +#if DEBUG_JOINT_SOLVER + LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE + << "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE + << "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE + << "bRotLocal = " << mJointB->getRotation() << LL_NEWLINE + << "cRotLocal = " << mJointC->getRotation() << LL_NEWLINE + << "aPos : " << aPos << LL_NEWLINE + << "bPos : " << bPos << LL_NEWLINE + << "cPos : " << cPos << LL_NEWLINE + << "gPos : " << gPos << LL_ENDL; +#endif + + //------------------------------------------------------------------------- + // get the poleVector in world space + //------------------------------------------------------------------------- + LLMatrix4 worldJointAParentMat; + if ( mJointA->getParent() ) + { + worldJointAParentMat = mJointA->getParent()->getWorldMatrix(); + } + LLVector3 poleVec = rotate_vector( mPoleVector, worldJointAParentMat ); + + //------------------------------------------------------------------------- + // compute the following: + // vector from A to B + // vector from B to C + // vector from A to C + // vector from A to G (goal) + //------------------------------------------------------------------------- + LLVector3 abVec = bPos - aPos; + LLVector3 bcVec = cPos - bPos; + LLVector3 acVec = cPos - aPos; + LLVector3 agVec = gPos - aPos; + + //------------------------------------------------------------------------- + // compute needed lengths of those vectors + //------------------------------------------------------------------------- + F32 abLen = abVec.magVec(); + F32 bcLen = bcVec.magVec(); + F32 agLen = agVec.magVec(); + + //------------------------------------------------------------------------- + // compute component vector of (A->B) orthogonal to (A->C) + //------------------------------------------------------------------------- + LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec)); + +#if DEBUG_JOINT_SOLVER + LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE + << "bcVec : " << bcVec << LL_NEWLINE + << "acVec : " << acVec << LL_NEWLINE + << "agVec : " << agVec << LL_NEWLINE + << "abLen : " << abLen << LL_NEWLINE + << "bcLen : " << bcLen << LL_NEWLINE + << "agLen : " << agLen << LL_NEWLINE + << "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL; +#endif + + //------------------------------------------------------------------------- + // compute the normal of the original ABC plane (and store for later) + //------------------------------------------------------------------------- + LLVector3 abcNorm; + if (!mbUseBAxis) + { + if( are_parallel(abVec, bcVec, 0.001f) ) + { + // the current solution is maxed out, so we use the axis that is + // orthogonal to both poleVec and A->B + if ( are_parallel(poleVec, abVec, 0.001f) ) + { + // ACK! the problem is singular + if ( are_parallel(poleVec, agVec, 0.001f) ) + { + // the solutions is also singular + return; + } + else + { + abcNorm = poleVec % agVec; + } + } + else + { + abcNorm = poleVec % abVec; + } + } + else + { + abcNorm = abVec % bcVec; + } + } + else + { + abcNorm = mBAxis * mJointB->getWorldRotation(); + } + + //------------------------------------------------------------------------- + // compute rotation of B + //------------------------------------------------------------------------- + // angle between A->B and B->C + F32 abbcAng = angle_between(abVec, bcVec); + + // vector orthogonal to A->B and B->C + LLVector3 abbcOrthoVec = abVec % bcVec; + if (abbcOrthoVec.magVecSquared() < 0.001f) + { + abbcOrthoVec = poleVec % abVec; + abacCompOrthoVec = poleVec; + } + abbcOrthoVec.normVec(); + + F32 agLenSq = agLen * agLen; + + // angle arm for extension + F32 cosTheta = (agLenSq - abLen*abLen - bcLen*bcLen) / (2.0f * abLen * bcLen); + if (cosTheta > 1.0f) + cosTheta = 1.0f; + else if (cosTheta < -1.0f) + cosTheta = -1.0f; + + F32 theta = acos(cosTheta); + + LLQuaternion bRot(theta - abbcAng, abbcOrthoVec); + +#if DEBUG_JOINT_SOLVER + LL_DEBUGS("JointSolver") << "abbcAng : " << abbcAng << LL_NEWLINE + << "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE + << "agLenSq : " << agLenSq << LL_NEWLINE + << "cosTheta : " << cosTheta << LL_NEWLINE + << "theta : " << theta << LL_NEWLINE + << "bRot : " << bRot << LL_NEWLINE + << "theta abbcAng theta-abbcAng: " + << theta*180.0/F_PI << " " + << abbcAng*180.0f/F_PI << " " + << (theta - abbcAng)*180.0f/F_PI + << LL_ENDL; +#endif + + //------------------------------------------------------------------------- + // compute rotation that rotates new A->C to A->G + //------------------------------------------------------------------------- + // rotate B->C by bRot + bcVec = bcVec * bRot; + + // update A->C + acVec = abVec + bcVec; + + LLQuaternion cgRot; + cgRot.shortestArc( acVec, agVec ); + +#if DEBUG_JOINT_SOLVER + LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE + << "acVec : " << acVec << LL_NEWLINE + << "cgRot : " << cgRot << LL_ENDL; +#endif + + // update A->B and B->C with rotation from C to G + abVec = abVec * cgRot; + bcVec = bcVec * cgRot; + abcNorm = abcNorm * cgRot; + acVec = abVec + bcVec; + + //------------------------------------------------------------------------- + // compute the normal of the APG plane + //------------------------------------------------------------------------- + if (are_parallel(agVec, poleVec, 0.001f)) + { + // the solution plane is undefined ==> we're done + return; + } + LLVector3 apgNorm = poleVec % agVec; + apgNorm.normVec(); + + if (!mbUseBAxis) + { + //--------------------------------------------------------------------- + // compute the normal of the new ABC plane + // (only necessary if we're NOT using mBAxis) + //--------------------------------------------------------------------- + if( are_parallel(abVec, bcVec, 0.001f) ) + { + // G is either too close or too far away + // we'll use the old ABCnormal + } + else + { + abcNorm = abVec % bcVec; + } + abcNorm.normVec(); + } + + //------------------------------------------------------------------------- + // calcuate plane rotation + //------------------------------------------------------------------------- + LLQuaternion pRot; + if ( are_parallel( abcNorm, apgNorm, 0.001f) ) + { + if (abcNorm * apgNorm < 0.0f) + { + // we must be PI radians off ==> rotate by PI around agVec + pRot.setQuat(F_PI, agVec); + } + else + { + // we're done + } + } + else + { + pRot.shortestArc( abcNorm, apgNorm ); + } + + //------------------------------------------------------------------------- + // compute twist rotation + //------------------------------------------------------------------------- + LLQuaternion twistRot( mTwist, agVec ); + +#if DEBUG_JOINT_SOLVER + LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE + << "apgNorm = " << apgNorm << LL_NEWLINE + << "pRot = " << pRot << LL_NEWLINE + << "twist : " << mTwist*180.0/F_PI << LL_NEWLINE + << "twistRot : " << twistRot << LL_ENDL; +#endif + + //------------------------------------------------------------------------- + // compute rotation of A + //------------------------------------------------------------------------- + LLQuaternion aRot = cgRot * pRot * twistRot; + + //------------------------------------------------------------------------- + // apply the rotations + //------------------------------------------------------------------------- + mJointB->setWorldRotation( mJointB->getWorldRotation() * bRot ); + mJointA->setWorldRotation( mJointA->getWorldRotation() * aRot ); +} + + +// End diff --git a/indra/llcharacter/lljointsolverrp3.h b/indra/llcharacter/lljointsolverrp3.h index db0a935fea..b5c8e24a64 100644 --- a/indra/llcharacter/lljointsolverrp3.h +++ b/indra/llcharacter/lljointsolverrp3.h @@ -1,176 +1,176 @@ -/**
- * @file lljointsolverrp3.h
- * @brief Implementation of LLJointSolverRP3 class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLJOINTSOLVERRP3_H
-#define LL_LLJOINTSOLVERRP3_H
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "lljoint.h"
-
-/* -some compilers don't like line continuation chars-
-//-----------------------------------------------------------------------------
-// class LLJointSolverRP3
-//
-// This class is a "poor man's" IK for simple 3 joint kinematic chains.
-// It is modeled after the 'ikRPSolver' in Maya.
-// This class takes 4 LLJoints:
-// jointA
-// jointB
-// jointC
-// jointGoal
-//
-// Such that jointA is the parent of jointB, jointB is the parent of jointC.
-// When invoked, this class modifies the rotations of jointA and jointB such
-// that the position of the jointC attempts to reach the position of jointGoal.
-//
-// At object initialization time, the distances between jointA - jointB and
-// jointB - jointC are cached. During evaluation these bone lengths are
-// preserved.
-//
-// A A
-// | |
-// | |
-// B B---CG A---B---C...G
-// \
-// \
-// CG
-//
-//
-// In addition a "poleVector" is specified that does two things:
-//
-// a) defines the plane in which the solution occurs, thus
-// reducing an infinite number of solutions, down to 2.
-//
-// b) disambiguates the resulting two solutions as follows:
-//
-// A A A--->poleVector
-// | \ \
-// | \ \
-// B vs. B ==> B
-// \ | |
-// \ | |
-// CG CG CG
-//
-// A "twist" setting allows the solution plane to be rotated about the
-// line between A and C. A handy animation feature.
-//
-// For "smarter" results for non-coplanar limbs, specify the joints axis
-// of bend in the B's local frame (see setBAxis())
-//-----------------------------------------------------------------------------
-*/
-
-class LLJointSolverRP3
-{
-protected:
- LLJoint *mJointA;
- LLJoint *mJointB;
- LLJoint *mJointC;
- LLJoint *mJointGoal;
-
- F32 mLengthAB;
- F32 mLengthBC;
-
- LLVector3 mPoleVector;
- LLVector3 mBAxis;
- bool mbUseBAxis;
-
- F32 mTwist;
-
- bool mFirstTime;
- LLMatrix4 mSavedJointAMat;
- LLMatrix4 mSavedInvPlaneMat;
-
- LLQuaternion mJointABaseRotation;
- LLQuaternion mJointBBaseRotation;
-
-public:
- //-------------------------------------------------------------------------
- // Constructor/Destructor
- //-------------------------------------------------------------------------
- LLJointSolverRP3();
- virtual ~LLJointSolverRP3();
-
- //-------------------------------------------------------------------------
- // setupJoints()
- // This must be called one time to setup the solver.
- // This must be called AFTER the skeleton has been created, all parent/child
- // relationships are established, and after the joints are placed in
- // a valid configuration (as distances between them will be cached).
- //-------------------------------------------------------------------------
- void setupJoints( LLJoint* jointA,
- LLJoint* jointB,
- LLJoint* jointC,
- LLJoint* jointGoal );
-
- //-------------------------------------------------------------------------
- // getPoleVector()
- // Returns the current pole vector.
- //-------------------------------------------------------------------------
- const LLVector3& getPoleVector();
-
- //-------------------------------------------------------------------------
- // setPoleVector()
- // Sets the pole vector.
- // The pole vector is defined relative to (in the space of) jointA's parent.
- // The default pole vector is (1,0,0), and this is used if this function
- // is never called.
- // This vector is normalized when set.
- //-------------------------------------------------------------------------
- void setPoleVector( const LLVector3& poleVector );
-
- //-------------------------------------------------------------------------
- // setBAxis()
- // Sets the joint's axis in B's local frame, and enable "smarter" solve().
- // This allows for smarter IK when for twisted limbs.
- //-------------------------------------------------------------------------
- void setBAxis( const LLVector3& bAxis );
-
- //-------------------------------------------------------------------------
- // getTwist()
- // Returns the current twist in radians.
- //-------------------------------------------------------------------------
- F32 getTwist();
-
- //-------------------------------------------------------------------------
- // setTwist()
- // Sets the twist value.
- // The default is 0.0.
- //-------------------------------------------------------------------------
- void setTwist( F32 twist );
-
- //-------------------------------------------------------------------------
- // solve()
- // This is the "work" function.
- // When called, the rotations of jointA and jointB will be modified
- // such that jointC attempts to reach jointGoal.
- //-------------------------------------------------------------------------
- void solve();
-};
-
-#endif // LL_LLJOINTSOLVERRP3_H
-
+/** + * @file lljointsolverrp3.h + * @brief Implementation of LLJointSolverRP3 class + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLJOINTSOLVERRP3_H +#define LL_LLJOINTSOLVERRP3_H + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "lljoint.h" + +/* -some compilers don't like line continuation chars- +//----------------------------------------------------------------------------- +// class LLJointSolverRP3 +// +// This class is a "poor man's" IK for simple 3 joint kinematic chains. +// It is modeled after the 'ikRPSolver' in Maya. +// This class takes 4 LLJoints: +// jointA +// jointB +// jointC +// jointGoal +// +// Such that jointA is the parent of jointB, jointB is the parent of jointC. +// When invoked, this class modifies the rotations of jointA and jointB such +// that the position of the jointC attempts to reach the position of jointGoal. +// +// At object initialization time, the distances between jointA - jointB and +// jointB - jointC are cached. During evaluation these bone lengths are +// preserved. +// +// A A +// | | +// | | +// B B---CG A---B---C...G +// \ +// \ +// CG +// +// +// In addition a "poleVector" is specified that does two things: +// +// a) defines the plane in which the solution occurs, thus +// reducing an infinite number of solutions, down to 2. +// +// b) disambiguates the resulting two solutions as follows: +// +// A A A--->poleVector +// | \ \ +// | \ \ +// B vs. B ==> B +// \ | | +// \ | | +// CG CG CG +// +// A "twist" setting allows the solution plane to be rotated about the +// line between A and C. A handy animation feature. +// +// For "smarter" results for non-coplanar limbs, specify the joints axis +// of bend in the B's local frame (see setBAxis()) +//----------------------------------------------------------------------------- +*/ + +class LLJointSolverRP3 +{ +protected: + LLJoint *mJointA; + LLJoint *mJointB; + LLJoint *mJointC; + LLJoint *mJointGoal; + + F32 mLengthAB; + F32 mLengthBC; + + LLVector3 mPoleVector; + LLVector3 mBAxis; + bool mbUseBAxis; + + F32 mTwist; + + bool mFirstTime; + LLMatrix4 mSavedJointAMat; + LLMatrix4 mSavedInvPlaneMat; + + LLQuaternion mJointABaseRotation; + LLQuaternion mJointBBaseRotation; + +public: + //------------------------------------------------------------------------- + // Constructor/Destructor + //------------------------------------------------------------------------- + LLJointSolverRP3(); + virtual ~LLJointSolverRP3(); + + //------------------------------------------------------------------------- + // setupJoints() + // This must be called one time to setup the solver. + // This must be called AFTER the skeleton has been created, all parent/child + // relationships are established, and after the joints are placed in + // a valid configuration (as distances between them will be cached). + //------------------------------------------------------------------------- + void setupJoints( LLJoint* jointA, + LLJoint* jointB, + LLJoint* jointC, + LLJoint* jointGoal ); + + //------------------------------------------------------------------------- + // getPoleVector() + // Returns the current pole vector. + //------------------------------------------------------------------------- + const LLVector3& getPoleVector(); + + //------------------------------------------------------------------------- + // setPoleVector() + // Sets the pole vector. + // The pole vector is defined relative to (in the space of) jointA's parent. + // The default pole vector is (1,0,0), and this is used if this function + // is never called. + // This vector is normalized when set. + //------------------------------------------------------------------------- + void setPoleVector( const LLVector3& poleVector ); + + //------------------------------------------------------------------------- + // setBAxis() + // Sets the joint's axis in B's local frame, and enable "smarter" solve(). + // This allows for smarter IK when for twisted limbs. + //------------------------------------------------------------------------- + void setBAxis( const LLVector3& bAxis ); + + //------------------------------------------------------------------------- + // getTwist() + // Returns the current twist in radians. + //------------------------------------------------------------------------- + F32 getTwist(); + + //------------------------------------------------------------------------- + // setTwist() + // Sets the twist value. + // The default is 0.0. + //------------------------------------------------------------------------- + void setTwist( F32 twist ); + + //------------------------------------------------------------------------- + // solve() + // This is the "work" function. + // When called, the rotations of jointA and jointB will be modified + // such that jointC attempts to reach jointGoal. + //------------------------------------------------------------------------- + void solve(); +}; + +#endif // LL_LLJOINTSOLVERRP3_H + diff --git a/indra/llcharacter/lljointstate.h b/indra/llcharacter/lljointstate.h index 7c4ded36ac..1b17400200 100644 --- a/indra/llcharacter/lljointstate.h +++ b/indra/llcharacter/lljointstate.h @@ -1,124 +1,124 @@ -/**
- * @file lljointstate.h
- * @brief Implementation of LLJointState class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLJOINTSTATE_H
-#define LL_LLJOINTSTATE_H
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "lljoint.h"
-#include "llrefcount.h"
-
-//-----------------------------------------------------------------------------
-// class LLJointState
-//-----------------------------------------------------------------------------
-class LLJointState : public LLRefCount
-{
-public:
- enum BlendPhase
- {
- INACTIVE,
- EASE_IN,
- ACTIVE,
- EASE_OUT
- };
-protected:
- // associated joint
- LLJoint *mJoint;
-
- // indicates which members are used
- U32 mUsage;
-
- // indicates weighted effect of this joint
- F32 mWeight;
-
- // transformation members
- LLVector3 mPosition; // position relative to parent joint
- LLQuaternion mRotation; // joint rotation relative to parent joint
- LLVector3 mScale; // scale relative to rotated frame
- LLJoint::JointPriority mPriority; // how important this joint state is relative to others
-public:
- // Constructor
- LLJointState()
- : mUsage(0)
- , mJoint(NULL)
- , mWeight(0.f)
- , mPriority(LLJoint::USE_MOTION_PRIORITY)
- {}
-
- LLJointState(LLJoint* joint)
- : mUsage(0)
- , mJoint(joint)
- , mWeight(0.f)
- , mPriority(LLJoint::USE_MOTION_PRIORITY)
- {}
-
- // joint that this state is applied to
- LLJoint* getJoint() { return mJoint; }
- const LLJoint* getJoint() const { return mJoint; }
- bool setJoint( LLJoint *joint ) { mJoint = joint; return mJoint != NULL; }
-
- // transform type (bitwise flags can be combined)
- // Note that these are set automatically when various
- // member setPos/setRot/setScale functions are called.
- enum Usage
- {
- POS = 1,
- ROT = 2,
- SCALE = 4,
- };
- U32 getUsage() const { return mUsage; }
- void setUsage( U32 usage ) { mUsage = usage; }
- F32 getWeight() const { return mWeight; }
- void setWeight( F32 weight ) { mWeight = weight; }
-
- // get/set position
- const LLVector3& getPosition() const { return mPosition; }
- void setPosition( const LLVector3& pos ) { llassert(mUsage & POS); mPosition = pos; }
-
- // get/set rotation
- const LLQuaternion& getRotation() const { return mRotation; }
- void setRotation( const LLQuaternion& rot ) { llassert(mUsage & ROT); mRotation = rot; }
-
- // get/set scale
- const LLVector3& getScale() const { return mScale; }
- void setScale( const LLVector3& scale ) { llassert(mUsage & SCALE); mScale = scale; }
-
- // get/set priority
- LLJoint::JointPriority getPriority() const { return mPriority; }
- void setPriority( LLJoint::JointPriority priority ) { mPriority = priority; }
-
-protected:
- // Destructor
- virtual ~LLJointState()
- {
- }
-
-};
-
-#endif // LL_LLJOINTSTATE_H
-
+/** + * @file lljointstate.h + * @brief Implementation of LLJointState class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLJOINTSTATE_H +#define LL_LLJOINTSTATE_H + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "lljoint.h" +#include "llrefcount.h" + +//----------------------------------------------------------------------------- +// class LLJointState +//----------------------------------------------------------------------------- +class LLJointState : public LLRefCount +{ +public: + enum BlendPhase + { + INACTIVE, + EASE_IN, + ACTIVE, + EASE_OUT + }; +protected: + // associated joint + LLJoint *mJoint; + + // indicates which members are used + U32 mUsage; + + // indicates weighted effect of this joint + F32 mWeight; + + // transformation members + LLVector3 mPosition; // position relative to parent joint + LLQuaternion mRotation; // joint rotation relative to parent joint + LLVector3 mScale; // scale relative to rotated frame + LLJoint::JointPriority mPriority; // how important this joint state is relative to others +public: + // Constructor + LLJointState() + : mUsage(0) + , mJoint(NULL) + , mWeight(0.f) + , mPriority(LLJoint::USE_MOTION_PRIORITY) + {} + + LLJointState(LLJoint* joint) + : mUsage(0) + , mJoint(joint) + , mWeight(0.f) + , mPriority(LLJoint::USE_MOTION_PRIORITY) + {} + + // joint that this state is applied to + LLJoint* getJoint() { return mJoint; } + const LLJoint* getJoint() const { return mJoint; } + bool setJoint( LLJoint *joint ) { mJoint = joint; return mJoint != NULL; } + + // transform type (bitwise flags can be combined) + // Note that these are set automatically when various + // member setPos/setRot/setScale functions are called. + enum Usage + { + POS = 1, + ROT = 2, + SCALE = 4, + }; + U32 getUsage() const { return mUsage; } + void setUsage( U32 usage ) { mUsage = usage; } + F32 getWeight() const { return mWeight; } + void setWeight( F32 weight ) { mWeight = weight; } + + // get/set position + const LLVector3& getPosition() const { return mPosition; } + void setPosition( const LLVector3& pos ) { llassert(mUsage & POS); mPosition = pos; } + + // get/set rotation + const LLQuaternion& getRotation() const { return mRotation; } + void setRotation( const LLQuaternion& rot ) { llassert(mUsage & ROT); mRotation = rot; } + + // get/set scale + const LLVector3& getScale() const { return mScale; } + void setScale( const LLVector3& scale ) { llassert(mUsage & SCALE); mScale = scale; } + + // get/set priority + LLJoint::JointPriority getPriority() const { return mPriority; } + void setPriority( LLJoint::JointPriority priority ) { mPriority = priority; } + +protected: + // Destructor + virtual ~LLJointState() + { + } + +}; + +#endif // LL_LLJOINTSTATE_H + diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp index 58fd99bc5c..82ffc87843 100644 --- a/indra/llcharacter/llkeyframefallmotion.cpp +++ b/indra/llcharacter/llkeyframefallmotion.cpp @@ -1,150 +1,150 @@ -/**
- * @file llkeyframefallmotion.cpp
- * @brief Implementation of LLKeyframeFallMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llkeyframefallmotion.h"
-#include "llcharacter.h"
-#include "m3math.h"
-
-//-----------------------------------------------------------------------------
-// Macros
-//-----------------------------------------------------------------------------
-#define GO_TO_KEY_POSE 1
-#define MIN_TRACK_SPEED 0.01f
-
-//-----------------------------------------------------------------------------
-// LLKeyframeFallMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id)
-{
- mVelocityZ = 0.f;
- mCharacter = NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLKeyframeFallMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLKeyframeFallMotion::~LLKeyframeFallMotion()
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// LLKeyframeFallMotion::onInitialize()
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLKeyframeFallMotion::onInitialize(LLCharacter *character)
-{
- // save character pointer for later use
- mCharacter = character;
-
- // load keyframe data, setup pose and joint states
- LLMotion::LLMotionInitStatus result = LLKeyframeMotion::onInitialize(character);
-
- if (result != LLMotion::STATUS_SUCCESS)
- {
- return result;
- }
-
- for (U32 jm=0; jm<mJointMotionList->getNumJointMotions(); jm++)
- {
- if (!mJointStates[jm]->getJoint())
- continue;
- if (mJointStates[jm]->getJoint()->getName() == std::string("mPelvis"))
- {
- mPelvisState = mJointStates[jm];
- }
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeFallMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeFallMotion::onActivate()
-{
- LLVector3 ground_pos;
- LLVector3 ground_normal;
- LLQuaternion inverse_pelvis_rot;
- LLVector3 fwd_axis(1.f, 0.f, 0.f);
-
- mVelocityZ = -mCharacter->getCharacterVelocity().mV[VZ];
- mCharacter->getGround( mCharacter->getCharacterPosition(), ground_pos, ground_normal);
- ground_normal.normVec();
-
- inverse_pelvis_rot = mCharacter->getCharacterRotation();
- inverse_pelvis_rot.transQuat();
-
- // find ground normal in pelvis space
- ground_normal = ground_normal * inverse_pelvis_rot;
-
- // calculate new foward axis
- fwd_axis = fwd_axis - (ground_normal * (ground_normal * fwd_axis));
- fwd_axis.normVec();
- mRotationToGroundNormal = LLQuaternion(fwd_axis, ground_normal % fwd_axis, ground_normal);
-
- return LLKeyframeMotion::onActivate();
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeFallMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- bool result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
- F32 slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
-
- if (mPelvisState.notNull())
- {
- mPelvisState->setRotation(mPelvisState->getRotation() * slerp(slerp_amt, mRotationToGroundNormal, LLQuaternion()));
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeFallMotion::getEaseInDuration()
-//-----------------------------------------------------------------------------
-F32 LLKeyframeFallMotion::getEaseInDuration()
-{
- if (mVelocityZ == 0.f)
- {
- // we've already hit the ground
- return 0.4f;
- }
-
- return mCharacter->getPreferredPelvisHeight() / mVelocityZ;
-}
-
-// End
+/** + * @file llkeyframefallmotion.cpp + * @brief Implementation of LLKeyframeFallMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llkeyframefallmotion.h" +#include "llcharacter.h" +#include "m3math.h" + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- +#define GO_TO_KEY_POSE 1 +#define MIN_TRACK_SPEED 0.01f + +//----------------------------------------------------------------------------- +// LLKeyframeFallMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id) +{ + mVelocityZ = 0.f; + mCharacter = NULL; +} + + +//----------------------------------------------------------------------------- +// ~LLKeyframeFallMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLKeyframeFallMotion::~LLKeyframeFallMotion() +{ +} + + +//----------------------------------------------------------------------------- +// LLKeyframeFallMotion::onInitialize() +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLKeyframeFallMotion::onInitialize(LLCharacter *character) +{ + // save character pointer for later use + mCharacter = character; + + // load keyframe data, setup pose and joint states + LLMotion::LLMotionInitStatus result = LLKeyframeMotion::onInitialize(character); + + if (result != LLMotion::STATUS_SUCCESS) + { + return result; + } + + for (U32 jm=0; jm<mJointMotionList->getNumJointMotions(); jm++) + { + if (!mJointStates[jm]->getJoint()) + continue; + if (mJointStates[jm]->getJoint()->getName() == std::string("mPelvis")) + { + mPelvisState = mJointStates[jm]; + } + } + + return result; +} + +//----------------------------------------------------------------------------- +// LLKeyframeFallMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLKeyframeFallMotion::onActivate() +{ + LLVector3 ground_pos; + LLVector3 ground_normal; + LLQuaternion inverse_pelvis_rot; + LLVector3 fwd_axis(1.f, 0.f, 0.f); + + mVelocityZ = -mCharacter->getCharacterVelocity().mV[VZ]; + mCharacter->getGround( mCharacter->getCharacterPosition(), ground_pos, ground_normal); + ground_normal.normVec(); + + inverse_pelvis_rot = mCharacter->getCharacterRotation(); + inverse_pelvis_rot.transQuat(); + + // find ground normal in pelvis space + ground_normal = ground_normal * inverse_pelvis_rot; + + // calculate new foward axis + fwd_axis = fwd_axis - (ground_normal * (ground_normal * fwd_axis)); + fwd_axis.normVec(); + mRotationToGroundNormal = LLQuaternion(fwd_axis, ground_normal % fwd_axis, ground_normal); + + return LLKeyframeMotion::onActivate(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeFallMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + bool result = LLKeyframeMotion::onUpdate(activeTime, joint_mask); + F32 slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f); + + if (mPelvisState.notNull()) + { + mPelvisState->setRotation(mPelvisState->getRotation() * slerp(slerp_amt, mRotationToGroundNormal, LLQuaternion())); + } + + return result; +} + +//----------------------------------------------------------------------------- +// LLKeyframeFallMotion::getEaseInDuration() +//----------------------------------------------------------------------------- +F32 LLKeyframeFallMotion::getEaseInDuration() +{ + if (mVelocityZ == 0.f) + { + // we've already hit the ground + return 0.4f; + } + + return mCharacter->getPreferredPelvisHeight() / mVelocityZ; +} + +// End diff --git a/indra/llcharacter/llkeyframefallmotion.h b/indra/llcharacter/llkeyframefallmotion.h index e0a212bcc8..8049aff328 100644 --- a/indra/llcharacter/llkeyframefallmotion.h +++ b/indra/llcharacter/llkeyframefallmotion.h @@ -1,78 +1,78 @@ -/**
- * @file llkeyframefallmotion.h
- * @brief Implementation of LLKeframeWalkMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLKeyframeFallMotion_H
-#define LL_LLKeyframeFallMotion_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llkeyframemotion.h"
-#include "llcharacter.h"
-
-//-----------------------------------------------------------------------------
-// class LLKeyframeFallMotion
-//-----------------------------------------------------------------------------
-class LLKeyframeFallMotion :
- public LLKeyframeMotion
-{
-public:
- // Constructor
- LLKeyframeFallMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLKeyframeFallMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
- virtual bool onActivate();
- virtual F32 getEaseInDuration();
- virtual bool onUpdate(F32 activeTime, U8* joint_mask);
-
-protected:
- //-------------------------------------------------------------------------
- // Member Data
- //-------------------------------------------------------------------------
- LLCharacter* mCharacter;
- F32 mVelocityZ;
- LLPointer<LLJointState> mPelvisState;
- LLQuaternion mRotationToGroundNormal;
-};
-
-#endif // LL_LLKeyframeFallMotion_H
-
+/** + * @file llkeyframefallmotion.h + * @brief Implementation of LLKeframeWalkMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLKeyframeFallMotion_H +#define LL_LLKeyframeFallMotion_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llkeyframemotion.h" +#include "llcharacter.h" + +//----------------------------------------------------------------------------- +// class LLKeyframeFallMotion +//----------------------------------------------------------------------------- +class LLKeyframeFallMotion : + public LLKeyframeMotion +{ +public: + // Constructor + LLKeyframeFallMotion(const LLUUID &id); + + // Destructor + virtual ~LLKeyframeFallMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + virtual bool onActivate(); + virtual F32 getEaseInDuration(); + virtual bool onUpdate(F32 activeTime, U8* joint_mask); + +protected: + //------------------------------------------------------------------------- + // Member Data + //------------------------------------------------------------------------- + LLCharacter* mCharacter; + F32 mVelocityZ; + LLPointer<LLJointState> mPelvisState; + LLQuaternion mRotationToGroundNormal; +}; + +#endif // LL_LLKeyframeFallMotion_H + diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 4eb0bc4410..99ee3198d6 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -1,2584 +1,2584 @@ -/**
- * @file llkeyframemotion.cpp
- * @brief Implementation of LLKeyframeMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llmath.h"
-#include "llanimationstates.h"
-#include "llassetstorage.h"
-#include "lldatapacker.h"
-#include "llcharacter.h"
-#include "llcriticaldamp.h"
-#include "lldir.h"
-#include "llendianswizzle.h"
-#include "llkeyframemotion.h"
-#include "llquantize.h"
-#include "m3math.h"
-#include "message.h"
-#include "llfilesystem.h"
-
-//-----------------------------------------------------------------------------
-// Static Definitions
-//-----------------------------------------------------------------------------
-LLKeyframeDataCache::keyframe_data_map_t LLKeyframeDataCache::sKeyframeDataMap;
-
-//-----------------------------------------------------------------------------
-// Globals
-//-----------------------------------------------------------------------------
-static F32 JOINT_LENGTH_K = 0.7f;
-static S32 MAX_ITERATIONS = 20;
-static S32 MIN_ITERATIONS = 1;
-static S32 MIN_ITERATION_COUNT = 2;
-static F32 MAX_PIXEL_AREA_CONSTRAINTS = 80000.f;
-static F32 MIN_PIXEL_AREA_CONSTRAINTS = 1000.f;
-static F32 MIN_ACCELERATION_SQUARED = 0.0005f * 0.0005f;
-
-static F32 MAX_CONSTRAINTS = 10;
-
-//-----------------------------------------------------------------------------
-// JointMotionList
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::JointMotionList::JointMotionList()
- : mDuration(0.f),
- mLoop(false),
- mLoopInPoint(0.f),
- mLoopOutPoint(0.f),
- mEaseInDuration(0.f),
- mEaseOutDuration(0.f),
- mBasePriority(LLJoint::LOW_PRIORITY),
- mHandPose(LLHandMotion::HAND_POSE_SPREAD),
- mMaxPriority(LLJoint::LOW_PRIORITY)
-{
-}
-
-LLKeyframeMotion::JointMotionList::~JointMotionList()
-{
- for_each(mConstraints.begin(), mConstraints.end(), DeletePointer());
- mConstraints.clear();
- for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer());
- mJointMotionArray.clear();
-}
-
-U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo()
-{
- S32 total_size = sizeof(JointMotionList);
-
- for (U32 i = 0; i < getNumJointMotions(); i++)
- {
- LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i];
-
- LL_INFOS() << "\tJoint " << joint_motion_p->mJointName << LL_ENDL;
- if (joint_motion_p->mUsage & LLJointState::SCALE)
- {
- LL_INFOS() << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
- << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << LL_ENDL;
-
- total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey);
- }
- if (joint_motion_p->mUsage & LLJointState::ROT)
- {
- LL_INFOS() << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
- << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << LL_ENDL;
-
- total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey);
- }
- if (joint_motion_p->mUsage & LLJointState::POS)
- {
- LL_INFOS() << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
- << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << LL_ENDL;
-
- total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey);
- }
- }
- LL_INFOS() << "Size: " << total_size << " bytes" << LL_ENDL;
-
- return total_size;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// ****Curve classes
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-
-//-----------------------------------------------------------------------------
-// ScaleCurve::ScaleCurve()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::ScaleCurve::ScaleCurve()
-{
- mInterpolationType = LLKeyframeMotion::IT_LINEAR;
- mNumKeys = 0;
-}
-
-//-----------------------------------------------------------------------------
-// ScaleCurve::~ScaleCurve()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::ScaleCurve::~ScaleCurve()
-{
- mKeys.clear();
- mNumKeys = 0;
-}
-
-//-----------------------------------------------------------------------------
-// getValue()
-//-----------------------------------------------------------------------------
-LLVector3 LLKeyframeMotion::ScaleCurve::getValue(F32 time, F32 duration)
-{
- LLVector3 value;
-
- if (mKeys.empty())
- {
- value.clearVec();
- return value;
- }
-
- key_map_t::iterator right = mKeys.lower_bound(time);
- if (right == mKeys.end())
- {
- // Past last key
- --right;
- value = right->second.mScale;
- }
- else if (right == mKeys.begin() || right->first == time)
- {
- // Before first key or exactly on a key
- value = right->second.mScale;
- }
- else
- {
- // Between two keys
- key_map_t::iterator left = right; --left;
- F32 index_before = left->first;
- F32 index_after = right->first;
- ScaleKey& scale_before = left->second;
- ScaleKey& scale_after = right->second;
- if (right == mKeys.end())
- {
- scale_after = mLoopInKey;
- index_after = duration;
- }
-
- F32 u = (time - index_before) / (index_after - index_before);
- value = interp(u, scale_before, scale_after);
- }
- return value;
-}
-
-//-----------------------------------------------------------------------------
-// interp()
-//-----------------------------------------------------------------------------
-LLVector3 LLKeyframeMotion::ScaleCurve::interp(F32 u, ScaleKey& before, ScaleKey& after)
-{
- switch (mInterpolationType)
- {
- case IT_STEP:
- return before.mScale;
-
- default:
- case IT_LINEAR:
- case IT_SPLINE:
- return lerp(before.mScale, after.mScale, u);
- }
-}
-
-//-----------------------------------------------------------------------------
-// RotationCurve::RotationCurve()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::RotationCurve::RotationCurve()
-{
- mInterpolationType = LLKeyframeMotion::IT_LINEAR;
- mNumKeys = 0;
-}
-
-//-----------------------------------------------------------------------------
-// RotationCurve::~RotationCurve()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::RotationCurve::~RotationCurve()
-{
- mKeys.clear();
- mNumKeys = 0;
-}
-
-//-----------------------------------------------------------------------------
-// RotationCurve::getValue()
-//-----------------------------------------------------------------------------
-LLQuaternion LLKeyframeMotion::RotationCurve::getValue(F32 time, F32 duration)
-{
- LLQuaternion value;
-
- if (mKeys.empty())
- {
- value = LLQuaternion::DEFAULT;
- return value;
- }
-
- key_map_t::iterator right = mKeys.lower_bound(time);
- if (right == mKeys.end())
- {
- // Past last key
- --right;
- value = right->second.mRotation;
- }
- else if (right == mKeys.begin() || right->first == time)
- {
- // Before first key or exactly on a key
- value = right->second.mRotation;
- }
- else
- {
- // Between two keys
- key_map_t::iterator left = right; --left;
- F32 index_before = left->first;
- F32 index_after = right->first;
- RotationKey& rot_before = left->second;
- RotationKey& rot_after = right->second;
- if (right == mKeys.end())
- {
- rot_after = mLoopInKey;
- index_after = duration;
- }
-
- F32 u = (time - index_before) / (index_after - index_before);
- value = interp(u, rot_before, rot_after);
- }
- return value;
-}
-
-//-----------------------------------------------------------------------------
-// interp()
-//-----------------------------------------------------------------------------
-LLQuaternion LLKeyframeMotion::RotationCurve::interp(F32 u, RotationKey& before, RotationKey& after)
-{
- switch (mInterpolationType)
- {
- case IT_STEP:
- return before.mRotation;
-
- default:
- case IT_LINEAR:
- case IT_SPLINE:
- return nlerp(u, before.mRotation, after.mRotation);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// PositionCurve::PositionCurve()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::PositionCurve::PositionCurve()
-{
- mInterpolationType = LLKeyframeMotion::IT_LINEAR;
- mNumKeys = 0;
-}
-
-//-----------------------------------------------------------------------------
-// PositionCurve::~PositionCurve()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::PositionCurve::~PositionCurve()
-{
- mKeys.clear();
- mNumKeys = 0;
-}
-
-//-----------------------------------------------------------------------------
-// PositionCurve::getValue()
-//-----------------------------------------------------------------------------
-LLVector3 LLKeyframeMotion::PositionCurve::getValue(F32 time, F32 duration)
-{
- LLVector3 value;
-
- if (mKeys.empty())
- {
- value.clearVec();
- return value;
- }
-
- key_map_t::iterator right = mKeys.lower_bound(time);
- if (right == mKeys.end())
- {
- // Past last key
- --right;
- value = right->second.mPosition;
- }
- else if (right == mKeys.begin() || right->first == time)
- {
- // Before first key or exactly on a key
- value = right->second.mPosition;
- }
- else
- {
- // Between two keys
- key_map_t::iterator left = right; --left;
- F32 index_before = left->first;
- F32 index_after = right->first;
- PositionKey& pos_before = left->second;
- PositionKey& pos_after = right->second;
- if (right == mKeys.end())
- {
- pos_after = mLoopInKey;
- index_after = duration;
- }
-
- F32 u = (time - index_before) / (index_after - index_before);
- value = interp(u, pos_before, pos_after);
- }
-
- llassert(value.isFinite());
-
- return value;
-}
-
-//-----------------------------------------------------------------------------
-// interp()
-//-----------------------------------------------------------------------------
-LLVector3 LLKeyframeMotion::PositionCurve::interp(F32 u, PositionKey& before, PositionKey& after)
-{
- switch (mInterpolationType)
- {
- case IT_STEP:
- return before.mPosition;
- default:
- case IT_LINEAR:
- case IT_SPLINE:
- return lerp(before.mPosition, after.mPosition, u);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// JointMotion class
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// JointMotion::update()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, F32 duration)
-{
- // this value being 0 is the cause of https://jira.lindenlab.com/browse/SL-22678 but I haven't
- // managed to get a stack to see how it got here. Testing for 0 here will stop the crash.
- if ( joint_state == NULL )
- {
- return;
- }
-
- U32 usage = joint_state->getUsage();
-
- //-------------------------------------------------------------------------
- // update scale component of joint state
- //-------------------------------------------------------------------------
- if ((usage & LLJointState::SCALE) && mScaleCurve.mNumKeys)
- {
- joint_state->setScale( mScaleCurve.getValue( time, duration ) );
- }
-
- //-------------------------------------------------------------------------
- // update rotation component of joint state
- //-------------------------------------------------------------------------
- if ((usage & LLJointState::ROT) && mRotationCurve.mNumKeys)
- {
- joint_state->setRotation( mRotationCurve.getValue( time, duration ) );
- }
-
- //-------------------------------------------------------------------------
- // update position component of joint state
- //-------------------------------------------------------------------------
- if ((usage & LLJointState::POS) && mPositionCurve.mNumKeys)
- {
- joint_state->setPosition( mPositionCurve.getValue( time, duration ) );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLKeyframeMotion class
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id)
- : LLMotion(id),
- mJointMotionList(NULL),
- mPelvisp(NULL),
- mLastSkeletonSerialNum(0),
- mLastUpdateTime(0.f),
- mLastLoopedTime(0.f),
- mAssetStatus(ASSET_UNDEFINED)
-{
-
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLKeyframeMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::~LLKeyframeMotion()
-{
- for_each(mConstraints.begin(), mConstraints.end(), DeletePointer());
- mConstraints.clear();
-}
-
-//-----------------------------------------------------------------------------
-// create()
-//-----------------------------------------------------------------------------
-LLMotion *LLKeyframeMotion::create(const LLUUID &id)
-{
- return new LLKeyframeMotion(id);
-}
-
-//-----------------------------------------------------------------------------
-// getJointState()
-//-----------------------------------------------------------------------------
-LLPointer<LLJointState>& LLKeyframeMotion::getJointState(U32 index)
-{
- llassert_always (index < mJointStates.size());
- return mJointStates[index];
-}
-
-//-----------------------------------------------------------------------------
-// getJoint()
-//-----------------------------------------------------------------------------
-LLJoint* LLKeyframeMotion::getJoint(U32 index)
-{
- llassert_always (index < mJointStates.size());
- LLJoint* joint = mJointStates[index]->getJoint();
-
- //Commented out 06-28-11 by Aura.
- //llassert_always (joint);
- return joint;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotion::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- LLUUID* character_id;
-
- // asset already loaded?
- switch(mAssetStatus)
- {
- case ASSET_NEEDS_FETCH:
- // request asset
- mAssetStatus = ASSET_FETCHED;
-
- if (mID.notNull())
- {
- LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL;
- character_id = new LLUUID(mCharacter->getID());
- gAssetStorage->getAssetData(mID,
- LLAssetType::AT_ANIMATION,
- onLoadComplete,
- (void*)character_id,
- false);
- }
- else
- {
- LL_INFOS("Animation") << "Attempted to fetch animation '" << mName << "' with null id"
- << " for character " << mCharacter->getID() << LL_ENDL;
- }
-
- return STATUS_HOLD;
- case ASSET_FETCHED:
- return STATUS_HOLD;
- case ASSET_FETCH_FAILED:
- return STATUS_FAILURE;
- case ASSET_LOADED:
- return STATUS_SUCCESS;
- default:
- // we don't know what state the asset is in yet, so keep going
- // check keyframe cache first then file cache then asset request
- break;
- }
-
- LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
-
- if(joint_motion_list)
- {
- // motion already existed in cache, so grab it
- mJointMotionList = joint_motion_list;
-
- mJointStates.reserve(mJointMotionList->getNumJointMotions());
-
- // don't forget to allocate joint states
- // set up joint states to point to character joints
- for(U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
- {
- JointMotion* joint_motion = mJointMotionList->getJointMotion(i);
- if (LLJoint *joint = mCharacter->getJoint(joint_motion->mJointName))
- {
- LLPointer<LLJointState> joint_state = new LLJointState;
- mJointStates.push_back(joint_state);
- joint_state->setJoint(joint);
- joint_state->setUsage(joint_motion->mUsage);
- joint_state->setPriority(joint_motion->mPriority);
- }
- else
- {
- // add dummy joint state with no associated joint
- mJointStates.push_back(new LLJointState);
- }
- }
- mAssetStatus = ASSET_LOADED;
- setupPose();
- return STATUS_SUCCESS;
- }
-
- //-------------------------------------------------------------------------
- // Load named file by concatenating the character prefix with the motion name.
- // Load data into a buffer to be parsed.
- //-------------------------------------------------------------------------
- U8 *anim_data;
- S32 anim_file_size;
-
- bool success = false;
- LLFileSystem* anim_file = new LLFileSystem(mID, LLAssetType::AT_ANIMATION);
- if (!anim_file || !anim_file->getSize())
- {
- delete anim_file;
- anim_file = NULL;
-
- // request asset over network on next call to load
- mAssetStatus = ASSET_NEEDS_FETCH;
-
- return STATUS_HOLD;
- }
- else
- {
- anim_file_size = anim_file->getSize();
- anim_data = new(std::nothrow) U8[anim_file_size];
- if (anim_data)
- {
- success = anim_file->read(anim_data, anim_file_size); /*Flawfinder: ignore*/
- }
- else
- {
- LL_WARNS() << "Failed to allocate buffer: " << anim_file_size << mID << LL_ENDL;
- }
- delete anim_file;
- anim_file = NULL;
- }
-
- if (!success)
- {
- LL_WARNS() << "Can't open animation file " << mID << LL_ENDL;
- mAssetStatus = ASSET_FETCH_FAILED;
- return STATUS_FAILURE;
- }
-
- LL_DEBUGS() << "Loading keyframe data for: " << getName() << ":" << getID() << " (" << anim_file_size << " bytes)" << LL_ENDL;
-
- LLDataPackerBinaryBuffer dp(anim_data, anim_file_size);
-
- if (!deserialize(dp, getID()))
- {
- LL_WARNS() << "Failed to decode asset for animation " << getName() << ":" << getID() << LL_ENDL;
- mAssetStatus = ASSET_FETCH_FAILED;
- return STATUS_FAILURE;
- }
-
- delete []anim_data;
-
- mAssetStatus = ASSET_LOADED;
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// setupPose()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotion::setupPose()
-{
- // add all valid joint states to the pose
- for (U32 jm=0; jm<mJointMotionList->getNumJointMotions(); jm++)
- {
- LLPointer<LLJointState> joint_state = getJointState(jm);
- if ( joint_state->getJoint() )
- {
- addJointState( joint_state );
- }
- }
-
- // initialize joint constraints
- for (JointConstraintSharedData* shared_constraintp : mJointMotionList->mConstraints)
- {
- JointConstraint* constraintp = new JointConstraint(shared_constraintp);
- initializeConstraint(constraintp);
- mConstraints.push_front(constraintp);
- }
-
- if (mJointMotionList->mConstraints.size())
- {
- mPelvisp = mCharacter->getJoint("mPelvis");
- if (!mPelvisp)
- {
- return false;
- }
- }
-
- // setup loop keys
- setLoopIn(mJointMotionList->mLoopInPoint);
- setLoopOut(mJointMotionList->mLoopOutPoint);
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotion::onActivate()
-{
- // If the keyframe anim has an associated emote, trigger it.
- if (mJointMotionList->mEmoteID.notNull())
- {
- // don't start emote if already active to avoid recursion
- if (!mCharacter->isMotionActive(mJointMotionList->mEmoteID))
- {
- mCharacter->startMotion(mJointMotionList->mEmoteID);
- }
- }
-
- mLastLoopedTime = 0.f;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- // llassert(time >= 0.f); // This will fire
- time = llmax(0.f, time);
-
- if (mJointMotionList->mLoop)
- {
- if (mJointMotionList->mDuration == 0.0f)
- {
- time = 0.f;
- mLastLoopedTime = 0.0f;
- }
- else if (mStopped)
- {
- mLastLoopedTime = llmin(mJointMotionList->mDuration, mLastLoopedTime + time - mLastUpdateTime);
- }
- else if (time > mJointMotionList->mLoopOutPoint)
- {
- if ((mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint) == 0.f)
- {
- mLastLoopedTime = mJointMotionList->mLoopOutPoint;
- }
- else
- {
- mLastLoopedTime = mJointMotionList->mLoopInPoint +
- fmod(time - mJointMotionList->mLoopOutPoint,
- mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
- }
- }
- else
- {
- mLastLoopedTime = time;
- }
- }
- else
- {
- mLastLoopedTime = time;
- }
-
- applyKeyframes(mLastLoopedTime);
-
- applyConstraints(mLastLoopedTime, joint_mask);
-
- mLastUpdateTime = time;
-
- return mLastLoopedTime <= mJointMotionList->mDuration;
-}
-
-//-----------------------------------------------------------------------------
-// applyKeyframes()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::applyKeyframes(F32 time)
-{
- llassert_always (mJointMotionList->getNumJointMotions() <= mJointStates.size());
- for (U32 i=0; i<mJointMotionList->getNumJointMotions(); i++)
- {
- mJointMotionList->getJointMotion(i)->update(mJointStates[i],
- time,
- mJointMotionList->mDuration );
- }
-
- LLJoint::JointPriority* pose_priority = (LLJoint::JointPriority* )mCharacter->getAnimationData("Hand Pose Priority");
- if (pose_priority)
- {
- if (mJointMotionList->mMaxPriority >= *pose_priority)
- {
- mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose);
- mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority);
- }
- }
- else
- {
- mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose);
- mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority);
- }
-}
-
-//-----------------------------------------------------------------------------
-// applyConstraints()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::applyConstraints(F32 time, U8* joint_mask)
-{
- //TODO: investigate replacing spring simulation with critically damped motion
-
- // re-init constraints if skeleton has changed
- if (mCharacter->getSkeletonSerialNum() != mLastSkeletonSerialNum)
- {
- mLastSkeletonSerialNum = mCharacter->getSkeletonSerialNum();
- for (JointConstraint* constraintp : mConstraints)
- {
- initializeConstraint(constraintp);
- }
- }
-
- // apply constraints
- for (JointConstraint* constraintp : mConstraints)
- {
- applyConstraint(constraintp, time, joint_mask);
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::onDeactivate()
-{
- for (JointConstraint* constraintp : mConstraints)
- {
- deactivateConstraint(constraintp);
- }
-}
-
-//-----------------------------------------------------------------------------
-// setStopTime()
-//-----------------------------------------------------------------------------
-// time is in seconds since character creation
-void LLKeyframeMotion::setStopTime(F32 time)
-{
- LLMotion::setStopTime(time);
-
- if (mJointMotionList->mLoop && mJointMotionList->mLoopOutPoint != mJointMotionList->mDuration)
- {
- F32 start_loop_time = mActivationTimestamp + mJointMotionList->mLoopInPoint;
- F32 loop_fraction_time;
- if (mJointMotionList->mLoopOutPoint == mJointMotionList->mLoopInPoint)
- {
- loop_fraction_time = 0.f;
- }
- else
- {
- loop_fraction_time = fmod(time - start_loop_time,
- mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
- }
- mStopTimestamp = llmax(time,
- (time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration());
- }
-}
-
-//-----------------------------------------------------------------------------
-// initializeConstraint()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
-{
- JointConstraintSharedData *shared_data = constraint->mSharedData;
-
- S32 joint_num;
- LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
- LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
- if ( !cur_joint )
- {
- return;
- }
-
- F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
-
- constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
-
- // grab joint lengths
- for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
- {
- cur_joint = getJointState(shared_data->mJointStateIndices[joint_num])->getJoint();
- if (!cur_joint)
- {
- return;
- }
- constraint->mJointLengths[joint_num] = dist_vec(cur_joint->getWorldPosition(), cur_joint->getParent()->getWorldPosition());
- constraint->mTotalLength += constraint->mJointLengths[joint_num];
- }
-
- // store fraction of total chain length so we know how to shear the entire chain towards the goal position
- for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
- {
- constraint->mJointLengthFractions[joint_num] = constraint->mJointLengths[joint_num] / constraint->mTotalLength;
- }
-
- // add last step in chain, from final joint to constraint position
- constraint->mTotalLength += source_pos_offset;
-
- constraint->mSourceVolume = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume);
- constraint->mTargetVolume = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume);
-}
-
-//-----------------------------------------------------------------------------
-// activateConstraint()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
-{
- JointConstraintSharedData *shared_data = constraint->mSharedData;
- constraint->mActive = true;
- S32 joint_num;
-
- // grab ground position if we need to
- if (shared_data->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND)
- {
- LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
- LLVector3 ground_pos_agent;
- mCharacter->getGround(source_pos, ground_pos_agent, constraint->mGroundNorm);
- constraint->mGroundPos = mCharacter->getPosGlobalFromAgent(ground_pos_agent + shared_data->mTargetConstraintOffset);
- }
-
- for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
- {
- LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
- if ( !cur_joint )
- {
- return;
- }
- constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
- }
-
- constraint->mWeight = 1.f;
-}
-
-//-----------------------------------------------------------------------------
-// deactivateConstraint()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::deactivateConstraint(JointConstraint *constraintp)
-{
- if (constraintp->mSourceVolume)
- {
- constraintp->mSourceVolume->mUpdateXform = false;
- }
-
- if (constraintp->mSharedData->mConstraintTargetType != CONSTRAINT_TARGET_TYPE_GROUND)
- {
- if (constraintp->mTargetVolume)
- {
- constraintp->mTargetVolume->mUpdateXform = false;
- }
- }
- constraintp->mActive = false;
-}
-
-//-----------------------------------------------------------------------------
-// applyConstraint()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8* joint_mask)
-{
- JointConstraintSharedData *shared_data = constraint->mSharedData;
- if (!shared_data) return;
-
- LLVector3 positions[MAX_CHAIN_LENGTH];
- const F32* joint_lengths = constraint->mJointLengths;
- LLVector3 velocities[MAX_CHAIN_LENGTH - 1];
- LLQuaternion old_rots[MAX_CHAIN_LENGTH];
- S32 joint_num;
-
- if (time < shared_data->mEaseInStartTime)
- {
- return;
- }
-
- if (time > shared_data->mEaseOutStopTime)
- {
- if (constraint->mActive)
- {
- deactivateConstraint(constraint);
- }
- return;
- }
-
- if (!constraint->mActive || time < shared_data->mEaseInStopTime)
- {
- activateConstraint(constraint);
- }
-
- LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
- if (! root_joint)
- {
- return;
- }
-
- LLVector3 root_pos = root_joint->getWorldPosition();
-// LLQuaternion root_rot =
- root_joint->getParent()->getWorldRotation();
-// LLQuaternion inv_root_rot = ~root_rot;
-
-// LLVector3 current_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
-
- //apply underlying keyframe animation to get nominal "kinematic" joint positions
- for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
- {
- LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
- if (!cur_joint)
- {
- return;
- }
-
- if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
- {
- // skip constraint
- return;
- }
- old_rots[joint_num] = cur_joint->getRotation();
- cur_joint->setRotation(getJointState(shared_data->mJointStateIndices[joint_num])->getRotation());
- }
-
-
- LLVector3 keyframe_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
- LLVector3 target_pos;
-
- switch(shared_data->mConstraintTargetType)
- {
- case CONSTRAINT_TARGET_TYPE_GROUND:
- target_pos = mCharacter->getPosAgentFromGlobal(constraint->mGroundPos);
-// LL_INFOS() << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
- break;
- case CONSTRAINT_TARGET_TYPE_BODY:
- target_pos = mCharacter->getVolumePos(shared_data->mTargetConstraintVolume, shared_data->mTargetConstraintOffset);
- break;
- default:
- break;
- }
-
- LLVector3 norm;
- LLJoint *source_jointp = NULL;
- LLJoint *target_jointp = NULL;
-
- if (shared_data->mConstraintType == CONSTRAINT_TYPE_PLANE)
- {
- switch(shared_data->mConstraintTargetType)
- {
- case CONSTRAINT_TARGET_TYPE_GROUND:
- norm = constraint->mGroundNorm;
- break;
- case CONSTRAINT_TARGET_TYPE_BODY:
- target_jointp = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume);
- if (target_jointp)
- {
- // *FIX: do proper normal calculation for stretched
- // spheres (inverse transpose)
- norm = target_pos - target_jointp->getWorldPosition();
- }
-
- if (norm.isExactlyZero())
- {
- source_jointp = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume);
- norm = -1.f * shared_data->mSourceConstraintOffset;
- if (source_jointp)
- {
- norm = norm * source_jointp->getWorldRotation();
- }
- }
- norm.normVec();
- break;
- default:
- norm.clearVec();
- break;
- }
-
- target_pos = keyframe_source_pos + (norm * ((target_pos - keyframe_source_pos) * norm));
- }
-
- if (constraint->mSharedData->mChainLength != 0 &&
- dist_vec_squared(root_pos, target_pos) * 0.95f > constraint->mTotalLength * constraint->mTotalLength)
- {
- constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 0.f, 0.1f);
- }
- else
- {
- constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 1.f, 0.3f);
- }
-
- F32 weight = constraint->mWeight * ((shared_data->mEaseOutStopTime == 0.f) ? 1.f :
- llmin(clamp_rescale(time, shared_data->mEaseInStartTime, shared_data->mEaseInStopTime, 0.f, 1.f),
- clamp_rescale(time, shared_data->mEaseOutStartTime, shared_data->mEaseOutStopTime, 1.f, 0.f)));
-
- LLVector3 source_to_target = target_pos - keyframe_source_pos;
-
- S32 max_iteration_count = ll_round(clamp_rescale(
- mCharacter->getPixelArea(),
- MAX_PIXEL_AREA_CONSTRAINTS,
- MIN_PIXEL_AREA_CONSTRAINTS,
- (F32)MAX_ITERATIONS,
- (F32)MIN_ITERATIONS));
-
- if (shared_data->mChainLength)
- {
- LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
-
- if (!end_joint)
- {
- return;
- }
-
- LLQuaternion end_rot = end_joint->getWorldRotation();
-
- // slam start and end of chain to the proper positions (rest of chain stays put)
- positions[0] = lerp(keyframe_source_pos, target_pos, weight);
- positions[shared_data->mChainLength] = root_pos;
-
- // grab keyframe-specified positions of joints
- for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
- {
- LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
-
- if (!cur_joint)
- {
- return;
- }
-
- LLVector3 kinematic_position = cur_joint->getWorldPosition() +
- (source_to_target * constraint->mJointLengthFractions[joint_num]);
-
- // convert intermediate joint positions to world coordinates
- positions[joint_num] = ( constraint->mPositions[joint_num] * mPelvisp->getWorldRotation()) + mPelvisp->getWorldPosition();
- F32 time_constant = 1.f / clamp_rescale(constraint->mFixupDistanceRMS, 0.f, 0.5f, 0.2f, 8.f);
-// LL_INFOS() << "Interpolant " << LLSmoothInterpolation::getInterpolant(time_constant, false) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
- positions[joint_num] = lerp(positions[joint_num], kinematic_position,
- LLSmoothInterpolation::getInterpolant(time_constant, false));
- }
-
- S32 iteration_count;
- for (iteration_count = 0; iteration_count < max_iteration_count; iteration_count++)
- {
- S32 num_joints_finished = 0;
- for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
- {
- // constraint to child
- LLVector3 acceleration = (positions[joint_num - 1] - positions[joint_num]) *
- (dist_vec(positions[joint_num], positions[joint_num - 1]) - joint_lengths[joint_num - 1]) * JOINT_LENGTH_K;
- // constraint to parent
- acceleration += (positions[joint_num + 1] - positions[joint_num]) *
- (dist_vec(positions[joint_num + 1], positions[joint_num]) - joint_lengths[joint_num]) * JOINT_LENGTH_K;
-
- if (acceleration.magVecSquared() < MIN_ACCELERATION_SQUARED)
- {
- num_joints_finished++;
- }
-
- velocities[joint_num - 1] = velocities[joint_num - 1] * 0.7f;
- positions[joint_num] += velocities[joint_num - 1] + (acceleration * 0.5f);
- velocities[joint_num - 1] += acceleration;
- }
-
- if ((iteration_count >= MIN_ITERATION_COUNT) &&
- (num_joints_finished == shared_data->mChainLength - 1))
- {
-// LL_INFOS() << iteration_count << " iterations on " <<
-// mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
- break;
- }
- }
-
- for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
- {
- LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
-
- if (!cur_joint)
- {
- return;
- }
- LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
- if (!child_joint)
- {
- return;
- }
-
- LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
-
- LLQuaternion cur_rot = cur_joint->getWorldRotation();
- LLQuaternion fixup_rot;
-
- LLVector3 target_at = positions[joint_num - 1] - positions[joint_num];
- LLVector3 current_at;
-
- // at bottom of chain, use point on collision volume, not joint position
- if (joint_num == 1)
- {
- current_at = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset) -
- cur_joint->getWorldPosition();
- }
- else
- {
- current_at = child_joint->getPosition() * cur_rot;
- }
- fixup_rot.shortestArc(current_at, target_at);
-
- LLQuaternion target_rot = cur_rot * fixup_rot;
- target_rot = target_rot * ~parent_rot;
-
- if (weight != 1.f)
- {
- LLQuaternion cur_rot = getJointState(shared_data->mJointStateIndices[joint_num])->getRotation();
- target_rot = nlerp(weight, cur_rot, target_rot);
- }
-
- getJointState(shared_data->mJointStateIndices[joint_num])->setRotation(target_rot);
- cur_joint->setRotation(target_rot);
- }
-
- LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
-
- if (weight == 1.f)
- {
- getJointState(shared_data->mJointStateIndices[0])->setRotation(end_local_rot);
- }
- else
- {
- LLQuaternion cur_rot = getJointState(shared_data->mJointStateIndices[0])->getRotation();
- getJointState(shared_data->mJointStateIndices[0])->setRotation(nlerp(weight, cur_rot, end_local_rot));
- }
-
- // save simulated positions in pelvis-space and calculate total fixup distance
- constraint->mFixupDistanceRMS = 0.f;
- F32 delta_time = llmax(0.02f, llabs(time - mLastUpdateTime));
- for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
- {
- LLVector3 new_pos = (positions[joint_num] - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
- constraint->mFixupDistanceRMS += dist_vec_squared(new_pos, constraint->mPositions[joint_num]) / delta_time;
- constraint->mPositions[joint_num] = new_pos;
- }
- constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
- constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
-
- //reset old joint rots
- for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
- {
- LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
- if (!cur_joint)
- {
- return;
- }
-
- cur_joint->setRotation(old_rots[joint_num]);
- }
- }
- // simple positional constraint (pelvis only)
- else if (getJointState(shared_data->mJointStateIndices[0])->getUsage() & LLJointState::POS)
- {
- LLVector3 delta = source_to_target * weight;
- LLPointer<LLJointState> current_joint_state = getJointState(shared_data->mJointStateIndices[0]);
- LLQuaternion parent_rot = current_joint_state->getJoint()->getParent()->getWorldRotation();
- delta = delta * ~parent_rot;
- current_joint_state->setPosition(current_joint_state->getJoint()->getPosition() + delta);
- }
-}
-
-//-----------------------------------------------------------------------------
-// deserialize()
-//
-// allow_invalid_joints should be true when handling existing content, to avoid breakage.
-// During upload, we should be more restrictive and reject such animations.
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints)
-{
- bool old_version = false;
- std::unique_ptr<LLKeyframeMotion::JointMotionList> joint_motion_list(new LLKeyframeMotion::JointMotionList);
-
- //-------------------------------------------------------------------------
- // get base priority
- //-------------------------------------------------------------------------
- S32 temp_priority;
- U16 version;
- U16 sub_version;
-
- // Amimation identifier for log messages
- auto asset = [&]() -> std::string
- {
- return asset_id.asString() + ", char " + mCharacter->getID().asString();
- };
-
- if (!dp.unpackU16(version, "version"))
- {
- LL_WARNS() << "can't read version number"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackU16(sub_version, "sub_version"))
- {
- LL_WARNS() << "can't read sub version number"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (version == 0 && sub_version == 1)
- {
- old_version = true;
- }
- else if (version != KEYFRAME_MOTION_VERSION || sub_version != KEYFRAME_MOTION_SUBVERSION)
- {
-#if LL_RELEASE
- LL_WARNS() << "Bad animation version " << version << "." << sub_version
- << " for animation " << asset() << LL_ENDL;
- return false;
-#else
- LL_ERRS() << "Bad animation version " << version << "." << sub_version
- << " for animation " << asset() << LL_ENDL;
-#endif
- }
-
- if (!dp.unpackS32(temp_priority, "base_priority"))
- {
- LL_WARNS() << "can't read animation base_priority"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- joint_motion_list->mBasePriority = (LLJoint::JointPriority) temp_priority;
-
- if (joint_motion_list->mBasePriority >= LLJoint::ADDITIVE_PRIORITY)
- {
- joint_motion_list->mBasePriority = (LLJoint::JointPriority)((S32)LLJoint::ADDITIVE_PRIORITY-1);
- joint_motion_list->mMaxPriority = joint_motion_list->mBasePriority;
- }
- else if (joint_motion_list->mBasePriority < LLJoint::USE_MOTION_PRIORITY)
- {
- LL_WARNS() << "bad animation base_priority " << joint_motion_list->mBasePriority
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- //-------------------------------------------------------------------------
- // get duration
- //-------------------------------------------------------------------------
- if (!dp.unpackF32(joint_motion_list->mDuration, "duration"))
- {
- LL_WARNS() << "can't read duration"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (joint_motion_list->mDuration > MAX_ANIM_DURATION ||
- !llfinite(joint_motion_list->mDuration))
- {
- LL_WARNS() << "invalid animation duration"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- //-------------------------------------------------------------------------
- // get emote (optional)
- //-------------------------------------------------------------------------
- if (!dp.unpackString(joint_motion_list->mEmoteName, "emote_name"))
- {
- LL_WARNS() << "can't read emote_name"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!joint_motion_list->mEmoteName.empty())
- {
- if (joint_motion_list->mEmoteName == mID.asString())
- {
- LL_WARNS() << "Malformed animation mEmoteName==mID"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- // "Closed_Mouth" is a very popular emote name we should ignore
- if (joint_motion_list->mEmoteName == "Closed_Mouth")
- {
- joint_motion_list->mEmoteName.clear();
- }
- else
- {
- joint_motion_list->mEmoteID = gAnimLibrary.stringToAnimState(joint_motion_list->mEmoteName);
- if (joint_motion_list->mEmoteID.isNull())
- {
- LL_WARNS() << "unknown emote_name '" << joint_motion_list->mEmoteName << "'"
- << " for animation " << asset() << LL_ENDL;
- joint_motion_list->mEmoteName.clear();
- }
- }
- }
-
- //-------------------------------------------------------------------------
- // get loop
- //-------------------------------------------------------------------------
- if (!dp.unpackF32(joint_motion_list->mLoopInPoint, "loop_in_point") ||
- !llfinite(joint_motion_list->mLoopInPoint))
- {
- LL_WARNS() << "can't read loop point"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackF32(joint_motion_list->mLoopOutPoint, "loop_out_point") ||
- !llfinite(joint_motion_list->mLoopOutPoint))
- {
- LL_WARNS() << "can't read loop point"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- S32 loop{ 0 };
- if (!dp.unpackS32(loop, "loop"))
- {
- LL_WARNS() << "can't read loop"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- joint_motion_list->mLoop = static_cast<bool>(loop);
-
- //SL-17206 hack to alter Female_land loop setting, while current behavior won't be changed serverside
- LLUUID const female_land_anim("ca1baf4d-0a18-5a1f-0330-e4bd1e71f09e");
- LLUUID const formal_female_land_anim("6a9a173b-61fa-3ad5-01fa-a851cfc5f66a");
- if (female_land_anim == asset_id || formal_female_land_anim == asset_id)
- {
- LL_WARNS() << "Animation " << asset() << " won't be looped." << LL_ENDL;
- joint_motion_list->mLoop = false;
- }
-
- //-------------------------------------------------------------------------
- // get easeIn and easeOut
- //-------------------------------------------------------------------------
- if (!dp.unpackF32(joint_motion_list->mEaseInDuration, "ease_in_duration") ||
- !llfinite(joint_motion_list->mEaseInDuration))
- {
- LL_WARNS() << "can't read easeIn"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackF32(joint_motion_list->mEaseOutDuration, "ease_out_duration") ||
- !llfinite(joint_motion_list->mEaseOutDuration))
- {
- LL_WARNS() << "can't read easeOut"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- //-------------------------------------------------------------------------
- // get hand pose
- //-------------------------------------------------------------------------
- U32 word;
- if (!dp.unpackU32(word, "hand_pose"))
- {
- LL_WARNS() << "can't read hand pose"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (word > LLHandMotion::NUM_HAND_POSES)
- {
- LL_WARNS() << "invalid LLHandMotion::eHandPose index: " << word
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- joint_motion_list->mHandPose = (LLHandMotion::eHandPose)word;
-
- //-------------------------------------------------------------------------
- // get number of joint motions
- //-------------------------------------------------------------------------
- U32 num_motions = 0;
- S32 rotation_duplicates = 0;
- S32 position_duplicates = 0;
- if (!dp.unpackU32(num_motions, "num_joints"))
- {
- LL_WARNS() << "can't read number of joints"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (num_motions == 0)
- {
- LL_WARNS() << "no joints"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- else if (num_motions > LL_CHARACTER_MAX_ANIMATED_JOINTS)
- {
- LL_WARNS() << "too many joints"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- joint_motion_list->mJointMotionArray.clear();
- joint_motion_list->mJointMotionArray.reserve(num_motions);
- mJointStates.clear();
- mJointStates.reserve(num_motions);
-
- //-------------------------------------------------------------------------
- // initialize joint motions
- //-------------------------------------------------------------------------
-
- for (U32 i = 0; i < num_motions; ++i)
- {
- JointMotion* joint_motion = new JointMotion;
- joint_motion_list->mJointMotionArray.push_back(joint_motion);
-
- std::string joint_name;
- if (!dp.unpackString(joint_name, "joint_name"))
- {
- LL_WARNS() << "can't read joint name"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (joint_name == "mScreen" || joint_name == "mRoot")
- {
- LL_WARNS() << "attempted to animate special " << joint_name << " joint"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- //---------------------------------------------------------------------
- // find the corresponding joint
- //---------------------------------------------------------------------
- LLJoint *joint = mCharacter->getJoint( joint_name );
- if (joint)
- {
- S32 joint_num = joint->getJointNum();
- joint_name = joint->getName(); // canonical name in case this is an alias.
-// LL_INFOS() << " joint: " << joint_name << LL_ENDL;
- if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
- {
- LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num
- << " is outside of legal range [0-"
- << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName()
- << " for animation " << asset() << LL_ENDL;
- joint = NULL;
- }
- }
- else
- {
- LL_WARNS() << "invalid joint name: " << joint_name
- << " for animation " << asset() << LL_ENDL;
- if (!allow_invalid_joints)
- {
- return false;
- }
- }
-
- joint_motion->mJointName = joint_name;
-
- LLPointer<LLJointState> joint_state = new LLJointState;
- mJointStates.push_back(joint_state);
- joint_state->setJoint( joint ); // note: can accept NULL
- joint_state->setUsage( 0 );
-
- //---------------------------------------------------------------------
- // get joint priority
- //---------------------------------------------------------------------
- S32 joint_priority;
- if (!dp.unpackS32(joint_priority, "joint_priority"))
- {
- LL_WARNS() << "can't read joint priority."
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (joint_priority < LLJoint::USE_MOTION_PRIORITY)
- {
- LL_WARNS() << "joint priority unknown - too low."
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- joint_motion->mPriority = (LLJoint::JointPriority)joint_priority;
- if (joint_priority != LLJoint::USE_MOTION_PRIORITY &&
- joint_priority > joint_motion_list->mMaxPriority)
- {
- joint_motion_list->mMaxPriority = (LLJoint::JointPriority)joint_priority;
- }
-
- joint_state->setPriority((LLJoint::JointPriority)joint_priority);
-
- //---------------------------------------------------------------------
- // scan rotation curve header
- //---------------------------------------------------------------------
- if (!dp.unpackS32(joint_motion->mRotationCurve.mNumKeys, "num_rot_keys") || joint_motion->mRotationCurve.mNumKeys < 0)
- {
- LL_WARNS() << "can't read number of rotation keys"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- joint_motion->mRotationCurve.mInterpolationType = IT_LINEAR;
- if (joint_motion->mRotationCurve.mNumKeys != 0)
- {
- joint_state->setUsage(joint_state->getUsage() | LLJointState::ROT );
- }
-
- //---------------------------------------------------------------------
- // scan rotation curve keys
- //---------------------------------------------------------------------
- RotationCurve *rCurve = &joint_motion->mRotationCurve;
-
- for (S32 k = 0; k < joint_motion->mRotationCurve.mNumKeys; k++)
- {
- F32 time;
- U16 time_short;
-
- if (old_version)
- {
- if (!dp.unpackF32(time, "time") ||
- !llfinite(time))
- {
- LL_WARNS() << "can't read rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- }
- else
- {
- if (!dp.unpackU16(time_short, "time"))
- {
- LL_WARNS() << "can't read rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- time = U16_to_F32(time_short, 0.f, joint_motion_list->mDuration);
-
- if (time < 0 || time > joint_motion_list->mDuration)
- {
- LL_WARNS() << "invalid frame time"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- }
-
- RotationKey rot_key;
- rot_key.mTime = time;
- LLVector3 rot_angles;
- U16 x, y, z;
-
- if (old_version)
- {
- if (!dp.unpackVector3(rot_angles, "rot_angles"))
- {
- LL_WARNS() << "can't read rot_angles in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- if (!rot_angles.isFinite())
- {
- LL_WARNS() << "non-finite angle in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- LLQuaternion::Order ro = StringToOrder("ZYX");
- rot_key.mRotation = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro);
- }
- else
- {
- if (!dp.unpackU16(x, "rot_angle_x"))
- {
- LL_WARNS() << "can't read rot_angle_x in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- if (!dp.unpackU16(y, "rot_angle_y"))
- {
- LL_WARNS() << "can't read rot_angle_y in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- if (!dp.unpackU16(z, "rot_angle_z"))
- {
- LL_WARNS() << "can't read rot_angle_z in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- LLVector3 rot_vec;
- rot_vec.mV[VX] = U16_to_F32(x, -1.f, 1.f);
- rot_vec.mV[VY] = U16_to_F32(y, -1.f, 1.f);
- rot_vec.mV[VZ] = U16_to_F32(z, -1.f, 1.f);
-
- if (!rot_vec.isFinite())
- {
- LL_WARNS() << "non-finite angle in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- rot_key.mRotation.unpackFromVector3(rot_vec);
- }
-
- if (!rot_key.mRotation.isFinite())
- {
- LL_WARNS() << "non-finite angle in rotation key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- rCurve->mKeys[time] = rot_key;
- }
-
- if (joint_motion->mRotationCurve.mNumKeys > joint_motion->mRotationCurve.mKeys.size())
- {
- rotation_duplicates++;
- LL_INFOS() << "Motion " << asset() << " had duplicated rotation keys that were removed: "
- << joint_motion->mRotationCurve.mNumKeys << " > " << joint_motion->mRotationCurve.mKeys.size()
- << " (" << rotation_duplicates << ")" << LL_ENDL;
- }
-
- //---------------------------------------------------------------------
- // scan position curve header
- //---------------------------------------------------------------------
- if (!dp.unpackS32(joint_motion->mPositionCurve.mNumKeys, "num_pos_keys") || joint_motion->mPositionCurve.mNumKeys < 0)
- {
- LL_WARNS() << "can't read number of position keys"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- joint_motion->mPositionCurve.mInterpolationType = IT_LINEAR;
- if (joint_motion->mPositionCurve.mNumKeys != 0)
- {
- joint_state->setUsage(joint_state->getUsage() | LLJointState::POS );
- }
-
- //---------------------------------------------------------------------
- // scan position curve keys
- //---------------------------------------------------------------------
- PositionCurve *pCurve = &joint_motion->mPositionCurve;
- bool is_pelvis = joint_motion->mJointName == "mPelvis";
- for (S32 k = 0; k < joint_motion->mPositionCurve.mNumKeys; k++)
- {
- U16 time_short;
- PositionKey pos_key;
-
- if (old_version)
- {
- if (!dp.unpackF32(pos_key.mTime, "time") ||
- !llfinite(pos_key.mTime))
- {
- LL_WARNS() << "can't read position key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- }
- else
- {
- if (!dp.unpackU16(time_short, "time"))
- {
- LL_WARNS() << "can't read position key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- pos_key.mTime = U16_to_F32(time_short, 0.f, joint_motion_list->mDuration);
- }
-
- if (old_version)
- {
- if (!dp.unpackVector3(pos_key.mPosition, "pos"))
- {
- LL_WARNS() << "can't read pos in position key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- //MAINT-6162
- pos_key.mPosition.mV[VX] = llclamp( pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- pos_key.mPosition.mV[VY] = llclamp( pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- pos_key.mPosition.mV[VZ] = llclamp( pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
-
- }
- else
- {
- U16 x, y, z;
-
- if (!dp.unpackU16(x, "pos_x"))
- {
- LL_WARNS() << "can't read pos_x in position key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- if (!dp.unpackU16(y, "pos_y"))
- {
- LL_WARNS() << "can't read pos_y in position key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- if (!dp.unpackU16(z, "pos_z"))
- {
- LL_WARNS() << "can't read pos_z in position key (" << k << ")"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- pos_key.mPosition.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- pos_key.mPosition.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- pos_key.mPosition.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- }
-
- if (!pos_key.mPosition.isFinite())
- {
- LL_WARNS() << "non-finite position in key"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- pCurve->mKeys[pos_key.mTime] = pos_key;
-
- if (is_pelvis)
- {
- joint_motion_list->mPelvisBBox.addPoint(pos_key.mPosition);
- }
- }
-
- if (joint_motion->mPositionCurve.mNumKeys > joint_motion->mPositionCurve.mKeys.size())
- {
- position_duplicates++;
- LL_INFOS() << "Motion " << asset() << " had duplicated position keys that were removed: "
- << joint_motion->mPositionCurve.mNumKeys << " > " << joint_motion->mPositionCurve.mKeys.size()
- << " (" << position_duplicates << ")" << LL_ENDL;
- }
-
- joint_motion->mUsage = joint_state->getUsage();
- }
-
- if (rotation_duplicates > 0)
- {
- LL_INFOS() << "Motion " << asset() << " had " << rotation_duplicates
- << " duplicated rotation keys that were removed" << LL_ENDL;
- }
-
- if (position_duplicates > 0)
- {
- LL_INFOS() << "Motion " << asset() << " had " << position_duplicates
- << " duplicated position keys that were removed" << LL_ENDL;
- }
-
- //-------------------------------------------------------------------------
- // get number of constraints
- //-------------------------------------------------------------------------
- S32 num_constraints = 0;
- if (!dp.unpackS32(num_constraints, "num_constraints"))
- {
- LL_WARNS() << "can't read number of constraints"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (num_constraints > MAX_CONSTRAINTS || num_constraints < 0)
- {
- LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints
- << " for animation " << asset() << LL_ENDL;
- }
- else
- {
- //-------------------------------------------------------------------------
- // get constraints
- //-------------------------------------------------------------------------
- std::string str;
- for(S32 i = 0; i < num_constraints; ++i)
- {
- // read in constraint data
- std::unique_ptr<JointConstraintSharedData> constraintp(new JointConstraintSharedData);
- U8 byte = 0;
-
- if (!dp.unpackU8(byte, "chain_length"))
- {
- LL_WARNS() << "can't read constraint chain length"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- constraintp->mChainLength = (S32) byte;
-
- if((U32)constraintp->mChainLength > joint_motion_list->getNumJointMotions())
- {
- LL_WARNS() << "invalid constraint chain length"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackU8(byte, "constraint_type"))
- {
- LL_WARNS() << "can't read constraint type"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if( byte >= NUM_CONSTRAINT_TYPES )
- {
- LL_WARNS() << "invalid constraint type"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- constraintp->mConstraintType = (EConstraintType)byte;
-
- const S32 BIN_DATA_LENGTH = 16;
- U8 bin_data[BIN_DATA_LENGTH+1];
- if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "source_volume"))
- {
- LL_WARNS() << "can't read source volume name"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination
- str = (char*)bin_data;
- constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str);
- if (constraintp->mSourceConstraintVolume == -1)
- {
- LL_WARNS() << "not a valid source constraint volume " << str
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset"))
- {
- LL_WARNS() << "can't read constraint source offset"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if( !(constraintp->mSourceConstraintOffset.isFinite()) )
- {
- LL_WARNS() << "non-finite constraint source offset"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "target_volume"))
- {
- LL_WARNS() << "can't read target volume name"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination
- str = (char*)bin_data;
- if (str == "GROUND")
- {
- // constrain to ground
- constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_GROUND;
- }
- else
- {
- constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_BODY;
- constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str);
- if (constraintp->mTargetConstraintVolume == -1)
- {
- LL_WARNS() << "not a valid target constraint volume " << str
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- }
-
- if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset"))
- {
- LL_WARNS() << "can't read constraint target offset"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if( !(constraintp->mTargetConstraintOffset.isFinite()) )
- {
- LL_WARNS() << "non-finite constraint target offset"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackVector3(constraintp->mTargetConstraintDir, "target_dir"))
- {
- LL_WARNS() << "can't read constraint target direction"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if( !(constraintp->mTargetConstraintDir.isFinite()) )
- {
- LL_WARNS() << "non-finite constraint target direction"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!constraintp->mTargetConstraintDir.isExactlyZero())
- {
- constraintp->mUseTargetOffset = true;
- // constraintp->mTargetConstraintDir *= constraintp->mSourceConstraintOffset.magVec();
- }
-
- if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !llfinite(constraintp->mEaseInStartTime))
- {
- LL_WARNS() << "can't read constraint ease in start time"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !llfinite(constraintp->mEaseInStopTime))
- {
- LL_WARNS() << "can't read constraint ease in stop time"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !llfinite(constraintp->mEaseOutStartTime))
- {
- LL_WARNS() << "can't read constraint ease out start time"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !llfinite(constraintp->mEaseOutStopTime))
- {
- LL_WARNS() << "can't read constraint ease out stop time"
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- LLJoint* joint = mCharacter->findCollisionVolume(constraintp->mSourceConstraintVolume);
- // get joint to which this collision volume is attached
- if (!joint)
- {
- return false;
- }
-
- constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte
-
- for (S32 i = 0; i < constraintp->mChainLength + 1; i++)
- {
- LLJoint* parent = joint->getParent();
- if (!parent)
- {
- LL_WARNS() << "Joint with no parent: " << joint->getName()
- << " Emote: " << joint_motion_list->mEmoteName
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- joint = parent;
- constraintp->mJointStateIndices[i] = -1;
- for (U32 j = 0; j < joint_motion_list->getNumJointMotions(); j++)
- {
- LLJoint* constraint_joint = getJoint(j);
-
- if ( !constraint_joint )
- {
- LL_WARNS() << "Invalid joint " << j
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
-
- if(constraint_joint == joint)
- {
- constraintp->mJointStateIndices[i] = (S32)j;
- break;
- }
- }
- if (constraintp->mJointStateIndices[i] < 0 )
- {
- LL_WARNS() << "No joint index for constraint " << i
- << " for animation " << asset() << LL_ENDL;
- return false;
- }
- }
-
- joint_motion_list->mConstraints.push_front(constraintp.release());
- }
- }
-
- // *FIX: support cleanup of old keyframe data
- mJointMotionList = joint_motion_list.release(); // release from unique_ptr to member;
- LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList);
- mAssetStatus = ASSET_LOADED;
-
- setupPose();
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// serialize()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotion::serialize(LLDataPacker& dp) const
-{
- bool success = true;
-
- LL_DEBUGS("BVH") << "serializing" << LL_ENDL;
-
- success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version");
- success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
- success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority");
- success &= dp.packF32(mJointMotionList->mDuration, "duration");
- success &= dp.packString(mJointMotionList->mEmoteName, "emote_name");
- success &= dp.packF32(mJointMotionList->mLoopInPoint, "loop_in_point");
- success &= dp.packF32(mJointMotionList->mLoopOutPoint, "loop_out_point");
- success &= dp.packS32(mJointMotionList->mLoop, "loop");
- success &= dp.packF32(mJointMotionList->mEaseInDuration, "ease_in_duration");
- success &= dp.packF32(mJointMotionList->mEaseOutDuration, "ease_out_duration");
- success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose");
- success &= dp.packU32(mJointMotionList->getNumJointMotions(), "num_joints");
-
- LL_DEBUGS("BVH") << "version " << KEYFRAME_MOTION_VERSION << LL_ENDL;
- LL_DEBUGS("BVH") << "sub_version " << KEYFRAME_MOTION_SUBVERSION << LL_ENDL;
- LL_DEBUGS("BVH") << "base_priority " << mJointMotionList->mBasePriority << LL_ENDL;
- LL_DEBUGS("BVH") << "duration " << mJointMotionList->mDuration << LL_ENDL;
- LL_DEBUGS("BVH") << "emote_name " << mJointMotionList->mEmoteName << LL_ENDL;
- LL_DEBUGS("BVH") << "loop_in_point " << mJointMotionList->mLoopInPoint << LL_ENDL;
- LL_DEBUGS("BVH") << "loop_out_point " << mJointMotionList->mLoopOutPoint << LL_ENDL;
- LL_DEBUGS("BVH") << "loop " << mJointMotionList->mLoop << LL_ENDL;
- LL_DEBUGS("BVH") << "ease_in_duration " << mJointMotionList->mEaseInDuration << LL_ENDL;
- LL_DEBUGS("BVH") << "ease_out_duration " << mJointMotionList->mEaseOutDuration << LL_ENDL;
- LL_DEBUGS("BVH") << "hand_pose " << mJointMotionList->mHandPose << LL_ENDL;
- LL_DEBUGS("BVH") << "num_joints " << mJointMotionList->getNumJointMotions() << LL_ENDL;
-
- for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
- {
- JointMotion* joint_motionp = mJointMotionList->getJointMotion(i);
- success &= dp.packString(joint_motionp->mJointName, "joint_name");
- success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
- success &= dp.packS32(joint_motionp->mRotationCurve.mKeys.size(), "num_rot_keys");
-
- LL_DEBUGS("BVH") << "Joint " << i
- << " name: " << joint_motionp->mJointName
- << " Rotation keys: " << joint_motionp->mRotationCurve.mKeys.size()
- << " Position keys: " << joint_motionp->mPositionCurve.mKeys.size() << LL_ENDL;
- for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys)
- {
- RotationKey& rot_key = rot_pair.second;
- U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration);
- success &= dp.packU16(time_short, "time");
-
- LLVector3 rot_angles = rot_key.mRotation.packToVector3();
-
- U16 x, y, z;
- rot_angles.quantize16(-1.f, 1.f, -1.f, 1.f);
- x = F32_to_U16(rot_angles.mV[VX], -1.f, 1.f);
- y = F32_to_U16(rot_angles.mV[VY], -1.f, 1.f);
- z = F32_to_U16(rot_angles.mV[VZ], -1.f, 1.f);
- success &= dp.packU16(x, "rot_angle_x");
- success &= dp.packU16(y, "rot_angle_y");
- success &= dp.packU16(z, "rot_angle_z");
-
- LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
- }
-
- success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys");
- for (PositionCurve::key_map_t::value_type& pos_pair : joint_motionp->mPositionCurve.mKeys)
- {
- PositionKey& pos_key = pos_pair.second;
- U16 time_short = F32_to_U16(pos_key.mTime, 0.f, mJointMotionList->mDuration);
- success &= dp.packU16(time_short, "time");
-
- U16 x, y, z;
- pos_key.mPosition.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- x = F32_to_U16(pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- y = F32_to_U16(pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- z = F32_to_U16(pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- success &= dp.packU16(x, "pos_x");
- success &= dp.packU16(y, "pos_y");
- success &= dp.packU16(z, "pos_z");
-
- LL_DEBUGS("BVH") << " pos: t " << pos_key.mTime << " pos " << pos_key.mPosition.mV[VX] <<","<< pos_key.mPosition.mV[VY] <<","<< pos_key.mPosition.mV[VZ] << LL_ENDL;
- }
- }
-
- success &= dp.packS32(mJointMotionList->mConstraints.size(), "num_constraints");
- LL_DEBUGS("BVH") << "num_constraints " << mJointMotionList->mConstraints.size() << LL_ENDL;
- for (JointConstraintSharedData* shared_constraintp : mJointMotionList->mConstraints)
- {
- success &= dp.packU8(shared_constraintp->mChainLength, "chain_length");
- success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type");
- char source_volume[16]; /* Flawfinder: ignore */
- snprintf(source_volume, sizeof(source_volume), "%s", /* Flawfinder: ignore */
- mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str());
-
- success &= dp.packBinaryDataFixed((U8*)source_volume, 16, "source_volume");
- success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset");
- char target_volume[16]; /* Flawfinder: ignore */
- if (shared_constraintp->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND)
- {
- snprintf(target_volume,sizeof(target_volume), "%s", "GROUND"); /* Flawfinder: ignore */
- }
- else
- {
- snprintf(target_volume, sizeof(target_volume),"%s", /* Flawfinder: ignore */
- mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str());
- }
- success &= dp.packBinaryDataFixed((U8*)target_volume, 16, "target_volume");
- success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset");
- success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir");
- success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start");
- success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop");
- success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start");
- success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop");
-
- LL_DEBUGS("BVH") << " chain_length " << shared_constraintp->mChainLength << LL_ENDL;
- LL_DEBUGS("BVH") << " constraint_type " << (S32)shared_constraintp->mConstraintType << LL_ENDL;
- LL_DEBUGS("BVH") << " source_volume " << source_volume << LL_ENDL;
- LL_DEBUGS("BVH") << " source_offset " << shared_constraintp->mSourceConstraintOffset << LL_ENDL;
- LL_DEBUGS("BVH") << " target_volume " << target_volume << LL_ENDL;
- LL_DEBUGS("BVH") << " target_offset " << shared_constraintp->mTargetConstraintOffset << LL_ENDL;
- LL_DEBUGS("BVH") << " target_dir " << shared_constraintp->mTargetConstraintDir << LL_ENDL;
- LL_DEBUGS("BVH") << " ease_in_start " << shared_constraintp->mEaseInStartTime << LL_ENDL;
- LL_DEBUGS("BVH") << " ease_in_stop " << shared_constraintp->mEaseInStopTime << LL_ENDL;
- LL_DEBUGS("BVH") << " ease_out_start " << shared_constraintp->mEaseOutStartTime << LL_ENDL;
- LL_DEBUGS("BVH") << " ease_out_stop " << shared_constraintp->mEaseOutStopTime << LL_ENDL;
- }
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// getFileSize()
-//-----------------------------------------------------------------------------
-U32 LLKeyframeMotion::getFileSize()
-{
- // serialize into a dummy buffer to calculate required size
- LLDataPackerBinaryBuffer dp;
- serialize(dp);
-
- return dp.getCurrentSize();
-}
-
-//-----------------------------------------------------------------------------
-// dumpToFile()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotion::dumpToFile(const std::string& name)
-{
- bool succ = false;
- if (isLoaded())
- {
- std::string outfile_base;
- if (!name.empty())
- {
- outfile_base = name;
- }
- else if (!getName().empty())
- {
- outfile_base = getName();
- }
- else
- {
- const LLUUID& id = getID();
- outfile_base = id.asString();
- }
-
- if (gDirUtilp->getExtension(outfile_base).empty())
- {
- outfile_base += ".anim";
- }
- std::string outfilename;
- if (gDirUtilp->getDirName(outfile_base).empty())
- {
- outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base);
- }
- else
- {
- outfilename = outfile_base;
- }
- if (LLFile::isfile(outfilename))
- {
- LL_WARNS() << outfilename << " already exists, write failed" << LL_ENDL;
- return false;
- }
-
- S32 file_size = getFileSize();
- U8* buffer = new U8[file_size];
-
- LL_DEBUGS("BVH") << "Dumping " << outfilename << LL_ENDL;
- LLDataPackerBinaryBuffer dp(buffer, file_size);
- if (serialize(dp))
- {
- LLAPRFile outfile;
- outfile.open(outfilename, LL_APR_WPB);
- if (outfile.getFileHandle())
- {
- S32 wrote_bytes = outfile.write(buffer, file_size);
- succ = (wrote_bytes == file_size);
- }
- }
- delete [] buffer;
- }
- return succ;
-}
-
-//-----------------------------------------------------------------------------
-// getPelvisBBox()
-//-----------------------------------------------------------------------------
-const LLBBoxLocal &LLKeyframeMotion::getPelvisBBox()
-{
- return mJointMotionList->mPelvisBBox;
-}
-
-//-----------------------------------------------------------------------------
-// setPriority()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setPriority(S32 priority)
-{
- if (mJointMotionList)
- {
- S32 priority_delta = priority - mJointMotionList->mBasePriority;
- mJointMotionList->mBasePriority = (LLJoint::JointPriority)priority;
- mJointMotionList->mMaxPriority = mJointMotionList->mBasePriority;
-
- for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
- {
- JointMotion* joint_motion = mJointMotionList->getJointMotion(i);
- joint_motion->mPriority = (LLJoint::JointPriority)llclamp(
- (S32)joint_motion->mPriority + priority_delta,
- (S32)LLJoint::LOW_PRIORITY,
- (S32)LLJoint::HIGHEST_PRIORITY);
- getJointState(i)->setPriority(joint_motion->mPriority);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// setEmote()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setEmote(const LLUUID& emote_id)
-{
- const char* emote_name = gAnimLibrary.animStateToString(emote_id);
- if (emote_name)
- {
- mJointMotionList->mEmoteName = emote_name;
- mJointMotionList->mEmoteID = emote_id;
- }
- else
- {
- mJointMotionList->mEmoteName.clear();
- mJointMotionList->mEmoteID.setNull();
- }
-}
-
-//-----------------------------------------------------------------------------
-// setEaseIn()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setEaseIn(F32 ease_in)
-{
- if (mJointMotionList)
- {
- mJointMotionList->mEaseInDuration = llmax(ease_in, 0.f);
- }
-}
-
-//-----------------------------------------------------------------------------
-// setEaseOut()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setEaseOut(F32 ease_in)
-{
- if (mJointMotionList)
- {
- mJointMotionList->mEaseOutDuration = llmax(ease_in, 0.f);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// flushKeyframeCache()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::flushKeyframeCache()
-{
- // TODO: Make this safe to do
-// LLKeyframeDataCache::clear();
-}
-
-//-----------------------------------------------------------------------------
-// setLoop()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setLoop(bool loop)
-{
- if (mJointMotionList)
- {
- mJointMotionList->mLoop = loop;
- mSendStopTimestamp = F32_MAX;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// setLoopIn()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setLoopIn(F32 in_point)
-{
- if (mJointMotionList)
- {
- mJointMotionList->mLoopInPoint = in_point;
-
- // set up loop keys
- for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
- {
- JointMotion* joint_motion = mJointMotionList->getJointMotion(i);
-
- PositionCurve* pos_curve = &joint_motion->mPositionCurve;
- RotationCurve* rot_curve = &joint_motion->mRotationCurve;
- ScaleCurve* scale_curve = &joint_motion->mScaleCurve;
-
- pos_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
- rot_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
- scale_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
-
- pos_curve->mLoopInKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
- rot_curve->mLoopInKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
- scale_curve->mLoopInKey.mScale = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// setLoopOut()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::setLoopOut(F32 out_point)
-{
- if (mJointMotionList)
- {
- mJointMotionList->mLoopOutPoint = out_point;
-
- // set up loop keys
- for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
- {
- JointMotion* joint_motion = mJointMotionList->getJointMotion(i);
-
- PositionCurve* pos_curve = &joint_motion->mPositionCurve;
- RotationCurve* rot_curve = &joint_motion->mRotationCurve;
- ScaleCurve* scale_curve = &joint_motion->mScaleCurve;
-
- pos_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
- rot_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
- scale_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
-
- pos_curve->mLoopOutKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
- rot_curve->mLoopOutKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
- scale_curve->mLoopOutKey.mScale = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// onLoadComplete()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::onLoadComplete(const LLUUID& asset_uuid,
- LLAssetType::EType type,
- void* user_data, S32 status, LLExtStat ext_status)
-{
- LLUUID* id = (LLUUID*)user_data;
-
- std::vector<LLCharacter* >::iterator char_iter = LLCharacter::sInstances.begin();
-
- while(char_iter != LLCharacter::sInstances.end() &&
- (*char_iter)->getID() != *id)
- {
- ++char_iter;
- }
-
- delete id;
-
- if (char_iter == LLCharacter::sInstances.end())
- {
- return;
- }
-
- LLCharacter* character = *char_iter;
-
- // look for an existing instance of this motion
- LLKeyframeMotion* motionp = static_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid));
- if (motionp)
- {
- if (0 == status)
- {
- if (motionp->mAssetStatus == ASSET_LOADED)
- {
- // asset already loaded
- return;
- }
- LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
- S32 size = file.getSize();
-
- U8* buffer = new U8[size];
- file.read((U8*)buffer, size); /*Flawfinder: ignore*/
-
- LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL;
-
- LLDataPackerBinaryBuffer dp(buffer, size);
- if (motionp->deserialize(dp, asset_uuid))
- {
- motionp->mAssetStatus = ASSET_LOADED;
- }
- else
- {
- LL_WARNS() << "Failed to decode asset for animation " << motionp->getName() << ":" << motionp->getID() << LL_ENDL;
- motionp->mAssetStatus = ASSET_FETCH_FAILED;
- }
-
- delete[] buffer;
- }
- else
- {
- LL_WARNS() << "Failed to load asset for animation " << motionp->getName() << ":" << motionp->getID() << LL_ENDL;
- motionp->mAssetStatus = ASSET_FETCH_FAILED;
- }
- }
- else
- {
- LL_WARNS() << "No existing motion for asset data. UUID: " << asset_uuid << LL_ENDL;
- }
-}
-
-//--------------------------------------------------------------------
-// LLKeyframeDataCache::dumpDiagInfo()
-//--------------------------------------------------------------------
-void LLKeyframeDataCache::dumpDiagInfo()
-{
- // keep track of totals
- U32 total_size = 0;
-
- char buf[1024]; /* Flawfinder: ignore */
-
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- LL_INFOS() << " Global Motion Table (DEBUG only)" << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
-
- // print each loaded mesh, and it's memory usage
- for (keyframe_data_map_t::value_type& data_pair : sKeyframeDataMap)
- {
- U32 joint_motion_kb;
-
- LLKeyframeMotion::JointMotionList *motion_list_p = data_pair.second;
-
- LL_INFOS() << "Motion: " << data_pair.first << LL_ENDL;
-
- joint_motion_kb = motion_list_p->dumpDiagInfo();
-
- total_size += joint_motion_kb;
- }
-
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- LL_INFOS() << "Motions\tTotal Size" << LL_ENDL;
- snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */
- LL_INFOS() << buf << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
-}
-
-
-//--------------------------------------------------------------------
-// LLKeyframeDataCache::addKeyframeData()
-//--------------------------------------------------------------------
-void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp)
-{
- sKeyframeDataMap[id] = joint_motion_listp;
-}
-
-//--------------------------------------------------------------------
-// LLKeyframeDataCache::removeKeyframeData()
-//--------------------------------------------------------------------
-void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id)
-{
- keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
- if (found_data != sKeyframeDataMap.end())
- {
- delete found_data->second;
- sKeyframeDataMap.erase(found_data);
- }
-}
-
-//--------------------------------------------------------------------
-// LLKeyframeDataCache::getKeyframeData()
-//--------------------------------------------------------------------
-LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id)
-{
- keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
- if (found_data == sKeyframeDataMap.end())
- {
- return NULL;
- }
- return found_data->second;
-}
-
-//--------------------------------------------------------------------
-// ~LLKeyframeDataCache::LLKeyframeDataCache()
-//--------------------------------------------------------------------
-LLKeyframeDataCache::~LLKeyframeDataCache()
-{
- clear();
-}
-
-//-----------------------------------------------------------------------------
-// clear()
-//-----------------------------------------------------------------------------
-void LLKeyframeDataCache::clear()
-{
- for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer());
- sKeyframeDataMap.clear();
-}
-
-//-----------------------------------------------------------------------------
-// JointConstraint()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::JointConstraint::JointConstraint(JointConstraintSharedData* shared_data) : mSharedData(shared_data)
-{
- mWeight = 0.f;
- mTotalLength = 0.f;
- mActive = false;
- mSourceVolume = NULL;
- mTargetVolume = NULL;
- mFixupDistanceRMS = 0.f;
-
- for (S32 i=0; i<MAX_CHAIN_LENGTH; ++i)
- {
- mJointLengths[i] = 0.f;
- mJointLengthFractions[i] = 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// ~JointConstraint()
-//-----------------------------------------------------------------------------
-LLKeyframeMotion::JointConstraint::~JointConstraint()
-{
-}
-
-// End
-
+/** + * @file llkeyframemotion.cpp + * @brief Implementation of LLKeyframeMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llmath.h" +#include "llanimationstates.h" +#include "llassetstorage.h" +#include "lldatapacker.h" +#include "llcharacter.h" +#include "llcriticaldamp.h" +#include "lldir.h" +#include "llendianswizzle.h" +#include "llkeyframemotion.h" +#include "llquantize.h" +#include "m3math.h" +#include "message.h" +#include "llfilesystem.h" + +//----------------------------------------------------------------------------- +// Static Definitions +//----------------------------------------------------------------------------- +LLKeyframeDataCache::keyframe_data_map_t LLKeyframeDataCache::sKeyframeDataMap; + +//----------------------------------------------------------------------------- +// Globals +//----------------------------------------------------------------------------- +static F32 JOINT_LENGTH_K = 0.7f; +static S32 MAX_ITERATIONS = 20; +static S32 MIN_ITERATIONS = 1; +static S32 MIN_ITERATION_COUNT = 2; +static F32 MAX_PIXEL_AREA_CONSTRAINTS = 80000.f; +static F32 MIN_PIXEL_AREA_CONSTRAINTS = 1000.f; +static F32 MIN_ACCELERATION_SQUARED = 0.0005f * 0.0005f; + +static F32 MAX_CONSTRAINTS = 10; + +//----------------------------------------------------------------------------- +// JointMotionList +//----------------------------------------------------------------------------- +LLKeyframeMotion::JointMotionList::JointMotionList() + : mDuration(0.f), + mLoop(false), + mLoopInPoint(0.f), + mLoopOutPoint(0.f), + mEaseInDuration(0.f), + mEaseOutDuration(0.f), + mBasePriority(LLJoint::LOW_PRIORITY), + mHandPose(LLHandMotion::HAND_POSE_SPREAD), + mMaxPriority(LLJoint::LOW_PRIORITY) +{ +} + +LLKeyframeMotion::JointMotionList::~JointMotionList() +{ + for_each(mConstraints.begin(), mConstraints.end(), DeletePointer()); + mConstraints.clear(); + for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer()); + mJointMotionArray.clear(); +} + +U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo() +{ + S32 total_size = sizeof(JointMotionList); + + for (U32 i = 0; i < getNumJointMotions(); i++) + { + LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i]; + + LL_INFOS() << "\tJoint " << joint_motion_p->mJointName << LL_ENDL; + if (joint_motion_p->mUsage & LLJointState::SCALE) + { + LL_INFOS() << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at " + << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << LL_ENDL; + + total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey); + } + if (joint_motion_p->mUsage & LLJointState::ROT) + { + LL_INFOS() << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at " + << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << LL_ENDL; + + total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey); + } + if (joint_motion_p->mUsage & LLJointState::POS) + { + LL_INFOS() << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at " + << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << LL_ENDL; + + total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey); + } + } + LL_INFOS() << "Size: " << total_size << " bytes" << LL_ENDL; + + return total_size; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// ****Curve classes +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// ScaleCurve::ScaleCurve() +//----------------------------------------------------------------------------- +LLKeyframeMotion::ScaleCurve::ScaleCurve() +{ + mInterpolationType = LLKeyframeMotion::IT_LINEAR; + mNumKeys = 0; +} + +//----------------------------------------------------------------------------- +// ScaleCurve::~ScaleCurve() +//----------------------------------------------------------------------------- +LLKeyframeMotion::ScaleCurve::~ScaleCurve() +{ + mKeys.clear(); + mNumKeys = 0; +} + +//----------------------------------------------------------------------------- +// getValue() +//----------------------------------------------------------------------------- +LLVector3 LLKeyframeMotion::ScaleCurve::getValue(F32 time, F32 duration) +{ + LLVector3 value; + + if (mKeys.empty()) + { + value.clearVec(); + return value; + } + + key_map_t::iterator right = mKeys.lower_bound(time); + if (right == mKeys.end()) + { + // Past last key + --right; + value = right->second.mScale; + } + else if (right == mKeys.begin() || right->first == time) + { + // Before first key or exactly on a key + value = right->second.mScale; + } + else + { + // Between two keys + key_map_t::iterator left = right; --left; + F32 index_before = left->first; + F32 index_after = right->first; + ScaleKey& scale_before = left->second; + ScaleKey& scale_after = right->second; + if (right == mKeys.end()) + { + scale_after = mLoopInKey; + index_after = duration; + } + + F32 u = (time - index_before) / (index_after - index_before); + value = interp(u, scale_before, scale_after); + } + return value; +} + +//----------------------------------------------------------------------------- +// interp() +//----------------------------------------------------------------------------- +LLVector3 LLKeyframeMotion::ScaleCurve::interp(F32 u, ScaleKey& before, ScaleKey& after) +{ + switch (mInterpolationType) + { + case IT_STEP: + return before.mScale; + + default: + case IT_LINEAR: + case IT_SPLINE: + return lerp(before.mScale, after.mScale, u); + } +} + +//----------------------------------------------------------------------------- +// RotationCurve::RotationCurve() +//----------------------------------------------------------------------------- +LLKeyframeMotion::RotationCurve::RotationCurve() +{ + mInterpolationType = LLKeyframeMotion::IT_LINEAR; + mNumKeys = 0; +} + +//----------------------------------------------------------------------------- +// RotationCurve::~RotationCurve() +//----------------------------------------------------------------------------- +LLKeyframeMotion::RotationCurve::~RotationCurve() +{ + mKeys.clear(); + mNumKeys = 0; +} + +//----------------------------------------------------------------------------- +// RotationCurve::getValue() +//----------------------------------------------------------------------------- +LLQuaternion LLKeyframeMotion::RotationCurve::getValue(F32 time, F32 duration) +{ + LLQuaternion value; + + if (mKeys.empty()) + { + value = LLQuaternion::DEFAULT; + return value; + } + + key_map_t::iterator right = mKeys.lower_bound(time); + if (right == mKeys.end()) + { + // Past last key + --right; + value = right->second.mRotation; + } + else if (right == mKeys.begin() || right->first == time) + { + // Before first key or exactly on a key + value = right->second.mRotation; + } + else + { + // Between two keys + key_map_t::iterator left = right; --left; + F32 index_before = left->first; + F32 index_after = right->first; + RotationKey& rot_before = left->second; + RotationKey& rot_after = right->second; + if (right == mKeys.end()) + { + rot_after = mLoopInKey; + index_after = duration; + } + + F32 u = (time - index_before) / (index_after - index_before); + value = interp(u, rot_before, rot_after); + } + return value; +} + +//----------------------------------------------------------------------------- +// interp() +//----------------------------------------------------------------------------- +LLQuaternion LLKeyframeMotion::RotationCurve::interp(F32 u, RotationKey& before, RotationKey& after) +{ + switch (mInterpolationType) + { + case IT_STEP: + return before.mRotation; + + default: + case IT_LINEAR: + case IT_SPLINE: + return nlerp(u, before.mRotation, after.mRotation); + } +} + + +//----------------------------------------------------------------------------- +// PositionCurve::PositionCurve() +//----------------------------------------------------------------------------- +LLKeyframeMotion::PositionCurve::PositionCurve() +{ + mInterpolationType = LLKeyframeMotion::IT_LINEAR; + mNumKeys = 0; +} + +//----------------------------------------------------------------------------- +// PositionCurve::~PositionCurve() +//----------------------------------------------------------------------------- +LLKeyframeMotion::PositionCurve::~PositionCurve() +{ + mKeys.clear(); + mNumKeys = 0; +} + +//----------------------------------------------------------------------------- +// PositionCurve::getValue() +//----------------------------------------------------------------------------- +LLVector3 LLKeyframeMotion::PositionCurve::getValue(F32 time, F32 duration) +{ + LLVector3 value; + + if (mKeys.empty()) + { + value.clearVec(); + return value; + } + + key_map_t::iterator right = mKeys.lower_bound(time); + if (right == mKeys.end()) + { + // Past last key + --right; + value = right->second.mPosition; + } + else if (right == mKeys.begin() || right->first == time) + { + // Before first key or exactly on a key + value = right->second.mPosition; + } + else + { + // Between two keys + key_map_t::iterator left = right; --left; + F32 index_before = left->first; + F32 index_after = right->first; + PositionKey& pos_before = left->second; + PositionKey& pos_after = right->second; + if (right == mKeys.end()) + { + pos_after = mLoopInKey; + index_after = duration; + } + + F32 u = (time - index_before) / (index_after - index_before); + value = interp(u, pos_before, pos_after); + } + + llassert(value.isFinite()); + + return value; +} + +//----------------------------------------------------------------------------- +// interp() +//----------------------------------------------------------------------------- +LLVector3 LLKeyframeMotion::PositionCurve::interp(F32 u, PositionKey& before, PositionKey& after) +{ + switch (mInterpolationType) + { + case IT_STEP: + return before.mPosition; + default: + case IT_LINEAR: + case IT_SPLINE: + return lerp(before.mPosition, after.mPosition, u); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// JointMotion class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// JointMotion::update() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, F32 duration) +{ + // this value being 0 is the cause of https://jira.lindenlab.com/browse/SL-22678 but I haven't + // managed to get a stack to see how it got here. Testing for 0 here will stop the crash. + if ( joint_state == NULL ) + { + return; + } + + U32 usage = joint_state->getUsage(); + + //------------------------------------------------------------------------- + // update scale component of joint state + //------------------------------------------------------------------------- + if ((usage & LLJointState::SCALE) && mScaleCurve.mNumKeys) + { + joint_state->setScale( mScaleCurve.getValue( time, duration ) ); + } + + //------------------------------------------------------------------------- + // update rotation component of joint state + //------------------------------------------------------------------------- + if ((usage & LLJointState::ROT) && mRotationCurve.mNumKeys) + { + joint_state->setRotation( mRotationCurve.getValue( time, duration ) ); + } + + //------------------------------------------------------------------------- + // update position component of joint state + //------------------------------------------------------------------------- + if ((usage & LLJointState::POS) && mPositionCurve.mNumKeys) + { + joint_state->setPosition( mPositionCurve.getValue( time, duration ) ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLKeyframeMotion class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLKeyframeMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id) + : LLMotion(id), + mJointMotionList(NULL), + mPelvisp(NULL), + mLastSkeletonSerialNum(0), + mLastUpdateTime(0.f), + mLastLoopedTime(0.f), + mAssetStatus(ASSET_UNDEFINED) +{ + +} + + +//----------------------------------------------------------------------------- +// ~LLKeyframeMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLKeyframeMotion::~LLKeyframeMotion() +{ + for_each(mConstraints.begin(), mConstraints.end(), DeletePointer()); + mConstraints.clear(); +} + +//----------------------------------------------------------------------------- +// create() +//----------------------------------------------------------------------------- +LLMotion *LLKeyframeMotion::create(const LLUUID &id) +{ + return new LLKeyframeMotion(id); +} + +//----------------------------------------------------------------------------- +// getJointState() +//----------------------------------------------------------------------------- +LLPointer<LLJointState>& LLKeyframeMotion::getJointState(U32 index) +{ + llassert_always (index < mJointStates.size()); + return mJointStates[index]; +} + +//----------------------------------------------------------------------------- +// getJoint() +//----------------------------------------------------------------------------- +LLJoint* LLKeyframeMotion::getJoint(U32 index) +{ + llassert_always (index < mJointStates.size()); + LLJoint* joint = mJointStates[index]->getJoint(); + + //Commented out 06-28-11 by Aura. + //llassert_always (joint); + return joint; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotion::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + LLUUID* character_id; + + // asset already loaded? + switch(mAssetStatus) + { + case ASSET_NEEDS_FETCH: + // request asset + mAssetStatus = ASSET_FETCHED; + + if (mID.notNull()) + { + LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL; + character_id = new LLUUID(mCharacter->getID()); + gAssetStorage->getAssetData(mID, + LLAssetType::AT_ANIMATION, + onLoadComplete, + (void*)character_id, + false); + } + else + { + LL_INFOS("Animation") << "Attempted to fetch animation '" << mName << "' with null id" + << " for character " << mCharacter->getID() << LL_ENDL; + } + + return STATUS_HOLD; + case ASSET_FETCHED: + return STATUS_HOLD; + case ASSET_FETCH_FAILED: + return STATUS_FAILURE; + case ASSET_LOADED: + return STATUS_SUCCESS; + default: + // we don't know what state the asset is in yet, so keep going + // check keyframe cache first then file cache then asset request + break; + } + + LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID()); + + if(joint_motion_list) + { + // motion already existed in cache, so grab it + mJointMotionList = joint_motion_list; + + mJointStates.reserve(mJointMotionList->getNumJointMotions()); + + // don't forget to allocate joint states + // set up joint states to point to character joints + for(U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) + { + JointMotion* joint_motion = mJointMotionList->getJointMotion(i); + if (LLJoint *joint = mCharacter->getJoint(joint_motion->mJointName)) + { + LLPointer<LLJointState> joint_state = new LLJointState; + mJointStates.push_back(joint_state); + joint_state->setJoint(joint); + joint_state->setUsage(joint_motion->mUsage); + joint_state->setPriority(joint_motion->mPriority); + } + else + { + // add dummy joint state with no associated joint + mJointStates.push_back(new LLJointState); + } + } + mAssetStatus = ASSET_LOADED; + setupPose(); + return STATUS_SUCCESS; + } + + //------------------------------------------------------------------------- + // Load named file by concatenating the character prefix with the motion name. + // Load data into a buffer to be parsed. + //------------------------------------------------------------------------- + U8 *anim_data; + S32 anim_file_size; + + bool success = false; + LLFileSystem* anim_file = new LLFileSystem(mID, LLAssetType::AT_ANIMATION); + if (!anim_file || !anim_file->getSize()) + { + delete anim_file; + anim_file = NULL; + + // request asset over network on next call to load + mAssetStatus = ASSET_NEEDS_FETCH; + + return STATUS_HOLD; + } + else + { + anim_file_size = anim_file->getSize(); + anim_data = new(std::nothrow) U8[anim_file_size]; + if (anim_data) + { + success = anim_file->read(anim_data, anim_file_size); /*Flawfinder: ignore*/ + } + else + { + LL_WARNS() << "Failed to allocate buffer: " << anim_file_size << mID << LL_ENDL; + } + delete anim_file; + anim_file = NULL; + } + + if (!success) + { + LL_WARNS() << "Can't open animation file " << mID << LL_ENDL; + mAssetStatus = ASSET_FETCH_FAILED; + return STATUS_FAILURE; + } + + LL_DEBUGS() << "Loading keyframe data for: " << getName() << ":" << getID() << " (" << anim_file_size << " bytes)" << LL_ENDL; + + LLDataPackerBinaryBuffer dp(anim_data, anim_file_size); + + if (!deserialize(dp, getID())) + { + LL_WARNS() << "Failed to decode asset for animation " << getName() << ":" << getID() << LL_ENDL; + mAssetStatus = ASSET_FETCH_FAILED; + return STATUS_FAILURE; + } + + delete []anim_data; + + mAssetStatus = ASSET_LOADED; + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// setupPose() +//----------------------------------------------------------------------------- +bool LLKeyframeMotion::setupPose() +{ + // add all valid joint states to the pose + for (U32 jm=0; jm<mJointMotionList->getNumJointMotions(); jm++) + { + LLPointer<LLJointState> joint_state = getJointState(jm); + if ( joint_state->getJoint() ) + { + addJointState( joint_state ); + } + } + + // initialize joint constraints + for (JointConstraintSharedData* shared_constraintp : mJointMotionList->mConstraints) + { + JointConstraint* constraintp = new JointConstraint(shared_constraintp); + initializeConstraint(constraintp); + mConstraints.push_front(constraintp); + } + + if (mJointMotionList->mConstraints.size()) + { + mPelvisp = mCharacter->getJoint("mPelvis"); + if (!mPelvisp) + { + return false; + } + } + + // setup loop keys + setLoopIn(mJointMotionList->mLoopInPoint); + setLoopOut(mJointMotionList->mLoopOutPoint); + + return true; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLKeyframeMotion::onActivate() +{ + // If the keyframe anim has an associated emote, trigger it. + if (mJointMotionList->mEmoteID.notNull()) + { + // don't start emote if already active to avoid recursion + if (!mCharacter->isMotionActive(mJointMotionList->mEmoteID)) + { + mCharacter->startMotion(mJointMotionList->mEmoteID); + } + } + + mLastLoopedTime = 0.f; + + return true; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + // llassert(time >= 0.f); // This will fire + time = llmax(0.f, time); + + if (mJointMotionList->mLoop) + { + if (mJointMotionList->mDuration == 0.0f) + { + time = 0.f; + mLastLoopedTime = 0.0f; + } + else if (mStopped) + { + mLastLoopedTime = llmin(mJointMotionList->mDuration, mLastLoopedTime + time - mLastUpdateTime); + } + else if (time > mJointMotionList->mLoopOutPoint) + { + if ((mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint) == 0.f) + { + mLastLoopedTime = mJointMotionList->mLoopOutPoint; + } + else + { + mLastLoopedTime = mJointMotionList->mLoopInPoint + + fmod(time - mJointMotionList->mLoopOutPoint, + mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint); + } + } + else + { + mLastLoopedTime = time; + } + } + else + { + mLastLoopedTime = time; + } + + applyKeyframes(mLastLoopedTime); + + applyConstraints(mLastLoopedTime, joint_mask); + + mLastUpdateTime = time; + + return mLastLoopedTime <= mJointMotionList->mDuration; +} + +//----------------------------------------------------------------------------- +// applyKeyframes() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::applyKeyframes(F32 time) +{ + llassert_always (mJointMotionList->getNumJointMotions() <= mJointStates.size()); + for (U32 i=0; i<mJointMotionList->getNumJointMotions(); i++) + { + mJointMotionList->getJointMotion(i)->update(mJointStates[i], + time, + mJointMotionList->mDuration ); + } + + LLJoint::JointPriority* pose_priority = (LLJoint::JointPriority* )mCharacter->getAnimationData("Hand Pose Priority"); + if (pose_priority) + { + if (mJointMotionList->mMaxPriority >= *pose_priority) + { + mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose); + mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority); + } + } + else + { + mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose); + mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority); + } +} + +//----------------------------------------------------------------------------- +// applyConstraints() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::applyConstraints(F32 time, U8* joint_mask) +{ + //TODO: investigate replacing spring simulation with critically damped motion + + // re-init constraints if skeleton has changed + if (mCharacter->getSkeletonSerialNum() != mLastSkeletonSerialNum) + { + mLastSkeletonSerialNum = mCharacter->getSkeletonSerialNum(); + for (JointConstraint* constraintp : mConstraints) + { + initializeConstraint(constraintp); + } + } + + // apply constraints + for (JointConstraint* constraintp : mConstraints) + { + applyConstraint(constraintp, time, joint_mask); + } +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::onDeactivate() +{ + for (JointConstraint* constraintp : mConstraints) + { + deactivateConstraint(constraintp); + } +} + +//----------------------------------------------------------------------------- +// setStopTime() +//----------------------------------------------------------------------------- +// time is in seconds since character creation +void LLKeyframeMotion::setStopTime(F32 time) +{ + LLMotion::setStopTime(time); + + if (mJointMotionList->mLoop && mJointMotionList->mLoopOutPoint != mJointMotionList->mDuration) + { + F32 start_loop_time = mActivationTimestamp + mJointMotionList->mLoopInPoint; + F32 loop_fraction_time; + if (mJointMotionList->mLoopOutPoint == mJointMotionList->mLoopInPoint) + { + loop_fraction_time = 0.f; + } + else + { + loop_fraction_time = fmod(time - start_loop_time, + mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint); + } + mStopTimestamp = llmax(time, + (time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration()); + } +} + +//----------------------------------------------------------------------------- +// initializeConstraint() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint) +{ + JointConstraintSharedData *shared_data = constraint->mSharedData; + + S32 joint_num; + LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset); + LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]); + if ( !cur_joint ) + { + return; + } + + F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition()); + + constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos); + + // grab joint lengths + for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++) + { + cur_joint = getJointState(shared_data->mJointStateIndices[joint_num])->getJoint(); + if (!cur_joint) + { + return; + } + constraint->mJointLengths[joint_num] = dist_vec(cur_joint->getWorldPosition(), cur_joint->getParent()->getWorldPosition()); + constraint->mTotalLength += constraint->mJointLengths[joint_num]; + } + + // store fraction of total chain length so we know how to shear the entire chain towards the goal position + for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++) + { + constraint->mJointLengthFractions[joint_num] = constraint->mJointLengths[joint_num] / constraint->mTotalLength; + } + + // add last step in chain, from final joint to constraint position + constraint->mTotalLength += source_pos_offset; + + constraint->mSourceVolume = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume); + constraint->mTargetVolume = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume); +} + +//----------------------------------------------------------------------------- +// activateConstraint() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::activateConstraint(JointConstraint* constraint) +{ + JointConstraintSharedData *shared_data = constraint->mSharedData; + constraint->mActive = true; + S32 joint_num; + + // grab ground position if we need to + if (shared_data->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND) + { + LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset); + LLVector3 ground_pos_agent; + mCharacter->getGround(source_pos, ground_pos_agent, constraint->mGroundNorm); + constraint->mGroundPos = mCharacter->getPosGlobalFromAgent(ground_pos_agent + shared_data->mTargetConstraintOffset); + } + + for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++) + { + LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]); + if ( !cur_joint ) + { + return; + } + constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation(); + } + + constraint->mWeight = 1.f; +} + +//----------------------------------------------------------------------------- +// deactivateConstraint() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::deactivateConstraint(JointConstraint *constraintp) +{ + if (constraintp->mSourceVolume) + { + constraintp->mSourceVolume->mUpdateXform = false; + } + + if (constraintp->mSharedData->mConstraintTargetType != CONSTRAINT_TARGET_TYPE_GROUND) + { + if (constraintp->mTargetVolume) + { + constraintp->mTargetVolume->mUpdateXform = false; + } + } + constraintp->mActive = false; +} + +//----------------------------------------------------------------------------- +// applyConstraint() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8* joint_mask) +{ + JointConstraintSharedData *shared_data = constraint->mSharedData; + if (!shared_data) return; + + LLVector3 positions[MAX_CHAIN_LENGTH]; + const F32* joint_lengths = constraint->mJointLengths; + LLVector3 velocities[MAX_CHAIN_LENGTH - 1]; + LLQuaternion old_rots[MAX_CHAIN_LENGTH]; + S32 joint_num; + + if (time < shared_data->mEaseInStartTime) + { + return; + } + + if (time > shared_data->mEaseOutStopTime) + { + if (constraint->mActive) + { + deactivateConstraint(constraint); + } + return; + } + + if (!constraint->mActive || time < shared_data->mEaseInStopTime) + { + activateConstraint(constraint); + } + + LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]); + if (! root_joint) + { + return; + } + + LLVector3 root_pos = root_joint->getWorldPosition(); +// LLQuaternion root_rot = + root_joint->getParent()->getWorldRotation(); +// LLQuaternion inv_root_rot = ~root_rot; + +// LLVector3 current_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset); + + //apply underlying keyframe animation to get nominal "kinematic" joint positions + for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++) + { + LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]); + if (!cur_joint) + { + return; + } + + if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority()))) + { + // skip constraint + return; + } + old_rots[joint_num] = cur_joint->getRotation(); + cur_joint->setRotation(getJointState(shared_data->mJointStateIndices[joint_num])->getRotation()); + } + + + LLVector3 keyframe_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset); + LLVector3 target_pos; + + switch(shared_data->mConstraintTargetType) + { + case CONSTRAINT_TARGET_TYPE_GROUND: + target_pos = mCharacter->getPosAgentFromGlobal(constraint->mGroundPos); +// LL_INFOS() << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL; + break; + case CONSTRAINT_TARGET_TYPE_BODY: + target_pos = mCharacter->getVolumePos(shared_data->mTargetConstraintVolume, shared_data->mTargetConstraintOffset); + break; + default: + break; + } + + LLVector3 norm; + LLJoint *source_jointp = NULL; + LLJoint *target_jointp = NULL; + + if (shared_data->mConstraintType == CONSTRAINT_TYPE_PLANE) + { + switch(shared_data->mConstraintTargetType) + { + case CONSTRAINT_TARGET_TYPE_GROUND: + norm = constraint->mGroundNorm; + break; + case CONSTRAINT_TARGET_TYPE_BODY: + target_jointp = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume); + if (target_jointp) + { + // *FIX: do proper normal calculation for stretched + // spheres (inverse transpose) + norm = target_pos - target_jointp->getWorldPosition(); + } + + if (norm.isExactlyZero()) + { + source_jointp = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume); + norm = -1.f * shared_data->mSourceConstraintOffset; + if (source_jointp) + { + norm = norm * source_jointp->getWorldRotation(); + } + } + norm.normVec(); + break; + default: + norm.clearVec(); + break; + } + + target_pos = keyframe_source_pos + (norm * ((target_pos - keyframe_source_pos) * norm)); + } + + if (constraint->mSharedData->mChainLength != 0 && + dist_vec_squared(root_pos, target_pos) * 0.95f > constraint->mTotalLength * constraint->mTotalLength) + { + constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 0.f, 0.1f); + } + else + { + constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 1.f, 0.3f); + } + + F32 weight = constraint->mWeight * ((shared_data->mEaseOutStopTime == 0.f) ? 1.f : + llmin(clamp_rescale(time, shared_data->mEaseInStartTime, shared_data->mEaseInStopTime, 0.f, 1.f), + clamp_rescale(time, shared_data->mEaseOutStartTime, shared_data->mEaseOutStopTime, 1.f, 0.f))); + + LLVector3 source_to_target = target_pos - keyframe_source_pos; + + S32 max_iteration_count = ll_round(clamp_rescale( + mCharacter->getPixelArea(), + MAX_PIXEL_AREA_CONSTRAINTS, + MIN_PIXEL_AREA_CONSTRAINTS, + (F32)MAX_ITERATIONS, + (F32)MIN_ITERATIONS)); + + if (shared_data->mChainLength) + { + LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]); + + if (!end_joint) + { + return; + } + + LLQuaternion end_rot = end_joint->getWorldRotation(); + + // slam start and end of chain to the proper positions (rest of chain stays put) + positions[0] = lerp(keyframe_source_pos, target_pos, weight); + positions[shared_data->mChainLength] = root_pos; + + // grab keyframe-specified positions of joints + for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++) + { + LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]); + + if (!cur_joint) + { + return; + } + + LLVector3 kinematic_position = cur_joint->getWorldPosition() + + (source_to_target * constraint->mJointLengthFractions[joint_num]); + + // convert intermediate joint positions to world coordinates + positions[joint_num] = ( constraint->mPositions[joint_num] * mPelvisp->getWorldRotation()) + mPelvisp->getWorldPosition(); + F32 time_constant = 1.f / clamp_rescale(constraint->mFixupDistanceRMS, 0.f, 0.5f, 0.2f, 8.f); +// LL_INFOS() << "Interpolant " << LLSmoothInterpolation::getInterpolant(time_constant, false) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL; + positions[joint_num] = lerp(positions[joint_num], kinematic_position, + LLSmoothInterpolation::getInterpolant(time_constant, false)); + } + + S32 iteration_count; + for (iteration_count = 0; iteration_count < max_iteration_count; iteration_count++) + { + S32 num_joints_finished = 0; + for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++) + { + // constraint to child + LLVector3 acceleration = (positions[joint_num - 1] - positions[joint_num]) * + (dist_vec(positions[joint_num], positions[joint_num - 1]) - joint_lengths[joint_num - 1]) * JOINT_LENGTH_K; + // constraint to parent + acceleration += (positions[joint_num + 1] - positions[joint_num]) * + (dist_vec(positions[joint_num + 1], positions[joint_num]) - joint_lengths[joint_num]) * JOINT_LENGTH_K; + + if (acceleration.magVecSquared() < MIN_ACCELERATION_SQUARED) + { + num_joints_finished++; + } + + velocities[joint_num - 1] = velocities[joint_num - 1] * 0.7f; + positions[joint_num] += velocities[joint_num - 1] + (acceleration * 0.5f); + velocities[joint_num - 1] += acceleration; + } + + if ((iteration_count >= MIN_ITERATION_COUNT) && + (num_joints_finished == shared_data->mChainLength - 1)) + { +// LL_INFOS() << iteration_count << " iterations on " << +// mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL; + break; + } + } + + for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--) + { + LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]); + + if (!cur_joint) + { + return; + } + LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]); + if (!child_joint) + { + return; + } + + LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation(); + + LLQuaternion cur_rot = cur_joint->getWorldRotation(); + LLQuaternion fixup_rot; + + LLVector3 target_at = positions[joint_num - 1] - positions[joint_num]; + LLVector3 current_at; + + // at bottom of chain, use point on collision volume, not joint position + if (joint_num == 1) + { + current_at = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset) - + cur_joint->getWorldPosition(); + } + else + { + current_at = child_joint->getPosition() * cur_rot; + } + fixup_rot.shortestArc(current_at, target_at); + + LLQuaternion target_rot = cur_rot * fixup_rot; + target_rot = target_rot * ~parent_rot; + + if (weight != 1.f) + { + LLQuaternion cur_rot = getJointState(shared_data->mJointStateIndices[joint_num])->getRotation(); + target_rot = nlerp(weight, cur_rot, target_rot); + } + + getJointState(shared_data->mJointStateIndices[joint_num])->setRotation(target_rot); + cur_joint->setRotation(target_rot); + } + + LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation(); + + if (weight == 1.f) + { + getJointState(shared_data->mJointStateIndices[0])->setRotation(end_local_rot); + } + else + { + LLQuaternion cur_rot = getJointState(shared_data->mJointStateIndices[0])->getRotation(); + getJointState(shared_data->mJointStateIndices[0])->setRotation(nlerp(weight, cur_rot, end_local_rot)); + } + + // save simulated positions in pelvis-space and calculate total fixup distance + constraint->mFixupDistanceRMS = 0.f; + F32 delta_time = llmax(0.02f, llabs(time - mLastUpdateTime)); + for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++) + { + LLVector3 new_pos = (positions[joint_num] - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation(); + constraint->mFixupDistanceRMS += dist_vec_squared(new_pos, constraint->mPositions[joint_num]) / delta_time; + constraint->mPositions[joint_num] = new_pos; + } + constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1)); + constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS); + + //reset old joint rots + for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++) + { + LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]); + if (!cur_joint) + { + return; + } + + cur_joint->setRotation(old_rots[joint_num]); + } + } + // simple positional constraint (pelvis only) + else if (getJointState(shared_data->mJointStateIndices[0])->getUsage() & LLJointState::POS) + { + LLVector3 delta = source_to_target * weight; + LLPointer<LLJointState> current_joint_state = getJointState(shared_data->mJointStateIndices[0]); + LLQuaternion parent_rot = current_joint_state->getJoint()->getParent()->getWorldRotation(); + delta = delta * ~parent_rot; + current_joint_state->setPosition(current_joint_state->getJoint()->getPosition() + delta); + } +} + +//----------------------------------------------------------------------------- +// deserialize() +// +// allow_invalid_joints should be true when handling existing content, to avoid breakage. +// During upload, we should be more restrictive and reject such animations. +//----------------------------------------------------------------------------- +bool LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints) +{ + bool old_version = false; + std::unique_ptr<LLKeyframeMotion::JointMotionList> joint_motion_list(new LLKeyframeMotion::JointMotionList); + + //------------------------------------------------------------------------- + // get base priority + //------------------------------------------------------------------------- + S32 temp_priority; + U16 version; + U16 sub_version; + + // Amimation identifier for log messages + auto asset = [&]() -> std::string + { + return asset_id.asString() + ", char " + mCharacter->getID().asString(); + }; + + if (!dp.unpackU16(version, "version")) + { + LL_WARNS() << "can't read version number" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackU16(sub_version, "sub_version")) + { + LL_WARNS() << "can't read sub version number" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (version == 0 && sub_version == 1) + { + old_version = true; + } + else if (version != KEYFRAME_MOTION_VERSION || sub_version != KEYFRAME_MOTION_SUBVERSION) + { +#if LL_RELEASE + LL_WARNS() << "Bad animation version " << version << "." << sub_version + << " for animation " << asset() << LL_ENDL; + return false; +#else + LL_ERRS() << "Bad animation version " << version << "." << sub_version + << " for animation " << asset() << LL_ENDL; +#endif + } + + if (!dp.unpackS32(temp_priority, "base_priority")) + { + LL_WARNS() << "can't read animation base_priority" + << " for animation " << asset() << LL_ENDL; + return false; + } + joint_motion_list->mBasePriority = (LLJoint::JointPriority) temp_priority; + + if (joint_motion_list->mBasePriority >= LLJoint::ADDITIVE_PRIORITY) + { + joint_motion_list->mBasePriority = (LLJoint::JointPriority)((S32)LLJoint::ADDITIVE_PRIORITY-1); + joint_motion_list->mMaxPriority = joint_motion_list->mBasePriority; + } + else if (joint_motion_list->mBasePriority < LLJoint::USE_MOTION_PRIORITY) + { + LL_WARNS() << "bad animation base_priority " << joint_motion_list->mBasePriority + << " for animation " << asset() << LL_ENDL; + return false; + } + + //------------------------------------------------------------------------- + // get duration + //------------------------------------------------------------------------- + if (!dp.unpackF32(joint_motion_list->mDuration, "duration")) + { + LL_WARNS() << "can't read duration" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (joint_motion_list->mDuration > MAX_ANIM_DURATION || + !llfinite(joint_motion_list->mDuration)) + { + LL_WARNS() << "invalid animation duration" + << " for animation " << asset() << LL_ENDL; + return false; + } + + //------------------------------------------------------------------------- + // get emote (optional) + //------------------------------------------------------------------------- + if (!dp.unpackString(joint_motion_list->mEmoteName, "emote_name")) + { + LL_WARNS() << "can't read emote_name" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!joint_motion_list->mEmoteName.empty()) + { + if (joint_motion_list->mEmoteName == mID.asString()) + { + LL_WARNS() << "Malformed animation mEmoteName==mID" + << " for animation " << asset() << LL_ENDL; + return false; + } + // "Closed_Mouth" is a very popular emote name we should ignore + if (joint_motion_list->mEmoteName == "Closed_Mouth") + { + joint_motion_list->mEmoteName.clear(); + } + else + { + joint_motion_list->mEmoteID = gAnimLibrary.stringToAnimState(joint_motion_list->mEmoteName); + if (joint_motion_list->mEmoteID.isNull()) + { + LL_WARNS() << "unknown emote_name '" << joint_motion_list->mEmoteName << "'" + << " for animation " << asset() << LL_ENDL; + joint_motion_list->mEmoteName.clear(); + } + } + } + + //------------------------------------------------------------------------- + // get loop + //------------------------------------------------------------------------- + if (!dp.unpackF32(joint_motion_list->mLoopInPoint, "loop_in_point") || + !llfinite(joint_motion_list->mLoopInPoint)) + { + LL_WARNS() << "can't read loop point" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackF32(joint_motion_list->mLoopOutPoint, "loop_out_point") || + !llfinite(joint_motion_list->mLoopOutPoint)) + { + LL_WARNS() << "can't read loop point" + << " for animation " << asset() << LL_ENDL; + return false; + } + + S32 loop{ 0 }; + if (!dp.unpackS32(loop, "loop")) + { + LL_WARNS() << "can't read loop" + << " for animation " << asset() << LL_ENDL; + return false; + } + joint_motion_list->mLoop = static_cast<bool>(loop); + + //SL-17206 hack to alter Female_land loop setting, while current behavior won't be changed serverside + LLUUID const female_land_anim("ca1baf4d-0a18-5a1f-0330-e4bd1e71f09e"); + LLUUID const formal_female_land_anim("6a9a173b-61fa-3ad5-01fa-a851cfc5f66a"); + if (female_land_anim == asset_id || formal_female_land_anim == asset_id) + { + LL_WARNS() << "Animation " << asset() << " won't be looped." << LL_ENDL; + joint_motion_list->mLoop = false; + } + + //------------------------------------------------------------------------- + // get easeIn and easeOut + //------------------------------------------------------------------------- + if (!dp.unpackF32(joint_motion_list->mEaseInDuration, "ease_in_duration") || + !llfinite(joint_motion_list->mEaseInDuration)) + { + LL_WARNS() << "can't read easeIn" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackF32(joint_motion_list->mEaseOutDuration, "ease_out_duration") || + !llfinite(joint_motion_list->mEaseOutDuration)) + { + LL_WARNS() << "can't read easeOut" + << " for animation " << asset() << LL_ENDL; + return false; + } + + //------------------------------------------------------------------------- + // get hand pose + //------------------------------------------------------------------------- + U32 word; + if (!dp.unpackU32(word, "hand_pose")) + { + LL_WARNS() << "can't read hand pose" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (word > LLHandMotion::NUM_HAND_POSES) + { + LL_WARNS() << "invalid LLHandMotion::eHandPose index: " << word + << " for animation " << asset() << LL_ENDL; + return false; + } + + joint_motion_list->mHandPose = (LLHandMotion::eHandPose)word; + + //------------------------------------------------------------------------- + // get number of joint motions + //------------------------------------------------------------------------- + U32 num_motions = 0; + S32 rotation_duplicates = 0; + S32 position_duplicates = 0; + if (!dp.unpackU32(num_motions, "num_joints")) + { + LL_WARNS() << "can't read number of joints" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (num_motions == 0) + { + LL_WARNS() << "no joints" + << " for animation " << asset() << LL_ENDL; + return false; + } + else if (num_motions > LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + LL_WARNS() << "too many joints" + << " for animation " << asset() << LL_ENDL; + return false; + } + + joint_motion_list->mJointMotionArray.clear(); + joint_motion_list->mJointMotionArray.reserve(num_motions); + mJointStates.clear(); + mJointStates.reserve(num_motions); + + //------------------------------------------------------------------------- + // initialize joint motions + //------------------------------------------------------------------------- + + for (U32 i = 0; i < num_motions; ++i) + { + JointMotion* joint_motion = new JointMotion; + joint_motion_list->mJointMotionArray.push_back(joint_motion); + + std::string joint_name; + if (!dp.unpackString(joint_name, "joint_name")) + { + LL_WARNS() << "can't read joint name" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (joint_name == "mScreen" || joint_name == "mRoot") + { + LL_WARNS() << "attempted to animate special " << joint_name << " joint" + << " for animation " << asset() << LL_ENDL; + return false; + } + + //--------------------------------------------------------------------- + // find the corresponding joint + //--------------------------------------------------------------------- + LLJoint *joint = mCharacter->getJoint( joint_name ); + if (joint) + { + S32 joint_num = joint->getJointNum(); + joint_name = joint->getName(); // canonical name in case this is an alias. +// LL_INFOS() << " joint: " << joint_name << LL_ENDL; + if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) + { + LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num + << " is outside of legal range [0-" + << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName() + << " for animation " << asset() << LL_ENDL; + joint = NULL; + } + } + else + { + LL_WARNS() << "invalid joint name: " << joint_name + << " for animation " << asset() << LL_ENDL; + if (!allow_invalid_joints) + { + return false; + } + } + + joint_motion->mJointName = joint_name; + + LLPointer<LLJointState> joint_state = new LLJointState; + mJointStates.push_back(joint_state); + joint_state->setJoint( joint ); // note: can accept NULL + joint_state->setUsage( 0 ); + + //--------------------------------------------------------------------- + // get joint priority + //--------------------------------------------------------------------- + S32 joint_priority; + if (!dp.unpackS32(joint_priority, "joint_priority")) + { + LL_WARNS() << "can't read joint priority." + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (joint_priority < LLJoint::USE_MOTION_PRIORITY) + { + LL_WARNS() << "joint priority unknown - too low." + << " for animation " << asset() << LL_ENDL; + return false; + } + + joint_motion->mPriority = (LLJoint::JointPriority)joint_priority; + if (joint_priority != LLJoint::USE_MOTION_PRIORITY && + joint_priority > joint_motion_list->mMaxPriority) + { + joint_motion_list->mMaxPriority = (LLJoint::JointPriority)joint_priority; + } + + joint_state->setPriority((LLJoint::JointPriority)joint_priority); + + //--------------------------------------------------------------------- + // scan rotation curve header + //--------------------------------------------------------------------- + if (!dp.unpackS32(joint_motion->mRotationCurve.mNumKeys, "num_rot_keys") || joint_motion->mRotationCurve.mNumKeys < 0) + { + LL_WARNS() << "can't read number of rotation keys" + << " for animation " << asset() << LL_ENDL; + return false; + } + + joint_motion->mRotationCurve.mInterpolationType = IT_LINEAR; + if (joint_motion->mRotationCurve.mNumKeys != 0) + { + joint_state->setUsage(joint_state->getUsage() | LLJointState::ROT ); + } + + //--------------------------------------------------------------------- + // scan rotation curve keys + //--------------------------------------------------------------------- + RotationCurve *rCurve = &joint_motion->mRotationCurve; + + for (S32 k = 0; k < joint_motion->mRotationCurve.mNumKeys; k++) + { + F32 time; + U16 time_short; + + if (old_version) + { + if (!dp.unpackF32(time, "time") || + !llfinite(time)) + { + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + } + else + { + if (!dp.unpackU16(time_short, "time")) + { + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + time = U16_to_F32(time_short, 0.f, joint_motion_list->mDuration); + + if (time < 0 || time > joint_motion_list->mDuration) + { + LL_WARNS() << "invalid frame time" + << " for animation " << asset() << LL_ENDL; + return false; + } + } + + RotationKey rot_key; + rot_key.mTime = time; + LLVector3 rot_angles; + U16 x, y, z; + + if (old_version) + { + if (!dp.unpackVector3(rot_angles, "rot_angles")) + { + LL_WARNS() << "can't read rot_angles in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + if (!rot_angles.isFinite()) + { + LL_WARNS() << "non-finite angle in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + LLQuaternion::Order ro = StringToOrder("ZYX"); + rot_key.mRotation = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro); + } + else + { + if (!dp.unpackU16(x, "rot_angle_x")) + { + LL_WARNS() << "can't read rot_angle_x in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + if (!dp.unpackU16(y, "rot_angle_y")) + { + LL_WARNS() << "can't read rot_angle_y in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + if (!dp.unpackU16(z, "rot_angle_z")) + { + LL_WARNS() << "can't read rot_angle_z in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + LLVector3 rot_vec; + rot_vec.mV[VX] = U16_to_F32(x, -1.f, 1.f); + rot_vec.mV[VY] = U16_to_F32(y, -1.f, 1.f); + rot_vec.mV[VZ] = U16_to_F32(z, -1.f, 1.f); + + if (!rot_vec.isFinite()) + { + LL_WARNS() << "non-finite angle in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + rot_key.mRotation.unpackFromVector3(rot_vec); + } + + if (!rot_key.mRotation.isFinite()) + { + LL_WARNS() << "non-finite angle in rotation key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + rCurve->mKeys[time] = rot_key; + } + + if (joint_motion->mRotationCurve.mNumKeys > joint_motion->mRotationCurve.mKeys.size()) + { + rotation_duplicates++; + LL_INFOS() << "Motion " << asset() << " had duplicated rotation keys that were removed: " + << joint_motion->mRotationCurve.mNumKeys << " > " << joint_motion->mRotationCurve.mKeys.size() + << " (" << rotation_duplicates << ")" << LL_ENDL; + } + + //--------------------------------------------------------------------- + // scan position curve header + //--------------------------------------------------------------------- + if (!dp.unpackS32(joint_motion->mPositionCurve.mNumKeys, "num_pos_keys") || joint_motion->mPositionCurve.mNumKeys < 0) + { + LL_WARNS() << "can't read number of position keys" + << " for animation " << asset() << LL_ENDL; + return false; + } + + joint_motion->mPositionCurve.mInterpolationType = IT_LINEAR; + if (joint_motion->mPositionCurve.mNumKeys != 0) + { + joint_state->setUsage(joint_state->getUsage() | LLJointState::POS ); + } + + //--------------------------------------------------------------------- + // scan position curve keys + //--------------------------------------------------------------------- + PositionCurve *pCurve = &joint_motion->mPositionCurve; + bool is_pelvis = joint_motion->mJointName == "mPelvis"; + for (S32 k = 0; k < joint_motion->mPositionCurve.mNumKeys; k++) + { + U16 time_short; + PositionKey pos_key; + + if (old_version) + { + if (!dp.unpackF32(pos_key.mTime, "time") || + !llfinite(pos_key.mTime)) + { + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + } + else + { + if (!dp.unpackU16(time_short, "time")) + { + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + pos_key.mTime = U16_to_F32(time_short, 0.f, joint_motion_list->mDuration); + } + + if (old_version) + { + if (!dp.unpackVector3(pos_key.mPosition, "pos")) + { + LL_WARNS() << "can't read pos in position key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + //MAINT-6162 + pos_key.mPosition.mV[VX] = llclamp( pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mPosition.mV[VY] = llclamp( pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mPosition.mV[VZ] = llclamp( pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + + } + else + { + U16 x, y, z; + + if (!dp.unpackU16(x, "pos_x")) + { + LL_WARNS() << "can't read pos_x in position key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + if (!dp.unpackU16(y, "pos_y")) + { + LL_WARNS() << "can't read pos_y in position key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + if (!dp.unpackU16(z, "pos_z")) + { + LL_WARNS() << "can't read pos_z in position key (" << k << ")" + << " for animation " << asset() << LL_ENDL; + return false; + } + + pos_key.mPosition.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mPosition.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mPosition.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + } + + if (!pos_key.mPosition.isFinite()) + { + LL_WARNS() << "non-finite position in key" + << " for animation " << asset() << LL_ENDL; + return false; + } + + pCurve->mKeys[pos_key.mTime] = pos_key; + + if (is_pelvis) + { + joint_motion_list->mPelvisBBox.addPoint(pos_key.mPosition); + } + } + + if (joint_motion->mPositionCurve.mNumKeys > joint_motion->mPositionCurve.mKeys.size()) + { + position_duplicates++; + LL_INFOS() << "Motion " << asset() << " had duplicated position keys that were removed: " + << joint_motion->mPositionCurve.mNumKeys << " > " << joint_motion->mPositionCurve.mKeys.size() + << " (" << position_duplicates << ")" << LL_ENDL; + } + + joint_motion->mUsage = joint_state->getUsage(); + } + + if (rotation_duplicates > 0) + { + LL_INFOS() << "Motion " << asset() << " had " << rotation_duplicates + << " duplicated rotation keys that were removed" << LL_ENDL; + } + + if (position_duplicates > 0) + { + LL_INFOS() << "Motion " << asset() << " had " << position_duplicates + << " duplicated position keys that were removed" << LL_ENDL; + } + + //------------------------------------------------------------------------- + // get number of constraints + //------------------------------------------------------------------------- + S32 num_constraints = 0; + if (!dp.unpackS32(num_constraints, "num_constraints")) + { + LL_WARNS() << "can't read number of constraints" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (num_constraints > MAX_CONSTRAINTS || num_constraints < 0) + { + LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints + << " for animation " << asset() << LL_ENDL; + } + else + { + //------------------------------------------------------------------------- + // get constraints + //------------------------------------------------------------------------- + std::string str; + for(S32 i = 0; i < num_constraints; ++i) + { + // read in constraint data + std::unique_ptr<JointConstraintSharedData> constraintp(new JointConstraintSharedData); + U8 byte = 0; + + if (!dp.unpackU8(byte, "chain_length")) + { + LL_WARNS() << "can't read constraint chain length" + << " for animation " << asset() << LL_ENDL; + return false; + } + constraintp->mChainLength = (S32) byte; + + if((U32)constraintp->mChainLength > joint_motion_list->getNumJointMotions()) + { + LL_WARNS() << "invalid constraint chain length" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackU8(byte, "constraint_type")) + { + LL_WARNS() << "can't read constraint type" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if( byte >= NUM_CONSTRAINT_TYPES ) + { + LL_WARNS() << "invalid constraint type" + << " for animation " << asset() << LL_ENDL; + return false; + } + constraintp->mConstraintType = (EConstraintType)byte; + + const S32 BIN_DATA_LENGTH = 16; + U8 bin_data[BIN_DATA_LENGTH+1]; + if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "source_volume")) + { + LL_WARNS() << "can't read source volume name" + << " for animation " << asset() << LL_ENDL; + return false; + } + + bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination + str = (char*)bin_data; + constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str); + if (constraintp->mSourceConstraintVolume == -1) + { + LL_WARNS() << "not a valid source constraint volume " << str + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset")) + { + LL_WARNS() << "can't read constraint source offset" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if( !(constraintp->mSourceConstraintOffset.isFinite()) ) + { + LL_WARNS() << "non-finite constraint source offset" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "target_volume")) + { + LL_WARNS() << "can't read target volume name" + << " for animation " << asset() << LL_ENDL; + return false; + } + + bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination + str = (char*)bin_data; + if (str == "GROUND") + { + // constrain to ground + constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_GROUND; + } + else + { + constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_BODY; + constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str); + if (constraintp->mTargetConstraintVolume == -1) + { + LL_WARNS() << "not a valid target constraint volume " << str + << " for animation " << asset() << LL_ENDL; + return false; + } + } + + if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset")) + { + LL_WARNS() << "can't read constraint target offset" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if( !(constraintp->mTargetConstraintOffset.isFinite()) ) + { + LL_WARNS() << "non-finite constraint target offset" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackVector3(constraintp->mTargetConstraintDir, "target_dir")) + { + LL_WARNS() << "can't read constraint target direction" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if( !(constraintp->mTargetConstraintDir.isFinite()) ) + { + LL_WARNS() << "non-finite constraint target direction" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!constraintp->mTargetConstraintDir.isExactlyZero()) + { + constraintp->mUseTargetOffset = true; + // constraintp->mTargetConstraintDir *= constraintp->mSourceConstraintOffset.magVec(); + } + + if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !llfinite(constraintp->mEaseInStartTime)) + { + LL_WARNS() << "can't read constraint ease in start time" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !llfinite(constraintp->mEaseInStopTime)) + { + LL_WARNS() << "can't read constraint ease in stop time" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !llfinite(constraintp->mEaseOutStartTime)) + { + LL_WARNS() << "can't read constraint ease out start time" + << " for animation " << asset() << LL_ENDL; + return false; + } + + if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !llfinite(constraintp->mEaseOutStopTime)) + { + LL_WARNS() << "can't read constraint ease out stop time" + << " for animation " << asset() << LL_ENDL; + return false; + } + + LLJoint* joint = mCharacter->findCollisionVolume(constraintp->mSourceConstraintVolume); + // get joint to which this collision volume is attached + if (!joint) + { + return false; + } + + constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte + + for (S32 i = 0; i < constraintp->mChainLength + 1; i++) + { + LLJoint* parent = joint->getParent(); + if (!parent) + { + LL_WARNS() << "Joint with no parent: " << joint->getName() + << " Emote: " << joint_motion_list->mEmoteName + << " for animation " << asset() << LL_ENDL; + return false; + } + joint = parent; + constraintp->mJointStateIndices[i] = -1; + for (U32 j = 0; j < joint_motion_list->getNumJointMotions(); j++) + { + LLJoint* constraint_joint = getJoint(j); + + if ( !constraint_joint ) + { + LL_WARNS() << "Invalid joint " << j + << " for animation " << asset() << LL_ENDL; + return false; + } + + if(constraint_joint == joint) + { + constraintp->mJointStateIndices[i] = (S32)j; + break; + } + } + if (constraintp->mJointStateIndices[i] < 0 ) + { + LL_WARNS() << "No joint index for constraint " << i + << " for animation " << asset() << LL_ENDL; + return false; + } + } + + joint_motion_list->mConstraints.push_front(constraintp.release()); + } + } + + // *FIX: support cleanup of old keyframe data + mJointMotionList = joint_motion_list.release(); // release from unique_ptr to member; + LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList); + mAssetStatus = ASSET_LOADED; + + setupPose(); + + return true; +} + +//----------------------------------------------------------------------------- +// serialize() +//----------------------------------------------------------------------------- +bool LLKeyframeMotion::serialize(LLDataPacker& dp) const +{ + bool success = true; + + LL_DEBUGS("BVH") << "serializing" << LL_ENDL; + + success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version"); + success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version"); + success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority"); + success &= dp.packF32(mJointMotionList->mDuration, "duration"); + success &= dp.packString(mJointMotionList->mEmoteName, "emote_name"); + success &= dp.packF32(mJointMotionList->mLoopInPoint, "loop_in_point"); + success &= dp.packF32(mJointMotionList->mLoopOutPoint, "loop_out_point"); + success &= dp.packS32(mJointMotionList->mLoop, "loop"); + success &= dp.packF32(mJointMotionList->mEaseInDuration, "ease_in_duration"); + success &= dp.packF32(mJointMotionList->mEaseOutDuration, "ease_out_duration"); + success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose"); + success &= dp.packU32(mJointMotionList->getNumJointMotions(), "num_joints"); + + LL_DEBUGS("BVH") << "version " << KEYFRAME_MOTION_VERSION << LL_ENDL; + LL_DEBUGS("BVH") << "sub_version " << KEYFRAME_MOTION_SUBVERSION << LL_ENDL; + LL_DEBUGS("BVH") << "base_priority " << mJointMotionList->mBasePriority << LL_ENDL; + LL_DEBUGS("BVH") << "duration " << mJointMotionList->mDuration << LL_ENDL; + LL_DEBUGS("BVH") << "emote_name " << mJointMotionList->mEmoteName << LL_ENDL; + LL_DEBUGS("BVH") << "loop_in_point " << mJointMotionList->mLoopInPoint << LL_ENDL; + LL_DEBUGS("BVH") << "loop_out_point " << mJointMotionList->mLoopOutPoint << LL_ENDL; + LL_DEBUGS("BVH") << "loop " << mJointMotionList->mLoop << LL_ENDL; + LL_DEBUGS("BVH") << "ease_in_duration " << mJointMotionList->mEaseInDuration << LL_ENDL; + LL_DEBUGS("BVH") << "ease_out_duration " << mJointMotionList->mEaseOutDuration << LL_ENDL; + LL_DEBUGS("BVH") << "hand_pose " << mJointMotionList->mHandPose << LL_ENDL; + LL_DEBUGS("BVH") << "num_joints " << mJointMotionList->getNumJointMotions() << LL_ENDL; + + for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) + { + JointMotion* joint_motionp = mJointMotionList->getJointMotion(i); + success &= dp.packString(joint_motionp->mJointName, "joint_name"); + success &= dp.packS32(joint_motionp->mPriority, "joint_priority"); + success &= dp.packS32(joint_motionp->mRotationCurve.mKeys.size(), "num_rot_keys"); + + LL_DEBUGS("BVH") << "Joint " << i + << " name: " << joint_motionp->mJointName + << " Rotation keys: " << joint_motionp->mRotationCurve.mKeys.size() + << " Position keys: " << joint_motionp->mPositionCurve.mKeys.size() << LL_ENDL; + for (RotationCurve::key_map_t::value_type& rot_pair : joint_motionp->mRotationCurve.mKeys) + { + RotationKey& rot_key = rot_pair.second; + U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration); + success &= dp.packU16(time_short, "time"); + + LLVector3 rot_angles = rot_key.mRotation.packToVector3(); + + U16 x, y, z; + rot_angles.quantize16(-1.f, 1.f, -1.f, 1.f); + x = F32_to_U16(rot_angles.mV[VX], -1.f, 1.f); + y = F32_to_U16(rot_angles.mV[VY], -1.f, 1.f); + z = F32_to_U16(rot_angles.mV[VZ], -1.f, 1.f); + success &= dp.packU16(x, "rot_angle_x"); + success &= dp.packU16(y, "rot_angle_y"); + success &= dp.packU16(z, "rot_angle_z"); + + LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL; + } + + success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys"); + for (PositionCurve::key_map_t::value_type& pos_pair : joint_motionp->mPositionCurve.mKeys) + { + PositionKey& pos_key = pos_pair.second; + U16 time_short = F32_to_U16(pos_key.mTime, 0.f, mJointMotionList->mDuration); + success &= dp.packU16(time_short, "time"); + + U16 x, y, z; + pos_key.mPosition.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + x = F32_to_U16(pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + y = F32_to_U16(pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + z = F32_to_U16(pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + success &= dp.packU16(x, "pos_x"); + success &= dp.packU16(y, "pos_y"); + success &= dp.packU16(z, "pos_z"); + + LL_DEBUGS("BVH") << " pos: t " << pos_key.mTime << " pos " << pos_key.mPosition.mV[VX] <<","<< pos_key.mPosition.mV[VY] <<","<< pos_key.mPosition.mV[VZ] << LL_ENDL; + } + } + + success &= dp.packS32(mJointMotionList->mConstraints.size(), "num_constraints"); + LL_DEBUGS("BVH") << "num_constraints " << mJointMotionList->mConstraints.size() << LL_ENDL; + for (JointConstraintSharedData* shared_constraintp : mJointMotionList->mConstraints) + { + success &= dp.packU8(shared_constraintp->mChainLength, "chain_length"); + success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type"); + char source_volume[16]; /* Flawfinder: ignore */ + snprintf(source_volume, sizeof(source_volume), "%s", /* Flawfinder: ignore */ + mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str()); + + success &= dp.packBinaryDataFixed((U8*)source_volume, 16, "source_volume"); + success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset"); + char target_volume[16]; /* Flawfinder: ignore */ + if (shared_constraintp->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND) + { + snprintf(target_volume,sizeof(target_volume), "%s", "GROUND"); /* Flawfinder: ignore */ + } + else + { + snprintf(target_volume, sizeof(target_volume),"%s", /* Flawfinder: ignore */ + mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str()); + } + success &= dp.packBinaryDataFixed((U8*)target_volume, 16, "target_volume"); + success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset"); + success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir"); + success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start"); + success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop"); + success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start"); + success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop"); + + LL_DEBUGS("BVH") << " chain_length " << shared_constraintp->mChainLength << LL_ENDL; + LL_DEBUGS("BVH") << " constraint_type " << (S32)shared_constraintp->mConstraintType << LL_ENDL; + LL_DEBUGS("BVH") << " source_volume " << source_volume << LL_ENDL; + LL_DEBUGS("BVH") << " source_offset " << shared_constraintp->mSourceConstraintOffset << LL_ENDL; + LL_DEBUGS("BVH") << " target_volume " << target_volume << LL_ENDL; + LL_DEBUGS("BVH") << " target_offset " << shared_constraintp->mTargetConstraintOffset << LL_ENDL; + LL_DEBUGS("BVH") << " target_dir " << shared_constraintp->mTargetConstraintDir << LL_ENDL; + LL_DEBUGS("BVH") << " ease_in_start " << shared_constraintp->mEaseInStartTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_in_stop " << shared_constraintp->mEaseInStopTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_out_start " << shared_constraintp->mEaseOutStartTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_out_stop " << shared_constraintp->mEaseOutStopTime << LL_ENDL; + } + + return success; +} + +//----------------------------------------------------------------------------- +// getFileSize() +//----------------------------------------------------------------------------- +U32 LLKeyframeMotion::getFileSize() +{ + // serialize into a dummy buffer to calculate required size + LLDataPackerBinaryBuffer dp; + serialize(dp); + + return dp.getCurrentSize(); +} + +//----------------------------------------------------------------------------- +// dumpToFile() +//----------------------------------------------------------------------------- +bool LLKeyframeMotion::dumpToFile(const std::string& name) +{ + bool succ = false; + if (isLoaded()) + { + std::string outfile_base; + if (!name.empty()) + { + outfile_base = name; + } + else if (!getName().empty()) + { + outfile_base = getName(); + } + else + { + const LLUUID& id = getID(); + outfile_base = id.asString(); + } + + if (gDirUtilp->getExtension(outfile_base).empty()) + { + outfile_base += ".anim"; + } + std::string outfilename; + if (gDirUtilp->getDirName(outfile_base).empty()) + { + outfilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfile_base); + } + else + { + outfilename = outfile_base; + } + if (LLFile::isfile(outfilename)) + { + LL_WARNS() << outfilename << " already exists, write failed" << LL_ENDL; + return false; + } + + S32 file_size = getFileSize(); + U8* buffer = new U8[file_size]; + + LL_DEBUGS("BVH") << "Dumping " << outfilename << LL_ENDL; + LLDataPackerBinaryBuffer dp(buffer, file_size); + if (serialize(dp)) + { + LLAPRFile outfile; + outfile.open(outfilename, LL_APR_WPB); + if (outfile.getFileHandle()) + { + S32 wrote_bytes = outfile.write(buffer, file_size); + succ = (wrote_bytes == file_size); + } + } + delete [] buffer; + } + return succ; +} + +//----------------------------------------------------------------------------- +// getPelvisBBox() +//----------------------------------------------------------------------------- +const LLBBoxLocal &LLKeyframeMotion::getPelvisBBox() +{ + return mJointMotionList->mPelvisBBox; +} + +//----------------------------------------------------------------------------- +// setPriority() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setPriority(S32 priority) +{ + if (mJointMotionList) + { + S32 priority_delta = priority - mJointMotionList->mBasePriority; + mJointMotionList->mBasePriority = (LLJoint::JointPriority)priority; + mJointMotionList->mMaxPriority = mJointMotionList->mBasePriority; + + for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) + { + JointMotion* joint_motion = mJointMotionList->getJointMotion(i); + joint_motion->mPriority = (LLJoint::JointPriority)llclamp( + (S32)joint_motion->mPriority + priority_delta, + (S32)LLJoint::LOW_PRIORITY, + (S32)LLJoint::HIGHEST_PRIORITY); + getJointState(i)->setPriority(joint_motion->mPriority); + } + } +} + +//----------------------------------------------------------------------------- +// setEmote() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setEmote(const LLUUID& emote_id) +{ + const char* emote_name = gAnimLibrary.animStateToString(emote_id); + if (emote_name) + { + mJointMotionList->mEmoteName = emote_name; + mJointMotionList->mEmoteID = emote_id; + } + else + { + mJointMotionList->mEmoteName.clear(); + mJointMotionList->mEmoteID.setNull(); + } +} + +//----------------------------------------------------------------------------- +// setEaseIn() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setEaseIn(F32 ease_in) +{ + if (mJointMotionList) + { + mJointMotionList->mEaseInDuration = llmax(ease_in, 0.f); + } +} + +//----------------------------------------------------------------------------- +// setEaseOut() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setEaseOut(F32 ease_in) +{ + if (mJointMotionList) + { + mJointMotionList->mEaseOutDuration = llmax(ease_in, 0.f); + } +} + + +//----------------------------------------------------------------------------- +// flushKeyframeCache() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::flushKeyframeCache() +{ + // TODO: Make this safe to do +// LLKeyframeDataCache::clear(); +} + +//----------------------------------------------------------------------------- +// setLoop() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setLoop(bool loop) +{ + if (mJointMotionList) + { + mJointMotionList->mLoop = loop; + mSendStopTimestamp = F32_MAX; + } +} + + +//----------------------------------------------------------------------------- +// setLoopIn() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setLoopIn(F32 in_point) +{ + if (mJointMotionList) + { + mJointMotionList->mLoopInPoint = in_point; + + // set up loop keys + for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) + { + JointMotion* joint_motion = mJointMotionList->getJointMotion(i); + + PositionCurve* pos_curve = &joint_motion->mPositionCurve; + RotationCurve* rot_curve = &joint_motion->mRotationCurve; + ScaleCurve* scale_curve = &joint_motion->mScaleCurve; + + pos_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint; + rot_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint; + scale_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint; + + pos_curve->mLoopInKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); + rot_curve->mLoopInKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); + scale_curve->mLoopInKey.mScale = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); + } + } +} + +//----------------------------------------------------------------------------- +// setLoopOut() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::setLoopOut(F32 out_point) +{ + if (mJointMotionList) + { + mJointMotionList->mLoopOutPoint = out_point; + + // set up loop keys + for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) + { + JointMotion* joint_motion = mJointMotionList->getJointMotion(i); + + PositionCurve* pos_curve = &joint_motion->mPositionCurve; + RotationCurve* rot_curve = &joint_motion->mRotationCurve; + ScaleCurve* scale_curve = &joint_motion->mScaleCurve; + + pos_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint; + rot_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint; + scale_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint; + + pos_curve->mLoopOutKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); + rot_curve->mLoopOutKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); + scale_curve->mLoopOutKey.mScale = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); + } + } +} + +//----------------------------------------------------------------------------- +// onLoadComplete() +//----------------------------------------------------------------------------- +void LLKeyframeMotion::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLUUID* id = (LLUUID*)user_data; + + std::vector<LLCharacter* >::iterator char_iter = LLCharacter::sInstances.begin(); + + while(char_iter != LLCharacter::sInstances.end() && + (*char_iter)->getID() != *id) + { + ++char_iter; + } + + delete id; + + if (char_iter == LLCharacter::sInstances.end()) + { + return; + } + + LLCharacter* character = *char_iter; + + // look for an existing instance of this motion + LLKeyframeMotion* motionp = static_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid)); + if (motionp) + { + if (0 == status) + { + if (motionp->mAssetStatus == ASSET_LOADED) + { + // asset already loaded + return; + } + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); + S32 size = file.getSize(); + + U8* buffer = new U8[size]; + file.read((U8*)buffer, size); /*Flawfinder: ignore*/ + + LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL; + + LLDataPackerBinaryBuffer dp(buffer, size); + if (motionp->deserialize(dp, asset_uuid)) + { + motionp->mAssetStatus = ASSET_LOADED; + } + else + { + LL_WARNS() << "Failed to decode asset for animation " << motionp->getName() << ":" << motionp->getID() << LL_ENDL; + motionp->mAssetStatus = ASSET_FETCH_FAILED; + } + + delete[] buffer; + } + else + { + LL_WARNS() << "Failed to load asset for animation " << motionp->getName() << ":" << motionp->getID() << LL_ENDL; + motionp->mAssetStatus = ASSET_FETCH_FAILED; + } + } + else + { + LL_WARNS() << "No existing motion for asset data. UUID: " << asset_uuid << LL_ENDL; + } +} + +//-------------------------------------------------------------------- +// LLKeyframeDataCache::dumpDiagInfo() +//-------------------------------------------------------------------- +void LLKeyframeDataCache::dumpDiagInfo() +{ + // keep track of totals + U32 total_size = 0; + + char buf[1024]; /* Flawfinder: ignore */ + + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + LL_INFOS() << " Global Motion Table (DEBUG only)" << LL_ENDL; + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + + // print each loaded mesh, and it's memory usage + for (keyframe_data_map_t::value_type& data_pair : sKeyframeDataMap) + { + U32 joint_motion_kb; + + LLKeyframeMotion::JointMotionList *motion_list_p = data_pair.second; + + LL_INFOS() << "Motion: " << data_pair.first << LL_ENDL; + + joint_motion_kb = motion_list_p->dumpDiagInfo(); + + total_size += joint_motion_kb; + } + + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + LL_INFOS() << "Motions\tTotal Size" << LL_ENDL; + snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */ + LL_INFOS() << buf << LL_ENDL; + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; +} + + +//-------------------------------------------------------------------- +// LLKeyframeDataCache::addKeyframeData() +//-------------------------------------------------------------------- +void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp) +{ + sKeyframeDataMap[id] = joint_motion_listp; +} + +//-------------------------------------------------------------------- +// LLKeyframeDataCache::removeKeyframeData() +//-------------------------------------------------------------------- +void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id) +{ + keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id); + if (found_data != sKeyframeDataMap.end()) + { + delete found_data->second; + sKeyframeDataMap.erase(found_data); + } +} + +//-------------------------------------------------------------------- +// LLKeyframeDataCache::getKeyframeData() +//-------------------------------------------------------------------- +LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id) +{ + keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id); + if (found_data == sKeyframeDataMap.end()) + { + return NULL; + } + return found_data->second; +} + +//-------------------------------------------------------------------- +// ~LLKeyframeDataCache::LLKeyframeDataCache() +//-------------------------------------------------------------------- +LLKeyframeDataCache::~LLKeyframeDataCache() +{ + clear(); +} + +//----------------------------------------------------------------------------- +// clear() +//----------------------------------------------------------------------------- +void LLKeyframeDataCache::clear() +{ + for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer()); + sKeyframeDataMap.clear(); +} + +//----------------------------------------------------------------------------- +// JointConstraint() +//----------------------------------------------------------------------------- +LLKeyframeMotion::JointConstraint::JointConstraint(JointConstraintSharedData* shared_data) : mSharedData(shared_data) +{ + mWeight = 0.f; + mTotalLength = 0.f; + mActive = false; + mSourceVolume = NULL; + mTargetVolume = NULL; + mFixupDistanceRMS = 0.f; + + for (S32 i=0; i<MAX_CHAIN_LENGTH; ++i) + { + mJointLengths[i] = 0.f; + mJointLengthFractions[i] = 0.f; + } +} + +//----------------------------------------------------------------------------- +// ~JointConstraint() +//----------------------------------------------------------------------------- +LLKeyframeMotion::JointConstraint::~JointConstraint() +{ +} + +// End + diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index a2c3eacbe1..edf2308050 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -1,464 +1,464 @@ -/**
- * @file llkeyframemotion.h
- * @brief Implementation of LLKeframeMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLKEYFRAMEMOTION_H
-#define LL_LLKEYFRAMEMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-
-#include <string>
-
-#include "llassetstorage.h"
-#include "llbboxlocal.h"
-#include "llhandmotion.h"
-#include "lljointstate.h"
-#include "llmotion.h"
-#include "llquaternion.h"
-#include "v3dmath.h"
-#include "v3math.h"
-#include "llbvhconsts.h"
-
-class LLKeyframeDataCache;
-class LLDataPacker;
-
-#define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f)
-#define MAX_CHAIN_LENGTH (4)
-
-const S32 KEYFRAME_MOTION_VERSION = 1;
-const S32 KEYFRAME_MOTION_SUBVERSION = 0;
-
-//-----------------------------------------------------------------------------
-// class LLKeyframeMotion
-//-----------------------------------------------------------------------------
-class LLKeyframeMotion :
- public LLMotion
-{
- friend class LLKeyframeDataCache;
-public:
- // Constructor
- LLKeyframeMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLKeyframeMotion();
-
-private:
- // private helper functions to wrap some asserts
- LLPointer<LLJointState>& getJointState(U32 index);
- LLJoint* getJoint(U32 index );
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID& id);
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() {
- if (mJointMotionList) return mJointMotionList->mLoop;
- else return false;
- }
-
- // motions must report their total duration
- virtual F32 getDuration() {
- if (mJointMotionList) return mJointMotionList->mDuration;
- else return 0.f;
- }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() {
- if (mJointMotionList) return mJointMotionList->mEaseInDuration;
- else return 0.f;
- }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() {
- if (mJointMotionList) return mJointMotionList->mEaseOutDuration;
- else return 0.f;
- }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() {
- if (mJointMotionList) return mJointMotionList->mBasePriority;
- else return LLJoint::LOW_PRIORITY;
- }
-
- virtual S32 getNumJointMotions()
- {
- if (mJointMotionList)
- {
- return mJointMotionList->getNumJointMotions();
- }
- return 0;
- }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
- virtual void setStopTime(F32 time);
-
- static void onLoadComplete(const LLUUID& asset_uuid,
- LLAssetType::EType type,
- void* user_data, S32 status, LLExtStat ext_status);
-
-public:
- U32 getFileSize();
- bool serialize(LLDataPacker& dp) const;
- bool deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints = true);
- bool isLoaded() { return mJointMotionList != NULL; }
- bool dumpToFile(const std::string& name);
-
-
- // setters for modifying a keyframe animation
- void setLoop(bool loop);
-
- F32 getLoopIn() {
- return (mJointMotionList) ? mJointMotionList->mLoopInPoint : 0.f;
- }
-
- F32 getLoopOut() {
- return (mJointMotionList) ? mJointMotionList->mLoopOutPoint : 0.f;
- }
-
- void setLoopIn(F32 in_point);
-
- void setLoopOut(F32 out_point);
-
- void setHandPose(LLHandMotion::eHandPose pose) {
- if (mJointMotionList) mJointMotionList->mHandPose = pose;
- }
-
- LLHandMotion::eHandPose getHandPose() {
- return (mJointMotionList) ? mJointMotionList->mHandPose : LLHandMotion::HAND_POSE_RELAXED;
- }
-
- void setPriority(S32 priority);
-
- void setEmote(const LLUUID& emote_id);
-
- void setEaseIn(F32 ease_in);
-
- void setEaseOut(F32 ease_in);
-
- F32 getLastUpdateTime() { return mLastLoopedTime; }
-
- const LLBBoxLocal& getPelvisBBox();
-
- static void flushKeyframeCache();
-
-protected:
- //-------------------------------------------------------------------------
- // JointConstraintSharedData
- //-------------------------------------------------------------------------
- class JointConstraintSharedData
- {
- public:
- JointConstraintSharedData() :
- mChainLength(0),
- mEaseInStartTime(0.f),
- mEaseInStopTime(0.f),
- mEaseOutStartTime(0.f),
- mEaseOutStopTime(0.f),
- mUseTargetOffset(false),
- mConstraintType(CONSTRAINT_TYPE_POINT),
- mConstraintTargetType(CONSTRAINT_TARGET_TYPE_BODY),
- mSourceConstraintVolume(0),
- mTargetConstraintVolume(0),
- mJointStateIndices(NULL)
- { };
- ~JointConstraintSharedData() { delete [] mJointStateIndices; }
-
- S32 mSourceConstraintVolume;
- LLVector3 mSourceConstraintOffset;
- S32 mTargetConstraintVolume;
- LLVector3 mTargetConstraintOffset;
- LLVector3 mTargetConstraintDir;
- S32 mChainLength;
- S32* mJointStateIndices;
- F32 mEaseInStartTime;
- F32 mEaseInStopTime;
- F32 mEaseOutStartTime;
- F32 mEaseOutStopTime;
- bool mUseTargetOffset;
- EConstraintType mConstraintType;
- EConstraintTargetType mConstraintTargetType;
- };
-
- //-----------------------------------------------------------------------------
- // JointConstraint()
- //-----------------------------------------------------------------------------
- class JointConstraint
- {
- public:
- JointConstraint(JointConstraintSharedData* shared_data);
- ~JointConstraint();
-
- JointConstraintSharedData* mSharedData;
- F32 mWeight;
- F32 mTotalLength;
- LLVector3 mPositions[MAX_CHAIN_LENGTH];
- F32 mJointLengths[MAX_CHAIN_LENGTH];
- F32 mJointLengthFractions[MAX_CHAIN_LENGTH];
- bool mActive;
- LLVector3d mGroundPos;
- LLVector3 mGroundNorm;
- LLJoint* mSourceVolume;
- LLJoint* mTargetVolume;
- F32 mFixupDistanceRMS;
- };
-
- void applyKeyframes(F32 time);
-
- void applyConstraints(F32 time, U8* joint_mask);
-
- void activateConstraint(JointConstraint* constraintp);
-
- void initializeConstraint(JointConstraint* constraint);
-
- void deactivateConstraint(JointConstraint *constraintp);
-
- void applyConstraint(JointConstraint* constraintp, F32 time, U8* joint_mask);
-
- bool setupPose();
-
-public:
- enum AssetStatus { ASSET_LOADED, ASSET_FETCHED, ASSET_NEEDS_FETCH, ASSET_FETCH_FAILED, ASSET_UNDEFINED };
-
- enum InterpolationType { IT_STEP, IT_LINEAR, IT_SPLINE };
-
- //-------------------------------------------------------------------------
- // ScaleKey
- //-------------------------------------------------------------------------
- class ScaleKey
- {
- public:
- ScaleKey() { mTime = 0.0f; }
- ScaleKey(F32 time, const LLVector3 &scale) { mTime = time; mScale = scale; }
-
- F32 mTime;
- LLVector3 mScale;
- };
-
- //-------------------------------------------------------------------------
- // RotationKey
- //-------------------------------------------------------------------------
- class RotationKey
- {
- public:
- RotationKey() { mTime = 0.0f; }
- RotationKey(F32 time, const LLQuaternion &rotation) { mTime = time; mRotation = rotation; }
-
- F32 mTime;
- LLQuaternion mRotation;
- };
-
- //-------------------------------------------------------------------------
- // PositionKey
- //-------------------------------------------------------------------------
- class PositionKey
- {
- public:
- PositionKey() { mTime = 0.0f; }
- PositionKey(F32 time, const LLVector3 &position) { mTime = time; mPosition = position; }
-
- F32 mTime;
- LLVector3 mPosition;
- };
-
- //-------------------------------------------------------------------------
- // ScaleCurve
- //-------------------------------------------------------------------------
- class ScaleCurve
- {
- public:
- ScaleCurve();
- ~ScaleCurve();
- LLVector3 getValue(F32 time, F32 duration);
- LLVector3 interp(F32 u, ScaleKey& before, ScaleKey& after);
-
- InterpolationType mInterpolationType;
- S32 mNumKeys;
- typedef std::map<F32, ScaleKey> key_map_t;
- key_map_t mKeys;
- ScaleKey mLoopInKey;
- ScaleKey mLoopOutKey;
- };
-
- //-------------------------------------------------------------------------
- // RotationCurve
- //-------------------------------------------------------------------------
- class RotationCurve
- {
- public:
- RotationCurve();
- ~RotationCurve();
- LLQuaternion getValue(F32 time, F32 duration);
- LLQuaternion interp(F32 u, RotationKey& before, RotationKey& after);
-
- InterpolationType mInterpolationType;
- S32 mNumKeys;
- typedef std::map<F32, RotationKey> key_map_t;
- key_map_t mKeys;
- RotationKey mLoopInKey;
- RotationKey mLoopOutKey;
- };
-
- //-------------------------------------------------------------------------
- // PositionCurve
- //-------------------------------------------------------------------------
- class PositionCurve
- {
- public:
- PositionCurve();
- ~PositionCurve();
- LLVector3 getValue(F32 time, F32 duration);
- LLVector3 interp(F32 u, PositionKey& before, PositionKey& after);
-
- InterpolationType mInterpolationType;
- S32 mNumKeys;
- typedef std::map<F32, PositionKey> key_map_t;
- key_map_t mKeys;
- PositionKey mLoopInKey;
- PositionKey mLoopOutKey;
- };
-
- //-------------------------------------------------------------------------
- // JointMotion
- //-------------------------------------------------------------------------
- class JointMotion
- {
- public:
- PositionCurve mPositionCurve;
- RotationCurve mRotationCurve;
- ScaleCurve mScaleCurve;
- std::string mJointName;
- U32 mUsage;
- LLJoint::JointPriority mPriority;
-
- void update(LLJointState* joint_state, F32 time, F32 duration);
- };
-
- //-------------------------------------------------------------------------
- // JointMotionList
- //-------------------------------------------------------------------------
- class JointMotionList
- {
- public:
- std::vector<JointMotion*> mJointMotionArray;
- F32 mDuration;
- bool mLoop;
- F32 mLoopInPoint;
- F32 mLoopOutPoint;
- F32 mEaseInDuration;
- F32 mEaseOutDuration;
- LLJoint::JointPriority mBasePriority;
- LLHandMotion::eHandPose mHandPose;
- LLJoint::JointPriority mMaxPriority;
- typedef std::list<JointConstraintSharedData*> constraint_list_t;
- constraint_list_t mConstraints;
- LLBBoxLocal mPelvisBBox;
- // mEmoteName is a facial motion, but it's necessary to appear here so that it's cached.
- // TODO: LLKeyframeDataCache::getKeyframeData should probably return a class containing
- // JointMotionList and mEmoteName, see LLKeyframeMotion::onInitialize.
- std::string mEmoteName;
- LLUUID mEmoteID;
-
- public:
- JointMotionList();
- ~JointMotionList();
- U32 dumpDiagInfo();
- JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; }
- U32 getNumJointMotions() const { return mJointMotionArray.size(); }
- };
-
-protected:
- JointMotionList* mJointMotionList;
- std::vector<LLPointer<LLJointState> > mJointStates;
- LLJoint* mPelvisp;
- LLCharacter* mCharacter;
- typedef std::list<JointConstraint*> constraint_list_t;
- constraint_list_t mConstraints;
- U32 mLastSkeletonSerialNum;
- F32 mLastUpdateTime;
- F32 mLastLoopedTime;
- AssetStatus mAssetStatus;
-
-public:
- void setCharacter(LLCharacter* character) { mCharacter = character; }
-};
-
-class LLKeyframeDataCache
-{
-public:
- // *FIX: implement this as an actual singleton member of LLKeyframeMotion
- LLKeyframeDataCache(){};
- ~LLKeyframeDataCache();
-
- typedef std::map<LLUUID, class LLKeyframeMotion::JointMotionList*> keyframe_data_map_t;
- static keyframe_data_map_t sKeyframeDataMap;
-
- static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*);
- static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id);
-
- static void removeKeyframeData(const LLUUID& id);
-
- //print out diagnostic info
- static void dumpDiagInfo();
- static void clear();
-};
-
-#endif // LL_LLKEYFRAMEMOTION_H
-
-
+/** + * @file llkeyframemotion.h + * @brief Implementation of LLKeframeMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLKEYFRAMEMOTION_H +#define LL_LLKEYFRAMEMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- + +#include <string> + +#include "llassetstorage.h" +#include "llbboxlocal.h" +#include "llhandmotion.h" +#include "lljointstate.h" +#include "llmotion.h" +#include "llquaternion.h" +#include "v3dmath.h" +#include "v3math.h" +#include "llbvhconsts.h" + +class LLKeyframeDataCache; +class LLDataPacker; + +#define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f) +#define MAX_CHAIN_LENGTH (4) + +const S32 KEYFRAME_MOTION_VERSION = 1; +const S32 KEYFRAME_MOTION_SUBVERSION = 0; + +//----------------------------------------------------------------------------- +// class LLKeyframeMotion +//----------------------------------------------------------------------------- +class LLKeyframeMotion : + public LLMotion +{ + friend class LLKeyframeDataCache; +public: + // Constructor + LLKeyframeMotion(const LLUUID &id); + + // Destructor + virtual ~LLKeyframeMotion(); + +private: + // private helper functions to wrap some asserts + LLPointer<LLJointState>& getJointState(U32 index); + LLJoint* getJoint(U32 index ); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID& id); + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { + if (mJointMotionList) return mJointMotionList->mLoop; + else return false; + } + + // motions must report their total duration + virtual F32 getDuration() { + if (mJointMotionList) return mJointMotionList->mDuration; + else return 0.f; + } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { + if (mJointMotionList) return mJointMotionList->mEaseInDuration; + else return 0.f; + } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { + if (mJointMotionList) return mJointMotionList->mEaseOutDuration; + else return 0.f; + } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { + if (mJointMotionList) return mJointMotionList->mBasePriority; + else return LLJoint::LOW_PRIORITY; + } + + virtual S32 getNumJointMotions() + { + if (mJointMotionList) + { + return mJointMotionList->getNumJointMotions(); + } + return 0; + } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + + virtual void setStopTime(F32 time); + + static void onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + +public: + U32 getFileSize(); + bool serialize(LLDataPacker& dp) const; + bool deserialize(LLDataPacker& dp, const LLUUID& asset_id, bool allow_invalid_joints = true); + bool isLoaded() { return mJointMotionList != NULL; } + bool dumpToFile(const std::string& name); + + + // setters for modifying a keyframe animation + void setLoop(bool loop); + + F32 getLoopIn() { + return (mJointMotionList) ? mJointMotionList->mLoopInPoint : 0.f; + } + + F32 getLoopOut() { + return (mJointMotionList) ? mJointMotionList->mLoopOutPoint : 0.f; + } + + void setLoopIn(F32 in_point); + + void setLoopOut(F32 out_point); + + void setHandPose(LLHandMotion::eHandPose pose) { + if (mJointMotionList) mJointMotionList->mHandPose = pose; + } + + LLHandMotion::eHandPose getHandPose() { + return (mJointMotionList) ? mJointMotionList->mHandPose : LLHandMotion::HAND_POSE_RELAXED; + } + + void setPriority(S32 priority); + + void setEmote(const LLUUID& emote_id); + + void setEaseIn(F32 ease_in); + + void setEaseOut(F32 ease_in); + + F32 getLastUpdateTime() { return mLastLoopedTime; } + + const LLBBoxLocal& getPelvisBBox(); + + static void flushKeyframeCache(); + +protected: + //------------------------------------------------------------------------- + // JointConstraintSharedData + //------------------------------------------------------------------------- + class JointConstraintSharedData + { + public: + JointConstraintSharedData() : + mChainLength(0), + mEaseInStartTime(0.f), + mEaseInStopTime(0.f), + mEaseOutStartTime(0.f), + mEaseOutStopTime(0.f), + mUseTargetOffset(false), + mConstraintType(CONSTRAINT_TYPE_POINT), + mConstraintTargetType(CONSTRAINT_TARGET_TYPE_BODY), + mSourceConstraintVolume(0), + mTargetConstraintVolume(0), + mJointStateIndices(NULL) + { }; + ~JointConstraintSharedData() { delete [] mJointStateIndices; } + + S32 mSourceConstraintVolume; + LLVector3 mSourceConstraintOffset; + S32 mTargetConstraintVolume; + LLVector3 mTargetConstraintOffset; + LLVector3 mTargetConstraintDir; + S32 mChainLength; + S32* mJointStateIndices; + F32 mEaseInStartTime; + F32 mEaseInStopTime; + F32 mEaseOutStartTime; + F32 mEaseOutStopTime; + bool mUseTargetOffset; + EConstraintType mConstraintType; + EConstraintTargetType mConstraintTargetType; + }; + + //----------------------------------------------------------------------------- + // JointConstraint() + //----------------------------------------------------------------------------- + class JointConstraint + { + public: + JointConstraint(JointConstraintSharedData* shared_data); + ~JointConstraint(); + + JointConstraintSharedData* mSharedData; + F32 mWeight; + F32 mTotalLength; + LLVector3 mPositions[MAX_CHAIN_LENGTH]; + F32 mJointLengths[MAX_CHAIN_LENGTH]; + F32 mJointLengthFractions[MAX_CHAIN_LENGTH]; + bool mActive; + LLVector3d mGroundPos; + LLVector3 mGroundNorm; + LLJoint* mSourceVolume; + LLJoint* mTargetVolume; + F32 mFixupDistanceRMS; + }; + + void applyKeyframes(F32 time); + + void applyConstraints(F32 time, U8* joint_mask); + + void activateConstraint(JointConstraint* constraintp); + + void initializeConstraint(JointConstraint* constraint); + + void deactivateConstraint(JointConstraint *constraintp); + + void applyConstraint(JointConstraint* constraintp, F32 time, U8* joint_mask); + + bool setupPose(); + +public: + enum AssetStatus { ASSET_LOADED, ASSET_FETCHED, ASSET_NEEDS_FETCH, ASSET_FETCH_FAILED, ASSET_UNDEFINED }; + + enum InterpolationType { IT_STEP, IT_LINEAR, IT_SPLINE }; + + //------------------------------------------------------------------------- + // ScaleKey + //------------------------------------------------------------------------- + class ScaleKey + { + public: + ScaleKey() { mTime = 0.0f; } + ScaleKey(F32 time, const LLVector3 &scale) { mTime = time; mScale = scale; } + + F32 mTime; + LLVector3 mScale; + }; + + //------------------------------------------------------------------------- + // RotationKey + //------------------------------------------------------------------------- + class RotationKey + { + public: + RotationKey() { mTime = 0.0f; } + RotationKey(F32 time, const LLQuaternion &rotation) { mTime = time; mRotation = rotation; } + + F32 mTime; + LLQuaternion mRotation; + }; + + //------------------------------------------------------------------------- + // PositionKey + //------------------------------------------------------------------------- + class PositionKey + { + public: + PositionKey() { mTime = 0.0f; } + PositionKey(F32 time, const LLVector3 &position) { mTime = time; mPosition = position; } + + F32 mTime; + LLVector3 mPosition; + }; + + //------------------------------------------------------------------------- + // ScaleCurve + //------------------------------------------------------------------------- + class ScaleCurve + { + public: + ScaleCurve(); + ~ScaleCurve(); + LLVector3 getValue(F32 time, F32 duration); + LLVector3 interp(F32 u, ScaleKey& before, ScaleKey& after); + + InterpolationType mInterpolationType; + S32 mNumKeys; + typedef std::map<F32, ScaleKey> key_map_t; + key_map_t mKeys; + ScaleKey mLoopInKey; + ScaleKey mLoopOutKey; + }; + + //------------------------------------------------------------------------- + // RotationCurve + //------------------------------------------------------------------------- + class RotationCurve + { + public: + RotationCurve(); + ~RotationCurve(); + LLQuaternion getValue(F32 time, F32 duration); + LLQuaternion interp(F32 u, RotationKey& before, RotationKey& after); + + InterpolationType mInterpolationType; + S32 mNumKeys; + typedef std::map<F32, RotationKey> key_map_t; + key_map_t mKeys; + RotationKey mLoopInKey; + RotationKey mLoopOutKey; + }; + + //------------------------------------------------------------------------- + // PositionCurve + //------------------------------------------------------------------------- + class PositionCurve + { + public: + PositionCurve(); + ~PositionCurve(); + LLVector3 getValue(F32 time, F32 duration); + LLVector3 interp(F32 u, PositionKey& before, PositionKey& after); + + InterpolationType mInterpolationType; + S32 mNumKeys; + typedef std::map<F32, PositionKey> key_map_t; + key_map_t mKeys; + PositionKey mLoopInKey; + PositionKey mLoopOutKey; + }; + + //------------------------------------------------------------------------- + // JointMotion + //------------------------------------------------------------------------- + class JointMotion + { + public: + PositionCurve mPositionCurve; + RotationCurve mRotationCurve; + ScaleCurve mScaleCurve; + std::string mJointName; + U32 mUsage; + LLJoint::JointPriority mPriority; + + void update(LLJointState* joint_state, F32 time, F32 duration); + }; + + //------------------------------------------------------------------------- + // JointMotionList + //------------------------------------------------------------------------- + class JointMotionList + { + public: + std::vector<JointMotion*> mJointMotionArray; + F32 mDuration; + bool mLoop; + F32 mLoopInPoint; + F32 mLoopOutPoint; + F32 mEaseInDuration; + F32 mEaseOutDuration; + LLJoint::JointPriority mBasePriority; + LLHandMotion::eHandPose mHandPose; + LLJoint::JointPriority mMaxPriority; + typedef std::list<JointConstraintSharedData*> constraint_list_t; + constraint_list_t mConstraints; + LLBBoxLocal mPelvisBBox; + // mEmoteName is a facial motion, but it's necessary to appear here so that it's cached. + // TODO: LLKeyframeDataCache::getKeyframeData should probably return a class containing + // JointMotionList and mEmoteName, see LLKeyframeMotion::onInitialize. + std::string mEmoteName; + LLUUID mEmoteID; + + public: + JointMotionList(); + ~JointMotionList(); + U32 dumpDiagInfo(); + JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; } + U32 getNumJointMotions() const { return mJointMotionArray.size(); } + }; + +protected: + JointMotionList* mJointMotionList; + std::vector<LLPointer<LLJointState> > mJointStates; + LLJoint* mPelvisp; + LLCharacter* mCharacter; + typedef std::list<JointConstraint*> constraint_list_t; + constraint_list_t mConstraints; + U32 mLastSkeletonSerialNum; + F32 mLastUpdateTime; + F32 mLastLoopedTime; + AssetStatus mAssetStatus; + +public: + void setCharacter(LLCharacter* character) { mCharacter = character; } +}; + +class LLKeyframeDataCache +{ +public: + // *FIX: implement this as an actual singleton member of LLKeyframeMotion + LLKeyframeDataCache(){}; + ~LLKeyframeDataCache(); + + typedef std::map<LLUUID, class LLKeyframeMotion::JointMotionList*> keyframe_data_map_t; + static keyframe_data_map_t sKeyframeDataMap; + + static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*); + static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id); + + static void removeKeyframeData(const LLUUID& id); + + //print out diagnostic info + static void dumpDiagInfo(); + static void clear(); +}; + +#endif // LL_LLKEYFRAMEMOTION_H + + diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp index e2f1602353..e4552b96c9 100644 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -1,436 +1,436 @@ -/**
- * @file llkeyframemotionparam.cpp
- * @brief Implementation of LLKeyframeMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llkeyframemotionparam.h"
-#include "llcharacter.h"
-#include "llmath.h"
-#include "m3math.h"
-#include "lldir.h"
-#include "llanimationstates.h"
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam class
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id)
-{
- mDefaultKeyframeMotion = NULL;
- mCharacter = NULL;
-
- mEaseInDuration = 0.f;
- mEaseOutDuration = 0.f;
- mDuration = 0.f;
- mPriority = LLJoint::LOW_PRIORITY;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLKeyframeMotionParam()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLKeyframeMotionParam::~LLKeyframeMotionParam()
-{
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
- delete paramMotion.mMotion;
- }
- motionList.clear();
- }
- mParameterizedMotions.clear();
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- if (!loadMotions())
- {
- return STATUS_FAILURE;
- }
-
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
- LLMotion* motion = paramMotion.mMotion;
- motion->onInitialize(character);
-
- if (motion->getDuration() > mEaseInDuration)
- {
- mEaseInDuration = motion->getEaseInDuration();
- }
-
- if (motion->getEaseOutDuration() > mEaseOutDuration)
- {
- mEaseOutDuration = motion->getEaseOutDuration();
- }
-
- if (motion->getDuration() > mDuration)
- {
- mDuration = motion->getDuration();
- }
-
- if (motion->getPriority() > mPriority)
- {
- mPriority = motion->getPriority();
- }
-
- LLPose *pose = motion->getPose();
-
- mPoseBlender.addMotion(motion);
- for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
- {
- LLPose *blendedPose = mPoseBlender.getBlendedPose();
- blendedPose->addJointState(jsp);
- }
- }
- }
-
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam::onActivate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotionParam::onActivate()
-{
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
- paramMotion.mMotion->activate(mActivationTimestamp);
- }
- }
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
-
- // zero out all pose weights
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
-// LL_INFOS() << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << LL_ENDL;
- paramMotion.mMotion->getPose()->setWeight(0.f);
- }
- }
-
-
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- const std::string& paramName = motion_pair.first;
- F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName);
- if (NULL == paramValue) // unexpected, but...
- {
- LL_WARNS() << "paramValue == NULL" << LL_ENDL;
- continue;
- }
-
- // DANGER! Do not modify mParameterizedMotions while using these pointers!
- const ParameterizedMotion* firstMotion = NULL;
- const ParameterizedMotion* secondMotion = NULL;
-
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
- paramMotion.mMotion->onUpdate(time, joint_mask);
-
- F32 distToParam = paramMotion.mParam - *paramValue;
-
- if ( distToParam <= 0.f)
- {
- // keep track of the motion closest to the parameter value
- firstMotion = ¶mMotion;
- }
- else
- {
- // we've passed the parameter value
- // so store the first motion we find as the second one we want to blend...
- if (firstMotion && !secondMotion )
- {
- secondMotion = ¶mMotion;
- }
- //...or, if we've seen no other motion so far, make sure we blend to this only
- else if (!firstMotion)
- {
- firstMotion = ¶mMotion;
- secondMotion = ¶mMotion;
- }
- }
- }
-
- LLPose *firstPose;
- LLPose *secondPose;
-
- if (firstMotion)
- firstPose = firstMotion->mMotion->getPose();
- else
- firstPose = NULL;
-
- if (secondMotion)
- secondPose = secondMotion->mMotion->getPose();
- else
- secondPose = NULL;
-
- // now modify weight of the subanim (only if we are blending between two motions)
- if (firstMotion && secondMotion)
- {
- if (firstMotion == secondMotion)
- {
- firstPose->setWeight(weightFactor);
- }
- else if (firstMotion->mParam == secondMotion->mParam)
- {
- firstPose->setWeight(0.5f * weightFactor);
- secondPose->setWeight(0.5f * weightFactor);
- }
- else
- {
- F32 first_weight = 1.f -
- ((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) /
- (secondMotion->mParam - firstMotion->mParam));
- first_weight = llclamp(first_weight, 0.f, 1.f);
-
- F32 second_weight = 1.f - first_weight;
-
- firstPose->setWeight(first_weight * weightFactor);
- secondPose->setWeight(second_weight * weightFactor);
-
-// LL_INFOS() << "Parameter " << *paramName << ": " << *paramValue << LL_ENDL;
-// LL_INFOS() << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << LL_ENDL;
- }
- }
- else if (firstMotion && !secondMotion)
- {
- firstPose->setWeight(weightFactor);
- }
- }
-
- // blend poses
- mPoseBlender.blendAndApply();
-
- LL_INFOS() << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << LL_ENDL;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotionParam::onDeactivate()
-{
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
- paramMotion.mMotion->onDeactivate();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam::addKeyframeMotion()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value)
-{
- LLMotion *newMotion = mCharacter->createMotion( id );
-
- if (!newMotion)
- {
- return false;
- }
-
- newMotion->setName(name);
-
- // now add motion to this list
- mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value));
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLKeyframeMotionParam::setDefaultKeyframeMotion()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name)
-{
- for (motion_map_t::value_type& motion_pair : mParameterizedMotions)
- {
- motion_list_t& motionList = motion_pair.second;
- for (const ParameterizedMotion& paramMotion : motionList)
- {
- if (paramMotion.mMotion->getName() == name)
- {
- mDefaultKeyframeMotion = paramMotion.mMotion;
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// loadMotions()
-//-----------------------------------------------------------------------------
-bool LLKeyframeMotionParam::loadMotions()
-{
- //-------------------------------------------------------------------------
- // Load named file by concatenating the character prefix with the motion name.
- // Load data into a buffer to be parsed.
- //-------------------------------------------------------------------------
- //std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix())
- // + "_" + getName() + ".llp";
- //RN: deprecated unused reference to "motion" directory
- std::string path;
-
-
- //-------------------------------------------------------------------------
- // open the file
- //-------------------------------------------------------------------------
- S32 fileSize = 0;
- LLAPRFile infile ;
- infile.open(path, LL_APR_R, NULL, &fileSize);
- apr_file_t* fp = infile.getFileHandle() ;
- if (!fp || fileSize == 0)
- {
- LL_INFOS() << "ERROR: can't open: " << path << LL_ENDL;
- return false;
- }
-
- // allocate a text buffer
- std::vector<char> text(fileSize+1);
-
- //-------------------------------------------------------------------------
- // load data from file into buffer
- //-------------------------------------------------------------------------
- bool error = false;
- char *p = &text[0];
- while ( 1 )
- {
- if (apr_file_eof(fp) == APR_EOF)
- {
- break;
- }
- if (apr_file_gets(p, 1024, fp) != APR_SUCCESS)
- {
- error = true;
- break;
- }
- while ( *(++p) )
- ;
- }
-
- //-------------------------------------------------------------------------
- // close the file
- //-------------------------------------------------------------------------
- infile.close();
-
- //-------------------------------------------------------------------------
- // check for error
- //-------------------------------------------------------------------------
- llassert( p <= (&text[0] + fileSize) );
-
- if ( error )
- {
- LL_INFOS() << "ERROR: error while reading from " << path << LL_ENDL;
- return false;
- }
-
- LL_INFOS() << "Loading parametric keyframe data for: " << getName() << LL_ENDL;
-
- //-------------------------------------------------------------------------
- // parse the text and build keyframe data structures
- //-------------------------------------------------------------------------
- p = &text[0];
- S32 num;
- char strA[80]; /* Flawfinder: ignore */
- char strB[80]; /* Flawfinder: ignore */
- F32 floatA = 0.0f;
-
-
- //-------------------------------------------------------------------------
- // get priority
- //-------------------------------------------------------------------------
- bool isFirstMotion = true;
- num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */
-
- while(1)
- {
- if (num == 0 || num == EOF) break;
- if ((num != 3))
- {
- LL_INFOS() << "WARNING: can't read parametric motion" << LL_ENDL;
- return false;
- }
-
- addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA);
- if (isFirstMotion)
- {
- isFirstMotion = false;
- setDefaultKeyframeMotion(strA);
- }
-
- p = strstr(p, "\n");
- if (!p)
- {
- break;
- }
-
- p++;
- num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */
- }
-
- return true;
-}
-
-// End
+/** + * @file llkeyframemotionparam.cpp + * @brief Implementation of LLKeyframeMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llkeyframemotionparam.h" +#include "llcharacter.h" +#include "llmath.h" +#include "m3math.h" +#include "lldir.h" +#include "llanimationstates.h" + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam() +// Class Constructor +//----------------------------------------------------------------------------- +LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id) +{ + mDefaultKeyframeMotion = NULL; + mCharacter = NULL; + + mEaseInDuration = 0.f; + mEaseOutDuration = 0.f; + mDuration = 0.f; + mPriority = LLJoint::LOW_PRIORITY; +} + + +//----------------------------------------------------------------------------- +// ~LLKeyframeMotionParam() +// Class Destructor +//----------------------------------------------------------------------------- +LLKeyframeMotionParam::~LLKeyframeMotionParam() +{ + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { + delete paramMotion.mMotion; + } + motionList.clear(); + } + mParameterizedMotions.clear(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + if (!loadMotions()) + { + return STATUS_FAILURE; + } + + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { + LLMotion* motion = paramMotion.mMotion; + motion->onInitialize(character); + + if (motion->getDuration() > mEaseInDuration) + { + mEaseInDuration = motion->getEaseInDuration(); + } + + if (motion->getEaseOutDuration() > mEaseOutDuration) + { + mEaseOutDuration = motion->getEaseOutDuration(); + } + + if (motion->getDuration() > mDuration) + { + mDuration = motion->getDuration(); + } + + if (motion->getPriority() > mPriority) + { + mPriority = motion->getPriority(); + } + + LLPose *pose = motion->getPose(); + + mPoseBlender.addMotion(motion); + for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) + { + LLPose *blendedPose = mPoseBlender.getBlendedPose(); + blendedPose->addJointState(jsp); + } + } + } + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onActivate() +//----------------------------------------------------------------------------- +bool LLKeyframeMotionParam::onActivate() +{ + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { + paramMotion.mMotion->activate(mActivationTimestamp); + } + } + return true; +} + + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onUpdate() +//----------------------------------------------------------------------------- +bool LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + F32 weightFactor = 1.f / (F32)mParameterizedMotions.size(); + + // zero out all pose weights + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { +// LL_INFOS() << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << LL_ENDL; + paramMotion.mMotion->getPose()->setWeight(0.f); + } + } + + + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + const std::string& paramName = motion_pair.first; + F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName); + if (NULL == paramValue) // unexpected, but... + { + LL_WARNS() << "paramValue == NULL" << LL_ENDL; + continue; + } + + // DANGER! Do not modify mParameterizedMotions while using these pointers! + const ParameterizedMotion* firstMotion = NULL; + const ParameterizedMotion* secondMotion = NULL; + + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { + paramMotion.mMotion->onUpdate(time, joint_mask); + + F32 distToParam = paramMotion.mParam - *paramValue; + + if ( distToParam <= 0.f) + { + // keep track of the motion closest to the parameter value + firstMotion = ¶mMotion; + } + else + { + // we've passed the parameter value + // so store the first motion we find as the second one we want to blend... + if (firstMotion && !secondMotion ) + { + secondMotion = ¶mMotion; + } + //...or, if we've seen no other motion so far, make sure we blend to this only + else if (!firstMotion) + { + firstMotion = ¶mMotion; + secondMotion = ¶mMotion; + } + } + } + + LLPose *firstPose; + LLPose *secondPose; + + if (firstMotion) + firstPose = firstMotion->mMotion->getPose(); + else + firstPose = NULL; + + if (secondMotion) + secondPose = secondMotion->mMotion->getPose(); + else + secondPose = NULL; + + // now modify weight of the subanim (only if we are blending between two motions) + if (firstMotion && secondMotion) + { + if (firstMotion == secondMotion) + { + firstPose->setWeight(weightFactor); + } + else if (firstMotion->mParam == secondMotion->mParam) + { + firstPose->setWeight(0.5f * weightFactor); + secondPose->setWeight(0.5f * weightFactor); + } + else + { + F32 first_weight = 1.f - + ((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) / + (secondMotion->mParam - firstMotion->mParam)); + first_weight = llclamp(first_weight, 0.f, 1.f); + + F32 second_weight = 1.f - first_weight; + + firstPose->setWeight(first_weight * weightFactor); + secondPose->setWeight(second_weight * weightFactor); + +// LL_INFOS() << "Parameter " << *paramName << ": " << *paramValue << LL_ENDL; +// LL_INFOS() << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << LL_ENDL; + } + } + else if (firstMotion && !secondMotion) + { + firstPose->setWeight(weightFactor); + } + } + + // blend poses + mPoseBlender.blendAndApply(); + + LL_INFOS() << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << LL_ENDL; + + return true; +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::onDeactivate() +//----------------------------------------------------------------------------- +void LLKeyframeMotionParam::onDeactivate() +{ + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { + paramMotion.mMotion->onDeactivate(); + } + } +} + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::addKeyframeMotion() +//----------------------------------------------------------------------------- +bool LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value) +{ + LLMotion *newMotion = mCharacter->createMotion( id ); + + if (!newMotion) + { + return false; + } + + newMotion->setName(name); + + // now add motion to this list + mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value)); + + return true; +} + + +//----------------------------------------------------------------------------- +// LLKeyframeMotionParam::setDefaultKeyframeMotion() +//----------------------------------------------------------------------------- +void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name) +{ + for (motion_map_t::value_type& motion_pair : mParameterizedMotions) + { + motion_list_t& motionList = motion_pair.second; + for (const ParameterizedMotion& paramMotion : motionList) + { + if (paramMotion.mMotion->getName() == name) + { + mDefaultKeyframeMotion = paramMotion.mMotion; + } + } + } +} + +//----------------------------------------------------------------------------- +// loadMotions() +//----------------------------------------------------------------------------- +bool LLKeyframeMotionParam::loadMotions() +{ + //------------------------------------------------------------------------- + // Load named file by concatenating the character prefix with the motion name. + // Load data into a buffer to be parsed. + //------------------------------------------------------------------------- + //std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()) + // + "_" + getName() + ".llp"; + //RN: deprecated unused reference to "motion" directory + std::string path; + + + //------------------------------------------------------------------------- + // open the file + //------------------------------------------------------------------------- + S32 fileSize = 0; + LLAPRFile infile ; + infile.open(path, LL_APR_R, NULL, &fileSize); + apr_file_t* fp = infile.getFileHandle() ; + if (!fp || fileSize == 0) + { + LL_INFOS() << "ERROR: can't open: " << path << LL_ENDL; + return false; + } + + // allocate a text buffer + std::vector<char> text(fileSize+1); + + //------------------------------------------------------------------------- + // load data from file into buffer + //------------------------------------------------------------------------- + bool error = false; + char *p = &text[0]; + while ( 1 ) + { + if (apr_file_eof(fp) == APR_EOF) + { + break; + } + if (apr_file_gets(p, 1024, fp) != APR_SUCCESS) + { + error = true; + break; + } + while ( *(++p) ) + ; + } + + //------------------------------------------------------------------------- + // close the file + //------------------------------------------------------------------------- + infile.close(); + + //------------------------------------------------------------------------- + // check for error + //------------------------------------------------------------------------- + llassert( p <= (&text[0] + fileSize) ); + + if ( error ) + { + LL_INFOS() << "ERROR: error while reading from " << path << LL_ENDL; + return false; + } + + LL_INFOS() << "Loading parametric keyframe data for: " << getName() << LL_ENDL; + + //------------------------------------------------------------------------- + // parse the text and build keyframe data structures + //------------------------------------------------------------------------- + p = &text[0]; + S32 num; + char strA[80]; /* Flawfinder: ignore */ + char strB[80]; /* Flawfinder: ignore */ + F32 floatA = 0.0f; + + + //------------------------------------------------------------------------- + // get priority + //------------------------------------------------------------------------- + bool isFirstMotion = true; + num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ + + while(1) + { + if (num == 0 || num == EOF) break; + if ((num != 3)) + { + LL_INFOS() << "WARNING: can't read parametric motion" << LL_ENDL; + return false; + } + + addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA); + if (isFirstMotion) + { + isFirstMotion = false; + setDefaultKeyframeMotion(strA); + } + + p = strstr(p, "\n"); + if (!p) + { + break; + } + + p++; + num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ + } + + return true; +} + +// End diff --git a/indra/llcharacter/llkeyframemotionparam.h b/indra/llcharacter/llkeyframemotionparam.h index 97118ab370..8c57766e9b 100644 --- a/indra/llcharacter/llkeyframemotionparam.h +++ b/indra/llcharacter/llkeyframemotionparam.h @@ -1,169 +1,169 @@ -/**
- * @file llkeyframemotionparam.h
- * @brief Implementation of LLKeframeMotionParam class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLKEYFRAMEMOTIONPARAM_H
-#define LL_LLKEYFRAMEMOTIONPARAM_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-
-#include <string>
-
-#include "llmotion.h"
-#include "lljointstate.h"
-#include "v3math.h"
-#include "llquaternion.h"
-#include "llkeyframemotion.h"
-
-//-----------------------------------------------------------------------------
-// class LLKeyframeMotionParam
-//-----------------------------------------------------------------------------
-class LLKeyframeMotionParam :
- public LLMotion
-{
-public:
- // Constructor
- LLKeyframeMotionParam(const LLUUID &id);
-
- // Destructor
- virtual ~LLKeyframeMotionParam();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() {
- return true;
- }
-
- // motions must report their total duration
- virtual F32 getDuration() {
- return mDuration;
- }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() {
- return mEaseInDuration;
- }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() {
- return mEaseOutDuration;
- }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() {
- return mPriority;
- }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
- virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();}
-
-protected:
- //-------------------------------------------------------------------------
- // new functions defined by this subclass
- //-------------------------------------------------------------------------
- struct ParameterizedMotion
- {
- ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {}
- LLMotion* mMotion;
- F32 mParam;
- };
-
- // add a motion and associated parameter triplet
- bool addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value);
-
- // set default motion for LOD and retrieving blend constants
- void setDefaultKeyframeMotion(char *);
-
- bool loadMotions();
-
-protected:
- //-------------------------------------------------------------------------
- // Member Data
- //-------------------------------------------------------------------------
-
- struct compare_motions
- {
- bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const
- {
- if (a.mParam != b.mParam)
- return (a.mParam < b.mParam);
- else
- return a.mMotion < b.mMotion;
- }
- };
-
- typedef std::set < ParameterizedMotion, compare_motions > motion_list_t;
- typedef std::map <std::string, motion_list_t > motion_map_t;
- motion_map_t mParameterizedMotions;
- LLMotion* mDefaultKeyframeMotion;
- LLCharacter* mCharacter;
- LLPoseBlender mPoseBlender;
-
- F32 mEaseInDuration;
- F32 mEaseOutDuration;
- F32 mDuration;
- LLJoint::JointPriority mPriority;
-
- LLUUID mTransactionID;
-};
-
-#endif // LL_LLKEYFRAMEMOTIONPARAM_H
+/** + * @file llkeyframemotionparam.h + * @brief Implementation of LLKeframeMotionParam class. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLKEYFRAMEMOTIONPARAM_H +#define LL_LLKEYFRAMEMOTIONPARAM_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- + +#include <string> + +#include "llmotion.h" +#include "lljointstate.h" +#include "v3math.h" +#include "llquaternion.h" +#include "llkeyframemotion.h" + +//----------------------------------------------------------------------------- +// class LLKeyframeMotionParam +//----------------------------------------------------------------------------- +class LLKeyframeMotionParam : + public LLMotion +{ +public: + // Constructor + LLKeyframeMotionParam(const LLUUID &id); + + // Destructor + virtual ~LLKeyframeMotionParam(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { + return true; + } + + // motions must report their total duration + virtual F32 getDuration() { + return mDuration; + } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { + return mEaseInDuration; + } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { + return mEaseOutDuration; + } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { + return mPriority; + } + + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + + virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();} + +protected: + //------------------------------------------------------------------------- + // new functions defined by this subclass + //------------------------------------------------------------------------- + struct ParameterizedMotion + { + ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {} + LLMotion* mMotion; + F32 mParam; + }; + + // add a motion and associated parameter triplet + bool addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value); + + // set default motion for LOD and retrieving blend constants + void setDefaultKeyframeMotion(char *); + + bool loadMotions(); + +protected: + //------------------------------------------------------------------------- + // Member Data + //------------------------------------------------------------------------- + + struct compare_motions + { + bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const + { + if (a.mParam != b.mParam) + return (a.mParam < b.mParam); + else + return a.mMotion < b.mMotion; + } + }; + + typedef std::set < ParameterizedMotion, compare_motions > motion_list_t; + typedef std::map <std::string, motion_list_t > motion_map_t; + motion_map_t mParameterizedMotions; + LLMotion* mDefaultKeyframeMotion; + LLCharacter* mCharacter; + LLPoseBlender mPoseBlender; + + F32 mEaseInDuration; + F32 mEaseOutDuration; + F32 mDuration; + LLJoint::JointPriority mPriority; + + LLUUID mTransactionID; +}; + +#endif // LL_LLKEYFRAMEMOTIONPARAM_H diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp index 26a4907a01..a882ab3563 100644 --- a/indra/llcharacter/llkeyframestandmotion.cpp +++ b/indra/llcharacter/llkeyframestandmotion.cpp @@ -1,342 +1,342 @@ -/**
- * @file llkeyframestandmotion.cpp
- * @brief Implementation of LLKeyframeStandMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llkeyframestandmotion.h"
-#include "llcharacter.h"
-
-//-----------------------------------------------------------------------------
-// Macros and consts
-//-----------------------------------------------------------------------------
-#define GO_TO_KEY_POSE 1
-#define MIN_TRACK_SPEED 0.01f
-const F32 ROTATION_THRESHOLD = 0.6f;
-const F32 POSITION_THRESHOLD = 0.1f;
-
-//-----------------------------------------------------------------------------
-// LLKeyframeStandMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id)
-{
- mFlipFeet = false;
- mCharacter = NULL;
-
- // create kinematic hierarchy
- mPelvisJoint.addChild( &mHipLeftJoint );
- mHipLeftJoint.addChild( &mKneeLeftJoint );
- mKneeLeftJoint.addChild( &mAnkleLeftJoint );
- mPelvisJoint.addChild( &mHipRightJoint );
- mHipRightJoint.addChild( &mKneeRightJoint );
- mKneeRightJoint.addChild( &mAnkleRightJoint );
-
- mPelvisState = NULL;
-
- mHipLeftState = NULL;
- mKneeLeftState = NULL;
- mAnkleLeftState = NULL;
-
- mHipRightState = NULL;
- mKneeRightState = NULL;
- mAnkleRightState = NULL;
-
- mTrackAnkles = true;
-
- mFrameNum = 0;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLKeyframeStandMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLKeyframeStandMotion::~LLKeyframeStandMotion()
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// LLKeyframeStandMotion::onInitialize()
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLKeyframeStandMotion::onInitialize(LLCharacter *character)
-{
- // save character pointer for later use
- mCharacter = character;
-
- mFlipFeet = false;
-
- // load keyframe data, setup pose and joint states
- LLMotion::LLMotionInitStatus status = LLKeyframeMotion::onInitialize(character);
- if ( status == STATUS_FAILURE )
- {
- return status;
- }
-
- // find the necessary joint states
- LLPose *pose = getPose();
- mPelvisState = pose->findJointState("mPelvis");
-
- mHipLeftState = pose->findJointState("mHipLeft");
- mKneeLeftState = pose->findJointState("mKneeLeft");
- mAnkleLeftState = pose->findJointState("mAnkleLeft");
-
- mHipRightState = pose->findJointState("mHipRight");
- mKneeRightState = pose->findJointState("mKneeRight");
- mAnkleRightState = pose->findJointState("mAnkleRight");
-
- if ( !mPelvisState ||
- !mHipLeftState ||
- !mKneeLeftState ||
- !mAnkleLeftState ||
- !mHipRightState ||
- !mKneeRightState ||
- !mAnkleRightState )
- {
- LL_INFOS() << getName() << ": Can't find necessary joint states" << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeStandMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeStandMotion::onActivate()
-{
- //-------------------------------------------------------------------------
- // setup the IK solvers
- //-------------------------------------------------------------------------
- mIKLeft.setPoleVector( LLVector3(1.0f, 0.0f, 0.0f));
- mIKRight.setPoleVector( LLVector3(1.0f, 0.0f, 0.0f));
- mIKLeft.setBAxis( LLVector3(0.05f, 1.0f, 0.0f));
- mIKRight.setBAxis( LLVector3(-0.05f, 1.0f, 0.0f));
-
- mLastGoodPelvisRotation.loadIdentity();
- mLastGoodPosition.clearVec();
-
- mFrameNum = 0;
-
- return LLKeyframeMotion::onActivate();
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeStandMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLKeyframeStandMotion::onDeactivate()
-{
- LLKeyframeMotion::onDeactivate();
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeStandMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)
-{
- //-------------------------------------------------------------------------
- // let the base class update the cycle
- //-------------------------------------------------------------------------
- bool status = LLKeyframeMotion::onUpdate(time, joint_mask);
- if (!status)
- {
- return false;
- }
-
- LLVector3 root_world_pos = mPelvisState->getJoint()->getParent()->getWorldPosition();
-
- // have we received a valid world position for this avatar?
- if (root_world_pos.isExactlyZero())
- {
- return true;
- }
-
- //-------------------------------------------------------------------------
- // Stop tracking (start locking) ankles once ease in is done.
- // Setting this here ensures we track until we get valid foot position.
- //-------------------------------------------------------------------------
- if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD)
- {
- mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation();
- mLastGoodPelvisRotation.normalize();
- mTrackAnkles = true;
- }
- else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD)
- {
- mLastGoodPosition = mCharacter->getCharacterPosition();
- mTrackAnkles = true;
- }
- else if (mPose.getWeight() < 1.f)
- {
- mTrackAnkles = true;
- }
-
-
- //-------------------------------------------------------------------------
- // propagate joint positions to internal versions
- //-------------------------------------------------------------------------
- // SL-315
- mPelvisJoint.setPosition(
- root_world_pos +
- mPelvisState->getPosition() );
-
- // SL-315
- mHipLeftJoint.setPosition( mHipLeftState->getJoint()->getPosition() );
- mKneeLeftJoint.setPosition( mKneeLeftState->getJoint()->getPosition() );
- mAnkleLeftJoint.setPosition( mAnkleLeftState->getJoint()->getPosition() );
-
- mHipLeftJoint.setScale( mHipLeftState->getJoint()->getScale() );
- mKneeLeftJoint.setScale( mKneeLeftState->getJoint()->getScale() );
- mAnkleLeftJoint.setScale( mAnkleLeftState->getJoint()->getScale() );
-
- // SL-315
- mHipRightJoint.setPosition( mHipRightState->getJoint()->getPosition() );
- mKneeRightJoint.setPosition( mKneeRightState->getJoint()->getPosition() );
- mAnkleRightJoint.setPosition( mAnkleRightState->getJoint()->getPosition() );
-
- mHipRightJoint.setScale( mHipRightState->getJoint()->getScale() );
- mKneeRightJoint.setScale( mKneeRightState->getJoint()->getScale() );
- mAnkleRightJoint.setScale( mAnkleRightState->getJoint()->getScale() );
- //-------------------------------------------------------------------------
- // propagate joint rotations to internal versions
- //-------------------------------------------------------------------------
- mPelvisJoint.setRotation( mPelvisState->getJoint()->getWorldRotation() );
-
-#if GO_TO_KEY_POSE
- mHipLeftJoint.setRotation( mHipLeftState->getRotation() );
- mKneeLeftJoint.setRotation( mKneeLeftState->getRotation() );
- mAnkleLeftJoint.setRotation( mAnkleLeftState->getRotation() );
-
- mHipRightJoint.setRotation( mHipRightState->getRotation() );
- mKneeRightJoint.setRotation( mKneeRightState->getRotation() );
- mAnkleRightJoint.setRotation( mAnkleRightState->getRotation() );
-#else
- mHipLeftJoint.setRotation( mHipLeftState->getJoint()->getRotation() );
- mKneeLeftJoint.setRotation( mKneeLeftState->getJoint()->getRotation() );
- mAnkleLeftJoint.setRotation( mAnkleLeftState->getJoint()->getRotation() );
-
- mHipRightJoint.setRotation( mHipRightState->getJoint()->getRotation() );
- mKneeRightJoint.setRotation( mKneeRightState->getJoint()->getRotation() );
- mAnkleRightJoint.setRotation( mAnkleRightState->getJoint()->getRotation() );
-#endif
-
- // need to wait for underlying keyframe motion to affect the skeleton
- if (mFrameNum == 2)
- {
- mIKLeft.setupJoints( &mHipLeftJoint, &mKneeLeftJoint, &mAnkleLeftJoint, &mTargetLeft );
- mIKRight.setupJoints( &mHipRightJoint, &mKneeRightJoint, &mAnkleRightJoint, &mTargetRight );
- }
- else if (mFrameNum < 2)
- {
- mFrameNum++;
- return true;
- }
-
- mFrameNum++;
-
- //-------------------------------------------------------------------------
- // compute target position by projecting ankles to the ground
- //-------------------------------------------------------------------------
- if ( mTrackAnkles )
- {
- mCharacter->getGround( mAnkleLeftJoint.getWorldPosition(), mPositionLeft, mNormalLeft);
- mCharacter->getGround( mAnkleRightJoint.getWorldPosition(), mPositionRight, mNormalRight);
-
- // SL-315
- mTargetLeft.setPosition( mPositionLeft );
- mTargetRight.setPosition( mPositionRight );
- }
-
- //-------------------------------------------------------------------------
- // update solvers
- //-------------------------------------------------------------------------
- mIKLeft.solve();
- mIKRight.solve();
-
- //-------------------------------------------------------------------------
- // make ankle rotation conform to the ground
- //-------------------------------------------------------------------------
- if ( mTrackAnkles )
- {
- LLVector4 dirLeft4 = mAnkleLeftJoint.getWorldMatrix().getFwdRow4();
- LLVector4 dirRight4 = mAnkleRightJoint.getWorldMatrix().getFwdRow4();
- LLVector3 dirLeft = vec4to3( dirLeft4 );
- LLVector3 dirRight = vec4to3( dirRight4 );
-
- LLVector3 up;
- LLVector3 dir;
- LLVector3 left;
-
- up = mNormalLeft;
- up.normVec();
- if (mFlipFeet)
- {
- up *= -1.0f;
- }
- dir = dirLeft;
- dir.normVec();
- left = up % dir;
- left.normVec();
- dir = left % up;
- mRotationLeft = LLQuaternion( dir, left, up );
-
- up = mNormalRight;
- up.normVec();
- if (mFlipFeet)
- {
- up *= -1.0f;
- }
- dir = dirRight;
- dir.normVec();
- left = up % dir;
- left.normVec();
- dir = left % up;
- mRotationRight = LLQuaternion( dir, left, up );
- }
- mAnkleLeftJoint.setWorldRotation( mRotationLeft );
- mAnkleRightJoint.setWorldRotation( mRotationRight );
-
- //-------------------------------------------------------------------------
- // propagate joint rotations to joint states
- //-------------------------------------------------------------------------
- mHipLeftState->setRotation( mHipLeftJoint.getRotation() );
- mKneeLeftState->setRotation( mKneeLeftJoint.getRotation() );
- mAnkleLeftState->setRotation( mAnkleLeftJoint.getRotation() );
-
- mHipRightState->setRotation( mHipRightJoint.getRotation() );
- mKneeRightState->setRotation( mKneeRightJoint.getRotation() );
- mAnkleRightState->setRotation( mAnkleRightJoint.getRotation() );
-
- //LL_INFOS() << "Stand drift amount " << (mCharacter->getCharacterPosition() - mLastGoodPosition).magVec() << LL_ENDL;
-
-// LL_INFOS() << "DEBUG: " << speed << " : " << mTrackAnkles << LL_ENDL;
- return true;
-}
-
-// End
+/** + * @file llkeyframestandmotion.cpp + * @brief Implementation of LLKeyframeStandMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llkeyframestandmotion.h" +#include "llcharacter.h" + +//----------------------------------------------------------------------------- +// Macros and consts +//----------------------------------------------------------------------------- +#define GO_TO_KEY_POSE 1 +#define MIN_TRACK_SPEED 0.01f +const F32 ROTATION_THRESHOLD = 0.6f; +const F32 POSITION_THRESHOLD = 0.1f; + +//----------------------------------------------------------------------------- +// LLKeyframeStandMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id) +{ + mFlipFeet = false; + mCharacter = NULL; + + // create kinematic hierarchy + mPelvisJoint.addChild( &mHipLeftJoint ); + mHipLeftJoint.addChild( &mKneeLeftJoint ); + mKneeLeftJoint.addChild( &mAnkleLeftJoint ); + mPelvisJoint.addChild( &mHipRightJoint ); + mHipRightJoint.addChild( &mKneeRightJoint ); + mKneeRightJoint.addChild( &mAnkleRightJoint ); + + mPelvisState = NULL; + + mHipLeftState = NULL; + mKneeLeftState = NULL; + mAnkleLeftState = NULL; + + mHipRightState = NULL; + mKneeRightState = NULL; + mAnkleRightState = NULL; + + mTrackAnkles = true; + + mFrameNum = 0; +} + + +//----------------------------------------------------------------------------- +// ~LLKeyframeStandMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLKeyframeStandMotion::~LLKeyframeStandMotion() +{ +} + + +//----------------------------------------------------------------------------- +// LLKeyframeStandMotion::onInitialize() +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLKeyframeStandMotion::onInitialize(LLCharacter *character) +{ + // save character pointer for later use + mCharacter = character; + + mFlipFeet = false; + + // load keyframe data, setup pose and joint states + LLMotion::LLMotionInitStatus status = LLKeyframeMotion::onInitialize(character); + if ( status == STATUS_FAILURE ) + { + return status; + } + + // find the necessary joint states + LLPose *pose = getPose(); + mPelvisState = pose->findJointState("mPelvis"); + + mHipLeftState = pose->findJointState("mHipLeft"); + mKneeLeftState = pose->findJointState("mKneeLeft"); + mAnkleLeftState = pose->findJointState("mAnkleLeft"); + + mHipRightState = pose->findJointState("mHipRight"); + mKneeRightState = pose->findJointState("mKneeRight"); + mAnkleRightState = pose->findJointState("mAnkleRight"); + + if ( !mPelvisState || + !mHipLeftState || + !mKneeLeftState || + !mAnkleLeftState || + !mHipRightState || + !mKneeRightState || + !mAnkleRightState ) + { + LL_INFOS() << getName() << ": Can't find necessary joint states" << LL_ENDL; + return STATUS_FAILURE; + } + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLKeyframeStandMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLKeyframeStandMotion::onActivate() +{ + //------------------------------------------------------------------------- + // setup the IK solvers + //------------------------------------------------------------------------- + mIKLeft.setPoleVector( LLVector3(1.0f, 0.0f, 0.0f)); + mIKRight.setPoleVector( LLVector3(1.0f, 0.0f, 0.0f)); + mIKLeft.setBAxis( LLVector3(0.05f, 1.0f, 0.0f)); + mIKRight.setBAxis( LLVector3(-0.05f, 1.0f, 0.0f)); + + mLastGoodPelvisRotation.loadIdentity(); + mLastGoodPosition.clearVec(); + + mFrameNum = 0; + + return LLKeyframeMotion::onActivate(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeStandMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLKeyframeStandMotion::onDeactivate() +{ + LLKeyframeMotion::onDeactivate(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeStandMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) +{ + //------------------------------------------------------------------------- + // let the base class update the cycle + //------------------------------------------------------------------------- + bool status = LLKeyframeMotion::onUpdate(time, joint_mask); + if (!status) + { + return false; + } + + LLVector3 root_world_pos = mPelvisState->getJoint()->getParent()->getWorldPosition(); + + // have we received a valid world position for this avatar? + if (root_world_pos.isExactlyZero()) + { + return true; + } + + //------------------------------------------------------------------------- + // Stop tracking (start locking) ankles once ease in is done. + // Setting this here ensures we track until we get valid foot position. + //------------------------------------------------------------------------- + if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD) + { + mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation(); + mLastGoodPelvisRotation.normalize(); + mTrackAnkles = true; + } + else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD) + { + mLastGoodPosition = mCharacter->getCharacterPosition(); + mTrackAnkles = true; + } + else if (mPose.getWeight() < 1.f) + { + mTrackAnkles = true; + } + + + //------------------------------------------------------------------------- + // propagate joint positions to internal versions + //------------------------------------------------------------------------- + // SL-315 + mPelvisJoint.setPosition( + root_world_pos + + mPelvisState->getPosition() ); + + // SL-315 + mHipLeftJoint.setPosition( mHipLeftState->getJoint()->getPosition() ); + mKneeLeftJoint.setPosition( mKneeLeftState->getJoint()->getPosition() ); + mAnkleLeftJoint.setPosition( mAnkleLeftState->getJoint()->getPosition() ); + + mHipLeftJoint.setScale( mHipLeftState->getJoint()->getScale() ); + mKneeLeftJoint.setScale( mKneeLeftState->getJoint()->getScale() ); + mAnkleLeftJoint.setScale( mAnkleLeftState->getJoint()->getScale() ); + + // SL-315 + mHipRightJoint.setPosition( mHipRightState->getJoint()->getPosition() ); + mKneeRightJoint.setPosition( mKneeRightState->getJoint()->getPosition() ); + mAnkleRightJoint.setPosition( mAnkleRightState->getJoint()->getPosition() ); + + mHipRightJoint.setScale( mHipRightState->getJoint()->getScale() ); + mKneeRightJoint.setScale( mKneeRightState->getJoint()->getScale() ); + mAnkleRightJoint.setScale( mAnkleRightState->getJoint()->getScale() ); + //------------------------------------------------------------------------- + // propagate joint rotations to internal versions + //------------------------------------------------------------------------- + mPelvisJoint.setRotation( mPelvisState->getJoint()->getWorldRotation() ); + +#if GO_TO_KEY_POSE + mHipLeftJoint.setRotation( mHipLeftState->getRotation() ); + mKneeLeftJoint.setRotation( mKneeLeftState->getRotation() ); + mAnkleLeftJoint.setRotation( mAnkleLeftState->getRotation() ); + + mHipRightJoint.setRotation( mHipRightState->getRotation() ); + mKneeRightJoint.setRotation( mKneeRightState->getRotation() ); + mAnkleRightJoint.setRotation( mAnkleRightState->getRotation() ); +#else + mHipLeftJoint.setRotation( mHipLeftState->getJoint()->getRotation() ); + mKneeLeftJoint.setRotation( mKneeLeftState->getJoint()->getRotation() ); + mAnkleLeftJoint.setRotation( mAnkleLeftState->getJoint()->getRotation() ); + + mHipRightJoint.setRotation( mHipRightState->getJoint()->getRotation() ); + mKneeRightJoint.setRotation( mKneeRightState->getJoint()->getRotation() ); + mAnkleRightJoint.setRotation( mAnkleRightState->getJoint()->getRotation() ); +#endif + + // need to wait for underlying keyframe motion to affect the skeleton + if (mFrameNum == 2) + { + mIKLeft.setupJoints( &mHipLeftJoint, &mKneeLeftJoint, &mAnkleLeftJoint, &mTargetLeft ); + mIKRight.setupJoints( &mHipRightJoint, &mKneeRightJoint, &mAnkleRightJoint, &mTargetRight ); + } + else if (mFrameNum < 2) + { + mFrameNum++; + return true; + } + + mFrameNum++; + + //------------------------------------------------------------------------- + // compute target position by projecting ankles to the ground + //------------------------------------------------------------------------- + if ( mTrackAnkles ) + { + mCharacter->getGround( mAnkleLeftJoint.getWorldPosition(), mPositionLeft, mNormalLeft); + mCharacter->getGround( mAnkleRightJoint.getWorldPosition(), mPositionRight, mNormalRight); + + // SL-315 + mTargetLeft.setPosition( mPositionLeft ); + mTargetRight.setPosition( mPositionRight ); + } + + //------------------------------------------------------------------------- + // update solvers + //------------------------------------------------------------------------- + mIKLeft.solve(); + mIKRight.solve(); + + //------------------------------------------------------------------------- + // make ankle rotation conform to the ground + //------------------------------------------------------------------------- + if ( mTrackAnkles ) + { + LLVector4 dirLeft4 = mAnkleLeftJoint.getWorldMatrix().getFwdRow4(); + LLVector4 dirRight4 = mAnkleRightJoint.getWorldMatrix().getFwdRow4(); + LLVector3 dirLeft = vec4to3( dirLeft4 ); + LLVector3 dirRight = vec4to3( dirRight4 ); + + LLVector3 up; + LLVector3 dir; + LLVector3 left; + + up = mNormalLeft; + up.normVec(); + if (mFlipFeet) + { + up *= -1.0f; + } + dir = dirLeft; + dir.normVec(); + left = up % dir; + left.normVec(); + dir = left % up; + mRotationLeft = LLQuaternion( dir, left, up ); + + up = mNormalRight; + up.normVec(); + if (mFlipFeet) + { + up *= -1.0f; + } + dir = dirRight; + dir.normVec(); + left = up % dir; + left.normVec(); + dir = left % up; + mRotationRight = LLQuaternion( dir, left, up ); + } + mAnkleLeftJoint.setWorldRotation( mRotationLeft ); + mAnkleRightJoint.setWorldRotation( mRotationRight ); + + //------------------------------------------------------------------------- + // propagate joint rotations to joint states + //------------------------------------------------------------------------- + mHipLeftState->setRotation( mHipLeftJoint.getRotation() ); + mKneeLeftState->setRotation( mKneeLeftJoint.getRotation() ); + mAnkleLeftState->setRotation( mAnkleLeftJoint.getRotation() ); + + mHipRightState->setRotation( mHipRightJoint.getRotation() ); + mKneeRightState->setRotation( mKneeRightJoint.getRotation() ); + mAnkleRightState->setRotation( mAnkleRightJoint.getRotation() ); + + //LL_INFOS() << "Stand drift amount " << (mCharacter->getCharacterPosition() - mLastGoodPosition).magVec() << LL_ENDL; + +// LL_INFOS() << "DEBUG: " << speed << " : " << mTrackAnkles << LL_ENDL; + return true; +} + +// End diff --git a/indra/llcharacter/llkeyframestandmotion.h b/indra/llcharacter/llkeyframestandmotion.h index c77bdacc71..df458c7a0c 100644 --- a/indra/llcharacter/llkeyframestandmotion.h +++ b/indra/llcharacter/llkeyframestandmotion.h @@ -1,118 +1,118 @@ -/**
- * @file llkeyframestandmotion.h
- * @brief Implementation of LLKeyframeStandMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLKEYFRAMESTANDMOTION_H
-#define LL_LLKEYFRAMESTANDMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llkeyframemotion.h"
-#include "lljointsolverrp3.h"
-
-
-//-----------------------------------------------------------------------------
-// class LLKeyframeStandMotion
-//-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLKeyframeStandMotion :
- public LLKeyframeMotion
-{
- LL_ALIGN_NEW
-public:
- // Constructor
- LLKeyframeStandMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLKeyframeStandMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
- virtual bool onActivate();
- void onDeactivate();
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
-public:
- //-------------------------------------------------------------------------
- // Member Data
- //-------------------------------------------------------------------------
- LLJoint mPelvisJoint;
-
- LLJoint mHipLeftJoint;
- LLJoint mKneeLeftJoint;
- LLJoint mAnkleLeftJoint;
- LLJoint mTargetLeft;
-
- LLJoint mHipRightJoint;
- LLJoint mKneeRightJoint;
- LLJoint mAnkleRightJoint;
- LLJoint mTargetRight;
-
- LLCharacter *mCharacter;
-
- bool mFlipFeet;
-
- LLPointer<LLJointState> mPelvisState;
-
- LLPointer<LLJointState> mHipLeftState;
- LLPointer<LLJointState> mKneeLeftState;
- LLPointer<LLJointState> mAnkleLeftState;
-
- LLPointer<LLJointState> mHipRightState;
- LLPointer<LLJointState> mKneeRightState;
- LLPointer<LLJointState> mAnkleRightState;
-
- LLJointSolverRP3 mIKLeft;
- LLJointSolverRP3 mIKRight;
-
- LLVector3 mPositionLeft;
- LLVector3 mPositionRight;
- LLVector3 mNormalLeft;
- LLVector3 mNormalRight;
- LLQuaternion mRotationLeft;
- LLQuaternion mRotationRight;
-
- LLQuaternion mLastGoodPelvisRotation;
- LLVector3 mLastGoodPosition;
- bool mTrackAnkles;
-
- S32 mFrameNum;
-} LL_ALIGN_POSTFIX(16);
-
-#endif // LL_LLKEYFRAMESTANDMOTION_H
-
+/** + * @file llkeyframestandmotion.h + * @brief Implementation of LLKeyframeStandMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLKEYFRAMESTANDMOTION_H +#define LL_LLKEYFRAMESTANDMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llkeyframemotion.h" +#include "lljointsolverrp3.h" + + +//----------------------------------------------------------------------------- +// class LLKeyframeStandMotion +//----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) +class LLKeyframeStandMotion : + public LLKeyframeMotion +{ + LL_ALIGN_NEW +public: + // Constructor + LLKeyframeStandMotion(const LLUUID &id); + + // Destructor + virtual ~LLKeyframeStandMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + virtual bool onActivate(); + void onDeactivate(); + virtual bool onUpdate(F32 time, U8* joint_mask); + +public: + //------------------------------------------------------------------------- + // Member Data + //------------------------------------------------------------------------- + LLJoint mPelvisJoint; + + LLJoint mHipLeftJoint; + LLJoint mKneeLeftJoint; + LLJoint mAnkleLeftJoint; + LLJoint mTargetLeft; + + LLJoint mHipRightJoint; + LLJoint mKneeRightJoint; + LLJoint mAnkleRightJoint; + LLJoint mTargetRight; + + LLCharacter *mCharacter; + + bool mFlipFeet; + + LLPointer<LLJointState> mPelvisState; + + LLPointer<LLJointState> mHipLeftState; + LLPointer<LLJointState> mKneeLeftState; + LLPointer<LLJointState> mAnkleLeftState; + + LLPointer<LLJointState> mHipRightState; + LLPointer<LLJointState> mKneeRightState; + LLPointer<LLJointState> mAnkleRightState; + + LLJointSolverRP3 mIKLeft; + LLJointSolverRP3 mIKRight; + + LLVector3 mPositionLeft; + LLVector3 mPositionRight; + LLVector3 mNormalLeft; + LLVector3 mNormalRight; + LLQuaternion mRotationLeft; + LLQuaternion mRotationRight; + + LLQuaternion mLastGoodPelvisRotation; + LLVector3 mLastGoodPosition; + bool mTrackAnkles; + + S32 mFrameNum; +} LL_ALIGN_POSTFIX(16); + +#endif // LL_LLKEYFRAMESTANDMOTION_H + diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp index 0dce80f0da..605e15f442 100644 --- a/indra/llcharacter/llkeyframewalkmotion.cpp +++ b/indra/llcharacter/llkeyframewalkmotion.cpp @@ -1,393 +1,393 @@ -/**
- * @file llkeyframewalkmotion.cpp
- * @brief Implementation of LLKeyframeWalkMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llkeyframewalkmotion.h"
-#include "llcharacter.h"
-#include "llmath.h"
-#include "m3math.h"
-#include "llcriticaldamp.h"
-
-//-----------------------------------------------------------------------------
-// Macros
-//-----------------------------------------------------------------------------
-const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed
-
-const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection
-const F32 TIME_EPSILON = 0.001f; // minumum frame time
-const F32 MAX_TIME_DELTA = 2.f; // max two seconds a frame for calculating interpolation
-F32 SPEED_ADJUST_MAX_SEC = 2.f; // maximum adjustment to walk animation playback speed for a second
-F32 ANIM_SPEED_MAX = 1.5f; // absolute upper limit on animation speed
-const F32 MAX_ROLL = 0.6f;
-const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustment interpolation
-
-//-----------------------------------------------------------------------------
-// LLKeyframeWalkMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id)
-: LLKeyframeMotion(id),
- mCharacter(NULL),
- mCyclePhase(0.0f),
- mRealTimeLast(0.0f),
- mAdjTimeLast(0.0f),
- mDownFoot(0)
-{}
-
-
-//-----------------------------------------------------------------------------
-// ~LLKeyframeWalkMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLKeyframeWalkMotion::~LLKeyframeWalkMotion()
-{}
-
-
-//-----------------------------------------------------------------------------
-// LLKeyframeWalkMotion::onInitialize()
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- return LLKeyframeMotion::onInitialize(character);
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeWalkMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeWalkMotion::onActivate()
-{
- mRealTimeLast = 0.0f;
- mAdjTimeLast = 0.0f;
-
- return LLKeyframeMotion::onActivate();
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeWalkMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLKeyframeWalkMotion::onDeactivate()
-{
- mCharacter->removeAnimationData("Down Foot");
- LLKeyframeMotion::onDeactivate();
-}
-
-//-----------------------------------------------------------------------------
-// LLKeyframeWalkMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- // compute time since last update
- F32 deltaTime = time - mRealTimeLast;
-
- void* speed_ptr = mCharacter->getAnimationData("Walk Speed");
- F32 speed = (speed_ptr) ? *((F32 *)speed_ptr) : 1.f;
-
- // adjust the passage of time accordingly
- F32 adjusted_time = mAdjTimeLast + (deltaTime * speed);
-
- // save time for next update
- mRealTimeLast = time;
- mAdjTimeLast = adjusted_time;
-
- // handle wrap around
- if (adjusted_time < 0.0f)
- {
- adjusted_time = getDuration() + fmod(adjusted_time, getDuration());
- }
-
- // let the base class update the cycle
- return LLKeyframeMotion::onUpdate( adjusted_time, joint_mask );
-}
-
-// End
-
-
-//-----------------------------------------------------------------------------
-// LLWalkAdjustMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) :
- LLMotion(id),
- mLastTime(0.f),
- mAnimSpeed(0.f),
- mAdjustedSpeed(0.f),
- mRelativeDir(0.f),
- mAnkleOffset(0.f)
-{
- mName = "walk_adjust";
- mPelvisState = new LLJointState;
-}
-
-//-----------------------------------------------------------------------------
-// LLWalkAdjustMotion::onInitialize()
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
- mLeftAnkleJoint = mCharacter->getJoint("mAnkleLeft");
- mRightAnkleJoint = mCharacter->getJoint("mAnkleRight");
-
- mPelvisJoint = mCharacter->getJoint("mPelvis");
- mPelvisState->setJoint( mPelvisJoint );
- if ( !mPelvisJoint )
- {
- LL_WARNS() << getName() << ": Can't get pelvis joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mPelvisState->setUsage(LLJointState::POS);
- addJointState( mPelvisState );
-
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// LLWalkAdjustMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLWalkAdjustMotion::onActivate()
-{
- mAnimSpeed = 0.f;
- mAdjustedSpeed = 0.f;
- mRelativeDir = 1.f;
- mPelvisState->setPosition(LLVector3::zero);
- // store ankle positions for next frame
- mLastLeftFootGlobalPos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
- mLastLeftFootGlobalPos.mdV[VZ] = 0.0;
-
- mLastRightFootGlobalPos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
- mLastRightFootGlobalPos.mdV[VZ] = 0.0;
-
- F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
- F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
- mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLWalkAdjustMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- // delta_time is guaranteed to be non zero
- F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA);
- mLastTime = time;
-
- // find the avatar motion vector in the XY plane
- LLVector3 avatar_velocity = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
- avatar_velocity.mV[VZ] = 0.f;
-
- F32 speed = llclamp(avatar_velocity.magVec(), 0.f, MAX_WALK_PLAYBACK_SPEED);
-
- // grab avatar->world transforms
- LLQuaternion avatar_to_world_rot = mCharacter->getRootJoint()->getWorldRotation();
-
- LLQuaternion world_to_avatar_rot(avatar_to_world_rot);
- world_to_avatar_rot.conjugate();
-
- LLVector3 foot_slip_vector;
-
- // find foot drift along velocity vector
- if (speed > MIN_WALK_SPEED)
- { // walking/running
-
- // calculate world-space foot drift
- // use global coordinates to seamlessly handle region crossings
- LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
- leftFootGlobalPosition.mdV[VZ] = 0.0;
- LLVector3 leftFootDelta(leftFootGlobalPosition - mLastLeftFootGlobalPos);
- mLastLeftFootGlobalPos = leftFootGlobalPosition;
-
- LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
- rightFootGlobalPosition.mdV[VZ] = 0.0;
- LLVector3 rightFootDelta(rightFootGlobalPosition - mLastRightFootGlobalPos);
- mLastRightFootGlobalPos = rightFootGlobalPosition;
-
- // get foot drift along avatar direction of motion
- F32 left_foot_slip_amt = leftFootDelta * avatar_velocity;
- F32 right_foot_slip_amt = rightFootDelta * avatar_velocity;
-
- // if right foot is pushing back faster than left foot...
- if (right_foot_slip_amt < left_foot_slip_amt)
- { //...use it to calculate optimal animation speed
- foot_slip_vector = rightFootDelta;
- }
- else
- { // otherwise use the left foot
- foot_slip_vector = leftFootDelta;
- }
-
- // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
- // this will soak up transient slippage
- //
- // FIXME: this interacts poorly with speed adjustment
- // mPelvisOffset compensates for foot drift by moving the avatar pelvis in the opposite
- // direction of the drift, up to a certain limited distance
- // but this will cause the animation playback rate calculation below to
- // kick in too slowly and sometimes start playing the animation in reverse.
-
- //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLSmoothInterpolation::getInterpolant(0.1f));
-
- ////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED);
- //F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL;
-
- //// clamp pelvis offset to a 90 degree arc behind the nominal position
- //// NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
- //// must clamp with absolute position of pelvis in mind
- //LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition();
- //mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max, drift_comp_max );
- //mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max, drift_comp_max );
- //mPelvisOffset.mV[VZ] = 0.f;
- //
- //mLastRightFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot);
- //mLastLeftFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot);
-
- //foot_slip_vector -= mPelvisOffset;
-
- LLVector3 avatar_movement_dir = avatar_velocity;
- avatar_movement_dir.normalize();
-
- // planted foot speed is avatar velocity - foot slip amount along avatar movement direction
- F32 foot_speed = speed - ((foot_slip_vector * avatar_movement_dir) / delta_time);
-
- // multiply animation playback rate so that foot speed matches avatar speed
- F32 min_speed_multiplier = clamp_rescale(speed, 0.f, 1.f, 0.f, 0.1f);
- F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX);
-
- // blend towards new speed adjustment value
- F32 new_speed_adjust = LLSmoothInterpolation::lerp(mAdjustedSpeed, desired_speed_multiplier, SPEED_ADJUST_TIME_CONSTANT);
-
- // limit that rate at which the speed adjustment changes
- F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time);
- mAdjustedSpeed += speedDelta;
-
- // modulate speed by dot products of facing and velocity
- // so that if we are moving sideways, we slow down the animation
- // and if we're moving backward, we walk backward
- // do this at the end to be more responsive to direction changes instead of in the above speed calculations
- F32 directional_factor = (avatar_movement_dir * world_to_avatar_rot).mV[VX];
-
- mAnimSpeed = mAdjustedSpeed * directional_factor;
- }
- else
- { // standing/turning
-
- // damp out speed adjustment to 0
- mAnimSpeed = LLSmoothInterpolation::lerp(mAnimSpeed, 1.f, 0.2f);
- //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLSmoothInterpolation::getInterpolant(0.2f));
- }
-
- // broadcast walk speed change
- mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
-
- // set position
- // need to update *some* joint to keep this animation active
- mPelvisState->setPosition(mPelvisOffset);
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLWalkAdjustMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLWalkAdjustMotion::onDeactivate()
-{
- mCharacter->removeAnimationData("Walk Speed");
-}
-
-//-----------------------------------------------------------------------------
-// LLFlyAdjustMotion::LLFlyAdjustMotion()
-//-----------------------------------------------------------------------------
-LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id)
- : LLMotion(id),
- mRoll(0.f)
-{
- mName = "fly_adjust";
-
- mPelvisState = new LLJointState;
-}
-
-//-----------------------------------------------------------------------------
-// LLFlyAdjustMotion::onInitialize()
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- LLJoint* pelvisJoint = mCharacter->getJoint("mPelvis");
- mPelvisState->setJoint( pelvisJoint );
- if ( !pelvisJoint )
- {
- LL_WARNS() << getName() << ": Can't get pelvis joint." << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mPelvisState->setUsage(LLJointState::POS | LLJointState::ROT);
- addJointState( mPelvisState );
-
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// LLFlyAdjustMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLFlyAdjustMotion::onActivate()
-{
- mPelvisState->setPosition(LLVector3::zero);
- mPelvisState->setRotation(LLQuaternion::DEFAULT);
- mRoll = 0.f;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLFlyAdjustMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
- F32 speed = mCharacter->getCharacterVelocity().magVec();
-
- F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL);
- F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
-
- // roll is critically damped interpolation between current roll and angular velocity-derived target roll
- mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, U32Milliseconds(100));
-
- LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
- mPelvisState->setRotation(roll);
-
- return true;
-}
-
+/** + * @file llkeyframewalkmotion.cpp + * @brief Implementation of LLKeyframeWalkMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llkeyframewalkmotion.h" +#include "llcharacter.h" +#include "llmath.h" +#include "m3math.h" +#include "llcriticaldamp.h" + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- +const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed + +const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection +const F32 TIME_EPSILON = 0.001f; // minumum frame time +const F32 MAX_TIME_DELTA = 2.f; // max two seconds a frame for calculating interpolation +F32 SPEED_ADJUST_MAX_SEC = 2.f; // maximum adjustment to walk animation playback speed for a second +F32 ANIM_SPEED_MAX = 1.5f; // absolute upper limit on animation speed +const F32 MAX_ROLL = 0.6f; +const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustment interpolation + +//----------------------------------------------------------------------------- +// LLKeyframeWalkMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id) +: LLKeyframeMotion(id), + mCharacter(NULL), + mCyclePhase(0.0f), + mRealTimeLast(0.0f), + mAdjTimeLast(0.0f), + mDownFoot(0) +{} + + +//----------------------------------------------------------------------------- +// ~LLKeyframeWalkMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLKeyframeWalkMotion::~LLKeyframeWalkMotion() +{} + + +//----------------------------------------------------------------------------- +// LLKeyframeWalkMotion::onInitialize() +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + return LLKeyframeMotion::onInitialize(character); +} + +//----------------------------------------------------------------------------- +// LLKeyframeWalkMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLKeyframeWalkMotion::onActivate() +{ + mRealTimeLast = 0.0f; + mAdjTimeLast = 0.0f; + + return LLKeyframeMotion::onActivate(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeWalkMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLKeyframeWalkMotion::onDeactivate() +{ + mCharacter->removeAnimationData("Down Foot"); + LLKeyframeMotion::onDeactivate(); +} + +//----------------------------------------------------------------------------- +// LLKeyframeWalkMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + // compute time since last update + F32 deltaTime = time - mRealTimeLast; + + void* speed_ptr = mCharacter->getAnimationData("Walk Speed"); + F32 speed = (speed_ptr) ? *((F32 *)speed_ptr) : 1.f; + + // adjust the passage of time accordingly + F32 adjusted_time = mAdjTimeLast + (deltaTime * speed); + + // save time for next update + mRealTimeLast = time; + mAdjTimeLast = adjusted_time; + + // handle wrap around + if (adjusted_time < 0.0f) + { + adjusted_time = getDuration() + fmod(adjusted_time, getDuration()); + } + + // let the base class update the cycle + return LLKeyframeMotion::onUpdate( adjusted_time, joint_mask ); +} + +// End + + +//----------------------------------------------------------------------------- +// LLWalkAdjustMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : + LLMotion(id), + mLastTime(0.f), + mAnimSpeed(0.f), + mAdjustedSpeed(0.f), + mRelativeDir(0.f), + mAnkleOffset(0.f) +{ + mName = "walk_adjust"; + mPelvisState = new LLJointState; +} + +//----------------------------------------------------------------------------- +// LLWalkAdjustMotion::onInitialize() +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + mLeftAnkleJoint = mCharacter->getJoint("mAnkleLeft"); + mRightAnkleJoint = mCharacter->getJoint("mAnkleRight"); + + mPelvisJoint = mCharacter->getJoint("mPelvis"); + mPelvisState->setJoint( mPelvisJoint ); + if ( !mPelvisJoint ) + { + LL_WARNS() << getName() << ": Can't get pelvis joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mPelvisState->setUsage(LLJointState::POS); + addJointState( mPelvisState ); + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLWalkAdjustMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLWalkAdjustMotion::onActivate() +{ + mAnimSpeed = 0.f; + mAdjustedSpeed = 0.f; + mRelativeDir = 1.f; + mPelvisState->setPosition(LLVector3::zero); + // store ankle positions for next frame + mLastLeftFootGlobalPos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition()); + mLastLeftFootGlobalPos.mdV[VZ] = 0.0; + + mLastRightFootGlobalPos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition()); + mLastRightFootGlobalPos.mdV[VZ] = 0.0; + + F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec(); + F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec(); + mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset); + + return true; +} + +//----------------------------------------------------------------------------- +// LLWalkAdjustMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + // delta_time is guaranteed to be non zero + F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA); + mLastTime = time; + + // find the avatar motion vector in the XY plane + LLVector3 avatar_velocity = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation(); + avatar_velocity.mV[VZ] = 0.f; + + F32 speed = llclamp(avatar_velocity.magVec(), 0.f, MAX_WALK_PLAYBACK_SPEED); + + // grab avatar->world transforms + LLQuaternion avatar_to_world_rot = mCharacter->getRootJoint()->getWorldRotation(); + + LLQuaternion world_to_avatar_rot(avatar_to_world_rot); + world_to_avatar_rot.conjugate(); + + LLVector3 foot_slip_vector; + + // find foot drift along velocity vector + if (speed > MIN_WALK_SPEED) + { // walking/running + + // calculate world-space foot drift + // use global coordinates to seamlessly handle region crossings + LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition()); + leftFootGlobalPosition.mdV[VZ] = 0.0; + LLVector3 leftFootDelta(leftFootGlobalPosition - mLastLeftFootGlobalPos); + mLastLeftFootGlobalPos = leftFootGlobalPosition; + + LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition()); + rightFootGlobalPosition.mdV[VZ] = 0.0; + LLVector3 rightFootDelta(rightFootGlobalPosition - mLastRightFootGlobalPos); + mLastRightFootGlobalPos = rightFootGlobalPosition; + + // get foot drift along avatar direction of motion + F32 left_foot_slip_amt = leftFootDelta * avatar_velocity; + F32 right_foot_slip_amt = rightFootDelta * avatar_velocity; + + // if right foot is pushing back faster than left foot... + if (right_foot_slip_amt < left_foot_slip_amt) + { //...use it to calculate optimal animation speed + foot_slip_vector = rightFootDelta; + } + else + { // otherwise use the left foot + foot_slip_vector = leftFootDelta; + } + + // calculate ideal pelvis offset so that foot is glued to ground and damp towards it + // this will soak up transient slippage + // + // FIXME: this interacts poorly with speed adjustment + // mPelvisOffset compensates for foot drift by moving the avatar pelvis in the opposite + // direction of the drift, up to a certain limited distance + // but this will cause the animation playback rate calculation below to + // kick in too slowly and sometimes start playing the animation in reverse. + + //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLSmoothInterpolation::getInterpolant(0.1f)); + + ////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED); + //F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL; + + //// clamp pelvis offset to a 90 degree arc behind the nominal position + //// NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick + //// must clamp with absolute position of pelvis in mind + //LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition(); + //mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max, drift_comp_max ); + //mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max, drift_comp_max ); + //mPelvisOffset.mV[VZ] = 0.f; + // + //mLastRightFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot); + //mLastLeftFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot); + + //foot_slip_vector -= mPelvisOffset; + + LLVector3 avatar_movement_dir = avatar_velocity; + avatar_movement_dir.normalize(); + + // planted foot speed is avatar velocity - foot slip amount along avatar movement direction + F32 foot_speed = speed - ((foot_slip_vector * avatar_movement_dir) / delta_time); + + // multiply animation playback rate so that foot speed matches avatar speed + F32 min_speed_multiplier = clamp_rescale(speed, 0.f, 1.f, 0.f, 0.1f); + F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX); + + // blend towards new speed adjustment value + F32 new_speed_adjust = LLSmoothInterpolation::lerp(mAdjustedSpeed, desired_speed_multiplier, SPEED_ADJUST_TIME_CONSTANT); + + // limit that rate at which the speed adjustment changes + F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time); + mAdjustedSpeed += speedDelta; + + // modulate speed by dot products of facing and velocity + // so that if we are moving sideways, we slow down the animation + // and if we're moving backward, we walk backward + // do this at the end to be more responsive to direction changes instead of in the above speed calculations + F32 directional_factor = (avatar_movement_dir * world_to_avatar_rot).mV[VX]; + + mAnimSpeed = mAdjustedSpeed * directional_factor; + } + else + { // standing/turning + + // damp out speed adjustment to 0 + mAnimSpeed = LLSmoothInterpolation::lerp(mAnimSpeed, 1.f, 0.2f); + //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLSmoothInterpolation::getInterpolant(0.2f)); + } + + // broadcast walk speed change + mCharacter->setAnimationData("Walk Speed", &mAnimSpeed); + + // set position + // need to update *some* joint to keep this animation active + mPelvisState->setPosition(mPelvisOffset); + + return true; +} + +//----------------------------------------------------------------------------- +// LLWalkAdjustMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLWalkAdjustMotion::onDeactivate() +{ + mCharacter->removeAnimationData("Walk Speed"); +} + +//----------------------------------------------------------------------------- +// LLFlyAdjustMotion::LLFlyAdjustMotion() +//----------------------------------------------------------------------------- +LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id) + : LLMotion(id), + mRoll(0.f) +{ + mName = "fly_adjust"; + + mPelvisState = new LLJointState; +} + +//----------------------------------------------------------------------------- +// LLFlyAdjustMotion::onInitialize() +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + LLJoint* pelvisJoint = mCharacter->getJoint("mPelvis"); + mPelvisState->setJoint( pelvisJoint ); + if ( !pelvisJoint ) + { + LL_WARNS() << getName() << ": Can't get pelvis joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mPelvisState->setUsage(LLJointState::POS | LLJointState::ROT); + addJointState( mPelvisState ); + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLFlyAdjustMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLFlyAdjustMotion::onActivate() +{ + mPelvisState->setPosition(LLVector3::zero); + mPelvisState->setRotation(LLQuaternion::DEFAULT); + mRoll = 0.f; + return true; +} + +//----------------------------------------------------------------------------- +// LLFlyAdjustMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation(); + F32 speed = mCharacter->getCharacterVelocity().magVec(); + + F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL); + F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor; + + // roll is critically damped interpolation between current roll and angular velocity-derived target roll + mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, U32Milliseconds(100)); + + LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f)); + mPelvisState->setRotation(roll); + + return true; +} + diff --git a/indra/llcharacter/llkeyframewalkmotion.h b/indra/llcharacter/llkeyframewalkmotion.h index 0b89dfafa9..6320c81399 100644 --- a/indra/llcharacter/llkeyframewalkmotion.h +++ b/indra/llcharacter/llkeyframewalkmotion.h @@ -1,174 +1,174 @@ -/**
- * @file llkeyframewalkmotion.h
- * @brief Implementation of LLKeframeWalkMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLKEYFRAMEWALKMOTION_H
-#define LL_LLKEYFRAMEWALKMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llkeyframemotion.h"
-#include "llcharacter.h"
-#include "v3dmath.h"
-
-#define MIN_REQUIRED_PIXEL_AREA_WALK_ADJUST (20.f)
-#define MIN_REQUIRED_PIXEL_AREA_FLY_ADJUST (20.f)
-
-//-----------------------------------------------------------------------------
-// class LLKeyframeWalkMotion
-//-----------------------------------------------------------------------------
-class LLKeyframeWalkMotion :
- public LLKeyframeMotion
-{
- friend class LLWalkAdjustMotion;
-public:
- // Constructor
- LLKeyframeWalkMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLKeyframeWalkMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
- virtual bool onActivate();
- virtual void onDeactivate();
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
-public:
- //-------------------------------------------------------------------------
- // Member Data
- //-------------------------------------------------------------------------
- LLCharacter *mCharacter;
- F32 mCyclePhase;
- F32 mRealTimeLast;
- F32 mAdjTimeLast;
- S32 mDownFoot;
-};
-
-class LLWalkAdjustMotion : public LLMotion
-{
-public:
- // Constructor
- LLWalkAdjustMotion(const LLUUID &id);
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
- virtual bool onActivate();
- virtual void onDeactivate();
- virtual bool onUpdate(F32 time, U8* joint_mask);
- virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGH_PRIORITY;}
- virtual bool getLoop() { return true; }
- virtual F32 getDuration() { return 0.f; }
- virtual F32 getEaseInDuration() { return 0.f; }
- virtual F32 getEaseOutDuration() { return 0.f; }
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_WALK_ADJUST; }
- virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
-
-public:
- //-------------------------------------------------------------------------
- // Member Data
- //-------------------------------------------------------------------------
- LLCharacter *mCharacter;
- LLJoint* mLeftAnkleJoint;
- LLJoint* mRightAnkleJoint;
- LLPointer<LLJointState> mPelvisState;
- LLJoint* mPelvisJoint;
- LLVector3d mLastLeftFootGlobalPos;
- LLVector3d mLastRightFootGlobalPos;
- F32 mLastTime;
- F32 mAdjustedSpeed;
- F32 mAnimSpeed;
- F32 mRelativeDir;
- LLVector3 mPelvisOffset;
- F32 mAnkleOffset;
-};
-
-class LLFlyAdjustMotion : public LLMotion
-{
-public:
- // Constructor
- LLFlyAdjustMotion(const LLUUID &id);
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
- virtual bool onActivate();
- virtual void onDeactivate() {};
- virtual bool onUpdate(F32 time, U8* joint_mask);
- virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;}
- virtual bool getLoop() { return true; }
- virtual F32 getDuration() { return 0.f; }
- virtual F32 getEaseInDuration() { return 0.f; }
- virtual F32 getEaseOutDuration() { return 0.f; }
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_FLY_ADJUST; }
- virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
-
-protected:
- //-------------------------------------------------------------------------
- // Member Data
- //-------------------------------------------------------------------------
- LLCharacter *mCharacter;
- LLPointer<LLJointState> mPelvisState;
- F32 mRoll;
-};
-
-#endif // LL_LLKeyframeWalkMotion_H
-
+/** + * @file llkeyframewalkmotion.h + * @brief Implementation of LLKeframeWalkMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLKEYFRAMEWALKMOTION_H +#define LL_LLKEYFRAMEWALKMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llkeyframemotion.h" +#include "llcharacter.h" +#include "v3dmath.h" + +#define MIN_REQUIRED_PIXEL_AREA_WALK_ADJUST (20.f) +#define MIN_REQUIRED_PIXEL_AREA_FLY_ADJUST (20.f) + +//----------------------------------------------------------------------------- +// class LLKeyframeWalkMotion +//----------------------------------------------------------------------------- +class LLKeyframeWalkMotion : + public LLKeyframeMotion +{ + friend class LLWalkAdjustMotion; +public: + // Constructor + LLKeyframeWalkMotion(const LLUUID &id); + + // Destructor + virtual ~LLKeyframeWalkMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + virtual bool onActivate(); + virtual void onDeactivate(); + virtual bool onUpdate(F32 time, U8* joint_mask); + +public: + //------------------------------------------------------------------------- + // Member Data + //------------------------------------------------------------------------- + LLCharacter *mCharacter; + F32 mCyclePhase; + F32 mRealTimeLast; + F32 mAdjTimeLast; + S32 mDownFoot; +}; + +class LLWalkAdjustMotion : public LLMotion +{ +public: + // Constructor + LLWalkAdjustMotion(const LLUUID &id); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + virtual bool onActivate(); + virtual void onDeactivate(); + virtual bool onUpdate(F32 time, U8* joint_mask); + virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGH_PRIORITY;} + virtual bool getLoop() { return true; } + virtual F32 getDuration() { return 0.f; } + virtual F32 getEaseInDuration() { return 0.f; } + virtual F32 getEaseOutDuration() { return 0.f; } + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_WALK_ADJUST; } + virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } + +public: + //------------------------------------------------------------------------- + // Member Data + //------------------------------------------------------------------------- + LLCharacter *mCharacter; + LLJoint* mLeftAnkleJoint; + LLJoint* mRightAnkleJoint; + LLPointer<LLJointState> mPelvisState; + LLJoint* mPelvisJoint; + LLVector3d mLastLeftFootGlobalPos; + LLVector3d mLastRightFootGlobalPos; + F32 mLastTime; + F32 mAdjustedSpeed; + F32 mAnimSpeed; + F32 mRelativeDir; + LLVector3 mPelvisOffset; + F32 mAnkleOffset; +}; + +class LLFlyAdjustMotion : public LLMotion +{ +public: + // Constructor + LLFlyAdjustMotion(const LLUUID &id); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + virtual bool onActivate(); + virtual void onDeactivate() {}; + virtual bool onUpdate(F32 time, U8* joint_mask); + virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;} + virtual bool getLoop() { return true; } + virtual F32 getDuration() { return 0.f; } + virtual F32 getEaseInDuration() { return 0.f; } + virtual F32 getEaseOutDuration() { return 0.f; } + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_FLY_ADJUST; } + virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } + +protected: + //------------------------------------------------------------------------- + // Member Data + //------------------------------------------------------------------------- + LLCharacter *mCharacter; + LLPointer<LLJointState> mPelvisState; + F32 mRoll; +}; + +#endif // LL_LLKeyframeWalkMotion_H + diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index c7fbe20dbf..bc9f578660 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -1,178 +1,178 @@ -/**
- * @file llmotion.cpp
- * @brief Implementation of LLMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llmotion.h"
-#include "llcriticaldamp.h"
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLMotion class
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLMotion::LLMotion( const LLUUID &id ) :
- mStopped(true),
- mActive(false),
- mID(id),
- mActivationTimestamp(0.f),
- mStopTimestamp(0.f),
- mSendStopTimestamp(F32_MAX),
- mResidualWeight(0.f),
- mFadeWeight(1.f),
- mDeactivateCallback(NULL),
- mDeactivateCallbackUserData(NULL)
-{
- for (S32 i=0; i<3; ++i)
- memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
-}
-
-//-----------------------------------------------------------------------------
-// ~LLMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLMotion::~LLMotion()
-{
-}
-
-//-----------------------------------------------------------------------------
-// fadeOut()
-//-----------------------------------------------------------------------------
-void LLMotion::fadeOut()
-{
- if (mFadeWeight > 0.01f)
- {
- mFadeWeight = lerp(mFadeWeight, 0.f, LLSmoothInterpolation::getInterpolant(0.15f));
- }
- else
- {
- mFadeWeight = 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// fadeIn()
-//-----------------------------------------------------------------------------
-void LLMotion::fadeIn()
-{
- if (mFadeWeight < 0.99f)
- {
- mFadeWeight = lerp(mFadeWeight, 1.f, LLSmoothInterpolation::getInterpolant(0.15f));
- }
- else
- {
- mFadeWeight = 1.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// addJointState()
-//-----------------------------------------------------------------------------
-void LLMotion::addJointState(const LLPointer<LLJointState>& jointState)
-{
- mPose.addJointState(jointState);
- S32 priority = jointState->getPriority();
- if (priority == LLJoint::USE_MOTION_PRIORITY)
- {
- priority = getPriority();
- }
-
- U32 usage = jointState->getUsage();
-
- // for now, usage is everything
- S32 joint_num = jointState->getJoint()->getJointNum();
- if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
- {
- LL_WARNS() << "joint_num " << joint_num << " is outside of legal range [0-" << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << jointState->getJoint()->getName() << LL_ENDL;
- return;
- }
- mJointSignature[0][joint_num] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0;
- mJointSignature[1][joint_num] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0;
- mJointSignature[2][joint_num] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0;
-}
-
-void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata )
-{
- mDeactivateCallback = cb;
- mDeactivateCallbackUserData = userdata;
-}
-
-//virtual
-void LLMotion::setStopTime(F32 time)
-{
- mStopTimestamp = time;
- mStopped = true;
-}
-
-bool LLMotion::isBlending()
-{
- return mPose.getWeight() < 1.f;
-}
-
-//-----------------------------------------------------------------------------
-// activate()
-//-----------------------------------------------------------------------------
-void LLMotion::activate(F32 time)
-{
- mActivationTimestamp = time;
- mStopped = false;
- mActive = true;
- onActivate();
-}
-
-//-----------------------------------------------------------------------------
-// deactivate()
-//-----------------------------------------------------------------------------
-void LLMotion::deactivate()
-{
- mActive = false;
- mPose.setWeight(0.f);
-
- if (mDeactivateCallback)
- {
- (*mDeactivateCallback)(mDeactivateCallbackUserData);
- mDeactivateCallback = NULL; // only call callback once
- mDeactivateCallbackUserData = NULL;
- }
-
- onDeactivate();
-}
-
-bool LLMotion::canDeprecate()
-{
- return true;
-}
-
-// End
-
+/** + * @file llmotion.cpp + * @brief Implementation of LLMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llmotion.h" +#include "llcriticaldamp.h" + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLMotion class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLMotion::LLMotion( const LLUUID &id ) : + mStopped(true), + mActive(false), + mID(id), + mActivationTimestamp(0.f), + mStopTimestamp(0.f), + mSendStopTimestamp(F32_MAX), + mResidualWeight(0.f), + mFadeWeight(1.f), + mDeactivateCallback(NULL), + mDeactivateCallbackUserData(NULL) +{ + for (S32 i=0; i<3; ++i) + memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); +} + +//----------------------------------------------------------------------------- +// ~LLMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLMotion::~LLMotion() +{ +} + +//----------------------------------------------------------------------------- +// fadeOut() +//----------------------------------------------------------------------------- +void LLMotion::fadeOut() +{ + if (mFadeWeight > 0.01f) + { + mFadeWeight = lerp(mFadeWeight, 0.f, LLSmoothInterpolation::getInterpolant(0.15f)); + } + else + { + mFadeWeight = 0.f; + } +} + +//----------------------------------------------------------------------------- +// fadeIn() +//----------------------------------------------------------------------------- +void LLMotion::fadeIn() +{ + if (mFadeWeight < 0.99f) + { + mFadeWeight = lerp(mFadeWeight, 1.f, LLSmoothInterpolation::getInterpolant(0.15f)); + } + else + { + mFadeWeight = 1.f; + } +} + +//----------------------------------------------------------------------------- +// addJointState() +//----------------------------------------------------------------------------- +void LLMotion::addJointState(const LLPointer<LLJointState>& jointState) +{ + mPose.addJointState(jointState); + S32 priority = jointState->getPriority(); + if (priority == LLJoint::USE_MOTION_PRIORITY) + { + priority = getPriority(); + } + + U32 usage = jointState->getUsage(); + + // for now, usage is everything + S32 joint_num = jointState->getJoint()->getJointNum(); + if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) + { + LL_WARNS() << "joint_num " << joint_num << " is outside of legal range [0-" << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << jointState->getJoint()->getName() << LL_ENDL; + return; + } + mJointSignature[0][joint_num] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0; + mJointSignature[1][joint_num] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0; + mJointSignature[2][joint_num] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0; +} + +void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata ) +{ + mDeactivateCallback = cb; + mDeactivateCallbackUserData = userdata; +} + +//virtual +void LLMotion::setStopTime(F32 time) +{ + mStopTimestamp = time; + mStopped = true; +} + +bool LLMotion::isBlending() +{ + return mPose.getWeight() < 1.f; +} + +//----------------------------------------------------------------------------- +// activate() +//----------------------------------------------------------------------------- +void LLMotion::activate(F32 time) +{ + mActivationTimestamp = time; + mStopped = false; + mActive = true; + onActivate(); +} + +//----------------------------------------------------------------------------- +// deactivate() +//----------------------------------------------------------------------------- +void LLMotion::deactivate() +{ + mActive = false; + mPose.setWeight(0.f); + + if (mDeactivateCallback) + { + (*mDeactivateCallback)(mDeactivateCallbackUserData); + mDeactivateCallback = NULL; // only call callback once + mDeactivateCallbackUserData = NULL; + } + + onDeactivate(); +} + +bool LLMotion::canDeprecate() +{ + return true; +} + +// End + diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index ba719eaac6..4120de76a5 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -1,267 +1,267 @@ -/**
- * @file llmotion.h
- * @brief Implementation of LLMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMOTION_H
-#define LL_LLMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include <string>
-
-#include "llerror.h"
-#include "llpose.h"
-#include "lluuid.h"
-
-class LLCharacter;
-
-//-----------------------------------------------------------------------------
-// class LLMotion
-//-----------------------------------------------------------------------------
-class LLMotion
-{
- friend class LLMotionController;
-
-public:
- enum LLMotionBlendType
- {
- NORMAL_BLEND,
- ADDITIVE_BLEND
- };
-
- enum LLMotionInitStatus
- {
- STATUS_FAILURE,
- STATUS_SUCCESS,
- STATUS_HOLD
- };
-
- // Constructor
- LLMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // get the name of this instance
- const std::string &getName() const { return mName; }
-
- // set the name of this instance
- void setName(const std::string &name) { mName = name; }
-
- const LLUUID& getID() const { return mID; }
-
- // returns the pose associated with the current state of this motion
- virtual LLPose* getPose() { return &mPose;}
-
- void fadeOut();
-
- void fadeIn();
-
- F32 getFadeWeight() const { return mFadeWeight; }
-
- F32 getStopTime() const { return mStopTimestamp; }
-
- virtual void setStopTime(F32 time);
-
- bool isStopped() const { return mStopped; }
-
- void setStopped(bool stopped) { mStopped = stopped; }
-
- bool isBlending();
-
- // Activation functions.
- // It is OK for other classes to activate a motion,
- // but only the controller can deactivate it.
- // Thus, if mActive == true, the motion *may* be on the controllers active list,
- // but if mActive == false, the motion is gauranteed not to be on the active list.
-protected:
- // Used by LLMotionController only
- void deactivate();
- bool isActive() { return mActive; }
-public:
- void activate(F32 time);
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() = 0;
-
- // motions must report their total duration
- virtual F32 getDuration() = 0;
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() = 0;
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() = 0;
-
- // motions must report their priority level
- virtual LLJoint::JointPriority getPriority() = 0;
-
- // amount of affected joints
- virtual S32 getNumJointMotions() { return 0; };
-
- // motions must report their blend type
- virtual LLMotionBlendType getBlendType() = 0;
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() = 0;
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character) = 0;
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- virtual bool onUpdate(F32 activeTime, U8* joint_mask) = 0;
-
- // called when a motion is deactivated
- virtual void onDeactivate() = 0;
-
- // can we crossfade this motion with a new instance when restarted?
- // should ultimately always be true, but lack of emote blending, etc
- // requires this
- virtual bool canDeprecate();
-
- // optional callback routine called when animation deactivated.
- void setDeactivateCallback( void (*cb)(void *), void* userdata );
-
-protected:
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate() = 0;
-
- void addJointState(const LLPointer<LLJointState>& jointState);
-
-protected:
- LLPose mPose;
- bool mStopped; // motion has been stopped;
- bool mActive; // motion is on active list (can be stopped or not stopped)
-
- //-------------------------------------------------------------------------
- // these are set implicitly by the motion controller and
- // may be referenced (read only) in the above handlers.
- //-------------------------------------------------------------------------
- std::string mName; // instance name assigned by motion controller
- LLUUID mID;
-
- F32 mActivationTimestamp; // time when motion was activated
- F32 mStopTimestamp; // time when motion was told to stop
- F32 mSendStopTimestamp; // time when simulator should be told to stop this motion
- F32 mResidualWeight; // blend weight at beginning of stop motion phase
- F32 mFadeWeight; // for fading in and out based on LOD
- U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority
- void (*mDeactivateCallback)(void* data);
- void* mDeactivateCallbackUserData;
-};
-
-
-//-----------------------------------------------------------------------------
-// LLTestMotion
-//-----------------------------------------------------------------------------
-class LLTestMotion : public LLMotion
-{
-public:
- LLTestMotion(const LLUUID &id) : LLMotion(id){}
- ~LLTestMotion() {}
- static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); }
- bool getLoop() { return false; }
- F32 getDuration() { return 0.0f; }
- F32 getEaseInDuration() { return 0.0f; }
- F32 getEaseOutDuration() { return 0.0f; }
- LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; }
- LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
- F32 getMinPixelArea() { return 0.f; }
-
- LLMotionInitStatus onInitialize(LLCharacter*) { LL_INFOS() << "LLTestMotion::onInitialize()" << LL_ENDL; return STATUS_SUCCESS; }
- bool onActivate() { LL_INFOS() << "LLTestMotion::onActivate()" << LL_ENDL; return true; }
- bool onUpdate(F32 time, U8* joint_mask) { LL_INFOS() << "LLTestMotion::onUpdate(" << time << ")" << LL_ENDL; return true; }
- void onDeactivate() { LL_INFOS() << "LLTestMotion::onDeactivate()" << LL_ENDL; }
-};
-
-
-//-----------------------------------------------------------------------------
-// LLNullMotion
-//-----------------------------------------------------------------------------
-class LLNullMotion : public LLMotion
-{
-public:
- LLNullMotion(const LLUUID &id) : LLMotion(id) {}
- ~LLNullMotion() {}
- static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); }
-
- // motions must specify whether or not they loop
- /*virtual*/ bool getLoop() { return true; }
-
- // motions must report their total duration
- /*virtual*/ F32 getDuration() { return 1.f; }
-
- // motions must report their "ease in" duration
- /*virtual*/ F32 getEaseInDuration() { return 0.f; }
-
- // motions must report their "ease out" duration.
- /*virtual*/ F32 getEaseOutDuration() { return 0.f; }
-
- // motions must report their priority level
- /*virtual*/ LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; }
-
- // motions must report their blend type
- /*virtual*/ LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- /*virtual*/ F32 getMinPixelArea() { return 0.f; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- /*virtual*/ LLMotionInitStatus onInitialize(LLCharacter *character) { return STATUS_SUCCESS; }
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- /*virtual*/ bool onActivate() { return true; }
-
- // called per time step
- // must return true while it is active, and
- // must return false when the motion is completed.
- /*virtual*/ bool onUpdate(F32 activeTime, U8* joint_mask) { return true; }
-
- // called when a motion is deactivated
- /*virtual*/ void onDeactivate() {}
-};
-#endif // LL_LLMOTION_H
-
+/** + * @file llmotion.h + * @brief Implementation of LLMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMOTION_H +#define LL_LLMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include <string> + +#include "llerror.h" +#include "llpose.h" +#include "lluuid.h" + +class LLCharacter; + +//----------------------------------------------------------------------------- +// class LLMotion +//----------------------------------------------------------------------------- +class LLMotion +{ + friend class LLMotionController; + +public: + enum LLMotionBlendType + { + NORMAL_BLEND, + ADDITIVE_BLEND + }; + + enum LLMotionInitStatus + { + STATUS_FAILURE, + STATUS_SUCCESS, + STATUS_HOLD + }; + + // Constructor + LLMotion(const LLUUID &id); + + // Destructor + virtual ~LLMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // get the name of this instance + const std::string &getName() const { return mName; } + + // set the name of this instance + void setName(const std::string &name) { mName = name; } + + const LLUUID& getID() const { return mID; } + + // returns the pose associated with the current state of this motion + virtual LLPose* getPose() { return &mPose;} + + void fadeOut(); + + void fadeIn(); + + F32 getFadeWeight() const { return mFadeWeight; } + + F32 getStopTime() const { return mStopTimestamp; } + + virtual void setStopTime(F32 time); + + bool isStopped() const { return mStopped; } + + void setStopped(bool stopped) { mStopped = stopped; } + + bool isBlending(); + + // Activation functions. + // It is OK for other classes to activate a motion, + // but only the controller can deactivate it. + // Thus, if mActive == true, the motion *may* be on the controllers active list, + // but if mActive == false, the motion is gauranteed not to be on the active list. +protected: + // Used by LLMotionController only + void deactivate(); + bool isActive() { return mActive; } +public: + void activate(F32 time); + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() = 0; + + // motions must report their total duration + virtual F32 getDuration() = 0; + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() = 0; + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() = 0; + + // motions must report their priority level + virtual LLJoint::JointPriority getPriority() = 0; + + // amount of affected joints + virtual S32 getNumJointMotions() { return 0; }; + + // motions must report their blend type + virtual LLMotionBlendType getBlendType() = 0; + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() = 0; + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character) = 0; + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + virtual bool onUpdate(F32 activeTime, U8* joint_mask) = 0; + + // called when a motion is deactivated + virtual void onDeactivate() = 0; + + // can we crossfade this motion with a new instance when restarted? + // should ultimately always be true, but lack of emote blending, etc + // requires this + virtual bool canDeprecate(); + + // optional callback routine called when animation deactivated. + void setDeactivateCallback( void (*cb)(void *), void* userdata ); + +protected: + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate() = 0; + + void addJointState(const LLPointer<LLJointState>& jointState); + +protected: + LLPose mPose; + bool mStopped; // motion has been stopped; + bool mActive; // motion is on active list (can be stopped or not stopped) + + //------------------------------------------------------------------------- + // these are set implicitly by the motion controller and + // may be referenced (read only) in the above handlers. + //------------------------------------------------------------------------- + std::string mName; // instance name assigned by motion controller + LLUUID mID; + + F32 mActivationTimestamp; // time when motion was activated + F32 mStopTimestamp; // time when motion was told to stop + F32 mSendStopTimestamp; // time when simulator should be told to stop this motion + F32 mResidualWeight; // blend weight at beginning of stop motion phase + F32 mFadeWeight; // for fading in and out based on LOD + U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority + void (*mDeactivateCallback)(void* data); + void* mDeactivateCallbackUserData; +}; + + +//----------------------------------------------------------------------------- +// LLTestMotion +//----------------------------------------------------------------------------- +class LLTestMotion : public LLMotion +{ +public: + LLTestMotion(const LLUUID &id) : LLMotion(id){} + ~LLTestMotion() {} + static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); } + bool getLoop() { return false; } + F32 getDuration() { return 0.0f; } + F32 getEaseInDuration() { return 0.0f; } + F32 getEaseOutDuration() { return 0.0f; } + LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; } + LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + F32 getMinPixelArea() { return 0.f; } + + LLMotionInitStatus onInitialize(LLCharacter*) { LL_INFOS() << "LLTestMotion::onInitialize()" << LL_ENDL; return STATUS_SUCCESS; } + bool onActivate() { LL_INFOS() << "LLTestMotion::onActivate()" << LL_ENDL; return true; } + bool onUpdate(F32 time, U8* joint_mask) { LL_INFOS() << "LLTestMotion::onUpdate(" << time << ")" << LL_ENDL; return true; } + void onDeactivate() { LL_INFOS() << "LLTestMotion::onDeactivate()" << LL_ENDL; } +}; + + +//----------------------------------------------------------------------------- +// LLNullMotion +//----------------------------------------------------------------------------- +class LLNullMotion : public LLMotion +{ +public: + LLNullMotion(const LLUUID &id) : LLMotion(id) {} + ~LLNullMotion() {} + static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); } + + // motions must specify whether or not they loop + /*virtual*/ bool getLoop() { return true; } + + // motions must report their total duration + /*virtual*/ F32 getDuration() { return 1.f; } + + // motions must report their "ease in" duration + /*virtual*/ F32 getEaseInDuration() { return 0.f; } + + // motions must report their "ease out" duration. + /*virtual*/ F32 getEaseOutDuration() { return 0.f; } + + // motions must report their priority level + /*virtual*/ LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; } + + // motions must report their blend type + /*virtual*/ LLMotionBlendType getBlendType() { return NORMAL_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + /*virtual*/ F32 getMinPixelArea() { return 0.f; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + /*virtual*/ LLMotionInitStatus onInitialize(LLCharacter *character) { return STATUS_SUCCESS; } + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + /*virtual*/ bool onActivate() { return true; } + + // called per time step + // must return true while it is active, and + // must return false when the motion is completed. + /*virtual*/ bool onUpdate(F32 activeTime, U8* joint_mask) { return true; } + + // called when a motion is deactivated + /*virtual*/ void onDeactivate() {} +}; +#endif // LL_LLMOTION_H + diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index e4dc066d58..5f99633a58 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -1,1144 +1,1144 @@ -/**
- * @file llmotioncontroller.cpp
- * @brief Implementation of LLMotionController class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llmotioncontroller.h"
-#include "llfasttimer.h"
-#include "llkeyframemotion.h"
-#include "llmath.h"
-#include "lltimer.h"
-#include "llanimationstates.h"
-#include "llstl.h"
-
-// This is why LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be a multiple of 4.
-const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4;
-const U32 MAX_MOTION_INSTANCES = 32;
-
-//-----------------------------------------------------------------------------
-// Constants and statics
-//-----------------------------------------------------------------------------
-F32 LLMotionController::sCurrentTimeFactor = 1.f;
-LLMotionRegistry LLMotionController::sRegistry;
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLMotionRegistry class
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLMotionRegistry()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLMotionRegistry::LLMotionRegistry()
-{
-
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLMotionRegistry()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLMotionRegistry::~LLMotionRegistry()
-{
- mMotionTable.clear();
-}
-
-
-//-----------------------------------------------------------------------------
-// addMotion()
-//-----------------------------------------------------------------------------
-bool LLMotionRegistry::registerMotion( const LLUUID& id, LLMotionConstructor constructor )
-{
- // LL_INFOS() << "Registering motion: " << name << LL_ENDL;
- if (!is_in_map(mMotionTable, id))
- {
- mMotionTable[id] = constructor;
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// markBad()
-//-----------------------------------------------------------------------------
-void LLMotionRegistry::markBad( const LLUUID& id )
-{
- mMotionTable[id] = LLMotionConstructor(NULL);
-}
-
-//-----------------------------------------------------------------------------
-// createMotion()
-//-----------------------------------------------------------------------------
-LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
-{
- LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL));
- LLMotion* motion = NULL;
-
- if ( constructor == NULL )
- {
- // *FIX: need to replace with a better default scheme. RN
- motion = LLKeyframeMotion::create(id);
- }
- else
- {
- motion = constructor(id);
- }
-
- return motion;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLMotionController class
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLMotionController()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLMotionController::LLMotionController()
- : mTimeFactor(sCurrentTimeFactor),
- mCharacter(NULL),
- mAnimTime(0.f),
- mPrevTimerElapsed(0.f),
- mLastTime(0.0f),
- mHasRunOnce(false),
- mPaused(false),
- mPausedFrame(0),
- mTimeStep(0.f),
- mTimeStepCount(0),
- mLastInterp(0.f),
- mIsSelf(false),
- mLastCountAfterPurge(0)
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLMotionController()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLMotionController::~LLMotionController()
-{
- deleteAllMotions();
-}
-
-void LLMotionController::incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions)
-{
- num_motions += mAllMotions.size();
- num_loading_motions += mLoadingMotions.size();
- num_loaded_motions += mLoadedMotions.size();
- num_active_motions += mActiveMotions.size();
- num_deprecated_motions += mDeprecatedMotions.size();
-}
-
-//-----------------------------------------------------------------------------
-// deleteAllMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::deleteAllMotions()
-{
- mLoadingMotions.clear();
- mLoadedMotions.clear();
- mActiveMotions.clear();
-
- for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
- mAllMotions.clear();
-
- // stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from
- // mAllMotions to mDeprecatedMotions in method
- // LLMotionController::deprecateMotionInstance(). Thus, we should also clean
- // up the mDeprecatedMotions list as well.
- for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer());
- mDeprecatedMotions.clear();
-}
-
-//-----------------------------------------------------------------------------
-// purgeExcessMotion()
-//-----------------------------------------------------------------------------
-void LLMotionController::purgeExcessMotions()
-{
- if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
- {
- // clean up deprecated motions
- for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin();
- deprecated_motion_it != mDeprecatedMotions.end(); )
- {
- motion_set_t::iterator cur_iter = deprecated_motion_it++;
- LLMotion* cur_motionp = *cur_iter;
- if (!isMotionActive(cur_motionp))
- {
- // Motion is deprecated so we know it's not cannonical,
- // we can safely remove the instance
- removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions
- mDeprecatedMotions.erase(cur_iter);
- }
- }
- }
-
- std::set<LLUUID> motions_to_kill;
- if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
- {
- // too many motions active this frame, kill all blenders
- mPoseBlender.clearBlenders();
- for (LLMotion* cur_motionp : mLoadedMotions)
- {
- // motion isn't playing, delete it
- if (!isMotionActive(cur_motionp))
- {
- motions_to_kill.insert(cur_motionp->getID());
- }
- }
- }
-
- // clean up all inactive, loaded motions
- for (LLUUID motion_id : motions_to_kill)
- {
- // look up the motion again by ID to get canonical instance
- // and kill it only if that one is inactive
- LLMotion* motionp = findMotion(motion_id);
- if (motionp && !isMotionActive(motionp))
- {
- removeMotion(motion_id);
- }
- }
-
- U32 loaded_count = mLoadedMotions.size();
- if (loaded_count > (2 * MAX_MOTION_INSTANCES) && loaded_count > mLastCountAfterPurge)
- {
- LL_WARNS_ONCE("Animation") << loaded_count << " Loaded Motions. Amount of motions is over limit." << LL_ENDL;
- }
- mLastCountAfterPurge = loaded_count;
-}
-
-//-----------------------------------------------------------------------------
-// deactivateStoppedMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::deactivateStoppedMotions()
-{
- // Since we're hidden, deactivate any stopped motions.
- for (motion_list_t::iterator iter = mActiveMotions.begin();
- iter != mActiveMotions.end(); )
- {
- motion_list_t::iterator curiter = iter++;
- LLMotion* motionp = *curiter;
- if (motionp->isStopped())
- {
- deactivateMotionInstance(motionp);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// setTimeStep()
-//-----------------------------------------------------------------------------
-void LLMotionController::setTimeStep(F32 step)
-{
- mTimeStep = step;
-
- if (step != 0.f)
- {
- // make sure timestamps conform to new quantum
- for (motion_list_t::iterator iter = mActiveMotions.begin();
- iter != mActiveMotions.end(); ++iter)
- {
- LLMotion* motionp = *iter;
- F32 activation_time = motionp->mActivationTimestamp;
- motionp->mActivationTimestamp = (F32)(llfloor(activation_time / step)) * step;
- bool stopped = motionp->isStopped();
- motionp->setStopTime((F32)(llfloor(motionp->getStopTime() / step)) * step);
- motionp->setStopped(stopped);
- motionp->mSendStopTimestamp = (F32)llfloor(motionp->mSendStopTimestamp / step) * step;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// setTimeFactor()
-//-----------------------------------------------------------------------------
-void LLMotionController::setTimeFactor(F32 time_factor)
-{
- mTimeFactor = time_factor;
-}
-
-//-----------------------------------------------------------------------------
-// setCharacter()
-//-----------------------------------------------------------------------------
-void LLMotionController::setCharacter(LLCharacter *character)
-{
- mCharacter = character;
-}
-
-
-//-----------------------------------------------------------------------------
-// registerMotion()
-//-----------------------------------------------------------------------------
-bool LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor constructor )
-{
- return sRegistry.registerMotion(id, constructor);
-}
-
-//-----------------------------------------------------------------------------
-// removeMotion()
-//-----------------------------------------------------------------------------
-void LLMotionController::removeMotion( const LLUUID& id)
-{
- LLMotion* motionp = findMotion(id);
- mAllMotions.erase(id);
- removeMotionInstance(motionp);
-}
-
-// removes instance of a motion from all runtime structures, but does
-// not erase entry by ID, as this could be a duplicate instance
-// use removeMotion(id) to remove all references to a given motion by id.
-void LLMotionController::removeMotionInstance(LLMotion* motionp)
-{
- if (motionp)
- {
- llassert(findMotion(motionp->getID()) != motionp);
- if (motionp->isActive())
- motionp->deactivate();
- mLoadingMotions.erase(motionp);
- mLoadedMotions.erase(motionp);
- mActiveMotions.remove(motionp);
- delete motionp;
- }
-}
-
-//-----------------------------------------------------------------------------
-// createMotion()
-//-----------------------------------------------------------------------------
-LLMotion* LLMotionController::createMotion( const LLUUID &id )
-{
- // do we have an instance of this motion for this character?
- LLMotion *motion = findMotion(id);
-
- // if not, we need to create one
- if (!motion)
- {
- // look up constructor and create it
- motion = sRegistry.createMotion(id);
- if (!motion)
- {
- return NULL;
- }
-
- // look up name for default motions
- const char* motion_name = gAnimLibrary.animStateToString(id);
- if (motion_name)
- {
- motion->setName(motion_name);
- }
-
- // initialize the new instance
- LLMotion::LLMotionInitStatus stat = motion->onInitialize(mCharacter);
- switch(stat)
- {
- case LLMotion::STATUS_FAILURE:
- LL_INFOS() << "Motion " << id << " init failed." << LL_ENDL;
- sRegistry.markBad(id);
- delete motion;
- return NULL;
- case LLMotion::STATUS_HOLD:
- mLoadingMotions.insert(motion);
- break;
- case LLMotion::STATUS_SUCCESS:
- // add motion to our list
- mLoadedMotions.insert(motion);
- break;
- default:
- LL_ERRS() << "Invalid initialization status" << LL_ENDL;
- break;
- }
-
- mAllMotions[id] = motion;
- }
- return motion;
-}
-
-//-----------------------------------------------------------------------------
-// startMotion()
-//-----------------------------------------------------------------------------
-bool LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
-{
- // do we have an instance of this motion for this character?
- LLMotion *motion = findMotion(id);
-
- // motion that is stopping will be allowed to stop but
- // replaced by a new instance of that motion
- if (motion
- && !mPaused
- && motion->canDeprecate()
- && motion->getFadeWeight() > 0.01f // not LOD-ed out
- && (motion->isBlending() || motion->getStopTime() != 0.f))
- {
- deprecateMotionInstance(motion);
- // force creation of new instance
- motion = NULL;
- }
-
- // create new motion instance
- if (!motion)
- {
- motion = createMotion(id);
- }
-
- if (!motion)
- {
- return false;
- }
- //if the motion is already active and allows deprecation, then let it keep playing
- else if (motion->canDeprecate() && isMotionActive(motion))
- {
- return true;
- }
-
-// LL_INFOS() << "Starting motion " << name << LL_ENDL;
- return activateMotionInstance(motion, mAnimTime - start_offset);
-}
-
-
-//-----------------------------------------------------------------------------
-// stopMotionLocally()
-//-----------------------------------------------------------------------------
-bool LLMotionController::stopMotionLocally(const LLUUID &id, bool stop_immediate)
-{
- // if already inactive, return false
- LLMotion *motion = findMotion(id);
- // SL-1290: always stop immediate if paused
- return stopMotionInstance(motion, stop_immediate||mPaused);
-}
-
-bool LLMotionController::stopMotionInstance(LLMotion* motion, bool stop_immediate)
-{
- if (!motion)
- {
- return false;
- }
-
-
- // If on active list, stop it
- if (isMotionActive(motion) && !motion->isStopped())
- {
- motion->setStopTime(mAnimTime);
- if (stop_immediate)
- {
- deactivateMotionInstance(motion);
- }
- return true;
- }
- else if (isMotionLoading(motion))
- {
- motion->setStopped(true);
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// updateRegularMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::updateRegularMotions()
-{
- updateMotionsByType(LLMotion::NORMAL_BLEND);
-}
-
-//-----------------------------------------------------------------------------
-// updateAdditiveMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::updateAdditiveMotions()
-{
- updateMotionsByType(LLMotion::ADDITIVE_BLEND);
-}
-
-//-----------------------------------------------------------------------------
-// resetJointSignatures()
-//-----------------------------------------------------------------------------
-void LLMotionController::resetJointSignatures()
-{
- memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
- memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
-}
-
-//-----------------------------------------------------------------------------
-// updateIdleMotion()
-// minimal updates for active motions
-//-----------------------------------------------------------------------------
-void LLMotionController::updateIdleMotion(LLMotion* motionp)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
- {
- deactivateMotionInstance(motionp);
- }
- else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
- {
- // is this the first iteration in the ease out phase?
- if (mLastTime <= motionp->getStopTime())
- {
- // store residual weight for this motion
- motionp->mResidualWeight = motionp->getPose()->getWeight();
- }
- }
- else if (mAnimTime > motionp->mSendStopTimestamp)
- {
- // notify character of timed stop event on first iteration past sendstoptimestamp
- // this will only be called when an animation stops itself (runs out of time)
- if (mLastTime <= motionp->mSendStopTimestamp)
- {
- mCharacter->requestStopMotion( motionp );
- stopMotionInstance(motionp, false);
- }
- }
- else if (mAnimTime >= motionp->mActivationTimestamp)
- {
- if (mLastTime < motionp->mActivationTimestamp)
- {
- motionp->mResidualWeight = motionp->getPose()->getWeight();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateIdleActiveMotions()
-// Call this instead of updateMotionsByType for hidden avatars
-//-----------------------------------------------------------------------------
-void LLMotionController::updateIdleActiveMotions()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- for (motion_list_t::iterator iter = mActiveMotions.begin();
- iter != mActiveMotions.end(); )
- {
- motion_list_t::iterator curiter = iter++;
- LLMotion* motionp = *curiter;
- updateIdleMotion(motionp);
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateMotionsByType()
-//-----------------------------------------------------------------------------
-void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- bool update_result = true;
- U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
-
- memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
-
- // iterate through active motions in chronological order
- for (motion_list_t::iterator iter = mActiveMotions.begin();
- iter != mActiveMotions.end(); )
- {
- motion_list_t::iterator curiter = iter++;
- LLMotion* motionp = *curiter;
- if (motionp->getBlendType() != anim_type)
- {
- continue;
- }
-
- bool update_motion = false;
-
- if (motionp->getPose()->getWeight() < 1.f)
- {
- update_motion = true;
- }
- else
- {
- for (S32 i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++)
- {
- U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]);
- U32 test_signature = *(U32*)&(motionp->mJointSignature[0][i * 4]);
-
- if ((*current_signature | test_signature) > (*current_signature))
- {
- *current_signature |= test_signature;
- update_motion = true;
- }
-
- *((U32*)&last_joint_signature[i * 4]) = *(U32*)&(mJointSignature[1][i * 4]);
- current_signature = (U32*)&(mJointSignature[1][i * 4]);
- test_signature = *(U32*)&(motionp->mJointSignature[1][i * 4]);
-
- if ((*current_signature | test_signature) > (*current_signature))
- {
- *current_signature |= test_signature;
- update_motion = true;
- }
- }
- }
-
- if (!update_motion)
- {
- updateIdleMotion(motionp);
- continue;
- }
-
- LLPose *posep = motionp->getPose();
-
- // only filter by LOD after running every animation at least once (to prime the avatar state)
- if (mHasRunOnce && motionp->getMinPixelArea() > mCharacter->getPixelArea())
- {
- motionp->fadeOut();
-
- //should we notify the simulator that this motion should be stopped (check even if skipped by LOD logic)
- if (mAnimTime > motionp->mSendStopTimestamp)
- {
- // notify character of timed stop event on first iteration past sendstoptimestamp
- // this will only be called when an animation stops itself (runs out of time)
- if (mLastTime <= motionp->mSendStopTimestamp)
- {
- mCharacter->requestStopMotion( motionp );
- stopMotionInstance(motionp, false);
- }
- }
-
- if (motionp->getFadeWeight() < 0.01f)
- {
- if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
- {
- posep->setWeight(0.f);
- deactivateMotionInstance(motionp);
- }
- continue;
- }
- }
- else
- {
- motionp->fadeIn();
- }
-
- //**********************
- // MOTION INACTIVE
- //**********************
- if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
- {
- // this motion has gone on too long, deactivate it
- // did we have a chance to stop it?
- if (mLastTime <= motionp->getStopTime())
- {
- // if not, let's stop it this time through and deactivate it the next
-
- posep->setWeight(motionp->getFadeWeight());
- motionp->onUpdate(motionp->getStopTime() - motionp->mActivationTimestamp, last_joint_signature);
- }
- else
- {
- posep->setWeight(0.f);
- deactivateMotionInstance(motionp);
- continue;
- }
- }
-
- //**********************
- // MOTION EASE OUT
- //**********************
- else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
- {
- // is this the first iteration in the ease out phase?
- if (mLastTime <= motionp->getStopTime())
- {
- // store residual weight for this motion
- motionp->mResidualWeight = motionp->getPose()->getWeight();
- }
-
- if (motionp->getEaseOutDuration() == 0.f)
- {
- posep->setWeight(0.f);
- }
- else
- {
- posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight * cubic_step(1.f - ((mAnimTime - motionp->getStopTime()) / motionp->getEaseOutDuration())));
- }
-
- // perform motion update
- update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
- }
-
- //**********************
- // MOTION ACTIVE
- //**********************
- else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
- {
- posep->setWeight(motionp->getFadeWeight());
-
- //should we notify the simulator that this motion should be stopped?
- if (mAnimTime > motionp->mSendStopTimestamp)
- {
- // notify character of timed stop event on first iteration past sendstoptimestamp
- // this will only be called when an animation stops itself (runs out of time)
- if (mLastTime <= motionp->mSendStopTimestamp)
- {
- mCharacter->requestStopMotion( motionp );
- stopMotionInstance(motionp, false);
- }
- }
-
- // perform motion update
- {
- update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
- }
- }
-
- //**********************
- // MOTION EASE IN
- //**********************
- else if (mAnimTime >= motionp->mActivationTimestamp)
- {
- if (mLastTime < motionp->mActivationTimestamp)
- {
- motionp->mResidualWeight = motionp->getPose()->getWeight();
- }
- if (motionp->getEaseInDuration() == 0.f)
- {
- posep->setWeight(motionp->getFadeWeight());
- }
- else
- {
- // perform motion update
- posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight + (1.f - motionp->mResidualWeight) * cubic_step((mAnimTime - motionp->mActivationTimestamp) / motionp->getEaseInDuration()));
- }
- // perform motion update
- update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
- }
- else
- {
- posep->setWeight(0.f);
- update_result = motionp->onUpdate(0.f, last_joint_signature);
- }
-
- // allow motions to deactivate themselves
- if (!update_result)
- {
- if (!motionp->isStopped() || motionp->getStopTime() > mAnimTime)
- {
- // animation has stopped itself due to internal logic
- // propagate this to the network
- // as not all viewers are guaranteed to have access to the same logic
- mCharacter->requestStopMotion( motionp );
- stopMotionInstance(motionp, false);
- }
-
- }
-
- // even if onupdate returns false, add this motion in to the blend one last time
- mPoseBlender.addMotion(motionp);
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateLoadingMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::updateLoadingMotions()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- // query pending motions for completion
- for (motion_set_t::iterator iter = mLoadingMotions.begin();
- iter != mLoadingMotions.end(); )
- {
- motion_set_t::iterator curiter = iter++;
- LLMotion* motionp = *curiter;
- if( !motionp)
- {
- continue; // maybe shouldn't happen but i've seen it -MG
- }
- LLMotion::LLMotionInitStatus status = motionp->onInitialize(mCharacter);
- if (status == LLMotion::STATUS_SUCCESS)
- {
- mLoadingMotions.erase(curiter);
- // add motion to our loaded motion list
- mLoadedMotions.insert(motionp);
- // this motion should be playing
- if (!motionp->isStopped())
- {
- activateMotionInstance(motionp, mAnimTime);
- }
- }
- else if (status == LLMotion::STATUS_FAILURE)
- {
- LL_INFOS() << "Motion " << motionp->getID() << " init failed." << LL_ENDL;
- sRegistry.markBad(motionp->getID());
- mLoadingMotions.erase(curiter);
- motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
- if (found_it != mDeprecatedMotions.end())
- {
- mDeprecatedMotions.erase(found_it);
- }
- mAllMotions.erase(motionp->getID());
- delete motionp;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// call updateMotion() or updateMotionsMinimal() every frame
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// updateMotion()
-//-----------------------------------------------------------------------------
-void LLMotionController::updateMotions(bool force_update)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- // SL-763: "Distant animated objects run at super fast speed"
- // The use_quantum optimization or possibly the associated code in setTimeStamp()
- // does not work as implemented.
- // Currently setting mTimeStep to nonzero is disabled elsewhere.
- bool use_quantum = (mTimeStep != 0.f);
-
- // Always update mPrevTimerElapsed
- F32 cur_time = mTimer.getElapsedTimeF32();
- F32 delta_time = cur_time - mPrevTimerElapsed;
- mPrevTimerElapsed = cur_time;
- mLastTime = mAnimTime;
-
- // Always cap the number of loaded motions
- purgeExcessMotions();
-
- // Update timing info for this time step.
- if (!mPaused)
- {
- F32 update_time = mAnimTime + delta_time * mTimeFactor;
- if (use_quantum)
- {
- F32 time_interval = fmodf(update_time, mTimeStep);
-
- // always animate *ahead* of actual time
- S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1;
- if (quantum_count == mTimeStepCount)
- {
- // we're still in same time quantum as before, so just interpolate and exit
- if (!mPaused)
- {
- F32 interp = time_interval / mTimeStep;
- mPoseBlender.interpolate(interp - mLastInterp);
- mLastInterp = interp;
- }
-
- updateLoadingMotions();
-
- return;
- }
-
- // is calculating a new keyframe pose, make sure the last one gets applied
- mPoseBlender.interpolate(1.f);
- clearBlenders();
-
- mTimeStepCount = quantum_count;
- mAnimTime = (F32)quantum_count * mTimeStep;
- mLastInterp = 0.f;
- }
- else
- {
- mAnimTime = update_time;
- }
- }
-
- updateLoadingMotions();
-
- resetJointSignatures();
-
- if (mPaused && !force_update)
- {
- updateIdleActiveMotions();
- }
- else
- {
- // update additive motions
- updateAdditiveMotions();
-
- resetJointSignatures();
-
- // update all regular motions
- updateRegularMotions();
-
- if (use_quantum)
- {
- mPoseBlender.blendAndCache(true);
- }
- else
- {
- mPoseBlender.blendAndApply();
- }
- }
-
- mHasRunOnce = true;
-// LL_INFOS() << "Motion controller time " << motionTimer.getElapsedTimeF32() << LL_ENDL;
-}
-
-//-----------------------------------------------------------------------------
-// updateMotionsMinimal()
-// minimal update (e.g. while hidden)
-//-----------------------------------------------------------------------------
-void LLMotionController::updateMotionsMinimal()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- // Always update mPrevTimerElapsed
- mPrevTimerElapsed = mTimer.getElapsedTimeF32();
-
- purgeExcessMotions();
- updateLoadingMotions();
- resetJointSignatures();
-
- deactivateStoppedMotions();
-
- mHasRunOnce = true;
-}
-
-//-----------------------------------------------------------------------------
-// activateMotionInstance()
-//-----------------------------------------------------------------------------
-bool LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- // It's not clear why the getWeight() line seems to be crashing this, but
- // hopefully this fixes it.
- if (motion == NULL || motion->getPose() == NULL)
- {
- return false;
- }
-
- if (mLoadingMotions.find(motion) != mLoadingMotions.end())
- {
- // we want to start this motion, but we can't yet, so flag it as started
- motion->setStopped(false);
- // report pending animations as activated
- return true;
- }
-
- motion->mResidualWeight = motion->getPose()->getWeight();
-
- // set stop time based on given duration and ease out time
- if (motion->getDuration() != 0.f && !motion->getLoop())
- {
- F32 ease_out_time;
- F32 motion_duration;
-
- // should we stop at the end of motion duration, or a bit earlier
- // to allow it to ease out while moving?
- ease_out_time = motion->getEaseOutDuration();
-
- // is the clock running when the motion is easing in?
- // if not (POSTURE_EASE) then we need to wait that much longer before triggering the stop
- motion_duration = llmax(motion->getDuration() - ease_out_time, 0.f);
- motion->mSendStopTimestamp = time + motion_duration;
- }
- else
- {
- motion->mSendStopTimestamp = F32_MAX;
- }
-
- if (motion->isActive())
- {
- mActiveMotions.remove(motion);
- }
- mActiveMotions.push_front(motion);
-
- motion->activate(time);
- motion->onUpdate(0.f, mJointSignature[1]);
-
- if (mAnimTime >= motion->mSendStopTimestamp)
- {
- motion->setStopTime(motion->mSendStopTimestamp);
- if (motion->mResidualWeight == 0.0f)
- {
- // bit of a hack; if newly activating a motion while easing out, weight should = 1
- motion->mResidualWeight = 1.f;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// deactivateMotionInstance()
-//-----------------------------------------------------------------------------
-bool LLMotionController::deactivateMotionInstance(LLMotion *motion)
-{
- motion->deactivate();
-
- motion_set_t::iterator found_it = mDeprecatedMotions.find(motion);
- if (found_it != mDeprecatedMotions.end())
- {
- // deprecated motions need to be completely excised
- removeMotionInstance(motion);
- mDeprecatedMotions.erase(found_it);
- }
- else
- {
- // for motions that we are keeping, simply remove from active queue
- mActiveMotions.remove(motion);
- }
-
- return true;
-}
-
-void LLMotionController::deprecateMotionInstance(LLMotion* motion)
-{
- mDeprecatedMotions.insert(motion);
-
- //fade out deprecated motion
- stopMotionInstance(motion, false);
- //no longer canonical
- mAllMotions.erase(motion->getID());
-}
-
-//-----------------------------------------------------------------------------
-// isMotionActive()
-//-----------------------------------------------------------------------------
-bool LLMotionController::isMotionActive(LLMotion *motion)
-{
- return (motion && motion->isActive());
-}
-
-//-----------------------------------------------------------------------------
-// isMotionLoading()
-//-----------------------------------------------------------------------------
-bool LLMotionController::isMotionLoading(LLMotion* motion)
-{
- return (mLoadingMotions.find(motion) != mLoadingMotions.end());
-}
-
-
-//-----------------------------------------------------------------------------
-// findMotion()
-//-----------------------------------------------------------------------------
-LLMotion* LLMotionController::findMotion(const LLUUID& id) const
-{
- motion_map_t::const_iterator iter = mAllMotions.find(id);
- if(iter == mAllMotions.end())
- {
- return NULL;
- }
- else
- {
- return iter->second;
- }
-}
-
-//-----------------------------------------------------------------------------
-// dumpMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::dumpMotions()
-{
- LL_INFOS() << "=====================================" << LL_ENDL;
- for (motion_map_t::value_type& motion_pair : mAllMotions)
- {
- LLUUID id = motion_pair.first;
- std::string state_string;
- LLMotion *motion = motion_pair.second;
- if (mLoadingMotions.find(motion) != mLoadingMotions.end())
- state_string += std::string("l");
- if (mLoadedMotions.find(motion) != mLoadedMotions.end())
- state_string += std::string("L");
- if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
- state_string += std::string("A");
- if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end())
- state_string += std::string("D");
- LL_INFOS() << gAnimLibrary.animationName(id) << " " << state_string << LL_ENDL;
-
- }
-}
-
-//-----------------------------------------------------------------------------
-// deactivateAllMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::deactivateAllMotions()
-{
- for (motion_map_t::value_type& motion_pair : mAllMotions)
- {
- LLMotion* motionp = motion_pair.second;
- deactivateMotionInstance(motionp);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// flushAllMotions()
-//-----------------------------------------------------------------------------
-void LLMotionController::flushAllMotions()
-{
- std::vector<std::pair<LLUUID,F32> > active_motions;
- active_motions.reserve(mActiveMotions.size());
- for (motion_list_t::iterator iter = mActiveMotions.begin();
- iter != mActiveMotions.end(); )
- {
- motion_list_t::iterator curiter = iter++;
- LLMotion* motionp = *curiter;
- F32 dtime = mAnimTime - motionp->mActivationTimestamp;
- active_motions.push_back(std::make_pair(motionp->getID(),dtime));
- motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it
- }
- mActiveMotions.clear();
-
- // delete all motion instances
- deleteAllMotions();
-
- // kill current hand pose that was previously called out by
- // keyframe motion
- mCharacter->removeAnimationData("Hand Pose");
-
- // restart motions
- for (std::vector<std::pair<LLUUID,F32> >::value_type& motion_pair : active_motions)
- {
- startMotion(motion_pair.first, motion_pair.second);
- }
-}
-
-//-----------------------------------------------------------------------------
-// pause()
-//-----------------------------------------------------------------------------
-void LLMotionController::pauseAllMotions()
-{
- if (!mPaused)
- {
- //LL_INFOS() << "Pausing animations..." << LL_ENDL;
- mPaused = true;
- mPausedFrame = LLFrameTimer::getFrameCount();
- }
-
-}
-
-//-----------------------------------------------------------------------------
-// unpause()
-//-----------------------------------------------------------------------------
-void LLMotionController::unpauseAllMotions()
-{
- if (mPaused)
- {
- //LL_INFOS() << "Unpausing animations..." << LL_ENDL;
- mPaused = false;
- }
-}
-// End
+/** + * @file llmotioncontroller.cpp + * @brief Implementation of LLMotionController class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llmotioncontroller.h" +#include "llfasttimer.h" +#include "llkeyframemotion.h" +#include "llmath.h" +#include "lltimer.h" +#include "llanimationstates.h" +#include "llstl.h" + +// This is why LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be a multiple of 4. +const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4; +const U32 MAX_MOTION_INSTANCES = 32; + +//----------------------------------------------------------------------------- +// Constants and statics +//----------------------------------------------------------------------------- +F32 LLMotionController::sCurrentTimeFactor = 1.f; +LLMotionRegistry LLMotionController::sRegistry; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLMotionRegistry class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLMotionRegistry() +// Class Constructor +//----------------------------------------------------------------------------- +LLMotionRegistry::LLMotionRegistry() +{ + +} + + +//----------------------------------------------------------------------------- +// ~LLMotionRegistry() +// Class Destructor +//----------------------------------------------------------------------------- +LLMotionRegistry::~LLMotionRegistry() +{ + mMotionTable.clear(); +} + + +//----------------------------------------------------------------------------- +// addMotion() +//----------------------------------------------------------------------------- +bool LLMotionRegistry::registerMotion( const LLUUID& id, LLMotionConstructor constructor ) +{ + // LL_INFOS() << "Registering motion: " << name << LL_ENDL; + if (!is_in_map(mMotionTable, id)) + { + mMotionTable[id] = constructor; + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// markBad() +//----------------------------------------------------------------------------- +void LLMotionRegistry::markBad( const LLUUID& id ) +{ + mMotionTable[id] = LLMotionConstructor(NULL); +} + +//----------------------------------------------------------------------------- +// createMotion() +//----------------------------------------------------------------------------- +LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) +{ + LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL)); + LLMotion* motion = NULL; + + if ( constructor == NULL ) + { + // *FIX: need to replace with a better default scheme. RN + motion = LLKeyframeMotion::create(id); + } + else + { + motion = constructor(id); + } + + return motion; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLMotionController class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLMotionController() +// Class Constructor +//----------------------------------------------------------------------------- +LLMotionController::LLMotionController() + : mTimeFactor(sCurrentTimeFactor), + mCharacter(NULL), + mAnimTime(0.f), + mPrevTimerElapsed(0.f), + mLastTime(0.0f), + mHasRunOnce(false), + mPaused(false), + mPausedFrame(0), + mTimeStep(0.f), + mTimeStepCount(0), + mLastInterp(0.f), + mIsSelf(false), + mLastCountAfterPurge(0) +{ +} + + +//----------------------------------------------------------------------------- +// ~LLMotionController() +// Class Destructor +//----------------------------------------------------------------------------- +LLMotionController::~LLMotionController() +{ + deleteAllMotions(); +} + +void LLMotionController::incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions) +{ + num_motions += mAllMotions.size(); + num_loading_motions += mLoadingMotions.size(); + num_loaded_motions += mLoadedMotions.size(); + num_active_motions += mActiveMotions.size(); + num_deprecated_motions += mDeprecatedMotions.size(); +} + +//----------------------------------------------------------------------------- +// deleteAllMotions() +//----------------------------------------------------------------------------- +void LLMotionController::deleteAllMotions() +{ + mLoadingMotions.clear(); + mLoadedMotions.clear(); + mActiveMotions.clear(); + + for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer()); + mAllMotions.clear(); + + // stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from + // mAllMotions to mDeprecatedMotions in method + // LLMotionController::deprecateMotionInstance(). Thus, we should also clean + // up the mDeprecatedMotions list as well. + for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); + mDeprecatedMotions.clear(); +} + +//----------------------------------------------------------------------------- +// purgeExcessMotion() +//----------------------------------------------------------------------------- +void LLMotionController::purgeExcessMotions() +{ + if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) + { + // clean up deprecated motions + for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin(); + deprecated_motion_it != mDeprecatedMotions.end(); ) + { + motion_set_t::iterator cur_iter = deprecated_motion_it++; + LLMotion* cur_motionp = *cur_iter; + if (!isMotionActive(cur_motionp)) + { + // Motion is deprecated so we know it's not cannonical, + // we can safely remove the instance + removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions + mDeprecatedMotions.erase(cur_iter); + } + } + } + + std::set<LLUUID> motions_to_kill; + if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) + { + // too many motions active this frame, kill all blenders + mPoseBlender.clearBlenders(); + for (LLMotion* cur_motionp : mLoadedMotions) + { + // motion isn't playing, delete it + if (!isMotionActive(cur_motionp)) + { + motions_to_kill.insert(cur_motionp->getID()); + } + } + } + + // clean up all inactive, loaded motions + for (LLUUID motion_id : motions_to_kill) + { + // look up the motion again by ID to get canonical instance + // and kill it only if that one is inactive + LLMotion* motionp = findMotion(motion_id); + if (motionp && !isMotionActive(motionp)) + { + removeMotion(motion_id); + } + } + + U32 loaded_count = mLoadedMotions.size(); + if (loaded_count > (2 * MAX_MOTION_INSTANCES) && loaded_count > mLastCountAfterPurge) + { + LL_WARNS_ONCE("Animation") << loaded_count << " Loaded Motions. Amount of motions is over limit." << LL_ENDL; + } + mLastCountAfterPurge = loaded_count; +} + +//----------------------------------------------------------------------------- +// deactivateStoppedMotions() +//----------------------------------------------------------------------------- +void LLMotionController::deactivateStoppedMotions() +{ + // Since we're hidden, deactivate any stopped motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); + iter != mActiveMotions.end(); ) + { + motion_list_t::iterator curiter = iter++; + LLMotion* motionp = *curiter; + if (motionp->isStopped()) + { + deactivateMotionInstance(motionp); + } + } +} + +//----------------------------------------------------------------------------- +// setTimeStep() +//----------------------------------------------------------------------------- +void LLMotionController::setTimeStep(F32 step) +{ + mTimeStep = step; + + if (step != 0.f) + { + // make sure timestamps conform to new quantum + for (motion_list_t::iterator iter = mActiveMotions.begin(); + iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + F32 activation_time = motionp->mActivationTimestamp; + motionp->mActivationTimestamp = (F32)(llfloor(activation_time / step)) * step; + bool stopped = motionp->isStopped(); + motionp->setStopTime((F32)(llfloor(motionp->getStopTime() / step)) * step); + motionp->setStopped(stopped); + motionp->mSendStopTimestamp = (F32)llfloor(motionp->mSendStopTimestamp / step) * step; + } + } +} + +//----------------------------------------------------------------------------- +// setTimeFactor() +//----------------------------------------------------------------------------- +void LLMotionController::setTimeFactor(F32 time_factor) +{ + mTimeFactor = time_factor; +} + +//----------------------------------------------------------------------------- +// setCharacter() +//----------------------------------------------------------------------------- +void LLMotionController::setCharacter(LLCharacter *character) +{ + mCharacter = character; +} + + +//----------------------------------------------------------------------------- +// registerMotion() +//----------------------------------------------------------------------------- +bool LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor constructor ) +{ + return sRegistry.registerMotion(id, constructor); +} + +//----------------------------------------------------------------------------- +// removeMotion() +//----------------------------------------------------------------------------- +void LLMotionController::removeMotion( const LLUUID& id) +{ + LLMotion* motionp = findMotion(id); + mAllMotions.erase(id); + removeMotionInstance(motionp); +} + +// removes instance of a motion from all runtime structures, but does +// not erase entry by ID, as this could be a duplicate instance +// use removeMotion(id) to remove all references to a given motion by id. +void LLMotionController::removeMotionInstance(LLMotion* motionp) +{ + if (motionp) + { + llassert(findMotion(motionp->getID()) != motionp); + if (motionp->isActive()) + motionp->deactivate(); + mLoadingMotions.erase(motionp); + mLoadedMotions.erase(motionp); + mActiveMotions.remove(motionp); + delete motionp; + } +} + +//----------------------------------------------------------------------------- +// createMotion() +//----------------------------------------------------------------------------- +LLMotion* LLMotionController::createMotion( const LLUUID &id ) +{ + // do we have an instance of this motion for this character? + LLMotion *motion = findMotion(id); + + // if not, we need to create one + if (!motion) + { + // look up constructor and create it + motion = sRegistry.createMotion(id); + if (!motion) + { + return NULL; + } + + // look up name for default motions + const char* motion_name = gAnimLibrary.animStateToString(id); + if (motion_name) + { + motion->setName(motion_name); + } + + // initialize the new instance + LLMotion::LLMotionInitStatus stat = motion->onInitialize(mCharacter); + switch(stat) + { + case LLMotion::STATUS_FAILURE: + LL_INFOS() << "Motion " << id << " init failed." << LL_ENDL; + sRegistry.markBad(id); + delete motion; + return NULL; + case LLMotion::STATUS_HOLD: + mLoadingMotions.insert(motion); + break; + case LLMotion::STATUS_SUCCESS: + // add motion to our list + mLoadedMotions.insert(motion); + break; + default: + LL_ERRS() << "Invalid initialization status" << LL_ENDL; + break; + } + + mAllMotions[id] = motion; + } + return motion; +} + +//----------------------------------------------------------------------------- +// startMotion() +//----------------------------------------------------------------------------- +bool LLMotionController::startMotion(const LLUUID &id, F32 start_offset) +{ + // do we have an instance of this motion for this character? + LLMotion *motion = findMotion(id); + + // motion that is stopping will be allowed to stop but + // replaced by a new instance of that motion + if (motion + && !mPaused + && motion->canDeprecate() + && motion->getFadeWeight() > 0.01f // not LOD-ed out + && (motion->isBlending() || motion->getStopTime() != 0.f)) + { + deprecateMotionInstance(motion); + // force creation of new instance + motion = NULL; + } + + // create new motion instance + if (!motion) + { + motion = createMotion(id); + } + + if (!motion) + { + return false; + } + //if the motion is already active and allows deprecation, then let it keep playing + else if (motion->canDeprecate() && isMotionActive(motion)) + { + return true; + } + +// LL_INFOS() << "Starting motion " << name << LL_ENDL; + return activateMotionInstance(motion, mAnimTime - start_offset); +} + + +//----------------------------------------------------------------------------- +// stopMotionLocally() +//----------------------------------------------------------------------------- +bool LLMotionController::stopMotionLocally(const LLUUID &id, bool stop_immediate) +{ + // if already inactive, return false + LLMotion *motion = findMotion(id); + // SL-1290: always stop immediate if paused + return stopMotionInstance(motion, stop_immediate||mPaused); +} + +bool LLMotionController::stopMotionInstance(LLMotion* motion, bool stop_immediate) +{ + if (!motion) + { + return false; + } + + + // If on active list, stop it + if (isMotionActive(motion) && !motion->isStopped()) + { + motion->setStopTime(mAnimTime); + if (stop_immediate) + { + deactivateMotionInstance(motion); + } + return true; + } + else if (isMotionLoading(motion)) + { + motion->setStopped(true); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// updateRegularMotions() +//----------------------------------------------------------------------------- +void LLMotionController::updateRegularMotions() +{ + updateMotionsByType(LLMotion::NORMAL_BLEND); +} + +//----------------------------------------------------------------------------- +// updateAdditiveMotions() +//----------------------------------------------------------------------------- +void LLMotionController::updateAdditiveMotions() +{ + updateMotionsByType(LLMotion::ADDITIVE_BLEND); +} + +//----------------------------------------------------------------------------- +// resetJointSignatures() +//----------------------------------------------------------------------------- +void LLMotionController::resetJointSignatures() +{ + memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); + memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); +} + +//----------------------------------------------------------------------------- +// updateIdleMotion() +// minimal updates for active motions +//----------------------------------------------------------------------------- +void LLMotionController::updateIdleMotion(LLMotion* motionp) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration()) + { + deactivateMotionInstance(motionp); + } + else if (motionp->isStopped() && mAnimTime > motionp->getStopTime()) + { + // is this the first iteration in the ease out phase? + if (mLastTime <= motionp->getStopTime()) + { + // store residual weight for this motion + motionp->mResidualWeight = motionp->getPose()->getWeight(); + } + } + else if (mAnimTime > motionp->mSendStopTimestamp) + { + // notify character of timed stop event on first iteration past sendstoptimestamp + // this will only be called when an animation stops itself (runs out of time) + if (mLastTime <= motionp->mSendStopTimestamp) + { + mCharacter->requestStopMotion( motionp ); + stopMotionInstance(motionp, false); + } + } + else if (mAnimTime >= motionp->mActivationTimestamp) + { + if (mLastTime < motionp->mActivationTimestamp) + { + motionp->mResidualWeight = motionp->getPose()->getWeight(); + } + } +} + +//----------------------------------------------------------------------------- +// updateIdleActiveMotions() +// Call this instead of updateMotionsByType for hidden avatars +//----------------------------------------------------------------------------- +void LLMotionController::updateIdleActiveMotions() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + for (motion_list_t::iterator iter = mActiveMotions.begin(); + iter != mActiveMotions.end(); ) + { + motion_list_t::iterator curiter = iter++; + LLMotion* motionp = *curiter; + updateIdleMotion(motionp); + } +} + +//----------------------------------------------------------------------------- +// updateMotionsByType() +//----------------------------------------------------------------------------- +void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + bool update_result = true; + U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS]; + + memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); + + // iterate through active motions in chronological order + for (motion_list_t::iterator iter = mActiveMotions.begin(); + iter != mActiveMotions.end(); ) + { + motion_list_t::iterator curiter = iter++; + LLMotion* motionp = *curiter; + if (motionp->getBlendType() != anim_type) + { + continue; + } + + bool update_motion = false; + + if (motionp->getPose()->getWeight() < 1.f) + { + update_motion = true; + } + else + { + for (S32 i = 0; i < NUM_JOINT_SIGNATURE_STRIDES; i++) + { + U32 *current_signature = (U32*)&(mJointSignature[0][i * 4]); + U32 test_signature = *(U32*)&(motionp->mJointSignature[0][i * 4]); + + if ((*current_signature | test_signature) > (*current_signature)) + { + *current_signature |= test_signature; + update_motion = true; + } + + *((U32*)&last_joint_signature[i * 4]) = *(U32*)&(mJointSignature[1][i * 4]); + current_signature = (U32*)&(mJointSignature[1][i * 4]); + test_signature = *(U32*)&(motionp->mJointSignature[1][i * 4]); + + if ((*current_signature | test_signature) > (*current_signature)) + { + *current_signature |= test_signature; + update_motion = true; + } + } + } + + if (!update_motion) + { + updateIdleMotion(motionp); + continue; + } + + LLPose *posep = motionp->getPose(); + + // only filter by LOD after running every animation at least once (to prime the avatar state) + if (mHasRunOnce && motionp->getMinPixelArea() > mCharacter->getPixelArea()) + { + motionp->fadeOut(); + + //should we notify the simulator that this motion should be stopped (check even if skipped by LOD logic) + if (mAnimTime > motionp->mSendStopTimestamp) + { + // notify character of timed stop event on first iteration past sendstoptimestamp + // this will only be called when an animation stops itself (runs out of time) + if (mLastTime <= motionp->mSendStopTimestamp) + { + mCharacter->requestStopMotion( motionp ); + stopMotionInstance(motionp, false); + } + } + + if (motionp->getFadeWeight() < 0.01f) + { + if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration()) + { + posep->setWeight(0.f); + deactivateMotionInstance(motionp); + } + continue; + } + } + else + { + motionp->fadeIn(); + } + + //********************** + // MOTION INACTIVE + //********************** + if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration()) + { + // this motion has gone on too long, deactivate it + // did we have a chance to stop it? + if (mLastTime <= motionp->getStopTime()) + { + // if not, let's stop it this time through and deactivate it the next + + posep->setWeight(motionp->getFadeWeight()); + motionp->onUpdate(motionp->getStopTime() - motionp->mActivationTimestamp, last_joint_signature); + } + else + { + posep->setWeight(0.f); + deactivateMotionInstance(motionp); + continue; + } + } + + //********************** + // MOTION EASE OUT + //********************** + else if (motionp->isStopped() && mAnimTime > motionp->getStopTime()) + { + // is this the first iteration in the ease out phase? + if (mLastTime <= motionp->getStopTime()) + { + // store residual weight for this motion + motionp->mResidualWeight = motionp->getPose()->getWeight(); + } + + if (motionp->getEaseOutDuration() == 0.f) + { + posep->setWeight(0.f); + } + else + { + posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight * cubic_step(1.f - ((mAnimTime - motionp->getStopTime()) / motionp->getEaseOutDuration()))); + } + + // perform motion update + update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); + } + + //********************** + // MOTION ACTIVE + //********************** + else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration()) + { + posep->setWeight(motionp->getFadeWeight()); + + //should we notify the simulator that this motion should be stopped? + if (mAnimTime > motionp->mSendStopTimestamp) + { + // notify character of timed stop event on first iteration past sendstoptimestamp + // this will only be called when an animation stops itself (runs out of time) + if (mLastTime <= motionp->mSendStopTimestamp) + { + mCharacter->requestStopMotion( motionp ); + stopMotionInstance(motionp, false); + } + } + + // perform motion update + { + update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); + } + } + + //********************** + // MOTION EASE IN + //********************** + else if (mAnimTime >= motionp->mActivationTimestamp) + { + if (mLastTime < motionp->mActivationTimestamp) + { + motionp->mResidualWeight = motionp->getPose()->getWeight(); + } + if (motionp->getEaseInDuration() == 0.f) + { + posep->setWeight(motionp->getFadeWeight()); + } + else + { + // perform motion update + posep->setWeight(motionp->getFadeWeight() * motionp->mResidualWeight + (1.f - motionp->mResidualWeight) * cubic_step((mAnimTime - motionp->mActivationTimestamp) / motionp->getEaseInDuration())); + } + // perform motion update + update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); + } + else + { + posep->setWeight(0.f); + update_result = motionp->onUpdate(0.f, last_joint_signature); + } + + // allow motions to deactivate themselves + if (!update_result) + { + if (!motionp->isStopped() || motionp->getStopTime() > mAnimTime) + { + // animation has stopped itself due to internal logic + // propagate this to the network + // as not all viewers are guaranteed to have access to the same logic + mCharacter->requestStopMotion( motionp ); + stopMotionInstance(motionp, false); + } + + } + + // even if onupdate returns false, add this motion in to the blend one last time + mPoseBlender.addMotion(motionp); + } +} + +//----------------------------------------------------------------------------- +// updateLoadingMotions() +//----------------------------------------------------------------------------- +void LLMotionController::updateLoadingMotions() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + // query pending motions for completion + for (motion_set_t::iterator iter = mLoadingMotions.begin(); + iter != mLoadingMotions.end(); ) + { + motion_set_t::iterator curiter = iter++; + LLMotion* motionp = *curiter; + if( !motionp) + { + continue; // maybe shouldn't happen but i've seen it -MG + } + LLMotion::LLMotionInitStatus status = motionp->onInitialize(mCharacter); + if (status == LLMotion::STATUS_SUCCESS) + { + mLoadingMotions.erase(curiter); + // add motion to our loaded motion list + mLoadedMotions.insert(motionp); + // this motion should be playing + if (!motionp->isStopped()) + { + activateMotionInstance(motionp, mAnimTime); + } + } + else if (status == LLMotion::STATUS_FAILURE) + { + LL_INFOS() << "Motion " << motionp->getID() << " init failed." << LL_ENDL; + sRegistry.markBad(motionp->getID()); + mLoadingMotions.erase(curiter); + motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp); + if (found_it != mDeprecatedMotions.end()) + { + mDeprecatedMotions.erase(found_it); + } + mAllMotions.erase(motionp->getID()); + delete motionp; + } + } +} + +//----------------------------------------------------------------------------- +// call updateMotion() or updateMotionsMinimal() every frame +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// updateMotion() +//----------------------------------------------------------------------------- +void LLMotionController::updateMotions(bool force_update) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + // SL-763: "Distant animated objects run at super fast speed" + // The use_quantum optimization or possibly the associated code in setTimeStamp() + // does not work as implemented. + // Currently setting mTimeStep to nonzero is disabled elsewhere. + bool use_quantum = (mTimeStep != 0.f); + + // Always update mPrevTimerElapsed + F32 cur_time = mTimer.getElapsedTimeF32(); + F32 delta_time = cur_time - mPrevTimerElapsed; + mPrevTimerElapsed = cur_time; + mLastTime = mAnimTime; + + // Always cap the number of loaded motions + purgeExcessMotions(); + + // Update timing info for this time step. + if (!mPaused) + { + F32 update_time = mAnimTime + delta_time * mTimeFactor; + if (use_quantum) + { + F32 time_interval = fmodf(update_time, mTimeStep); + + // always animate *ahead* of actual time + S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1; + if (quantum_count == mTimeStepCount) + { + // we're still in same time quantum as before, so just interpolate and exit + if (!mPaused) + { + F32 interp = time_interval / mTimeStep; + mPoseBlender.interpolate(interp - mLastInterp); + mLastInterp = interp; + } + + updateLoadingMotions(); + + return; + } + + // is calculating a new keyframe pose, make sure the last one gets applied + mPoseBlender.interpolate(1.f); + clearBlenders(); + + mTimeStepCount = quantum_count; + mAnimTime = (F32)quantum_count * mTimeStep; + mLastInterp = 0.f; + } + else + { + mAnimTime = update_time; + } + } + + updateLoadingMotions(); + + resetJointSignatures(); + + if (mPaused && !force_update) + { + updateIdleActiveMotions(); + } + else + { + // update additive motions + updateAdditiveMotions(); + + resetJointSignatures(); + + // update all regular motions + updateRegularMotions(); + + if (use_quantum) + { + mPoseBlender.blendAndCache(true); + } + else + { + mPoseBlender.blendAndApply(); + } + } + + mHasRunOnce = true; +// LL_INFOS() << "Motion controller time " << motionTimer.getElapsedTimeF32() << LL_ENDL; +} + +//----------------------------------------------------------------------------- +// updateMotionsMinimal() +// minimal update (e.g. while hidden) +//----------------------------------------------------------------------------- +void LLMotionController::updateMotionsMinimal() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + // Always update mPrevTimerElapsed + mPrevTimerElapsed = mTimer.getElapsedTimeF32(); + + purgeExcessMotions(); + updateLoadingMotions(); + resetJointSignatures(); + + deactivateStoppedMotions(); + + mHasRunOnce = true; +} + +//----------------------------------------------------------------------------- +// activateMotionInstance() +//----------------------------------------------------------------------------- +bool LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + // It's not clear why the getWeight() line seems to be crashing this, but + // hopefully this fixes it. + if (motion == NULL || motion->getPose() == NULL) + { + return false; + } + + if (mLoadingMotions.find(motion) != mLoadingMotions.end()) + { + // we want to start this motion, but we can't yet, so flag it as started + motion->setStopped(false); + // report pending animations as activated + return true; + } + + motion->mResidualWeight = motion->getPose()->getWeight(); + + // set stop time based on given duration and ease out time + if (motion->getDuration() != 0.f && !motion->getLoop()) + { + F32 ease_out_time; + F32 motion_duration; + + // should we stop at the end of motion duration, or a bit earlier + // to allow it to ease out while moving? + ease_out_time = motion->getEaseOutDuration(); + + // is the clock running when the motion is easing in? + // if not (POSTURE_EASE) then we need to wait that much longer before triggering the stop + motion_duration = llmax(motion->getDuration() - ease_out_time, 0.f); + motion->mSendStopTimestamp = time + motion_duration; + } + else + { + motion->mSendStopTimestamp = F32_MAX; + } + + if (motion->isActive()) + { + mActiveMotions.remove(motion); + } + mActiveMotions.push_front(motion); + + motion->activate(time); + motion->onUpdate(0.f, mJointSignature[1]); + + if (mAnimTime >= motion->mSendStopTimestamp) + { + motion->setStopTime(motion->mSendStopTimestamp); + if (motion->mResidualWeight == 0.0f) + { + // bit of a hack; if newly activating a motion while easing out, weight should = 1 + motion->mResidualWeight = 1.f; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// deactivateMotionInstance() +//----------------------------------------------------------------------------- +bool LLMotionController::deactivateMotionInstance(LLMotion *motion) +{ + motion->deactivate(); + + motion_set_t::iterator found_it = mDeprecatedMotions.find(motion); + if (found_it != mDeprecatedMotions.end()) + { + // deprecated motions need to be completely excised + removeMotionInstance(motion); + mDeprecatedMotions.erase(found_it); + } + else + { + // for motions that we are keeping, simply remove from active queue + mActiveMotions.remove(motion); + } + + return true; +} + +void LLMotionController::deprecateMotionInstance(LLMotion* motion) +{ + mDeprecatedMotions.insert(motion); + + //fade out deprecated motion + stopMotionInstance(motion, false); + //no longer canonical + mAllMotions.erase(motion->getID()); +} + +//----------------------------------------------------------------------------- +// isMotionActive() +//----------------------------------------------------------------------------- +bool LLMotionController::isMotionActive(LLMotion *motion) +{ + return (motion && motion->isActive()); +} + +//----------------------------------------------------------------------------- +// isMotionLoading() +//----------------------------------------------------------------------------- +bool LLMotionController::isMotionLoading(LLMotion* motion) +{ + return (mLoadingMotions.find(motion) != mLoadingMotions.end()); +} + + +//----------------------------------------------------------------------------- +// findMotion() +//----------------------------------------------------------------------------- +LLMotion* LLMotionController::findMotion(const LLUUID& id) const +{ + motion_map_t::const_iterator iter = mAllMotions.find(id); + if(iter == mAllMotions.end()) + { + return NULL; + } + else + { + return iter->second; + } +} + +//----------------------------------------------------------------------------- +// dumpMotions() +//----------------------------------------------------------------------------- +void LLMotionController::dumpMotions() +{ + LL_INFOS() << "=====================================" << LL_ENDL; + for (motion_map_t::value_type& motion_pair : mAllMotions) + { + LLUUID id = motion_pair.first; + std::string state_string; + LLMotion *motion = motion_pair.second; + if (mLoadingMotions.find(motion) != mLoadingMotions.end()) + state_string += std::string("l"); + if (mLoadedMotions.find(motion) != mLoadedMotions.end()) + state_string += std::string("L"); + if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end()) + state_string += std::string("A"); + if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end()) + state_string += std::string("D"); + LL_INFOS() << gAnimLibrary.animationName(id) << " " << state_string << LL_ENDL; + + } +} + +//----------------------------------------------------------------------------- +// deactivateAllMotions() +//----------------------------------------------------------------------------- +void LLMotionController::deactivateAllMotions() +{ + for (motion_map_t::value_type& motion_pair : mAllMotions) + { + LLMotion* motionp = motion_pair.second; + deactivateMotionInstance(motionp); + } +} + + +//----------------------------------------------------------------------------- +// flushAllMotions() +//----------------------------------------------------------------------------- +void LLMotionController::flushAllMotions() +{ + std::vector<std::pair<LLUUID,F32> > active_motions; + active_motions.reserve(mActiveMotions.size()); + for (motion_list_t::iterator iter = mActiveMotions.begin(); + iter != mActiveMotions.end(); ) + { + motion_list_t::iterator curiter = iter++; + LLMotion* motionp = *curiter; + F32 dtime = mAnimTime - motionp->mActivationTimestamp; + active_motions.push_back(std::make_pair(motionp->getID(),dtime)); + motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it + } + mActiveMotions.clear(); + + // delete all motion instances + deleteAllMotions(); + + // kill current hand pose that was previously called out by + // keyframe motion + mCharacter->removeAnimationData("Hand Pose"); + + // restart motions + for (std::vector<std::pair<LLUUID,F32> >::value_type& motion_pair : active_motions) + { + startMotion(motion_pair.first, motion_pair.second); + } +} + +//----------------------------------------------------------------------------- +// pause() +//----------------------------------------------------------------------------- +void LLMotionController::pauseAllMotions() +{ + if (!mPaused) + { + //LL_INFOS() << "Pausing animations..." << LL_ENDL; + mPaused = true; + mPausedFrame = LLFrameTimer::getFrameCount(); + } + +} + +//----------------------------------------------------------------------------- +// unpause() +//----------------------------------------------------------------------------- +void LLMotionController::unpauseAllMotions() +{ + if (mPaused) + { + //LL_INFOS() << "Unpausing animations..." << LL_ENDL; + mPaused = false; + } +} +// End diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 422a038da7..0c262bf24a 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -1,241 +1,241 @@ -/**
- * @file llmotioncontroller.h
- * @brief Implementation of LLMotionController class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMOTIONCONTROLLER_H
-#define LL_LLMOTIONCONTROLLER_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include <string>
-#include <map>
-#include <deque>
-
-#include "llmotion.h"
-#include "llpose.h"
-#include "llframetimer.h"
-#include "llstatemachine.h"
-#include "llstring.h"
-
-//-----------------------------------------------------------------------------
-// Class predeclaration
-// This is necessary because llcharacter.h includes this file.
-//-----------------------------------------------------------------------------
-class LLCharacter;
-
-//-----------------------------------------------------------------------------
-// LLMotionRegistry
-//-----------------------------------------------------------------------------
-typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id);
-
-class LLMotionRegistry
-{
-public:
- // Constructor
- LLMotionRegistry();
-
- // Destructor
- ~LLMotionRegistry();
-
- // adds motion classes to the registry
- // returns true if successfull
- bool registerMotion( const LLUUID& id, LLMotionConstructor create);
-
- // creates a new instance of a named motion
- // returns NULL motion is not registered
- LLMotion *createMotion( const LLUUID &id );
-
- // initialization of motion failed, don't try to create this motion again
- void markBad( const LLUUID& id );
-
-
-protected:
- typedef std::map<LLUUID, LLMotionConstructor> motion_map_t;
- motion_map_t mMotionTable;
-};
-
-//-----------------------------------------------------------------------------
-// class LLMotionController
-//-----------------------------------------------------------------------------
-class LLMotionController
-{
-public:
- typedef std::list<LLMotion*> motion_list_t;
- typedef std::set<LLMotion*> motion_set_t;
- bool mIsSelf;
-
-public:
- // Constructor
- LLMotionController();
-
- // Destructor
- virtual ~LLMotionController();
-
- // set associated character
- // this must be called exactly once by the containing character class.
- // this is generally done in the Character constructor
- void setCharacter( LLCharacter *character );
-
- // registers a motion with the controller
- // (actually just forwards call to motion registry)
- // returns true if successfull
- bool registerMotion( const LLUUID& id, LLMotionConstructor create );
-
- // creates a motion from the registry
- LLMotion *createMotion( const LLUUID &id );
-
- // unregisters a motion with the controller
- // (actually just forwards call to motion registry)
- // returns true if successfull
- void removeMotion( const LLUUID& id );
-
- // start motion
- // begins playing the specified motion
- // returns true if successful
- bool startMotion( const LLUUID &id, F32 start_offset );
-
- // stop motion
- // stops a playing motion
- // in reality, it begins the ease out transition phase
- // returns true if successful
- bool stopMotionLocally( const LLUUID &id, bool stop_immediate );
-
- // Move motions from loading to loaded
- void updateLoadingMotions();
-
- // update motions
- // invokes the update handlers for each active motion
- // activates sequenced motions
- // deactivates terminated motions`
- void updateMotions(bool force_update = false);
-
- // minimal update (e.g. while hidden)
- void updateMotionsMinimal();
-
- void clearBlenders() { mPoseBlender.clearBlenders(); }
-
- // flush motions
- // releases all motion instances
- void flushAllMotions();
-
- //Flush is a liar.
- void deactivateAllMotions();
-
- // pause and continue all motions
- void pauseAllMotions();
- void unpauseAllMotions();
- bool isPaused() const { return mPaused; }
- S32 getPausedFrame() const { return mPausedFrame; }
-
- void setTimeStep(F32 step);
- F32 getTimeStep() const { return mTimeStep; }
-
- void setTimeFactor(F32 time_factor);
- F32 getTimeFactor() const { return mTimeFactor; }
-
- F32 getAnimTime() const { return mAnimTime; }
-
- motion_list_t& getActiveMotions() { return mActiveMotions; }
-
- void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions);
-
-//protected:
- bool isMotionActive( LLMotion *motion );
- bool isMotionLoading( LLMotion *motion );
- LLMotion *findMotion( const LLUUID& id ) const;
-
- void dumpMotions();
-
- const LLFrameTimer& getFrameTimer() { return mTimer; }
-
- static F32 getCurrentTimeFactor() { return sCurrentTimeFactor; };
- static void setCurrentTimeFactor(F32 factor) { sCurrentTimeFactor = factor; };
-
-protected:
- // internal operations act on motion instances directly
- // as there can be duplicate motions per id during blending overlap
- void deleteAllMotions();
- bool activateMotionInstance(LLMotion *motion, F32 time);
- bool deactivateMotionInstance(LLMotion *motion);
- void deprecateMotionInstance(LLMotion* motion);
- bool stopMotionInstance(LLMotion *motion, bool stop_imemdiate);
- void removeMotionInstance(LLMotion* motion);
- void updateRegularMotions();
- void updateAdditiveMotions();
- void resetJointSignatures();
- void updateMotionsByType(LLMotion::LLMotionBlendType motion_type);
- void updateIdleMotion(LLMotion* motionp);
- void updateIdleActiveMotions();
- void purgeExcessMotions();
- void deactivateStoppedMotions();
-
-protected:
- F32 mTimeFactor; // 1.f for normal speed
- static F32 sCurrentTimeFactor; // Value to use for initialization
- static LLMotionRegistry sRegistry;
- LLPoseBlender mPoseBlender;
-
- LLCharacter *mCharacter;
-
-// Life cycle of an animation:
-//
-// Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime.
-// If the animations depend on any asset data, the appropriate data is fetched from the data server,
-// and the animation is put on the mLoadingMotions list.
-// Once an animations is loaded, it will be initialized and put on the mLoadedMotions list.
-// Any animation that is currently playing also sits in the mActiveMotions list.
-
- typedef std::map<LLUUID, LLMotion*> motion_map_t;
- motion_map_t mAllMotions;
-
- motion_set_t mLoadingMotions;
- motion_set_t mLoadedMotions;
- motion_list_t mActiveMotions;
- motion_set_t mDeprecatedMotions;
-
- LLFrameTimer mTimer;
- F32 mPrevTimerElapsed;
- F32 mAnimTime;
- F32 mLastTime;
- bool mHasRunOnce;
- bool mPaused;
- S32 mPausedFrame;
- F32 mTimeStep;
- S32 mTimeStepCount;
- F32 mLastInterp;
-
- U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS];
-private:
- U32 mLastCountAfterPurge; //for logging and debugging purposes
-};
-
-//-----------------------------------------------------------------------------
-// Class declaractions
-//-----------------------------------------------------------------------------
-#include "llcharacter.h"
-
-#endif // LL_LLMOTIONCONTROLLER_H
-
+/** + * @file llmotioncontroller.h + * @brief Implementation of LLMotionController class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMOTIONCONTROLLER_H +#define LL_LLMOTIONCONTROLLER_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include <string> +#include <map> +#include <deque> + +#include "llmotion.h" +#include "llpose.h" +#include "llframetimer.h" +#include "llstatemachine.h" +#include "llstring.h" + +//----------------------------------------------------------------------------- +// Class predeclaration +// This is necessary because llcharacter.h includes this file. +//----------------------------------------------------------------------------- +class LLCharacter; + +//----------------------------------------------------------------------------- +// LLMotionRegistry +//----------------------------------------------------------------------------- +typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id); + +class LLMotionRegistry +{ +public: + // Constructor + LLMotionRegistry(); + + // Destructor + ~LLMotionRegistry(); + + // adds motion classes to the registry + // returns true if successfull + bool registerMotion( const LLUUID& id, LLMotionConstructor create); + + // creates a new instance of a named motion + // returns NULL motion is not registered + LLMotion *createMotion( const LLUUID &id ); + + // initialization of motion failed, don't try to create this motion again + void markBad( const LLUUID& id ); + + +protected: + typedef std::map<LLUUID, LLMotionConstructor> motion_map_t; + motion_map_t mMotionTable; +}; + +//----------------------------------------------------------------------------- +// class LLMotionController +//----------------------------------------------------------------------------- +class LLMotionController +{ +public: + typedef std::list<LLMotion*> motion_list_t; + typedef std::set<LLMotion*> motion_set_t; + bool mIsSelf; + +public: + // Constructor + LLMotionController(); + + // Destructor + virtual ~LLMotionController(); + + // set associated character + // this must be called exactly once by the containing character class. + // this is generally done in the Character constructor + void setCharacter( LLCharacter *character ); + + // registers a motion with the controller + // (actually just forwards call to motion registry) + // returns true if successfull + bool registerMotion( const LLUUID& id, LLMotionConstructor create ); + + // creates a motion from the registry + LLMotion *createMotion( const LLUUID &id ); + + // unregisters a motion with the controller + // (actually just forwards call to motion registry) + // returns true if successfull + void removeMotion( const LLUUID& id ); + + // start motion + // begins playing the specified motion + // returns true if successful + bool startMotion( const LLUUID &id, F32 start_offset ); + + // stop motion + // stops a playing motion + // in reality, it begins the ease out transition phase + // returns true if successful + bool stopMotionLocally( const LLUUID &id, bool stop_immediate ); + + // Move motions from loading to loaded + void updateLoadingMotions(); + + // update motions + // invokes the update handlers for each active motion + // activates sequenced motions + // deactivates terminated motions` + void updateMotions(bool force_update = false); + + // minimal update (e.g. while hidden) + void updateMotionsMinimal(); + + void clearBlenders() { mPoseBlender.clearBlenders(); } + + // flush motions + // releases all motion instances + void flushAllMotions(); + + //Flush is a liar. + void deactivateAllMotions(); + + // pause and continue all motions + void pauseAllMotions(); + void unpauseAllMotions(); + bool isPaused() const { return mPaused; } + S32 getPausedFrame() const { return mPausedFrame; } + + void setTimeStep(F32 step); + F32 getTimeStep() const { return mTimeStep; } + + void setTimeFactor(F32 time_factor); + F32 getTimeFactor() const { return mTimeFactor; } + + F32 getAnimTime() const { return mAnimTime; } + + motion_list_t& getActiveMotions() { return mActiveMotions; } + + void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions); + +//protected: + bool isMotionActive( LLMotion *motion ); + bool isMotionLoading( LLMotion *motion ); + LLMotion *findMotion( const LLUUID& id ) const; + + void dumpMotions(); + + const LLFrameTimer& getFrameTimer() { return mTimer; } + + static F32 getCurrentTimeFactor() { return sCurrentTimeFactor; }; + static void setCurrentTimeFactor(F32 factor) { sCurrentTimeFactor = factor; }; + +protected: + // internal operations act on motion instances directly + // as there can be duplicate motions per id during blending overlap + void deleteAllMotions(); + bool activateMotionInstance(LLMotion *motion, F32 time); + bool deactivateMotionInstance(LLMotion *motion); + void deprecateMotionInstance(LLMotion* motion); + bool stopMotionInstance(LLMotion *motion, bool stop_imemdiate); + void removeMotionInstance(LLMotion* motion); + void updateRegularMotions(); + void updateAdditiveMotions(); + void resetJointSignatures(); + void updateMotionsByType(LLMotion::LLMotionBlendType motion_type); + void updateIdleMotion(LLMotion* motionp); + void updateIdleActiveMotions(); + void purgeExcessMotions(); + void deactivateStoppedMotions(); + +protected: + F32 mTimeFactor; // 1.f for normal speed + static F32 sCurrentTimeFactor; // Value to use for initialization + static LLMotionRegistry sRegistry; + LLPoseBlender mPoseBlender; + + LLCharacter *mCharacter; + +// Life cycle of an animation: +// +// Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime. +// If the animations depend on any asset data, the appropriate data is fetched from the data server, +// and the animation is put on the mLoadingMotions list. +// Once an animations is loaded, it will be initialized and put on the mLoadedMotions list. +// Any animation that is currently playing also sits in the mActiveMotions list. + + typedef std::map<LLUUID, LLMotion*> motion_map_t; + motion_map_t mAllMotions; + + motion_set_t mLoadingMotions; + motion_set_t mLoadedMotions; + motion_list_t mActiveMotions; + motion_set_t mDeprecatedMotions; + + LLFrameTimer mTimer; + F32 mPrevTimerElapsed; + F32 mAnimTime; + F32 mLastTime; + bool mHasRunOnce; + bool mPaused; + S32 mPausedFrame; + F32 mTimeStep; + S32 mTimeStepCount; + F32 mLastInterp; + + U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS]; +private: + U32 mLastCountAfterPurge; //for logging and debugging purposes +}; + +//----------------------------------------------------------------------------- +// Class declaractions +//----------------------------------------------------------------------------- +#include "llcharacter.h" + +#endif // LL_LLMOTIONCONTROLLER_H + diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp index c6b2d84960..a3118a401f 100644 --- a/indra/llcharacter/llmultigesture.cpp +++ b/indra/llcharacter/llmultigesture.cpp @@ -1,501 +1,501 @@ -/**
- * @file llmultigesture.cpp
- * @brief Gestures that are asset-based and can have multiple steps.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include <algorithm>
-
-#include "stdio.h"
-
-#include "llmultigesture.h"
-
-#include "llerror.h"
-#include "lldatapacker.h"
-#include "llstl.h"
-
-const S32 GESTURE_VERSION = 2;
-
-//---------------------------------------------------------------------------
-// LLMultiGesture
-//---------------------------------------------------------------------------
-LLMultiGesture::LLMultiGesture()
-{
- reset();
-}
-
-LLMultiGesture::~LLMultiGesture()
-{
- std::for_each(mSteps.begin(), mSteps.end(), DeletePointer());
- mSteps.clear();
-}
-
-void LLMultiGesture::reset()
-{
- mPlaying = false;
- mCurrentStep = 0;
- mWaitTimer.reset();
- mWaitingAnimations = false;
- mWaitingKeyRelease = false;
- mWaitingTimer = false;
- mTriggeredByKey = false;
- mKeyReleased = false;
- mWaitingAtEnd = false;
- mRequestedAnimIDs.clear();
- mPlayingAnimIDs.clear();
-}
-
-S32 LLMultiGesture::getMaxSerialSize() const
-{
- S32 max_size = 0;
-
- // ascii format, being very conservative about possible
- // label lengths.
- max_size += 64; // version S32
- max_size += 64; // key U8
- max_size += 64; // mask U32
- max_size += 256; // trigger string
- max_size += 256; // replace string
-
- max_size += 64; // step count S32
-
- for (LLGestureStep* step : mSteps)
- {
- max_size += 64; // type S32
- max_size += step->getMaxSerialSize();
- }
-
- /* binary format
- max_size += sizeof(S32); // version
- max_size += sizeof(mKey);
- max_size += sizeof(mMask);
- max_size += mTrigger.length() + 1; // for null
-
- max_size += sizeof(S32); // step count
-
- std::vector<LLGestureStep*>::const_iterator it;
- for (it = mSteps.begin(); it != mSteps.end(); ++it)
- {
- LLGestureStep* step = *it;
- max_size += sizeof(S32); // type
- max_size += step->getMaxSerialSize();
- }
- */
-
- return max_size;
-}
-
-bool LLMultiGesture::serialize(LLDataPacker& dp) const
-{
- dp.packS32(GESTURE_VERSION, "version");
- dp.packU8(mKey, "key");
- dp.packU32(mMask, "mask");
- dp.packString(mTrigger, "trigger");
- dp.packString(mReplaceText, "replace");
-
- S32 count = (S32)mSteps.size();
- dp.packS32(count, "step_count");
- S32 i;
- for (i = 0; i < count; ++i)
- {
- LLGestureStep* step = mSteps[i];
-
- dp.packS32(step->getType(), "step_type");
- bool ok = step->serialize(dp);
- if (!ok)
- {
- return false;
- }
- }
- return true;
-}
-
-bool LLMultiGesture::deserialize(LLDataPacker& dp)
-{
- S32 version;
- dp.unpackS32(version, "version");
- if (version != GESTURE_VERSION)
- {
- LL_WARNS() << "Bad LLMultiGesture version " << version
- << " should be " << GESTURE_VERSION
- << LL_ENDL;
- return false;
- }
-
- dp.unpackU8(mKey, "key");
- dp.unpackU32(mMask, "mask");
-
-
- dp.unpackString(mTrigger, "trigger");
-
- dp.unpackString(mReplaceText, "replace");
-
- S32 count;
- dp.unpackS32(count, "step_count");
- if (count < 0)
- {
- LL_WARNS() << "Bad LLMultiGesture step count " << count << LL_ENDL;
- return false;
- }
-
- S32 i;
- for (i = 0; i < count; ++i)
- {
- S32 type;
- dp.unpackS32(type, "step_type");
-
- EStepType step_type = (EStepType)type;
- switch(step_type)
- {
- case STEP_ANIMATION:
- {
- LLGestureStepAnimation* step = new LLGestureStepAnimation();
- bool ok = step->deserialize(dp);
- if (!ok) return false;
- mSteps.push_back(step);
- break;
- }
- case STEP_SOUND:
- {
- LLGestureStepSound* step = new LLGestureStepSound();
- bool ok = step->deserialize(dp);
- if (!ok) return false;
- mSteps.push_back(step);
- break;
- }
- case STEP_CHAT:
- {
- LLGestureStepChat* step = new LLGestureStepChat();
- bool ok = step->deserialize(dp);
- if (!ok) return false;
- mSteps.push_back(step);
- break;
- }
- case STEP_WAIT:
- {
- LLGestureStepWait* step = new LLGestureStepWait();
- bool ok = step->deserialize(dp);
- if (!ok) return false;
- mSteps.push_back(step);
- break;
- }
- default:
- {
- LL_WARNS() << "Bad LLMultiGesture step type " << type << LL_ENDL;
- return false;
- }
- }
- }
- return true;
-}
-
-void LLMultiGesture::dump()
-{
- LL_INFOS() << "key " << S32(mKey) << " mask " << U32(mMask)
- << " trigger " << mTrigger
- << " replace " << mReplaceText
- << LL_ENDL;
- U32 i;
- for (i = 0; i < mSteps.size(); ++i)
- {
- LLGestureStep* step = mSteps[i];
- step->dump();
- }
-}
-
-//---------------------------------------------------------------------------
-// LLGestureStepAnimation
-//---------------------------------------------------------------------------
-LLGestureStepAnimation::LLGestureStepAnimation()
-: LLGestureStep(),
- mAnimName("None"),
- mAnimAssetID(),
- mFlags(0x0)
-{ }
-
-LLGestureStepAnimation::~LLGestureStepAnimation()
-{ }
-
-S32 LLGestureStepAnimation::getMaxSerialSize() const
-{
- S32 max_size = 0;
-
- // ascii
- max_size += 256; // anim name
- max_size += 64; // anim asset id
- max_size += 64; // flags
-
- /* binary
- max_size += mAnimName.length() + 1;
- max_size += sizeof(mAnimAssetID);
- max_size += sizeof(mFlags);
- */
- return max_size;
-}
-
-bool LLGestureStepAnimation::serialize(LLDataPacker& dp) const
-{
- dp.packString(mAnimName, "anim_name");
- dp.packUUID(mAnimAssetID, "asset_id");
- dp.packU32(mFlags, "flags");
- return true;
-}
-
-bool LLGestureStepAnimation::deserialize(LLDataPacker& dp)
-{
- dp.unpackString(mAnimName, "anim_name");
-
- // Apparently an earlier version of the gesture code added \r to the end
- // of the animation names. Get rid of it. JC
- if (!mAnimName.empty() && mAnimName[mAnimName.length() - 1] == '\r')
- {
- // chop the last character
- mAnimName.resize(mAnimName.length() - 1);
- }
-
- dp.unpackUUID(mAnimAssetID, "asset_id");
- dp.unpackU32(mFlags, "flags");
- return true;
-}
-// *NOTE: result is translated in LLPreviewGesture::getLabel()
-std::vector<std::string> LLGestureStepAnimation::getLabel() const
-{
- std::vector<std::string> strings;
-
-// std::string label;
- if (mFlags & ANIM_FLAG_STOP)
- {
- strings.push_back( "AnimFlagStop");
-
-// label = "Stop Animation: ";
- }
- else
- {
- strings.push_back( "AnimFlagStart");
-
-// label = "Start Animation: ";
- }
- strings.push_back( mAnimName);
-// label += mAnimName;
- return strings;
-}
-
-void LLGestureStepAnimation::dump()
-{
- LL_INFOS() << "step animation " << mAnimName
- << " id " << mAnimAssetID
- << " flags " << mFlags
- << LL_ENDL;
-}
-
-//---------------------------------------------------------------------------
-// LLGestureStepSound
-//---------------------------------------------------------------------------
-LLGestureStepSound::LLGestureStepSound()
-: LLGestureStep(),
- mSoundName("None"),
- mSoundAssetID(),
- mFlags(0x0)
-{ }
-
-LLGestureStepSound::~LLGestureStepSound()
-{ }
-
-S32 LLGestureStepSound::getMaxSerialSize() const
-{
- S32 max_size = 0;
- max_size += 256; // sound name
- max_size += 64; // sound asset id
- max_size += 64; // flags
- /* binary
- max_size += mSoundName.length() + 1;
- max_size += sizeof(mSoundAssetID);
- max_size += sizeof(mFlags);
- */
- return max_size;
-}
-
-bool LLGestureStepSound::serialize(LLDataPacker& dp) const
-{
- dp.packString(mSoundName, "sound_name");
- dp.packUUID(mSoundAssetID, "asset_id");
- dp.packU32(mFlags, "flags");
- return true;
-}
-
-bool LLGestureStepSound::deserialize(LLDataPacker& dp)
-{
- dp.unpackString(mSoundName, "sound_name");
-
- dp.unpackUUID(mSoundAssetID, "asset_id");
- dp.unpackU32(mFlags, "flags");
- return true;
-}
-// *NOTE: result is translated in LLPreviewGesture::getLabel()
-std::vector<std::string> LLGestureStepSound::getLabel() const
-{
- std::vector<std::string> strings;
- strings.push_back( "Sound");
- strings.push_back( mSoundName);
-// std::string label("Sound: ");
-// label += mSoundName;
- return strings;
-}
-
-void LLGestureStepSound::dump()
-{
- LL_INFOS() << "step sound " << mSoundName
- << " id " << mSoundAssetID
- << " flags " << mFlags
- << LL_ENDL;
-}
-
-
-//---------------------------------------------------------------------------
-// LLGestureStepChat
-//---------------------------------------------------------------------------
-LLGestureStepChat::LLGestureStepChat()
-: LLGestureStep(),
- mChatText(),
- mFlags(0x0)
-{ }
-
-LLGestureStepChat::~LLGestureStepChat()
-{ }
-
-S32 LLGestureStepChat::getMaxSerialSize() const
-{
- S32 max_size = 0;
- max_size += 256; // chat text
- max_size += 64; // flags
- /* binary
- max_size += mChatText.length() + 1;
- max_size += sizeof(mFlags);
- */
- return max_size;
-}
-
-bool LLGestureStepChat::serialize(LLDataPacker& dp) const
-{
- dp.packString(mChatText, "chat_text");
- dp.packU32(mFlags, "flags");
- return true;
-}
-
-bool LLGestureStepChat::deserialize(LLDataPacker& dp)
-{
- dp.unpackString(mChatText, "chat_text");
-
- dp.unpackU32(mFlags, "flags");
- return true;
-}
-// *NOTE: result is translated in LLPreviewGesture::getLabel()
-std::vector<std::string> LLGestureStepChat::getLabel() const
-{
- std::vector<std::string> strings;
- strings.push_back("Chat");
- strings.push_back(mChatText);
- return strings;
-}
-
-void LLGestureStepChat::dump()
-{
- LL_INFOS() << "step chat " << mChatText
- << " flags " << mFlags
- << LL_ENDL;
-}
-
-
-//---------------------------------------------------------------------------
-// LLGestureStepWait
-//---------------------------------------------------------------------------
-LLGestureStepWait::LLGestureStepWait()
-: LLGestureStep(),
- mWaitSeconds(0.f),
- mFlags(0x0)
-{ }
-
-LLGestureStepWait::~LLGestureStepWait()
-{ }
-
-S32 LLGestureStepWait::getMaxSerialSize() const
-{
- S32 max_size = 0;
- max_size += 64; // wait seconds
- max_size += 64; // flags
- /* binary
- max_size += sizeof(mWaitSeconds);
- max_size += sizeof(mFlags);
- */
- return max_size;
-}
-
-bool LLGestureStepWait::serialize(LLDataPacker& dp) const
-{
- dp.packF32(mWaitSeconds, "wait_seconds");
- dp.packU32(mFlags, "flags");
- return true;
-}
-
-bool LLGestureStepWait::deserialize(LLDataPacker& dp)
-{
- dp.unpackF32(mWaitSeconds, "wait_seconds");
- dp.unpackU32(mFlags, "flags");
- return true;
-}
-// *NOTE: result is translated in LLPreviewGesture::getLabel()
-std::vector<std::string> LLGestureStepWait::getLabel() const
-{
- std::vector<std::string> strings;
- strings.push_back( "Wait" );
-
-// std::string label("--- Wait: ");
- if (mFlags & WAIT_FLAG_TIME)
- {
- char buffer[64]; /* Flawfinder: ignore */
- snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */
- strings.push_back(buffer);
-// label += buffer;
- }
- else if (mFlags & WAIT_FLAG_ALL_ANIM)
- {
- strings.push_back("until animations are done");
- // label += "until animations are done";
- }
- else
- {
- strings.push_back("");
- }
-
- return strings;
-}
-
-
-void LLGestureStepWait::dump()
-{
- LL_INFOS() << "step wait " << mWaitSeconds
- << " flags " << mFlags
- << LL_ENDL;
-}
+/** + * @file llmultigesture.cpp + * @brief Gestures that are asset-based and can have multiple steps. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include <algorithm> + +#include "stdio.h" + +#include "llmultigesture.h" + +#include "llerror.h" +#include "lldatapacker.h" +#include "llstl.h" + +const S32 GESTURE_VERSION = 2; + +//--------------------------------------------------------------------------- +// LLMultiGesture +//--------------------------------------------------------------------------- +LLMultiGesture::LLMultiGesture() +{ + reset(); +} + +LLMultiGesture::~LLMultiGesture() +{ + std::for_each(mSteps.begin(), mSteps.end(), DeletePointer()); + mSteps.clear(); +} + +void LLMultiGesture::reset() +{ + mPlaying = false; + mCurrentStep = 0; + mWaitTimer.reset(); + mWaitingAnimations = false; + mWaitingKeyRelease = false; + mWaitingTimer = false; + mTriggeredByKey = false; + mKeyReleased = false; + mWaitingAtEnd = false; + mRequestedAnimIDs.clear(); + mPlayingAnimIDs.clear(); +} + +S32 LLMultiGesture::getMaxSerialSize() const +{ + S32 max_size = 0; + + // ascii format, being very conservative about possible + // label lengths. + max_size += 64; // version S32 + max_size += 64; // key U8 + max_size += 64; // mask U32 + max_size += 256; // trigger string + max_size += 256; // replace string + + max_size += 64; // step count S32 + + for (LLGestureStep* step : mSteps) + { + max_size += 64; // type S32 + max_size += step->getMaxSerialSize(); + } + + /* binary format + max_size += sizeof(S32); // version + max_size += sizeof(mKey); + max_size += sizeof(mMask); + max_size += mTrigger.length() + 1; // for null + + max_size += sizeof(S32); // step count + + std::vector<LLGestureStep*>::const_iterator it; + for (it = mSteps.begin(); it != mSteps.end(); ++it) + { + LLGestureStep* step = *it; + max_size += sizeof(S32); // type + max_size += step->getMaxSerialSize(); + } + */ + + return max_size; +} + +bool LLMultiGesture::serialize(LLDataPacker& dp) const +{ + dp.packS32(GESTURE_VERSION, "version"); + dp.packU8(mKey, "key"); + dp.packU32(mMask, "mask"); + dp.packString(mTrigger, "trigger"); + dp.packString(mReplaceText, "replace"); + + S32 count = (S32)mSteps.size(); + dp.packS32(count, "step_count"); + S32 i; + for (i = 0; i < count; ++i) + { + LLGestureStep* step = mSteps[i]; + + dp.packS32(step->getType(), "step_type"); + bool ok = step->serialize(dp); + if (!ok) + { + return false; + } + } + return true; +} + +bool LLMultiGesture::deserialize(LLDataPacker& dp) +{ + S32 version; + dp.unpackS32(version, "version"); + if (version != GESTURE_VERSION) + { + LL_WARNS() << "Bad LLMultiGesture version " << version + << " should be " << GESTURE_VERSION + << LL_ENDL; + return false; + } + + dp.unpackU8(mKey, "key"); + dp.unpackU32(mMask, "mask"); + + + dp.unpackString(mTrigger, "trigger"); + + dp.unpackString(mReplaceText, "replace"); + + S32 count; + dp.unpackS32(count, "step_count"); + if (count < 0) + { + LL_WARNS() << "Bad LLMultiGesture step count " << count << LL_ENDL; + return false; + } + + S32 i; + for (i = 0; i < count; ++i) + { + S32 type; + dp.unpackS32(type, "step_type"); + + EStepType step_type = (EStepType)type; + switch(step_type) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* step = new LLGestureStepAnimation(); + bool ok = step->deserialize(dp); + if (!ok) return false; + mSteps.push_back(step); + break; + } + case STEP_SOUND: + { + LLGestureStepSound* step = new LLGestureStepSound(); + bool ok = step->deserialize(dp); + if (!ok) return false; + mSteps.push_back(step); + break; + } + case STEP_CHAT: + { + LLGestureStepChat* step = new LLGestureStepChat(); + bool ok = step->deserialize(dp); + if (!ok) return false; + mSteps.push_back(step); + break; + } + case STEP_WAIT: + { + LLGestureStepWait* step = new LLGestureStepWait(); + bool ok = step->deserialize(dp); + if (!ok) return false; + mSteps.push_back(step); + break; + } + default: + { + LL_WARNS() << "Bad LLMultiGesture step type " << type << LL_ENDL; + return false; + } + } + } + return true; +} + +void LLMultiGesture::dump() +{ + LL_INFOS() << "key " << S32(mKey) << " mask " << U32(mMask) + << " trigger " << mTrigger + << " replace " << mReplaceText + << LL_ENDL; + U32 i; + for (i = 0; i < mSteps.size(); ++i) + { + LLGestureStep* step = mSteps[i]; + step->dump(); + } +} + +//--------------------------------------------------------------------------- +// LLGestureStepAnimation +//--------------------------------------------------------------------------- +LLGestureStepAnimation::LLGestureStepAnimation() +: LLGestureStep(), + mAnimName("None"), + mAnimAssetID(), + mFlags(0x0) +{ } + +LLGestureStepAnimation::~LLGestureStepAnimation() +{ } + +S32 LLGestureStepAnimation::getMaxSerialSize() const +{ + S32 max_size = 0; + + // ascii + max_size += 256; // anim name + max_size += 64; // anim asset id + max_size += 64; // flags + + /* binary + max_size += mAnimName.length() + 1; + max_size += sizeof(mAnimAssetID); + max_size += sizeof(mFlags); + */ + return max_size; +} + +bool LLGestureStepAnimation::serialize(LLDataPacker& dp) const +{ + dp.packString(mAnimName, "anim_name"); + dp.packUUID(mAnimAssetID, "asset_id"); + dp.packU32(mFlags, "flags"); + return true; +} + +bool LLGestureStepAnimation::deserialize(LLDataPacker& dp) +{ + dp.unpackString(mAnimName, "anim_name"); + + // Apparently an earlier version of the gesture code added \r to the end + // of the animation names. Get rid of it. JC + if (!mAnimName.empty() && mAnimName[mAnimName.length() - 1] == '\r') + { + // chop the last character + mAnimName.resize(mAnimName.length() - 1); + } + + dp.unpackUUID(mAnimAssetID, "asset_id"); + dp.unpackU32(mFlags, "flags"); + return true; +} +// *NOTE: result is translated in LLPreviewGesture::getLabel() +std::vector<std::string> LLGestureStepAnimation::getLabel() const +{ + std::vector<std::string> strings; + +// std::string label; + if (mFlags & ANIM_FLAG_STOP) + { + strings.push_back( "AnimFlagStop"); + +// label = "Stop Animation: "; + } + else + { + strings.push_back( "AnimFlagStart"); + +// label = "Start Animation: "; + } + strings.push_back( mAnimName); +// label += mAnimName; + return strings; +} + +void LLGestureStepAnimation::dump() +{ + LL_INFOS() << "step animation " << mAnimName + << " id " << mAnimAssetID + << " flags " << mFlags + << LL_ENDL; +} + +//--------------------------------------------------------------------------- +// LLGestureStepSound +//--------------------------------------------------------------------------- +LLGestureStepSound::LLGestureStepSound() +: LLGestureStep(), + mSoundName("None"), + mSoundAssetID(), + mFlags(0x0) +{ } + +LLGestureStepSound::~LLGestureStepSound() +{ } + +S32 LLGestureStepSound::getMaxSerialSize() const +{ + S32 max_size = 0; + max_size += 256; // sound name + max_size += 64; // sound asset id + max_size += 64; // flags + /* binary + max_size += mSoundName.length() + 1; + max_size += sizeof(mSoundAssetID); + max_size += sizeof(mFlags); + */ + return max_size; +} + +bool LLGestureStepSound::serialize(LLDataPacker& dp) const +{ + dp.packString(mSoundName, "sound_name"); + dp.packUUID(mSoundAssetID, "asset_id"); + dp.packU32(mFlags, "flags"); + return true; +} + +bool LLGestureStepSound::deserialize(LLDataPacker& dp) +{ + dp.unpackString(mSoundName, "sound_name"); + + dp.unpackUUID(mSoundAssetID, "asset_id"); + dp.unpackU32(mFlags, "flags"); + return true; +} +// *NOTE: result is translated in LLPreviewGesture::getLabel() +std::vector<std::string> LLGestureStepSound::getLabel() const +{ + std::vector<std::string> strings; + strings.push_back( "Sound"); + strings.push_back( mSoundName); +// std::string label("Sound: "); +// label += mSoundName; + return strings; +} + +void LLGestureStepSound::dump() +{ + LL_INFOS() << "step sound " << mSoundName + << " id " << mSoundAssetID + << " flags " << mFlags + << LL_ENDL; +} + + +//--------------------------------------------------------------------------- +// LLGestureStepChat +//--------------------------------------------------------------------------- +LLGestureStepChat::LLGestureStepChat() +: LLGestureStep(), + mChatText(), + mFlags(0x0) +{ } + +LLGestureStepChat::~LLGestureStepChat() +{ } + +S32 LLGestureStepChat::getMaxSerialSize() const +{ + S32 max_size = 0; + max_size += 256; // chat text + max_size += 64; // flags + /* binary + max_size += mChatText.length() + 1; + max_size += sizeof(mFlags); + */ + return max_size; +} + +bool LLGestureStepChat::serialize(LLDataPacker& dp) const +{ + dp.packString(mChatText, "chat_text"); + dp.packU32(mFlags, "flags"); + return true; +} + +bool LLGestureStepChat::deserialize(LLDataPacker& dp) +{ + dp.unpackString(mChatText, "chat_text"); + + dp.unpackU32(mFlags, "flags"); + return true; +} +// *NOTE: result is translated in LLPreviewGesture::getLabel() +std::vector<std::string> LLGestureStepChat::getLabel() const +{ + std::vector<std::string> strings; + strings.push_back("Chat"); + strings.push_back(mChatText); + return strings; +} + +void LLGestureStepChat::dump() +{ + LL_INFOS() << "step chat " << mChatText + << " flags " << mFlags + << LL_ENDL; +} + + +//--------------------------------------------------------------------------- +// LLGestureStepWait +//--------------------------------------------------------------------------- +LLGestureStepWait::LLGestureStepWait() +: LLGestureStep(), + mWaitSeconds(0.f), + mFlags(0x0) +{ } + +LLGestureStepWait::~LLGestureStepWait() +{ } + +S32 LLGestureStepWait::getMaxSerialSize() const +{ + S32 max_size = 0; + max_size += 64; // wait seconds + max_size += 64; // flags + /* binary + max_size += sizeof(mWaitSeconds); + max_size += sizeof(mFlags); + */ + return max_size; +} + +bool LLGestureStepWait::serialize(LLDataPacker& dp) const +{ + dp.packF32(mWaitSeconds, "wait_seconds"); + dp.packU32(mFlags, "flags"); + return true; +} + +bool LLGestureStepWait::deserialize(LLDataPacker& dp) +{ + dp.unpackF32(mWaitSeconds, "wait_seconds"); + dp.unpackU32(mFlags, "flags"); + return true; +} +// *NOTE: result is translated in LLPreviewGesture::getLabel() +std::vector<std::string> LLGestureStepWait::getLabel() const +{ + std::vector<std::string> strings; + strings.push_back( "Wait" ); + +// std::string label("--- Wait: "); + if (mFlags & WAIT_FLAG_TIME) + { + char buffer[64]; /* Flawfinder: ignore */ + snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */ + strings.push_back(buffer); +// label += buffer; + } + else if (mFlags & WAIT_FLAG_ALL_ANIM) + { + strings.push_back("until animations are done"); + // label += "until animations are done"; + } + else + { + strings.push_back(""); + } + + return strings; +} + + +void LLGestureStepWait::dump() +{ + LL_INFOS() << "step wait " << mWaitSeconds + << " flags " << mFlags + << LL_ENDL; +} diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h index b166510721..af0cb08650 100644 --- a/indra/llcharacter/llmultigesture.h +++ b/indra/llcharacter/llmultigesture.h @@ -1,245 +1,245 @@ -/**
- * @file llmultigesture.h
- * @brief Gestures that are asset-based and can have multiple steps.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMULTIGESTURE_H
-#define LL_LLMULTIGESTURE_H
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "lluuid.h"
-#include "llframetimer.h"
-
-class LLDataPacker;
-class LLGestureStep;
-
-class LLMultiGesture
-{
-public:
- LLMultiGesture();
- virtual ~LLMultiGesture();
-
- // Maximum number of bytes this could hold once serialized.
- S32 getMaxSerialSize() const;
-
- bool serialize(LLDataPacker& dp) const;
- bool deserialize(LLDataPacker& dp);
-
- void dump();
-
- void reset();
-
- const std::string& getTrigger() const { return mTrigger; }
-protected:
- LLMultiGesture(const LLMultiGesture& gest);
- const LLMultiGesture& operator=(const LLMultiGesture& rhs);
-
-public:
- KEY mKey { 0 };
- MASK mMask { 0 };
-
- // This name can be empty if the inventory item is not around and
- // the gesture manager has not yet set the name
- std::string mName;
-
- // String, like "/foo" or "hello" that makes it play
- std::string mTrigger;
-
- // Replaces the trigger substring with this text
- std::string mReplaceText;
-
- std::vector<LLGestureStep*> mSteps;
-
- // Is the gesture currently playing?
- bool mPlaying { false };
-
- // "instruction pointer" for steps
- S32 mCurrentStep { 0 };
-
- // We're waiting for triggered animations to stop playing
- bool mWaitingAnimations { false };
-
- // We're waiting for key release
- bool mWaitingKeyRelease { false };
-
- // We're waiting a fixed amount of time
- bool mWaitingTimer { false };
-
- // We're waiting for triggered animations to stop playing
- bool mTriggeredByKey { false };
-
- // Has the key been released?
- bool mKeyReleased { false };
-
- // Waiting after the last step played for all animations to complete
- bool mWaitingAtEnd { false };
-
- // Timer for waiting
- LLFrameTimer mWaitTimer;
-
- void (*mDoneCallback)(LLMultiGesture* gesture, void* data) { NULL };
- void* mCallbackData { NULL };
-
- // Animations that we requested to start
- std::set<LLUUID> mRequestedAnimIDs;
-
- // Once the animation starts playing (sim says to start playing)
- // the ID is moved from mRequestedAnimIDs to here.
- std::set<LLUUID> mPlayingAnimIDs;
-};
-
-
-// Order must match the library_list in floater_preview_gesture.xml!
-
-enum EStepType
-{
- STEP_ANIMATION = 0,
- STEP_SOUND = 1,
- STEP_CHAT = 2,
- STEP_WAIT = 3,
-
- STEP_EOF = 4
-};
-
-
-class LLGestureStep
-{
-public:
- LLGestureStep() {}
- virtual ~LLGestureStep() {}
-
- virtual EStepType getType() = 0;
-
- // Return a user-readable label for this step
- virtual std::vector<std::string> getLabel() const = 0;
-
- virtual S32 getMaxSerialSize() const = 0;
- virtual bool serialize(LLDataPacker& dp) const = 0;
- virtual bool deserialize(LLDataPacker& dp) = 0;
-
- virtual void dump() = 0;
-};
-
-
-// By default, animation steps start animations.
-// If the least significant bit is 1, it will stop animations.
-const U32 ANIM_FLAG_STOP = 0x01;
-
-class LLGestureStepAnimation : public LLGestureStep
-{
-public:
- LLGestureStepAnimation();
- virtual ~LLGestureStepAnimation();
-
- virtual EStepType getType() { return STEP_ANIMATION; }
-
- virtual std::vector<std::string> getLabel() const;
-
- virtual S32 getMaxSerialSize() const;
- virtual bool serialize(LLDataPacker& dp) const;
- virtual bool deserialize(LLDataPacker& dp);
-
- virtual void dump();
-
-public:
- std::string mAnimName;
- LLUUID mAnimAssetID;
- U32 mFlags;
-};
-
-
-class LLGestureStepSound : public LLGestureStep
-{
-public:
- LLGestureStepSound();
- virtual ~LLGestureStepSound();
-
- virtual EStepType getType() { return STEP_SOUND; }
-
- virtual std::vector<std::string> getLabel() const;
-
- virtual S32 getMaxSerialSize() const;
- virtual bool serialize(LLDataPacker& dp) const;
- virtual bool deserialize(LLDataPacker& dp);
-
- virtual void dump();
-
-public:
- std::string mSoundName;
- LLUUID mSoundAssetID;
- U32 mFlags;
-};
-
-
-class LLGestureStepChat : public LLGestureStep
-{
-public:
- LLGestureStepChat();
- virtual ~LLGestureStepChat();
-
- virtual EStepType getType() { return STEP_CHAT; }
-
- virtual std::vector<std::string> getLabel() const;
-
- virtual S32 getMaxSerialSize() const;
- virtual bool serialize(LLDataPacker& dp) const;
- virtual bool deserialize(LLDataPacker& dp);
-
- virtual void dump();
-
-public:
- std::string mChatText;
- U32 mFlags;
-};
-
-
-const U32 WAIT_FLAG_TIME = 0x01;
-const U32 WAIT_FLAG_ALL_ANIM = 0x02;
-const U32 WAIT_FLAG_KEY_RELEASE = 0x04;
-
-class LLGestureStepWait : public LLGestureStep
-{
-public:
- LLGestureStepWait();
- virtual ~LLGestureStepWait();
-
- virtual EStepType getType() { return STEP_WAIT; }
-
- virtual std::vector<std::string> getLabel() const;
-
- virtual S32 getMaxSerialSize() const;
- virtual bool serialize(LLDataPacker& dp) const;
- virtual bool deserialize(LLDataPacker& dp);
-
- virtual void dump();
-
-public:
- F32 mWaitSeconds;
- U32 mFlags;
-};
-
-#endif
+/** + * @file llmultigesture.h + * @brief Gestures that are asset-based and can have multiple steps. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMULTIGESTURE_H +#define LL_LLMULTIGESTURE_H + +#include <set> +#include <string> +#include <vector> + +#include "lluuid.h" +#include "llframetimer.h" + +class LLDataPacker; +class LLGestureStep; + +class LLMultiGesture +{ +public: + LLMultiGesture(); + virtual ~LLMultiGesture(); + + // Maximum number of bytes this could hold once serialized. + S32 getMaxSerialSize() const; + + bool serialize(LLDataPacker& dp) const; + bool deserialize(LLDataPacker& dp); + + void dump(); + + void reset(); + + const std::string& getTrigger() const { return mTrigger; } +protected: + LLMultiGesture(const LLMultiGesture& gest); + const LLMultiGesture& operator=(const LLMultiGesture& rhs); + +public: + KEY mKey { 0 }; + MASK mMask { 0 }; + + // This name can be empty if the inventory item is not around and + // the gesture manager has not yet set the name + std::string mName; + + // String, like "/foo" or "hello" that makes it play + std::string mTrigger; + + // Replaces the trigger substring with this text + std::string mReplaceText; + + std::vector<LLGestureStep*> mSteps; + + // Is the gesture currently playing? + bool mPlaying { false }; + + // "instruction pointer" for steps + S32 mCurrentStep { 0 }; + + // We're waiting for triggered animations to stop playing + bool mWaitingAnimations { false }; + + // We're waiting for key release + bool mWaitingKeyRelease { false }; + + // We're waiting a fixed amount of time + bool mWaitingTimer { false }; + + // We're waiting for triggered animations to stop playing + bool mTriggeredByKey { false }; + + // Has the key been released? + bool mKeyReleased { false }; + + // Waiting after the last step played for all animations to complete + bool mWaitingAtEnd { false }; + + // Timer for waiting + LLFrameTimer mWaitTimer; + + void (*mDoneCallback)(LLMultiGesture* gesture, void* data) { NULL }; + void* mCallbackData { NULL }; + + // Animations that we requested to start + std::set<LLUUID> mRequestedAnimIDs; + + // Once the animation starts playing (sim says to start playing) + // the ID is moved from mRequestedAnimIDs to here. + std::set<LLUUID> mPlayingAnimIDs; +}; + + +// Order must match the library_list in floater_preview_gesture.xml! + +enum EStepType +{ + STEP_ANIMATION = 0, + STEP_SOUND = 1, + STEP_CHAT = 2, + STEP_WAIT = 3, + + STEP_EOF = 4 +}; + + +class LLGestureStep +{ +public: + LLGestureStep() {} + virtual ~LLGestureStep() {} + + virtual EStepType getType() = 0; + + // Return a user-readable label for this step + virtual std::vector<std::string> getLabel() const = 0; + + virtual S32 getMaxSerialSize() const = 0; + virtual bool serialize(LLDataPacker& dp) const = 0; + virtual bool deserialize(LLDataPacker& dp) = 0; + + virtual void dump() = 0; +}; + + +// By default, animation steps start animations. +// If the least significant bit is 1, it will stop animations. +const U32 ANIM_FLAG_STOP = 0x01; + +class LLGestureStepAnimation : public LLGestureStep +{ +public: + LLGestureStepAnimation(); + virtual ~LLGestureStepAnimation(); + + virtual EStepType getType() { return STEP_ANIMATION; } + + virtual std::vector<std::string> getLabel() const; + + virtual S32 getMaxSerialSize() const; + virtual bool serialize(LLDataPacker& dp) const; + virtual bool deserialize(LLDataPacker& dp); + + virtual void dump(); + +public: + std::string mAnimName; + LLUUID mAnimAssetID; + U32 mFlags; +}; + + +class LLGestureStepSound : public LLGestureStep +{ +public: + LLGestureStepSound(); + virtual ~LLGestureStepSound(); + + virtual EStepType getType() { return STEP_SOUND; } + + virtual std::vector<std::string> getLabel() const; + + virtual S32 getMaxSerialSize() const; + virtual bool serialize(LLDataPacker& dp) const; + virtual bool deserialize(LLDataPacker& dp); + + virtual void dump(); + +public: + std::string mSoundName; + LLUUID mSoundAssetID; + U32 mFlags; +}; + + +class LLGestureStepChat : public LLGestureStep +{ +public: + LLGestureStepChat(); + virtual ~LLGestureStepChat(); + + virtual EStepType getType() { return STEP_CHAT; } + + virtual std::vector<std::string> getLabel() const; + + virtual S32 getMaxSerialSize() const; + virtual bool serialize(LLDataPacker& dp) const; + virtual bool deserialize(LLDataPacker& dp); + + virtual void dump(); + +public: + std::string mChatText; + U32 mFlags; +}; + + +const U32 WAIT_FLAG_TIME = 0x01; +const U32 WAIT_FLAG_ALL_ANIM = 0x02; +const U32 WAIT_FLAG_KEY_RELEASE = 0x04; + +class LLGestureStepWait : public LLGestureStep +{ +public: + LLGestureStepWait(); + virtual ~LLGestureStepWait(); + + virtual EStepType getType() { return STEP_WAIT; } + + virtual std::vector<std::string> getLabel() const; + + virtual S32 getMaxSerialSize() const; + virtual bool serialize(LLDataPacker& dp) const; + virtual bool deserialize(LLDataPacker& dp); + + virtual void dump(); + +public: + F32 mWaitSeconds; + U32 mFlags; +}; + +#endif diff --git a/indra/llcharacter/llpose.cpp b/indra/llcharacter/llpose.cpp index 0853655199..0652e9eb25 100644 --- a/indra/llcharacter/llpose.cpp +++ b/indra/llcharacter/llpose.cpp @@ -1,569 +1,569 @@ -/**
- * @file llpose.cpp
- * @brief Implementation of LLPose class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llpose.h"
-
-#include "llmotion.h"
-#include "llmath.h"
-#include "llstl.h"
-
-//-----------------------------------------------------------------------------
-// Static
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLPose
-//-----------------------------------------------------------------------------
-LLPose::~LLPose()
-{
-}
-
-//-----------------------------------------------------------------------------
-// getFirstJointState()
-//-----------------------------------------------------------------------------
-LLJointState* LLPose::getFirstJointState()
-{
- mListIter = mJointMap.begin();
- if (mListIter == mJointMap.end())
- {
- return NULL;
- }
- else
- {
- return mListIter->second;
- }
-}
-
-//-----------------------------------------------------------------------------
-// getNextJointState()
-//-----------------------------------------------------------------------------
-LLJointState *LLPose::getNextJointState()
-{
- mListIter++;
- if (mListIter == mJointMap.end())
- {
- return NULL;
- }
- else
- {
- return mListIter->second;
- }
-}
-
-//-----------------------------------------------------------------------------
-// addJointState()
-//-----------------------------------------------------------------------------
-bool LLPose::addJointState(const LLPointer<LLJointState>& jointState)
-{
- if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
- {
- mJointMap[jointState->getJoint()->getName()] = jointState;
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// removeJointState()
-//-----------------------------------------------------------------------------
-bool LLPose::removeJointState(const LLPointer<LLJointState>& jointState)
-{
- mJointMap.erase(jointState->getJoint()->getName());
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// removeAllJointStates()
-//-----------------------------------------------------------------------------
-bool LLPose::removeAllJointStates()
-{
- mJointMap.clear();
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// findJointState()
-//-----------------------------------------------------------------------------
-LLJointState* LLPose::findJointState(LLJoint *joint)
-{
- joint_map_iterator iter = mJointMap.find(joint->getName());
-
- if (iter == mJointMap.end())
- {
- return NULL;
- }
- else
- {
- return iter->second;
- }
-}
-
-//-----------------------------------------------------------------------------
-// findJointState()
-//-----------------------------------------------------------------------------
-LLJointState* LLPose::findJointState(const std::string &name)
-{
- joint_map_iterator iter = mJointMap.find(name);
-
- if (iter == mJointMap.end())
- {
- return NULL;
- }
- else
- {
- return iter->second;
- }
-}
-
-//-----------------------------------------------------------------------------
-// setWeight()
-//-----------------------------------------------------------------------------
-void LLPose::setWeight(F32 weight)
-{
- joint_map_iterator iter;
- for (joint_map_value_type& joint_pair : mJointMap)
- {
- joint_pair.second->setWeight(weight);
- }
- mWeight = weight;
-}
-
-//-----------------------------------------------------------------------------
-// getWeight()
-//-----------------------------------------------------------------------------
-F32 LLPose::getWeight() const
-{
- return mWeight;
-}
-
-//-----------------------------------------------------------------------------
-// getNumJointStates()
-//-----------------------------------------------------------------------------
-S32 LLPose::getNumJointStates() const
-{
- return (S32)mJointMap.size();
-}
-
-//-----------------------------------------------------------------------------
-// LLJointStateBlender
-//-----------------------------------------------------------------------------
-
-LLJointStateBlender::LLJointStateBlender()
-{
- for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
- {
- mJointStates[i] = NULL;
- mPriorities[i] = S32_MIN;
- mAdditiveBlends[i] = false;
- }
-}
-
-LLJointStateBlender::~LLJointStateBlender()
-{
-
-}
-
-//-----------------------------------------------------------------------------
-// addJointState()
-//-----------------------------------------------------------------------------
-bool LLJointStateBlender::addJointState(const LLPointer<LLJointState>& joint_state, S32 priority, bool additive_blend)
-{
- llassert(joint_state);
-
- if (!joint_state->getJoint())
- // this joint state doesn't point to an actual joint, so we don't care about applying it
- return false;
-
- for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
- {
- if (mJointStates[i].isNull())
- {
- mJointStates[i] = joint_state;
- mPriorities[i] = priority;
- mAdditiveBlends[i] = additive_blend;
- return true;
- }
- else if (priority > mPriorities[i])
- {
- // we're at a higher priority than the current joint state in this slot
- // so shift everyone over
- // previous joint states (newer motions) with same priority should stay in place
- for (S32 j = JSB_NUM_JOINT_STATES - 1; j > i; j--)
- {
- mJointStates[j] = mJointStates[j - 1];
- mPriorities[j] = mPriorities[j - 1];
- mAdditiveBlends[j] = mAdditiveBlends[j - 1];
- }
- // now store ourselves in this slot
- mJointStates[i] = joint_state;
- mPriorities[i] = priority;
- mAdditiveBlends[i] = additive_blend;
- return true;
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// blendJointStates()
-//-----------------------------------------------------------------------------
-void LLJointStateBlender::blendJointStates(bool apply_now)
-{
- // we need at least one joint to blend
- // if there is one, it will be in slot zero according to insertion logic
- // instead of resetting joint state to default, just leave it unchanged from last frame
- if (mJointStates[0].isNull())
- {
- return;
- }
-
- LLJoint* target_joint = apply_now ? mJointStates[0]->getJoint() : &mJointCache;
-
- const S32 POS_WEIGHT = 0;
- const S32 ROT_WEIGHT = 1;
- const S32 SCALE_WEIGHT = 2;
-
- F32 sum_weights[3];
- U32 sum_usage = 0;
-
- LLVector3 blended_pos = target_joint->getPosition();
- LLQuaternion blended_rot = target_joint->getRotation();
- LLVector3 blended_scale = target_joint->getScale();
-
- LLVector3 added_pos;
- LLQuaternion added_rot;
- LLVector3 added_scale;
-
- //S32 joint_state_index;
-
- sum_weights[POS_WEIGHT] = 0.f;
- sum_weights[ROT_WEIGHT] = 0.f;
- sum_weights[SCALE_WEIGHT] = 0.f;
-
- for(S32 joint_state_index = 0;
- joint_state_index < JSB_NUM_JOINT_STATES && mJointStates[joint_state_index].notNull();
- joint_state_index++)
- {
- LLJointState* jsp = mJointStates[joint_state_index];
- U32 current_usage = jsp->getUsage();
- F32 current_weight = jsp->getWeight();
-
- if (current_weight == 0.f)
- {
- continue;
- }
-
- if (mAdditiveBlends[joint_state_index])
- {
- if(current_usage & LLJointState::POS)
- {
- F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]);
-
- // add in pos for this jointstate modulated by weight
- added_pos += jsp->getPosition() * (new_weight_sum - sum_weights[POS_WEIGHT]);
- }
-
- if(current_usage & LLJointState::SCALE)
- {
- F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]);
-
- // add in scale for this jointstate modulated by weight
- added_scale += jsp->getScale() * (new_weight_sum - sum_weights[SCALE_WEIGHT]);
- }
-
- if (current_usage & LLJointState::ROT)
- {
- F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]);
-
- // add in rotation for this jointstate modulated by weight
- added_rot = nlerp((new_weight_sum - sum_weights[ROT_WEIGHT]), added_rot, jsp->getRotation()) * added_rot;
- }
- }
- else
- {
- // blend two jointstates together
-
- // blend position
- if(current_usage & LLJointState::POS)
- {
- if(sum_usage & LLJointState::POS)
- {
- F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]);
-
- // blend positions from both
- blended_pos = lerp(jsp->getPosition(), blended_pos, sum_weights[POS_WEIGHT] / new_weight_sum);
- sum_weights[POS_WEIGHT] = new_weight_sum;
- }
- else
- {
- // copy position from current
- blended_pos = jsp->getPosition();
- sum_weights[POS_WEIGHT] = current_weight;
- }
- }
-
- // now do scale
- if(current_usage & LLJointState::SCALE)
- {
- if(sum_usage & LLJointState::SCALE)
- {
- F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]);
-
- // blend scales from both
- blended_scale = lerp(jsp->getScale(), blended_scale, sum_weights[SCALE_WEIGHT] / new_weight_sum);
- sum_weights[SCALE_WEIGHT] = new_weight_sum;
- }
- else
- {
- // copy scale from current
- blended_scale = jsp->getScale();
- sum_weights[SCALE_WEIGHT] = current_weight;
- }
- }
-
- // rotation
- if (current_usage & LLJointState::ROT)
- {
- if(sum_usage & LLJointState::ROT)
- {
- F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]);
-
- // blend rotations from both
- blended_rot = nlerp(sum_weights[ROT_WEIGHT] / new_weight_sum, jsp->getRotation(), blended_rot);
- sum_weights[ROT_WEIGHT] = new_weight_sum;
- }
- else
- {
- // copy rotation from current
- blended_rot = jsp->getRotation();
- sum_weights[ROT_WEIGHT] = current_weight;
- }
- }
-
- // update resulting usage mask
- sum_usage = sum_usage | current_usage;
- }
- }
-
- if (!added_scale.isFinite())
- {
- added_scale.clearVec();
- }
-
- if (!blended_scale.isFinite())
- {
- blended_scale.setVec(1,1,1);
- }
-
- // apply transforms
- // SL-315
- target_joint->setPosition(blended_pos + added_pos);
- target_joint->setScale(blended_scale + added_scale);
- target_joint->setRotation(added_rot * blended_rot);
-
- if (apply_now)
- {
- // now clear joint states
- for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
- {
- mJointStates[i] = NULL;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// interpolate()
-//-----------------------------------------------------------------------------
-void LLJointStateBlender::interpolate(F32 u)
-{
- // only interpolate if we have a joint state
- if (!mJointStates[0])
- {
- return;
- }
- LLJoint* target_joint = mJointStates[0]->getJoint();
-
- if (!target_joint)
- {
- return;
- }
-
- // SL-315
- target_joint->setPosition(lerp(target_joint->getPosition(), mJointCache.getPosition(), u));
- target_joint->setScale(lerp(target_joint->getScale(), mJointCache.getScale(), u));
- target_joint->setRotation(nlerp(u, target_joint->getRotation(), mJointCache.getRotation()));
-}
-
-//-----------------------------------------------------------------------------
-// clear()
-//-----------------------------------------------------------------------------
-void LLJointStateBlender::clear()
-{
- // now clear joint states
- for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++)
- {
- mJointStates[i] = NULL;
- }
-}
-
-//-----------------------------------------------------------------------------
-// resetCachedJoint()
-//-----------------------------------------------------------------------------
-void LLJointStateBlender::resetCachedJoint()
-{
- if (!mJointStates[0])
- {
- return;
- }
- LLJoint* source_joint = mJointStates[0]->getJoint();
- // SL-315
- mJointCache.setPosition(source_joint->getPosition());
- mJointCache.setScale(source_joint->getScale());
- mJointCache.setRotation(source_joint->getRotation());
-}
-
-//-----------------------------------------------------------------------------
-// LLPoseBlender
-//-----------------------------------------------------------------------------
-
-LLPoseBlender::LLPoseBlender()
- : mNextPoseSlot(0)
-{
-}
-
-LLPoseBlender::~LLPoseBlender()
-{
- for_each(mJointStateBlenderPool.begin(), mJointStateBlenderPool.end(), DeletePairedPointer());
- mJointStateBlenderPool.clear();
-}
-
-//-----------------------------------------------------------------------------
-// addMotion()
-//-----------------------------------------------------------------------------
-bool LLPoseBlender::addMotion(LLMotion* motion)
-{
- LLPose* pose = motion->getPose();
-
- for(LLJointState* jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
- {
- LLJoint *jointp = jsp->getJoint();
- LLJointStateBlender* joint_blender;
- if (mJointStateBlenderPool.find(jointp) == mJointStateBlenderPool.end())
- {
- // this is the first time we are animating this joint
- // so create new jointblender and add it to our pool
- joint_blender = new LLJointStateBlender();
- mJointStateBlenderPool[jointp] = joint_blender;
- }
- else
- {
- joint_blender = mJointStateBlenderPool[jointp];
- }
-
- if (jsp->getPriority() == LLJoint::USE_MOTION_PRIORITY)
- {
- joint_blender->addJointState(jsp, motion->getPriority(), motion->getBlendType() == LLMotion::ADDITIVE_BLEND);
- }
- else
- {
- joint_blender->addJointState(jsp, jsp->getPriority(), motion->getBlendType() == LLMotion::ADDITIVE_BLEND);
- }
-
- // add it to our list of active blenders
- if (std::find(mActiveBlenders.begin(), mActiveBlenders.end(), joint_blender) == mActiveBlenders.end())
- {
- mActiveBlenders.push_front(joint_blender);
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// blendAndApply()
-//-----------------------------------------------------------------------------
-void LLPoseBlender::blendAndApply()
-{
- for (blender_list_t::iterator iter = mActiveBlenders.begin();
- iter != mActiveBlenders.end(); )
- {
- LLJointStateBlender* jsbp = *iter++;
- jsbp->blendJointStates();
- }
-
- // we're done now so there are no more active blenders for this frame
- mActiveBlenders.clear();
-}
-
-//-----------------------------------------------------------------------------
-// blendAndCache()
-//-----------------------------------------------------------------------------
-void LLPoseBlender::blendAndCache(bool reset_cached_joints)
-{
- for (blender_list_t::iterator iter = mActiveBlenders.begin();
- iter != mActiveBlenders.end(); ++iter)
- {
- LLJointStateBlender* jsbp = *iter;
- if (reset_cached_joints)
- {
- jsbp->resetCachedJoint();
- }
- jsbp->blendJointStates(false);
- }
-}
-
-//-----------------------------------------------------------------------------
-// interpolate()
-//-----------------------------------------------------------------------------
-void LLPoseBlender::interpolate(F32 u)
-{
- for (blender_list_t::iterator iter = mActiveBlenders.begin();
- iter != mActiveBlenders.end(); ++iter)
- {
- LLJointStateBlender* jsbp = *iter;
- jsbp->interpolate(u);
- }
-}
-
-//-----------------------------------------------------------------------------
-// clearBlenders()
-//-----------------------------------------------------------------------------
-void LLPoseBlender::clearBlenders()
-{
- for (blender_list_t::iterator iter = mActiveBlenders.begin();
- iter != mActiveBlenders.end(); ++iter)
- {
- LLJointStateBlender* jsbp = *iter;
- jsbp->clear();
- }
-
- mActiveBlenders.clear();
-}
-
+/** + * @file llpose.cpp + * @brief Implementation of LLPose class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llpose.h" + +#include "llmotion.h" +#include "llmath.h" +#include "llstl.h" + +//----------------------------------------------------------------------------- +// Static +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLPose +//----------------------------------------------------------------------------- +LLPose::~LLPose() +{ +} + +//----------------------------------------------------------------------------- +// getFirstJointState() +//----------------------------------------------------------------------------- +LLJointState* LLPose::getFirstJointState() +{ + mListIter = mJointMap.begin(); + if (mListIter == mJointMap.end()) + { + return NULL; + } + else + { + return mListIter->second; + } +} + +//----------------------------------------------------------------------------- +// getNextJointState() +//----------------------------------------------------------------------------- +LLJointState *LLPose::getNextJointState() +{ + mListIter++; + if (mListIter == mJointMap.end()) + { + return NULL; + } + else + { + return mListIter->second; + } +} + +//----------------------------------------------------------------------------- +// addJointState() +//----------------------------------------------------------------------------- +bool LLPose::addJointState(const LLPointer<LLJointState>& jointState) +{ + if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end()) + { + mJointMap[jointState->getJoint()->getName()] = jointState; + } + return true; +} + +//----------------------------------------------------------------------------- +// removeJointState() +//----------------------------------------------------------------------------- +bool LLPose::removeJointState(const LLPointer<LLJointState>& jointState) +{ + mJointMap.erase(jointState->getJoint()->getName()); + return true; +} + +//----------------------------------------------------------------------------- +// removeAllJointStates() +//----------------------------------------------------------------------------- +bool LLPose::removeAllJointStates() +{ + mJointMap.clear(); + return true; +} + +//----------------------------------------------------------------------------- +// findJointState() +//----------------------------------------------------------------------------- +LLJointState* LLPose::findJointState(LLJoint *joint) +{ + joint_map_iterator iter = mJointMap.find(joint->getName()); + + if (iter == mJointMap.end()) + { + return NULL; + } + else + { + return iter->second; + } +} + +//----------------------------------------------------------------------------- +// findJointState() +//----------------------------------------------------------------------------- +LLJointState* LLPose::findJointState(const std::string &name) +{ + joint_map_iterator iter = mJointMap.find(name); + + if (iter == mJointMap.end()) + { + return NULL; + } + else + { + return iter->second; + } +} + +//----------------------------------------------------------------------------- +// setWeight() +//----------------------------------------------------------------------------- +void LLPose::setWeight(F32 weight) +{ + joint_map_iterator iter; + for (joint_map_value_type& joint_pair : mJointMap) + { + joint_pair.second->setWeight(weight); + } + mWeight = weight; +} + +//----------------------------------------------------------------------------- +// getWeight() +//----------------------------------------------------------------------------- +F32 LLPose::getWeight() const +{ + return mWeight; +} + +//----------------------------------------------------------------------------- +// getNumJointStates() +//----------------------------------------------------------------------------- +S32 LLPose::getNumJointStates() const +{ + return (S32)mJointMap.size(); +} + +//----------------------------------------------------------------------------- +// LLJointStateBlender +//----------------------------------------------------------------------------- + +LLJointStateBlender::LLJointStateBlender() +{ + for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++) + { + mJointStates[i] = NULL; + mPriorities[i] = S32_MIN; + mAdditiveBlends[i] = false; + } +} + +LLJointStateBlender::~LLJointStateBlender() +{ + +} + +//----------------------------------------------------------------------------- +// addJointState() +//----------------------------------------------------------------------------- +bool LLJointStateBlender::addJointState(const LLPointer<LLJointState>& joint_state, S32 priority, bool additive_blend) +{ + llassert(joint_state); + + if (!joint_state->getJoint()) + // this joint state doesn't point to an actual joint, so we don't care about applying it + return false; + + for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++) + { + if (mJointStates[i].isNull()) + { + mJointStates[i] = joint_state; + mPriorities[i] = priority; + mAdditiveBlends[i] = additive_blend; + return true; + } + else if (priority > mPriorities[i]) + { + // we're at a higher priority than the current joint state in this slot + // so shift everyone over + // previous joint states (newer motions) with same priority should stay in place + for (S32 j = JSB_NUM_JOINT_STATES - 1; j > i; j--) + { + mJointStates[j] = mJointStates[j - 1]; + mPriorities[j] = mPriorities[j - 1]; + mAdditiveBlends[j] = mAdditiveBlends[j - 1]; + } + // now store ourselves in this slot + mJointStates[i] = joint_state; + mPriorities[i] = priority; + mAdditiveBlends[i] = additive_blend; + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// blendJointStates() +//----------------------------------------------------------------------------- +void LLJointStateBlender::blendJointStates(bool apply_now) +{ + // we need at least one joint to blend + // if there is one, it will be in slot zero according to insertion logic + // instead of resetting joint state to default, just leave it unchanged from last frame + if (mJointStates[0].isNull()) + { + return; + } + + LLJoint* target_joint = apply_now ? mJointStates[0]->getJoint() : &mJointCache; + + const S32 POS_WEIGHT = 0; + const S32 ROT_WEIGHT = 1; + const S32 SCALE_WEIGHT = 2; + + F32 sum_weights[3]; + U32 sum_usage = 0; + + LLVector3 blended_pos = target_joint->getPosition(); + LLQuaternion blended_rot = target_joint->getRotation(); + LLVector3 blended_scale = target_joint->getScale(); + + LLVector3 added_pos; + LLQuaternion added_rot; + LLVector3 added_scale; + + //S32 joint_state_index; + + sum_weights[POS_WEIGHT] = 0.f; + sum_weights[ROT_WEIGHT] = 0.f; + sum_weights[SCALE_WEIGHT] = 0.f; + + for(S32 joint_state_index = 0; + joint_state_index < JSB_NUM_JOINT_STATES && mJointStates[joint_state_index].notNull(); + joint_state_index++) + { + LLJointState* jsp = mJointStates[joint_state_index]; + U32 current_usage = jsp->getUsage(); + F32 current_weight = jsp->getWeight(); + + if (current_weight == 0.f) + { + continue; + } + + if (mAdditiveBlends[joint_state_index]) + { + if(current_usage & LLJointState::POS) + { + F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]); + + // add in pos for this jointstate modulated by weight + added_pos += jsp->getPosition() * (new_weight_sum - sum_weights[POS_WEIGHT]); + } + + if(current_usage & LLJointState::SCALE) + { + F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]); + + // add in scale for this jointstate modulated by weight + added_scale += jsp->getScale() * (new_weight_sum - sum_weights[SCALE_WEIGHT]); + } + + if (current_usage & LLJointState::ROT) + { + F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]); + + // add in rotation for this jointstate modulated by weight + added_rot = nlerp((new_weight_sum - sum_weights[ROT_WEIGHT]), added_rot, jsp->getRotation()) * added_rot; + } + } + else + { + // blend two jointstates together + + // blend position + if(current_usage & LLJointState::POS) + { + if(sum_usage & LLJointState::POS) + { + F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]); + + // blend positions from both + blended_pos = lerp(jsp->getPosition(), blended_pos, sum_weights[POS_WEIGHT] / new_weight_sum); + sum_weights[POS_WEIGHT] = new_weight_sum; + } + else + { + // copy position from current + blended_pos = jsp->getPosition(); + sum_weights[POS_WEIGHT] = current_weight; + } + } + + // now do scale + if(current_usage & LLJointState::SCALE) + { + if(sum_usage & LLJointState::SCALE) + { + F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]); + + // blend scales from both + blended_scale = lerp(jsp->getScale(), blended_scale, sum_weights[SCALE_WEIGHT] / new_weight_sum); + sum_weights[SCALE_WEIGHT] = new_weight_sum; + } + else + { + // copy scale from current + blended_scale = jsp->getScale(); + sum_weights[SCALE_WEIGHT] = current_weight; + } + } + + // rotation + if (current_usage & LLJointState::ROT) + { + if(sum_usage & LLJointState::ROT) + { + F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]); + + // blend rotations from both + blended_rot = nlerp(sum_weights[ROT_WEIGHT] / new_weight_sum, jsp->getRotation(), blended_rot); + sum_weights[ROT_WEIGHT] = new_weight_sum; + } + else + { + // copy rotation from current + blended_rot = jsp->getRotation(); + sum_weights[ROT_WEIGHT] = current_weight; + } + } + + // update resulting usage mask + sum_usage = sum_usage | current_usage; + } + } + + if (!added_scale.isFinite()) + { + added_scale.clearVec(); + } + + if (!blended_scale.isFinite()) + { + blended_scale.setVec(1,1,1); + } + + // apply transforms + // SL-315 + target_joint->setPosition(blended_pos + added_pos); + target_joint->setScale(blended_scale + added_scale); + target_joint->setRotation(added_rot * blended_rot); + + if (apply_now) + { + // now clear joint states + for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++) + { + mJointStates[i] = NULL; + } + } +} + +//----------------------------------------------------------------------------- +// interpolate() +//----------------------------------------------------------------------------- +void LLJointStateBlender::interpolate(F32 u) +{ + // only interpolate if we have a joint state + if (!mJointStates[0]) + { + return; + } + LLJoint* target_joint = mJointStates[0]->getJoint(); + + if (!target_joint) + { + return; + } + + // SL-315 + target_joint->setPosition(lerp(target_joint->getPosition(), mJointCache.getPosition(), u)); + target_joint->setScale(lerp(target_joint->getScale(), mJointCache.getScale(), u)); + target_joint->setRotation(nlerp(u, target_joint->getRotation(), mJointCache.getRotation())); +} + +//----------------------------------------------------------------------------- +// clear() +//----------------------------------------------------------------------------- +void LLJointStateBlender::clear() +{ + // now clear joint states + for(S32 i = 0; i < JSB_NUM_JOINT_STATES; i++) + { + mJointStates[i] = NULL; + } +} + +//----------------------------------------------------------------------------- +// resetCachedJoint() +//----------------------------------------------------------------------------- +void LLJointStateBlender::resetCachedJoint() +{ + if (!mJointStates[0]) + { + return; + } + LLJoint* source_joint = mJointStates[0]->getJoint(); + // SL-315 + mJointCache.setPosition(source_joint->getPosition()); + mJointCache.setScale(source_joint->getScale()); + mJointCache.setRotation(source_joint->getRotation()); +} + +//----------------------------------------------------------------------------- +// LLPoseBlender +//----------------------------------------------------------------------------- + +LLPoseBlender::LLPoseBlender() + : mNextPoseSlot(0) +{ +} + +LLPoseBlender::~LLPoseBlender() +{ + for_each(mJointStateBlenderPool.begin(), mJointStateBlenderPool.end(), DeletePairedPointer()); + mJointStateBlenderPool.clear(); +} + +//----------------------------------------------------------------------------- +// addMotion() +//----------------------------------------------------------------------------- +bool LLPoseBlender::addMotion(LLMotion* motion) +{ + LLPose* pose = motion->getPose(); + + for(LLJointState* jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) + { + LLJoint *jointp = jsp->getJoint(); + LLJointStateBlender* joint_blender; + if (mJointStateBlenderPool.find(jointp) == mJointStateBlenderPool.end()) + { + // this is the first time we are animating this joint + // so create new jointblender and add it to our pool + joint_blender = new LLJointStateBlender(); + mJointStateBlenderPool[jointp] = joint_blender; + } + else + { + joint_blender = mJointStateBlenderPool[jointp]; + } + + if (jsp->getPriority() == LLJoint::USE_MOTION_PRIORITY) + { + joint_blender->addJointState(jsp, motion->getPriority(), motion->getBlendType() == LLMotion::ADDITIVE_BLEND); + } + else + { + joint_blender->addJointState(jsp, jsp->getPriority(), motion->getBlendType() == LLMotion::ADDITIVE_BLEND); + } + + // add it to our list of active blenders + if (std::find(mActiveBlenders.begin(), mActiveBlenders.end(), joint_blender) == mActiveBlenders.end()) + { + mActiveBlenders.push_front(joint_blender); + } + } + return true; +} + +//----------------------------------------------------------------------------- +// blendAndApply() +//----------------------------------------------------------------------------- +void LLPoseBlender::blendAndApply() +{ + for (blender_list_t::iterator iter = mActiveBlenders.begin(); + iter != mActiveBlenders.end(); ) + { + LLJointStateBlender* jsbp = *iter++; + jsbp->blendJointStates(); + } + + // we're done now so there are no more active blenders for this frame + mActiveBlenders.clear(); +} + +//----------------------------------------------------------------------------- +// blendAndCache() +//----------------------------------------------------------------------------- +void LLPoseBlender::blendAndCache(bool reset_cached_joints) +{ + for (blender_list_t::iterator iter = mActiveBlenders.begin(); + iter != mActiveBlenders.end(); ++iter) + { + LLJointStateBlender* jsbp = *iter; + if (reset_cached_joints) + { + jsbp->resetCachedJoint(); + } + jsbp->blendJointStates(false); + } +} + +//----------------------------------------------------------------------------- +// interpolate() +//----------------------------------------------------------------------------- +void LLPoseBlender::interpolate(F32 u) +{ + for (blender_list_t::iterator iter = mActiveBlenders.begin(); + iter != mActiveBlenders.end(); ++iter) + { + LLJointStateBlender* jsbp = *iter; + jsbp->interpolate(u); + } +} + +//----------------------------------------------------------------------------- +// clearBlenders() +//----------------------------------------------------------------------------- +void LLPoseBlender::clearBlenders() +{ + for (blender_list_t::iterator iter = mActiveBlenders.begin(); + iter != mActiveBlenders.end(); ++iter) + { + LLJointStateBlender* jsbp = *iter; + jsbp->clear(); + } + + mActiveBlenders.clear(); +} + diff --git a/indra/llcharacter/llpose.h b/indra/llcharacter/llpose.h index 536ff26f1c..f2032220e0 100644 --- a/indra/llcharacter/llpose.h +++ b/indra/llcharacter/llpose.h @@ -1,141 +1,141 @@ -/**
- * @file llpose.h
- * @brief Implementation of LLPose class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPOSE_H
-#define LL_LLPOSE_H
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-
-#include "lljointstate.h"
-#include "lljoint.h"
-#include "llpointer.h"
-
-#include <map>
-#include <string>
-
-
-//-----------------------------------------------------------------------------
-// class LLPose
-//-----------------------------------------------------------------------------
-class LLPose
-{
- friend class LLPoseBlender;
-protected:
- typedef std::map<std::string, LLPointer<LLJointState> > joint_map;
- typedef joint_map::iterator joint_map_iterator;
- typedef joint_map::value_type joint_map_value_type;
-
- joint_map mJointMap;
- F32 mWeight;
- joint_map_iterator mListIter;
-public:
- // Iterate through jointStates
- LLJointState* getFirstJointState();
- LLJointState* getNextJointState();
- LLJointState* findJointState(LLJoint *joint);
- LLJointState* findJointState(const std::string &name);
-public:
- // Constructor
- LLPose() : mWeight(0.f) {}
- // Destructor
- ~LLPose();
- // add a joint state in this pose
- bool addJointState(const LLPointer<LLJointState>& jointState);
- // remove a joint state from this pose
- bool removeJointState(const LLPointer<LLJointState>& jointState);
- // removes all joint states from this pose
- bool removeAllJointStates();
- // set weight for all joint states in this pose
- void setWeight(F32 weight);
- // get weight for this pose
- F32 getWeight() const;
- // returns number of joint states stored in this pose
- S32 getNumJointStates() const;
-};
-
-const S32 JSB_NUM_JOINT_STATES = 6;
-
-LL_ALIGN_PREFIX(16)
-class LLJointStateBlender
-{
- LL_ALIGN_NEW
-protected:
- LLPointer<LLJointState> mJointStates[JSB_NUM_JOINT_STATES];
- S32 mPriorities[JSB_NUM_JOINT_STATES];
- bool mAdditiveBlends[JSB_NUM_JOINT_STATES];
-public:
- LLJointStateBlender();
- ~LLJointStateBlender();
- void blendJointStates(bool apply_now = true);
- bool addJointState(const LLPointer<LLJointState>& joint_state, S32 priority, bool additive_blend);
- void interpolate(F32 u);
- void clear();
- void resetCachedJoint();
-
-public:
- LL_ALIGN_16(LLJoint mJointCache);
-} LL_ALIGN_POSTFIX(16);
-
-class LLMotion;
-
-class LLPoseBlender
-{
-protected:
- typedef std::list<LLJointStateBlender*> blender_list_t;
- typedef std::map<LLJoint*,LLJointStateBlender*> blender_map_t;
- blender_map_t mJointStateBlenderPool;
- blender_list_t mActiveBlenders;
-
- S32 mNextPoseSlot;
- LLPose mBlendedPose;
-public:
- // Constructor
- LLPoseBlender();
- // Destructor
- ~LLPoseBlender();
-
- // request motion joint states to be added to pose blender joint state records
- bool addMotion(LLMotion* motion);
-
- // blend all joint states and apply to skeleton
- void blendAndApply();
-
- // removes all joint state blenders from last time
- void clearBlenders();
-
- // blend all joint states and cache results
- void blendAndCache(bool reset_cached_joints);
-
- // interpolate all joints towards cached values
- void interpolate(F32 u);
-
- LLPose* getBlendedPose() { return &mBlendedPose; }
-};
-
-#endif // LL_LLPOSE_H
-
+/** + * @file llpose.h + * @brief Implementation of LLPose class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPOSE_H +#define LL_LLPOSE_H + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- + +#include "lljointstate.h" +#include "lljoint.h" +#include "llpointer.h" + +#include <map> +#include <string> + + +//----------------------------------------------------------------------------- +// class LLPose +//----------------------------------------------------------------------------- +class LLPose +{ + friend class LLPoseBlender; +protected: + typedef std::map<std::string, LLPointer<LLJointState> > joint_map; + typedef joint_map::iterator joint_map_iterator; + typedef joint_map::value_type joint_map_value_type; + + joint_map mJointMap; + F32 mWeight; + joint_map_iterator mListIter; +public: + // Iterate through jointStates + LLJointState* getFirstJointState(); + LLJointState* getNextJointState(); + LLJointState* findJointState(LLJoint *joint); + LLJointState* findJointState(const std::string &name); +public: + // Constructor + LLPose() : mWeight(0.f) {} + // Destructor + ~LLPose(); + // add a joint state in this pose + bool addJointState(const LLPointer<LLJointState>& jointState); + // remove a joint state from this pose + bool removeJointState(const LLPointer<LLJointState>& jointState); + // removes all joint states from this pose + bool removeAllJointStates(); + // set weight for all joint states in this pose + void setWeight(F32 weight); + // get weight for this pose + F32 getWeight() const; + // returns number of joint states stored in this pose + S32 getNumJointStates() const; +}; + +const S32 JSB_NUM_JOINT_STATES = 6; + +LL_ALIGN_PREFIX(16) +class LLJointStateBlender +{ + LL_ALIGN_NEW +protected: + LLPointer<LLJointState> mJointStates[JSB_NUM_JOINT_STATES]; + S32 mPriorities[JSB_NUM_JOINT_STATES]; + bool mAdditiveBlends[JSB_NUM_JOINT_STATES]; +public: + LLJointStateBlender(); + ~LLJointStateBlender(); + void blendJointStates(bool apply_now = true); + bool addJointState(const LLPointer<LLJointState>& joint_state, S32 priority, bool additive_blend); + void interpolate(F32 u); + void clear(); + void resetCachedJoint(); + +public: + LL_ALIGN_16(LLJoint mJointCache); +} LL_ALIGN_POSTFIX(16); + +class LLMotion; + +class LLPoseBlender +{ +protected: + typedef std::list<LLJointStateBlender*> blender_list_t; + typedef std::map<LLJoint*,LLJointStateBlender*> blender_map_t; + blender_map_t mJointStateBlenderPool; + blender_list_t mActiveBlenders; + + S32 mNextPoseSlot; + LLPose mBlendedPose; +public: + // Constructor + LLPoseBlender(); + // Destructor + ~LLPoseBlender(); + + // request motion joint states to be added to pose blender joint state records + bool addMotion(LLMotion* motion); + + // blend all joint states and apply to skeleton + void blendAndApply(); + + // removes all joint state blenders from last time + void clearBlenders(); + + // blend all joint states and cache results + void blendAndCache(bool reset_cached_joints); + + // interpolate all joints towards cached values + void interpolate(F32 u); + + LLPose* getBlendedPose() { return &mBlendedPose; } +}; + +#endif // LL_LLPOSE_H + diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp index 1908819ac8..38e9ef444c 100644 --- a/indra/llcharacter/llstatemachine.cpp +++ b/indra/llcharacter/llstatemachine.cpp @@ -1,384 +1,384 @@ -/**
- * @file llstatemachine.cpp
- * @brief LLStateMachine implementation file.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llstatemachine.h"
-#include "llapr.h"
-
-#define FSM_PRINT_STATE_TRANSITIONS (0)
-
-U32 LLUniqueID::sNextID = 0;
-
-bool operator==(const LLUniqueID &a, const LLUniqueID &b)
-{
- return (a.mId == b.mId);
-}
-
-bool operator!=(const LLUniqueID &a, const LLUniqueID &b)
-{
- return (a.mId != b.mId);
-}
-
-//-----------------------------------------------------------------------------
-// LLStateDiagram
-//-----------------------------------------------------------------------------
-LLStateDiagram::LLStateDiagram()
-{
- mDefaultState = NULL;
- mUseDefaultState = false;
-}
-
-LLStateDiagram::~LLStateDiagram()
-{
-
-}
-
-// add a state to the state graph
-bool LLStateDiagram::addState(LLFSMState *state)
-{
- mStates[state] = Transitions();
- return true;
-}
-
-// add a directed transition between 2 states
-bool LLStateDiagram::addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition)
-{
- StateMap::iterator state_it;
- state_it = mStates.find(&start_state);
- Transitions* state_transitions = NULL;
- if (state_it == mStates.end() )
- {
- addState(&start_state);
- state_transitions = &mStates[&start_state];
- }
- else
- {
- state_transitions = &state_it->second;
- }
- state_it = mStates.find(&end_state);
- if (state_it == mStates.end() )
- {
- addState(&end_state);
- }
-
- Transitions::iterator transition_it = state_transitions->find(&transition);
- if (transition_it != state_transitions->end())
- {
- LL_ERRS() << "LLStateTable::addDirectedTransition() : transition already exists" << LL_ENDL;
- return false; // transition already exists
- }
-
- (*state_transitions)[&transition] = &end_state;
- return true;
-}
-
-// add an undirected transition between 2 states
-bool LLStateDiagram::addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition)
-{
- bool result;
- result = addTransition(start_state, end_state, transition);
- if (result)
- {
- result = addTransition(end_state, start_state, transition);
- }
- return result;
-}
-
-// add a transition that exists for every state
-void LLStateDiagram::addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition)
-{
- mDefaultTransitions[&transition] = &end_state;
-}
-
-// process a possible transition, and get the resulting state
-LLFSMState* LLStateDiagram::processTransition(LLFSMState& start_state, LLFSMTransition& transition)
-{
- // look up transition
- //LLFSMState** dest_state = (mStates.getValue(&start_state))->getValue(&transition);
- LLFSMState* dest_state = NULL;
- StateMap::iterator state_it = mStates.find(&start_state);
- if (state_it == mStates.end())
- {
- return NULL;
- }
- Transitions::iterator transition_it = state_it->second.find(&transition);
-
- // try default transitions if state-specific transition not found
- if (transition_it == state_it->second.end())
- {
- dest_state = mDefaultTransitions[&transition];
- }
- else
- {
- dest_state = transition_it->second;
- }
-
- // if we have a destination state...
- if (NULL != dest_state)
- {
- // ...return it...
- return dest_state;
- }
- // ... otherwise ...
- else
- {
- // ...look for default state...
- if (mUseDefaultState)
- {
- // ...return it if we have it...
- return mDefaultState;
- }
- else
- {
- // ...or else we're still in the same state.
- return &start_state;
- }
- }
-}
-
-void LLStateDiagram::setDefaultState(LLFSMState& default_state)
-{
- mUseDefaultState = true;
- mDefaultState = &default_state;
-}
-
-S32 LLStateDiagram::numDeadendStates()
-{
- S32 numDeadends = 0;
- for (StateMap::value_type& state_pair : mStates)
- {
- if (state_pair.second.size() == 0)
- {
- numDeadends++;
- }
- }
- return numDeadends;
-}
-
-bool LLStateDiagram::stateIsValid(LLFSMState& state)
-{
- if (mStates.find(&state) != mStates.end())
- {
- return true;
- }
- return false;
-}
-
-LLFSMState* LLStateDiagram::getState(U32 state_id)
-{
- for (StateMap::value_type& state_pair : mStates)
- {
- if (state_pair.first->getID() == state_id)
- {
- return state_pair.first;
- }
- }
- return NULL;
-}
-
-bool LLStateDiagram::saveDotFile(const std::string& filename)
-{
- LLAPRFile outfile ;
- outfile.open(filename, LL_APR_W);
- apr_file_t* dot_file = outfile.getFileHandle() ;
-
- if (!dot_file)
- {
- LL_WARNS() << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << LL_ENDL;
- return false;
- }
- 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");
-
- for (StateMap::value_type& state_pair : mStates)
- {
- apr_file_printf(dot_file, "\t\"%s\" [fontsize=28,shape=box]\n", state_pair.first->getName().c_str());
- }
- apr_file_printf(dot_file, "\t\"All States\" [fontsize=30,style=bold,shape=box]\n");
-
- for (Transitions::value_type& transition_pair : mDefaultTransitions)
- {
- apr_file_printf(dot_file, "\t\"All States\" -> \"%s\" [label = \"%s\",fontsize=24];\n", transition_pair.second->getName().c_str(),
- transition_pair.second->getName().c_str());
- }
-
- if (mDefaultState)
- {
- apr_file_printf(dot_file, "\t\"All States\" -> \"%s\";\n", mDefaultState->getName().c_str());
- }
-
-
- for (StateMap::value_type& state_pair : mStates)
- {
- LLFSMState *state = state_pair.first;
-
- for (Transitions::value_type& transition_pair : state_pair.second)
- {
- std::string state_name = state->getName();
- std::string target_name = transition_pair.second->getName();
- std::string transition_name = transition_pair.first->getName();
- apr_file_printf(dot_file, "\t\"%s\" -> \"%s\" [label = \"%s\",fontsize=24];\n", state->getName().c_str(),
- target_name.c_str(),
- transition_name.c_str());
- }
- }
-
- apr_file_printf(dot_file, "}\n");
-
- return true;
-}
-
-std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM)
-{
- if (FSM.mDefaultState)
- {
- s << "Default State: " << FSM.mDefaultState->getName() << "\n";
- }
-
- for (LLStateDiagram::Transitions::value_type& transition_pair : FSM.mDefaultTransitions)
- {
- s << "Any State -- " << transition_pair.first->getName()
- << " --> " << transition_pair.second->getName() << "\n";
- }
-
- for (LLStateDiagram::StateMap::value_type& state_pair : FSM.mStates)
- {
- for (LLStateDiagram::Transitions::value_type& transition_pair : state_pair.second)
- {
- s << state_pair.first->getName() << " -- " << transition_pair.first->getName()
- << " --> " << transition_pair.second->getName() << "\n";
- }
- s << "\n";
- }
-
- return s;
-}
-
-//-----------------------------------------------------------------------------
-// LLStateMachine
-//-----------------------------------------------------------------------------
-
-LLStateMachine::LLStateMachine()
-{
- // we haven't received a starting state yet
- mCurrentState = NULL;
- mLastState = NULL;
- mLastTransition = NULL;
- mStateDiagram = NULL;
-}
-
-LLStateMachine::~LLStateMachine()
-{
-
-}
-
-// returns current state
-LLFSMState* LLStateMachine::getCurrentState() const
-{
- return mCurrentState;
-}
-
-// executes current state
-void LLStateMachine::runCurrentState(void *data)
-{
- mCurrentState->execute(data);
-}
-
-// set current state
-bool LLStateMachine::setCurrentState(LLFSMState *initial_state, void* user_data, bool skip_entry)
-{
- llassert(mStateDiagram);
-
- if (mStateDiagram->stateIsValid(*initial_state))
- {
- mLastState = mCurrentState = initial_state;
- if (!skip_entry)
- {
- initial_state->onEntry(user_data);
- }
- return true;
- }
-
- return false;
-}
-
-bool LLStateMachine::setCurrentState(U32 state_id, void* user_data, bool skip_entry)
-{
- llassert(mStateDiagram);
-
- LLFSMState* state = mStateDiagram->getState(state_id);
-
- if (state)
- {
- mLastState = mCurrentState = state;
- if (!skip_entry)
- {
- state->onEntry(user_data);
- }
- return true;
- }
-
- return false;
-}
-
-void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_data)
-{
- llassert(mStateDiagram);
-
- if (NULL == mCurrentState)
- {
- LL_WARNS() << "mCurrentState == NULL; aborting processTransition()" << LL_ENDL;
- return;
- }
-
- LLFSMState* new_state = mStateDiagram->processTransition(*mCurrentState, transition);
-
- if (NULL == new_state)
- {
- LL_WARNS() << "new_state == NULL; aborting processTransition()" << LL_ENDL;
- return;
- }
-
- mLastTransition = &transition;
- mLastState = mCurrentState;
-
- if (*mCurrentState != *new_state)
- {
- mCurrentState->onExit(user_data);
- mCurrentState = new_state;
- mCurrentState->onEntry(user_data);
-#if FSM_PRINT_STATE_TRANSITIONS
- LL_INFOS() << "Entering state " << mCurrentState->getName() <<
- " on transition " << transition.getName() << " from state " <<
- mLastState->getName() << LL_ENDL;
-#endif
- }
-}
-
-void LLStateMachine::setStateDiagram(LLStateDiagram* diagram)
-{
- mStateDiagram = diagram;
-}
+/** + * @file llstatemachine.cpp + * @brief LLStateMachine implementation file. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llstatemachine.h" +#include "llapr.h" + +#define FSM_PRINT_STATE_TRANSITIONS (0) + +U32 LLUniqueID::sNextID = 0; + +bool operator==(const LLUniqueID &a, const LLUniqueID &b) +{ + return (a.mId == b.mId); +} + +bool operator!=(const LLUniqueID &a, const LLUniqueID &b) +{ + return (a.mId != b.mId); +} + +//----------------------------------------------------------------------------- +// LLStateDiagram +//----------------------------------------------------------------------------- +LLStateDiagram::LLStateDiagram() +{ + mDefaultState = NULL; + mUseDefaultState = false; +} + +LLStateDiagram::~LLStateDiagram() +{ + +} + +// add a state to the state graph +bool LLStateDiagram::addState(LLFSMState *state) +{ + mStates[state] = Transitions(); + return true; +} + +// add a directed transition between 2 states +bool LLStateDiagram::addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition) +{ + StateMap::iterator state_it; + state_it = mStates.find(&start_state); + Transitions* state_transitions = NULL; + if (state_it == mStates.end() ) + { + addState(&start_state); + state_transitions = &mStates[&start_state]; + } + else + { + state_transitions = &state_it->second; + } + state_it = mStates.find(&end_state); + if (state_it == mStates.end() ) + { + addState(&end_state); + } + + Transitions::iterator transition_it = state_transitions->find(&transition); + if (transition_it != state_transitions->end()) + { + LL_ERRS() << "LLStateTable::addDirectedTransition() : transition already exists" << LL_ENDL; + return false; // transition already exists + } + + (*state_transitions)[&transition] = &end_state; + return true; +} + +// add an undirected transition between 2 states +bool LLStateDiagram::addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition) +{ + bool result; + result = addTransition(start_state, end_state, transition); + if (result) + { + result = addTransition(end_state, start_state, transition); + } + return result; +} + +// add a transition that exists for every state +void LLStateDiagram::addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition) +{ + mDefaultTransitions[&transition] = &end_state; +} + +// process a possible transition, and get the resulting state +LLFSMState* LLStateDiagram::processTransition(LLFSMState& start_state, LLFSMTransition& transition) +{ + // look up transition + //LLFSMState** dest_state = (mStates.getValue(&start_state))->getValue(&transition); + LLFSMState* dest_state = NULL; + StateMap::iterator state_it = mStates.find(&start_state); + if (state_it == mStates.end()) + { + return NULL; + } + Transitions::iterator transition_it = state_it->second.find(&transition); + + // try default transitions if state-specific transition not found + if (transition_it == state_it->second.end()) + { + dest_state = mDefaultTransitions[&transition]; + } + else + { + dest_state = transition_it->second; + } + + // if we have a destination state... + if (NULL != dest_state) + { + // ...return it... + return dest_state; + } + // ... otherwise ... + else + { + // ...look for default state... + if (mUseDefaultState) + { + // ...return it if we have it... + return mDefaultState; + } + else + { + // ...or else we're still in the same state. + return &start_state; + } + } +} + +void LLStateDiagram::setDefaultState(LLFSMState& default_state) +{ + mUseDefaultState = true; + mDefaultState = &default_state; +} + +S32 LLStateDiagram::numDeadendStates() +{ + S32 numDeadends = 0; + for (StateMap::value_type& state_pair : mStates) + { + if (state_pair.second.size() == 0) + { + numDeadends++; + } + } + return numDeadends; +} + +bool LLStateDiagram::stateIsValid(LLFSMState& state) +{ + if (mStates.find(&state) != mStates.end()) + { + return true; + } + return false; +} + +LLFSMState* LLStateDiagram::getState(U32 state_id) +{ + for (StateMap::value_type& state_pair : mStates) + { + if (state_pair.first->getID() == state_id) + { + return state_pair.first; + } + } + return NULL; +} + +bool LLStateDiagram::saveDotFile(const std::string& filename) +{ + LLAPRFile outfile ; + outfile.open(filename, LL_APR_W); + apr_file_t* dot_file = outfile.getFileHandle() ; + + if (!dot_file) + { + LL_WARNS() << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << LL_ENDL; + return false; + } + 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"); + + for (StateMap::value_type& state_pair : mStates) + { + apr_file_printf(dot_file, "\t\"%s\" [fontsize=28,shape=box]\n", state_pair.first->getName().c_str()); + } + apr_file_printf(dot_file, "\t\"All States\" [fontsize=30,style=bold,shape=box]\n"); + + for (Transitions::value_type& transition_pair : mDefaultTransitions) + { + apr_file_printf(dot_file, "\t\"All States\" -> \"%s\" [label = \"%s\",fontsize=24];\n", transition_pair.second->getName().c_str(), + transition_pair.second->getName().c_str()); + } + + if (mDefaultState) + { + apr_file_printf(dot_file, "\t\"All States\" -> \"%s\";\n", mDefaultState->getName().c_str()); + } + + + for (StateMap::value_type& state_pair : mStates) + { + LLFSMState *state = state_pair.first; + + for (Transitions::value_type& transition_pair : state_pair.second) + { + std::string state_name = state->getName(); + std::string target_name = transition_pair.second->getName(); + std::string transition_name = transition_pair.first->getName(); + apr_file_printf(dot_file, "\t\"%s\" -> \"%s\" [label = \"%s\",fontsize=24];\n", state->getName().c_str(), + target_name.c_str(), + transition_name.c_str()); + } + } + + apr_file_printf(dot_file, "}\n"); + + return true; +} + +std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM) +{ + if (FSM.mDefaultState) + { + s << "Default State: " << FSM.mDefaultState->getName() << "\n"; + } + + for (LLStateDiagram::Transitions::value_type& transition_pair : FSM.mDefaultTransitions) + { + s << "Any State -- " << transition_pair.first->getName() + << " --> " << transition_pair.second->getName() << "\n"; + } + + for (LLStateDiagram::StateMap::value_type& state_pair : FSM.mStates) + { + for (LLStateDiagram::Transitions::value_type& transition_pair : state_pair.second) + { + s << state_pair.first->getName() << " -- " << transition_pair.first->getName() + << " --> " << transition_pair.second->getName() << "\n"; + } + s << "\n"; + } + + return s; +} + +//----------------------------------------------------------------------------- +// LLStateMachine +//----------------------------------------------------------------------------- + +LLStateMachine::LLStateMachine() +{ + // we haven't received a starting state yet + mCurrentState = NULL; + mLastState = NULL; + mLastTransition = NULL; + mStateDiagram = NULL; +} + +LLStateMachine::~LLStateMachine() +{ + +} + +// returns current state +LLFSMState* LLStateMachine::getCurrentState() const +{ + return mCurrentState; +} + +// executes current state +void LLStateMachine::runCurrentState(void *data) +{ + mCurrentState->execute(data); +} + +// set current state +bool LLStateMachine::setCurrentState(LLFSMState *initial_state, void* user_data, bool skip_entry) +{ + llassert(mStateDiagram); + + if (mStateDiagram->stateIsValid(*initial_state)) + { + mLastState = mCurrentState = initial_state; + if (!skip_entry) + { + initial_state->onEntry(user_data); + } + return true; + } + + return false; +} + +bool LLStateMachine::setCurrentState(U32 state_id, void* user_data, bool skip_entry) +{ + llassert(mStateDiagram); + + LLFSMState* state = mStateDiagram->getState(state_id); + + if (state) + { + mLastState = mCurrentState = state; + if (!skip_entry) + { + state->onEntry(user_data); + } + return true; + } + + return false; +} + +void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_data) +{ + llassert(mStateDiagram); + + if (NULL == mCurrentState) + { + LL_WARNS() << "mCurrentState == NULL; aborting processTransition()" << LL_ENDL; + return; + } + + LLFSMState* new_state = mStateDiagram->processTransition(*mCurrentState, transition); + + if (NULL == new_state) + { + LL_WARNS() << "new_state == NULL; aborting processTransition()" << LL_ENDL; + return; + } + + mLastTransition = &transition; + mLastState = mCurrentState; + + if (*mCurrentState != *new_state) + { + mCurrentState->onExit(user_data); + mCurrentState = new_state; + mCurrentState->onEntry(user_data); +#if FSM_PRINT_STATE_TRANSITIONS + LL_INFOS() << "Entering state " << mCurrentState->getName() << + " on transition " << transition.getName() << " from state " << + mLastState->getName() << LL_ENDL; +#endif + } +} + +void LLStateMachine::setStateDiagram(LLStateDiagram* diagram) +{ + mStateDiagram = diagram; +} diff --git a/indra/llcharacter/llstatemachine.h b/indra/llcharacter/llstatemachine.h index 7ede949b35..9a33798d96 100644 --- a/indra/llcharacter/llstatemachine.h +++ b/indra/llcharacter/llstatemachine.h @@ -1,147 +1,147 @@ -/**
- * @file llstatemachine.h
- * @brief LLStateMachine class header file.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLSTATEMACHINE_H
-#define LL_LLSTATEMACHINE_H
-
-#include <string>
-
-#include "llerror.h"
-#include <map>
-
-class LLUniqueID
-{
- friend bool operator==(const LLUniqueID &a, const LLUniqueID &b);
- friend bool operator!=(const LLUniqueID &a, const LLUniqueID &b);
-protected:
- static U32 sNextID;
- U32 mId;
-public:
- LLUniqueID(){mId = sNextID++;}
- virtual ~LLUniqueID(){}
- U32 getID() {return mId;}
-};
-
-class LLFSMTransition : public LLUniqueID
-{
-public:
- LLFSMTransition() : LLUniqueID(){};
- virtual std::string getName()const { return "unnamed"; }
-};
-
-class LLFSMState : public LLUniqueID
-{
-public:
- LLFSMState() : LLUniqueID(){};
- virtual void onEntry(void *){};
- virtual void onExit(void *){};
- virtual void execute(void *){};
- virtual std::string getName() const { return "unnamed"; }
-};
-
-class LLStateDiagram
-{
-typedef std::map<LLFSMTransition*, LLFSMState*> Transitions;
-
-friend std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM);
-friend class LLStateMachine;
-
-protected:
- typedef std::map<LLFSMState*, Transitions> StateMap;
- StateMap mStates;
- Transitions mDefaultTransitions;
- LLFSMState* mDefaultState;
- bool mUseDefaultState;
-
-public:
- LLStateDiagram();
- virtual ~LLStateDiagram();
-
-protected:
- // add a state to the state graph, executed implicitly when adding transitions
- bool addState(LLFSMState *state);
-
- // add a directed transition between 2 states
- bool addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition);
-
- // add an undirected transition between 2 states
- bool addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition);
-
- // add a transition that is taken if none other exist
- void addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition);
-
- // process a possible transition, and get the resulting state
- LLFSMState* processTransition(LLFSMState& start_state, LLFSMTransition& transition);
-
- // add a transition that exists for every state
- void setDefaultState(LLFSMState& default_state);
-
- // return total number of states with no outgoing transitions
- S32 numDeadendStates();
-
- // does this state exist in the state diagram?
- bool stateIsValid(LLFSMState& state);
-
- // get a state pointer by ID
- LLFSMState* getState(U32 state_id);
-
-public:
- // save the graph in a DOT file for rendering and visualization
- bool saveDotFile(const std::string& filename);
-};
-
-class LLStateMachine
-{
-protected:
- LLFSMState* mCurrentState;
- LLFSMState* mLastState;
- LLFSMTransition* mLastTransition;
- LLStateDiagram* mStateDiagram;
-
-public:
- LLStateMachine();
- virtual ~LLStateMachine();
-
- // set state diagram
- void setStateDiagram(LLStateDiagram* diagram);
-
- // process this transition
- void processTransition(LLFSMTransition &transition, void* user_data);
-
- // returns current state
- LLFSMState* getCurrentState() const;
-
- // execute current state
- void runCurrentState(void *data);
-
- // set state by state pointer
- bool setCurrentState(LLFSMState *initial_state, void* user_data, bool skip_entry = true);
-
- // set state by unique ID
- bool setCurrentState(U32 state_id, void* user_data, bool skip_entry = true);
-};
-
-#endif //_LL_LLSTATEMACHINE_H
+/** + * @file llstatemachine.h + * @brief LLStateMachine class header file. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLSTATEMACHINE_H +#define LL_LLSTATEMACHINE_H + +#include <string> + +#include "llerror.h" +#include <map> + +class LLUniqueID +{ + friend bool operator==(const LLUniqueID &a, const LLUniqueID &b); + friend bool operator!=(const LLUniqueID &a, const LLUniqueID &b); +protected: + static U32 sNextID; + U32 mId; +public: + LLUniqueID(){mId = sNextID++;} + virtual ~LLUniqueID(){} + U32 getID() {return mId;} +}; + +class LLFSMTransition : public LLUniqueID +{ +public: + LLFSMTransition() : LLUniqueID(){}; + virtual std::string getName()const { return "unnamed"; } +}; + +class LLFSMState : public LLUniqueID +{ +public: + LLFSMState() : LLUniqueID(){}; + virtual void onEntry(void *){}; + virtual void onExit(void *){}; + virtual void execute(void *){}; + virtual std::string getName() const { return "unnamed"; } +}; + +class LLStateDiagram +{ +typedef std::map<LLFSMTransition*, LLFSMState*> Transitions; + +friend std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM); +friend class LLStateMachine; + +protected: + typedef std::map<LLFSMState*, Transitions> StateMap; + StateMap mStates; + Transitions mDefaultTransitions; + LLFSMState* mDefaultState; + bool mUseDefaultState; + +public: + LLStateDiagram(); + virtual ~LLStateDiagram(); + +protected: + // add a state to the state graph, executed implicitly when adding transitions + bool addState(LLFSMState *state); + + // add a directed transition between 2 states + bool addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition); + + // add an undirected transition between 2 states + bool addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition); + + // add a transition that is taken if none other exist + void addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition); + + // process a possible transition, and get the resulting state + LLFSMState* processTransition(LLFSMState& start_state, LLFSMTransition& transition); + + // add a transition that exists for every state + void setDefaultState(LLFSMState& default_state); + + // return total number of states with no outgoing transitions + S32 numDeadendStates(); + + // does this state exist in the state diagram? + bool stateIsValid(LLFSMState& state); + + // get a state pointer by ID + LLFSMState* getState(U32 state_id); + +public: + // save the graph in a DOT file for rendering and visualization + bool saveDotFile(const std::string& filename); +}; + +class LLStateMachine +{ +protected: + LLFSMState* mCurrentState; + LLFSMState* mLastState; + LLFSMTransition* mLastTransition; + LLStateDiagram* mStateDiagram; + +public: + LLStateMachine(); + virtual ~LLStateMachine(); + + // set state diagram + void setStateDiagram(LLStateDiagram* diagram); + + // process this transition + void processTransition(LLFSMTransition &transition, void* user_data); + + // returns current state + LLFSMState* getCurrentState() const; + + // execute current state + void runCurrentState(void *data); + + // set state by state pointer + bool setCurrentState(LLFSMState *initial_state, void* user_data, bool skip_entry = true); + + // set state by unique ID + bool setCurrentState(U32 state_id, void* user_data, bool skip_entry = true); +}; + +#endif //_LL_LLSTATEMACHINE_H diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp index 1029ba40eb..0683a1125c 100644 --- a/indra/llcharacter/lltargetingmotion.cpp +++ b/indra/llcharacter/lltargetingmotion.cpp @@ -1,170 +1,170 @@ -/**
- * @file lltargetingmotion.cpp
- * @brief Implementation of LLTargetingMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "lltargetingmotion.h"
-#include "llcharacter.h"
-#include "v3dmath.h"
-#include "llcriticaldamp.h"
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-const F32 TORSO_TARGET_HALF_LIFE = 0.25f;
-
-//-----------------------------------------------------------------------------
-// LLTargetingMotion()
-// Class Constructor
-//-----------------------------------------------------------------------------
-LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id)
-{
- mCharacter = NULL;
- mName = "targeting";
-
- mTorsoState = new LLJointState;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLTargetingMotion()
-// Class Destructor
-//-----------------------------------------------------------------------------
-LLTargetingMotion::~LLTargetingMotion()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLTargetingMotion::onInitialize(LLCharacter *character)
-//-----------------------------------------------------------------------------
-LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *character)
-{
- // save character for future use
- mCharacter = character;
-
- mPelvisJoint = mCharacter->getJoint("mPelvis");
- mTorsoJoint = mCharacter->getJoint("mTorso");
- mRightHandJoint = mCharacter->getJoint("mWristRight");
-
- // make sure character skeleton is copacetic
- if (!mPelvisJoint ||
- !mTorsoJoint ||
- !mRightHandJoint)
- {
- LL_WARNS() << "Invalid skeleton for targeting motion!" << LL_ENDL;
- return STATUS_FAILURE;
- }
-
- mTorsoState->setJoint( mTorsoJoint );
-
- // add joint states to the pose
- mTorsoState->setUsage(LLJointState::ROT);
- addJointState( mTorsoState );
-
- return STATUS_SUCCESS;
-}
-
-//-----------------------------------------------------------------------------
-// LLTargetingMotion::onActivate()
-//-----------------------------------------------------------------------------
-bool LLTargetingMotion::onActivate()
-{
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// LLTargetingMotion::onUpdate()
-//-----------------------------------------------------------------------------
-bool LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
-{
- LL_PROFILE_ZONE_SCOPED;
- F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE);
-
- LLVector3 target;
- LLVector3* lookAtPoint = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
-
- bool result = true;
-
- if (!lookAtPoint)
- {
- return true;
- }
- else
- {
- target = *lookAtPoint;
- target.normVec();
- }
-
- //LLVector3 target_plane_normal = LLVector3(1.f, 0.f, 0.f) * mPelvisJoint->getWorldRotation();
- //LLVector3 torso_dir = LLVector3(1.f, 0.f, 0.f) * (mTorsoJoint->getWorldRotation() * mTorsoState->getRotation());
-
- LLVector3 skyward(0.f, 0.f, 1.f);
- LLVector3 left(skyward % target);
- left.normVec();
- LLVector3 up(target % left);
- up.normVec();
- LLQuaternion target_aim_rot(target, left, up);
-
- LLQuaternion cur_torso_rot = mTorsoJoint->getWorldRotation();
-
- LLVector3 right_hand_at = LLVector3(0.f, -1.f, 0.f) * mRightHandJoint->getWorldRotation();
- left.setVec(skyward % right_hand_at);
- left.normVec();
- up.setVec(right_hand_at % left);
- up.normVec();
- LLQuaternion right_hand_rot(right_hand_at, left, up);
-
- LLQuaternion new_torso_rot = (cur_torso_rot * ~right_hand_rot) * target_aim_rot;
-
- // find ideal additive rotation to make torso point in correct direction
- new_torso_rot = new_torso_rot * ~cur_torso_rot;
-
- // slerp from current additive rotation to ideal additive rotation
- new_torso_rot = nlerp(slerp_amt, mTorsoState->getRotation(), new_torso_rot);
-
- // constraint overall torso rotation
- LLQuaternion total_rot = new_torso_rot * mTorsoJoint->getRotation();
- total_rot.constrain(F_PI_BY_TWO * 0.8f);
- new_torso_rot = total_rot * ~mTorsoJoint->getRotation();
-
- mTorsoState->setRotation(new_torso_rot);
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// LLTargetingMotion::onDeactivate()
-//-----------------------------------------------------------------------------
-void LLTargetingMotion::onDeactivate()
-{
-}
-
-
-// End
-
+/** + * @file lltargetingmotion.cpp + * @brief Implementation of LLTargetingMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "lltargetingmotion.h" +#include "llcharacter.h" +#include "v3dmath.h" +#include "llcriticaldamp.h" + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- +const F32 TORSO_TARGET_HALF_LIFE = 0.25f; + +//----------------------------------------------------------------------------- +// LLTargetingMotion() +// Class Constructor +//----------------------------------------------------------------------------- +LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id) +{ + mCharacter = NULL; + mName = "targeting"; + + mTorsoState = new LLJointState; +} + + +//----------------------------------------------------------------------------- +// ~LLTargetingMotion() +// Class Destructor +//----------------------------------------------------------------------------- +LLTargetingMotion::~LLTargetingMotion() +{ +} + +//----------------------------------------------------------------------------- +// LLTargetingMotion::onInitialize(LLCharacter *character) +//----------------------------------------------------------------------------- +LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *character) +{ + // save character for future use + mCharacter = character; + + mPelvisJoint = mCharacter->getJoint("mPelvis"); + mTorsoJoint = mCharacter->getJoint("mTorso"); + mRightHandJoint = mCharacter->getJoint("mWristRight"); + + // make sure character skeleton is copacetic + if (!mPelvisJoint || + !mTorsoJoint || + !mRightHandJoint) + { + LL_WARNS() << "Invalid skeleton for targeting motion!" << LL_ENDL; + return STATUS_FAILURE; + } + + mTorsoState->setJoint( mTorsoJoint ); + + // add joint states to the pose + mTorsoState->setUsage(LLJointState::ROT); + addJointState( mTorsoState ); + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// LLTargetingMotion::onActivate() +//----------------------------------------------------------------------------- +bool LLTargetingMotion::onActivate() +{ + return true; +} + +//----------------------------------------------------------------------------- +// LLTargetingMotion::onUpdate() +//----------------------------------------------------------------------------- +bool LLTargetingMotion::onUpdate(F32 time, U8* joint_mask) +{ + LL_PROFILE_ZONE_SCOPED; + F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE); + + LLVector3 target; + LLVector3* lookAtPoint = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); + + bool result = true; + + if (!lookAtPoint) + { + return true; + } + else + { + target = *lookAtPoint; + target.normVec(); + } + + //LLVector3 target_plane_normal = LLVector3(1.f, 0.f, 0.f) * mPelvisJoint->getWorldRotation(); + //LLVector3 torso_dir = LLVector3(1.f, 0.f, 0.f) * (mTorsoJoint->getWorldRotation() * mTorsoState->getRotation()); + + LLVector3 skyward(0.f, 0.f, 1.f); + LLVector3 left(skyward % target); + left.normVec(); + LLVector3 up(target % left); + up.normVec(); + LLQuaternion target_aim_rot(target, left, up); + + LLQuaternion cur_torso_rot = mTorsoJoint->getWorldRotation(); + + LLVector3 right_hand_at = LLVector3(0.f, -1.f, 0.f) * mRightHandJoint->getWorldRotation(); + left.setVec(skyward % right_hand_at); + left.normVec(); + up.setVec(right_hand_at % left); + up.normVec(); + LLQuaternion right_hand_rot(right_hand_at, left, up); + + LLQuaternion new_torso_rot = (cur_torso_rot * ~right_hand_rot) * target_aim_rot; + + // find ideal additive rotation to make torso point in correct direction + new_torso_rot = new_torso_rot * ~cur_torso_rot; + + // slerp from current additive rotation to ideal additive rotation + new_torso_rot = nlerp(slerp_amt, mTorsoState->getRotation(), new_torso_rot); + + // constraint overall torso rotation + LLQuaternion total_rot = new_torso_rot * mTorsoJoint->getRotation(); + total_rot.constrain(F_PI_BY_TWO * 0.8f); + new_torso_rot = total_rot * ~mTorsoJoint->getRotation(); + + mTorsoState->setRotation(new_torso_rot); + + return result; +} + +//----------------------------------------------------------------------------- +// LLTargetingMotion::onDeactivate() +//----------------------------------------------------------------------------- +void LLTargetingMotion::onDeactivate() +{ +} + + +// End + diff --git a/indra/llcharacter/lltargetingmotion.h b/indra/llcharacter/lltargetingmotion.h index 7317003497..9e46a76e33 100644 --- a/indra/llcharacter/lltargetingmotion.h +++ b/indra/llcharacter/lltargetingmotion.h @@ -1,116 +1,116 @@ -/**
- * @file lltargetingmotion.h
- * @brief Implementation of LLTargetingMotion class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLTARGETINGMOTION_H
-#define LL_LLTARGETINGMOTION_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llmotion.h"
-
-#define TARGETING_EASEIN_DURATION 0.3f
-#define TARGETING_EASEOUT_DURATION 0.5f
-#define TARGETING_PRIORITY LLJoint::HIGH_PRIORITY
-#define MIN_REQUIRED_PIXEL_AREA_TARGETING 1000.f;
-
-
-//-----------------------------------------------------------------------------
-// class LLTargetingMotion
-//-----------------------------------------------------------------------------
-class LLTargetingMotion :
- public LLMotion
-{
-public:
- // Constructor
- LLTargetingMotion(const LLUUID &id);
-
- // Destructor
- virtual ~LLTargetingMotion();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual bool getLoop() { return true; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return TARGETING_EASEIN_DURATION; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return TARGETING_EASEOUT_DURATION; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return TARGETING_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_TARGETING; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return true to indicate success, or else
- // it will be deactivated
- virtual bool onActivate();
-
- // called per time step
- // must return true while it is active, and
- // must return true when the motion is completed.
- virtual bool onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
-public:
-
- LLCharacter *mCharacter;
- LLPointer<LLJointState> mTorsoState;
- LLJoint* mPelvisJoint;
- LLJoint* mTorsoJoint;
- LLJoint* mRightHandJoint;
-};
-
-#endif // LL_LLTARGETINGMOTION_H
-
+/** + * @file lltargetingmotion.h + * @brief Implementation of LLTargetingMotion class. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTARGETINGMOTION_H +#define LL_LLTARGETINGMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" + +#define TARGETING_EASEIN_DURATION 0.3f +#define TARGETING_EASEOUT_DURATION 0.5f +#define TARGETING_PRIORITY LLJoint::HIGH_PRIORITY +#define MIN_REQUIRED_PIXEL_AREA_TARGETING 1000.f; + + +//----------------------------------------------------------------------------- +// class LLTargetingMotion +//----------------------------------------------------------------------------- +class LLTargetingMotion : + public LLMotion +{ +public: + // Constructor + LLTargetingMotion(const LLUUID &id); + + // Destructor + virtual ~LLTargetingMotion(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual bool getLoop() { return true; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return TARGETING_EASEIN_DURATION; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return TARGETING_EASEOUT_DURATION; } + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return TARGETING_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_TARGETING; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return true to indicate success, or else + // it will be deactivated + virtual bool onActivate(); + + // called per time step + // must return true while it is active, and + // must return true when the motion is completed. + virtual bool onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + +public: + + LLCharacter *mCharacter; + LLPointer<LLJointState> mTorsoState; + LLJoint* mPelvisJoint; + LLJoint* mTorsoJoint; + LLJoint* mRightHandJoint; +}; + +#endif // LL_LLTARGETINGMOTION_H + diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp index 7a5c2654be..105b31de65 100644 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -1,376 +1,376 @@ -/**
- * @file llvisualparam.cpp
- * @brief Implementation of LLPolyMesh class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "linden_common.h"
-
-#include "llvisualparam.h"
-
-//-----------------------------------------------------------------------------
-// LLVisualParamInfo()
-//-----------------------------------------------------------------------------
-LLVisualParamInfo::LLVisualParamInfo()
- :
- mID( -1 ),
- mGroup( VISUAL_PARAM_GROUP_TWEAKABLE ),
- mMinWeight( 0.f ),
- mMaxWeight( 1.f ),
- mDefaultWeight( 0.f ),
- mSex( SEX_BOTH )
-{
-}
-
-//-----------------------------------------------------------------------------
-// parseXml()
-//-----------------------------------------------------------------------------
-bool LLVisualParamInfo::parseXml(LLXmlTreeNode *node)
-{
- // attribute: id
- static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
- node->getFastAttributeS32( id_string, mID );
-
- // attribute: group
- U32 group = 0;
- static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
- if( node->getFastAttributeU32( group_string, group ) )
- {
- if( group < NUM_VISUAL_PARAM_GROUPS )
- {
- mGroup = (EVisualParamGroup)group;
- }
- }
-
- // attribute: value_min, value_max
- static LLStdStringHandle value_min_string = LLXmlTree::addAttributeString("value_min");
- static LLStdStringHandle value_max_string = LLXmlTree::addAttributeString("value_max");
- node->getFastAttributeF32( value_min_string, mMinWeight );
- node->getFastAttributeF32( value_max_string, mMaxWeight );
-
- // attribute: value_default
- F32 default_weight = 0;
- static LLStdStringHandle value_default_string = LLXmlTree::addAttributeString("value_default");
- if( node->getFastAttributeF32( value_default_string, default_weight ) )
- {
- mDefaultWeight = llclamp( default_weight, mMinWeight, mMaxWeight );
- if( default_weight != mDefaultWeight )
- {
- LL_WARNS() << "value_default attribute is out of range in node " << mName << " " << default_weight << LL_ENDL;
- }
- }
-
- // attribute: sex
- std::string sex = "both";
- static LLStdStringHandle sex_string = LLXmlTree::addAttributeString("sex");
- node->getFastAttributeString( sex_string, sex ); // optional
- if( sex == "both" )
- {
- mSex = SEX_BOTH;
- }
- else if( sex == "male" )
- {
- mSex = SEX_MALE;
- }
- else if( sex == "female" )
- {
- mSex = SEX_FEMALE;
- }
- else
- {
- LL_WARNS() << "Avatar file: <param> has invalid sex attribute: " << sex << LL_ENDL;
- return false;
- }
-
- // attribute: name
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if( !node->getFastAttributeString( name_string, mName ) )
- {
- LL_WARNS() << "Avatar file: <param> is missing name attribute" << LL_ENDL;
- return false;
- }
-
- // attribute: label
- static LLStdStringHandle label_string = LLXmlTree::addAttributeString("label");
- if( !node->getFastAttributeString( label_string, mDisplayName ) )
- {
- mDisplayName = mName;
- }
-
- // JC - make sure the display name includes the capitalization in the XML file,
- // not the lowercased version.
- LLStringUtil::toLower(mName);
-
- // attribute: label_min
- static LLStdStringHandle label_min_string = LLXmlTree::addAttributeString("label_min");
- if( !node->getFastAttributeString( label_min_string, mMinName ) )
- {
- mMinName = "Less";
- }
-
- // attribute: label_max
- static LLStdStringHandle label_max_string = LLXmlTree::addAttributeString("label_max");
- if( !node->getFastAttributeString( label_max_string, mMaxName ) )
- {
- mMaxName = "More";
- }
-
- return true;
-}
-
-//virtual
-void LLVisualParamInfo::toStream(std::ostream &out)
-{
- out << mID << "\t";
- out << mName << "\t";
- out << mDisplayName << "\t";
- out << mMinName << "\t";
- out << mMaxName << "\t";
- out << mGroup << "\t";
- out << mMinWeight << "\t";
- out << mMaxWeight << "\t";
- out << mDefaultWeight << "\t";
- out << mSex << "\t";
-}
-
-//-----------------------------------------------------------------------------
-// LLVisualParam()
-//-----------------------------------------------------------------------------
-LLVisualParam::LLVisualParam()
- : mCurWeight( 0.f ),
- mLastWeight( 0.f ),
- mNext( NULL ),
- mTargetWeight( 0.f ),
- mIsAnimating( false ),
- mIsDummy(false),
- mID( -1 ),
- mInfo( 0 ),
- mParamLocation(LOC_UNKNOWN)
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLVisualParam()
-//-----------------------------------------------------------------------------
-LLVisualParam::LLVisualParam(const LLVisualParam& pOther)
- : mCurWeight(pOther.mCurWeight),
- mLastWeight(pOther.mLastWeight),
- mNext(pOther.mNext),
- mTargetWeight(pOther.mTargetWeight),
- mIsAnimating(pOther.mIsAnimating),
- mIsDummy(pOther.mIsDummy),
- mID(pOther.mID),
- mInfo(pOther.mInfo),
- mParamLocation(pOther.mParamLocation)
-{
-}
-
-//-----------------------------------------------------------------------------
-// ~LLVisualParam()
-//-----------------------------------------------------------------------------
-LLVisualParam::~LLVisualParam()
-{
- delete mNext;
- mNext = NULL;
-}
-
-/*
-//=============================================================================
-// These virtual functions should always be overridden,
-// but are included here for use as templates
-//=============================================================================
-
-//-----------------------------------------------------------------------------
-// setInfo()
-//-----------------------------------------------------------------------------
-
-bool LLVisualParam::setInfo(LLVisualParamInfo *info)
-{
- llassert(mInfo == NULL);
- if (info->mID < 0)
- return false;
- mInfo = info;
- mID = info->mID;
- setWeight(getDefaultWeight(), false );
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// parseData()
-//-----------------------------------------------------------------------------
-bool LLVisualParam::parseData(LLXmlTreeNode *node)
-{
- LLVisualParamInfo *info = new LLVisualParamInfo;
-
- info->parseXml(node);
- if (!setInfo(info))
- return false;
-
- return true;
-}
-*/
-
-//-----------------------------------------------------------------------------
-// setWeight()
-//-----------------------------------------------------------------------------
-void LLVisualParam::setWeight(F32 weight)
-{
- if (mIsAnimating)
- {
- //RN: allow overshoot
- mCurWeight = weight;
- }
- else if (mInfo)
- {
- mCurWeight = llclamp(weight, mInfo->mMinWeight, mInfo->mMaxWeight);
- }
- else
- {
- mCurWeight = weight;
- }
-
- if (mNext)
- {
- mNext->setWeight(weight);
- }
-}
-
-//-----------------------------------------------------------------------------
-// setAnimationTarget()
-//-----------------------------------------------------------------------------
-void LLVisualParam::setAnimationTarget(F32 target_value)
-{
- // don't animate dummy parameters
- if (mIsDummy)
- {
- setWeight(target_value);
- mTargetWeight = mCurWeight;
- return;
- }
-
- if (mInfo)
- {
- if (isTweakable())
- {
- mTargetWeight = llclamp(target_value, mInfo->mMinWeight, mInfo->mMaxWeight);
- }
- }
- else
- {
- mTargetWeight = target_value;
- }
- mIsAnimating = true;
-
- if (mNext)
- {
- mNext->setAnimationTarget(target_value);
- }
-}
-
-//-----------------------------------------------------------------------------
-// setNextParam()
-//-----------------------------------------------------------------------------
-void LLVisualParam::setNextParam( LLVisualParam *next )
-{
- llassert(!mNext);
- llassert(getWeight() == getDefaultWeight()); // need to establish mNext before we start changing values on this, else initial value won't get mirrored (we can fix that, but better to forbid this pattern)
- mNext = next;
-}
-
-//-----------------------------------------------------------------------------
-// clearNextParam()
-//-----------------------------------------------------------------------------
-void LLVisualParam::clearNextParam()
-{
- mNext = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// animate()
-//-----------------------------------------------------------------------------
-void LLVisualParam::animate( F32 delta)
-{
- if (mIsAnimating)
- {
- F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight;
- setWeight(new_weight);
- }
-}
-
-//-----------------------------------------------------------------------------
-// stopAnimating()
-//-----------------------------------------------------------------------------
-void LLVisualParam::stopAnimating()
-{
- if (mIsAnimating && isTweakable())
- {
- mIsAnimating = false;
- setWeight(mTargetWeight);
- }
-}
-
-//virtual
-bool LLVisualParam::linkDrivenParams(visual_param_mapper mapper, bool only_cross_params)
-{
- // nothing to do for non-driver parameters
- return true;
-}
-
-//virtual
-void LLVisualParam::resetDrivenParams()
-{
- // nothing to do for non-driver parameters
- return;
-}
-
-const std::string param_location_name(const EParamLocation& loc)
-{
- switch (loc)
- {
- case LOC_UNKNOWN: return "unknown";
- case LOC_AV_SELF: return "self";
- case LOC_AV_OTHER: return "other";
- case LOC_WEARABLE: return "wearable";
- default: return "error";
- }
-}
-
-void LLVisualParam::setParamLocation(EParamLocation loc)
-{
- if (mParamLocation == LOC_UNKNOWN || loc == LOC_UNKNOWN)
- {
- mParamLocation = loc;
- }
- else if (mParamLocation == loc)
- {
- // no action
- }
- else
- {
- LL_DEBUGS() << "param location is already " << mParamLocation << ", not slamming to " << loc << LL_ENDL;
- }
-}
-
+/** + * @file llvisualparam.cpp + * @brief Implementation of LLPolyMesh class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" + +#include "llvisualparam.h" + +//----------------------------------------------------------------------------- +// LLVisualParamInfo() +//----------------------------------------------------------------------------- +LLVisualParamInfo::LLVisualParamInfo() + : + mID( -1 ), + mGroup( VISUAL_PARAM_GROUP_TWEAKABLE ), + mMinWeight( 0.f ), + mMaxWeight( 1.f ), + mDefaultWeight( 0.f ), + mSex( SEX_BOTH ) +{ +} + +//----------------------------------------------------------------------------- +// parseXml() +//----------------------------------------------------------------------------- +bool LLVisualParamInfo::parseXml(LLXmlTreeNode *node) +{ + // attribute: id + static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); + node->getFastAttributeS32( id_string, mID ); + + // attribute: group + U32 group = 0; + static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group"); + if( node->getFastAttributeU32( group_string, group ) ) + { + if( group < NUM_VISUAL_PARAM_GROUPS ) + { + mGroup = (EVisualParamGroup)group; + } + } + + // attribute: value_min, value_max + static LLStdStringHandle value_min_string = LLXmlTree::addAttributeString("value_min"); + static LLStdStringHandle value_max_string = LLXmlTree::addAttributeString("value_max"); + node->getFastAttributeF32( value_min_string, mMinWeight ); + node->getFastAttributeF32( value_max_string, mMaxWeight ); + + // attribute: value_default + F32 default_weight = 0; + static LLStdStringHandle value_default_string = LLXmlTree::addAttributeString("value_default"); + if( node->getFastAttributeF32( value_default_string, default_weight ) ) + { + mDefaultWeight = llclamp( default_weight, mMinWeight, mMaxWeight ); + if( default_weight != mDefaultWeight ) + { + LL_WARNS() << "value_default attribute is out of range in node " << mName << " " << default_weight << LL_ENDL; + } + } + + // attribute: sex + std::string sex = "both"; + static LLStdStringHandle sex_string = LLXmlTree::addAttributeString("sex"); + node->getFastAttributeString( sex_string, sex ); // optional + if( sex == "both" ) + { + mSex = SEX_BOTH; + } + else if( sex == "male" ) + { + mSex = SEX_MALE; + } + else if( sex == "female" ) + { + mSex = SEX_FEMALE; + } + else + { + LL_WARNS() << "Avatar file: <param> has invalid sex attribute: " << sex << LL_ENDL; + return false; + } + + // attribute: name + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if( !node->getFastAttributeString( name_string, mName ) ) + { + LL_WARNS() << "Avatar file: <param> is missing name attribute" << LL_ENDL; + return false; + } + + // attribute: label + static LLStdStringHandle label_string = LLXmlTree::addAttributeString("label"); + if( !node->getFastAttributeString( label_string, mDisplayName ) ) + { + mDisplayName = mName; + } + + // JC - make sure the display name includes the capitalization in the XML file, + // not the lowercased version. + LLStringUtil::toLower(mName); + + // attribute: label_min + static LLStdStringHandle label_min_string = LLXmlTree::addAttributeString("label_min"); + if( !node->getFastAttributeString( label_min_string, mMinName ) ) + { + mMinName = "Less"; + } + + // attribute: label_max + static LLStdStringHandle label_max_string = LLXmlTree::addAttributeString("label_max"); + if( !node->getFastAttributeString( label_max_string, mMaxName ) ) + { + mMaxName = "More"; + } + + return true; +} + +//virtual +void LLVisualParamInfo::toStream(std::ostream &out) +{ + out << mID << "\t"; + out << mName << "\t"; + out << mDisplayName << "\t"; + out << mMinName << "\t"; + out << mMaxName << "\t"; + out << mGroup << "\t"; + out << mMinWeight << "\t"; + out << mMaxWeight << "\t"; + out << mDefaultWeight << "\t"; + out << mSex << "\t"; +} + +//----------------------------------------------------------------------------- +// LLVisualParam() +//----------------------------------------------------------------------------- +LLVisualParam::LLVisualParam() + : mCurWeight( 0.f ), + mLastWeight( 0.f ), + mNext( NULL ), + mTargetWeight( 0.f ), + mIsAnimating( false ), + mIsDummy(false), + mID( -1 ), + mInfo( 0 ), + mParamLocation(LOC_UNKNOWN) +{ +} + +//----------------------------------------------------------------------------- +// LLVisualParam() +//----------------------------------------------------------------------------- +LLVisualParam::LLVisualParam(const LLVisualParam& pOther) + : mCurWeight(pOther.mCurWeight), + mLastWeight(pOther.mLastWeight), + mNext(pOther.mNext), + mTargetWeight(pOther.mTargetWeight), + mIsAnimating(pOther.mIsAnimating), + mIsDummy(pOther.mIsDummy), + mID(pOther.mID), + mInfo(pOther.mInfo), + mParamLocation(pOther.mParamLocation) +{ +} + +//----------------------------------------------------------------------------- +// ~LLVisualParam() +//----------------------------------------------------------------------------- +LLVisualParam::~LLVisualParam() +{ + delete mNext; + mNext = NULL; +} + +/* +//============================================================================= +// These virtual functions should always be overridden, +// but are included here for use as templates +//============================================================================= + +//----------------------------------------------------------------------------- +// setInfo() +//----------------------------------------------------------------------------- + +bool LLVisualParam::setInfo(LLVisualParamInfo *info) +{ + llassert(mInfo == NULL); + if (info->mID < 0) + return false; + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight(), false ); + return true; +} + +//----------------------------------------------------------------------------- +// parseData() +//----------------------------------------------------------------------------- +bool LLVisualParam::parseData(LLXmlTreeNode *node) +{ + LLVisualParamInfo *info = new LLVisualParamInfo; + + info->parseXml(node); + if (!setInfo(info)) + return false; + + return true; +} +*/ + +//----------------------------------------------------------------------------- +// setWeight() +//----------------------------------------------------------------------------- +void LLVisualParam::setWeight(F32 weight) +{ + if (mIsAnimating) + { + //RN: allow overshoot + mCurWeight = weight; + } + else if (mInfo) + { + mCurWeight = llclamp(weight, mInfo->mMinWeight, mInfo->mMaxWeight); + } + else + { + mCurWeight = weight; + } + + if (mNext) + { + mNext->setWeight(weight); + } +} + +//----------------------------------------------------------------------------- +// setAnimationTarget() +//----------------------------------------------------------------------------- +void LLVisualParam::setAnimationTarget(F32 target_value) +{ + // don't animate dummy parameters + if (mIsDummy) + { + setWeight(target_value); + mTargetWeight = mCurWeight; + return; + } + + if (mInfo) + { + if (isTweakable()) + { + mTargetWeight = llclamp(target_value, mInfo->mMinWeight, mInfo->mMaxWeight); + } + } + else + { + mTargetWeight = target_value; + } + mIsAnimating = true; + + if (mNext) + { + mNext->setAnimationTarget(target_value); + } +} + +//----------------------------------------------------------------------------- +// setNextParam() +//----------------------------------------------------------------------------- +void LLVisualParam::setNextParam( LLVisualParam *next ) +{ + llassert(!mNext); + llassert(getWeight() == getDefaultWeight()); // need to establish mNext before we start changing values on this, else initial value won't get mirrored (we can fix that, but better to forbid this pattern) + mNext = next; +} + +//----------------------------------------------------------------------------- +// clearNextParam() +//----------------------------------------------------------------------------- +void LLVisualParam::clearNextParam() +{ + mNext = NULL; +} + +//----------------------------------------------------------------------------- +// animate() +//----------------------------------------------------------------------------- +void LLVisualParam::animate( F32 delta) +{ + if (mIsAnimating) + { + F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight; + setWeight(new_weight); + } +} + +//----------------------------------------------------------------------------- +// stopAnimating() +//----------------------------------------------------------------------------- +void LLVisualParam::stopAnimating() +{ + if (mIsAnimating && isTweakable()) + { + mIsAnimating = false; + setWeight(mTargetWeight); + } +} + +//virtual +bool LLVisualParam::linkDrivenParams(visual_param_mapper mapper, bool only_cross_params) +{ + // nothing to do for non-driver parameters + return true; +} + +//virtual +void LLVisualParam::resetDrivenParams() +{ + // nothing to do for non-driver parameters + return; +} + +const std::string param_location_name(const EParamLocation& loc) +{ + switch (loc) + { + case LOC_UNKNOWN: return "unknown"; + case LOC_AV_SELF: return "self"; + case LOC_AV_OTHER: return "other"; + case LOC_WEARABLE: return "wearable"; + default: return "error"; + } +} + +void LLVisualParam::setParamLocation(EParamLocation loc) +{ + if (mParamLocation == LOC_UNKNOWN || loc == LOC_UNKNOWN) + { + mParamLocation = loc; + } + else if (mParamLocation == loc) + { + // no action + } + else + { + LL_DEBUGS() << "param location is already " << mParamLocation << ", not slamming to " << loc << LL_ENDL; + } +} + diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index 83f2269ea1..3caddb9c62 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -1,185 +1,185 @@ -/**
- * @file llvisualparam.h
- * @brief Implementation of LLPolyMesh class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLVisualParam_H
-#define LL_LLVisualParam_H
-
-#include "v3math.h"
-#include "llstring.h"
-#include "llxmltree.h"
-#include <boost/function.hpp>
-
-class LLPolyMesh;
-class LLXmlTreeNode;
-
-enum ESex
-{
- SEX_FEMALE = 0x01,
- SEX_MALE = 0x02,
- SEX_BOTH = 0x03 // values chosen to allow use as a bit field.
-};
-
-enum EVisualParamGroup
-{
- VISUAL_PARAM_GROUP_TWEAKABLE,
- VISUAL_PARAM_GROUP_ANIMATABLE,
- VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT,
- VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE, // deprecated params that used to be tweakable.
- NUM_VISUAL_PARAM_GROUPS
-};
-
-enum EParamLocation
-{
- LOC_UNKNOWN,
- LOC_AV_SELF,
- LOC_AV_OTHER,
- LOC_WEARABLE
-};
-
-const std::string param_location_name(const EParamLocation& loc);
-
-const S32 MAX_TRANSMITTED_VISUAL_PARAMS = 255;
-
-//-----------------------------------------------------------------------------
-// LLVisualParamInfo
-// Contains shared data for VisualParams
-//-----------------------------------------------------------------------------
-class LLVisualParamInfo
-{
- friend class LLVisualParam;
-public:
- LLVisualParamInfo();
- virtual ~LLVisualParamInfo() {};
-
- virtual bool parseXml(LLXmlTreeNode *node);
-
- S32 getID() const { return mID; }
-
- virtual void toStream(std::ostream &out);
-
-protected:
- S32 mID; // ID associated with VisualParam
-
- std::string mName; // name (for internal purposes)
- std::string mDisplayName; // name displayed to the user
- std::string mMinName; // name associated with minimum value
- std::string mMaxName; // name associated with maximum value
- EVisualParamGroup mGroup; // morph group for separating UI controls
- F32 mMinWeight; // minimum weight that can be assigned to this morph target
- F32 mMaxWeight; // maximum weight that can be assigned to this morph target
- F32 mDefaultWeight;
- ESex mSex; // Which gender(s) this param applies to.
-};
-
-//-----------------------------------------------------------------------------
-// LLVisualParam
-// VIRTUAL CLASS
-// An interface class for a generalized parametric modification of the avatar mesh
-// Contains data that is specific to each Avatar
-//-----------------------------------------------------------------------------
-LL_ALIGN_PREFIX(16)
-class LLVisualParam
-{
-public:
- typedef boost::function<LLVisualParam*(S32)> visual_param_mapper;
-
- LLVisualParam();
- virtual ~LLVisualParam();
-
- // Special: These functions are overridden by child classes
- // (They can not be virtual because they use specific derived Info classes)
- LLVisualParamInfo* getInfo() const { return mInfo; }
- // This sets mInfo and calls initialization functions
- bool setInfo(LLVisualParamInfo *info);
-
- // Virtual functions
- // Pure virtuals
- //virtual bool parseData( LLXmlTreeNode *node ) = 0;
- virtual void apply( ESex avatar_sex ) = 0;
- // Default functions
- virtual void setWeight(F32 weight);
- virtual void setAnimationTarget( F32 target_value);
- virtual void animate(F32 delta);
- virtual void stopAnimating();
-
- virtual bool linkDrivenParams(visual_param_mapper mapper, bool only_cross_params);
- virtual void resetDrivenParams();
-
- // Interface methods
- S32 getID() const { return mID; }
- void setID(S32 id) { llassert(!mInfo); mID = id; }
-
- const std::string& getName() const { return mInfo->mName; }
- const std::string& getDisplayName() const { return mInfo->mDisplayName; }
- const std::string& getMaxDisplayName() const { return mInfo->mMaxName; }
- const std::string& getMinDisplayName() const { return mInfo->mMinName; }
-
- void setDisplayName(const std::string& s) { mInfo->mDisplayName = s; }
- void setMaxDisplayName(const std::string& s) { mInfo->mMaxName = s; }
- void setMinDisplayName(const std::string& s) { mInfo->mMinName = s; }
-
- EVisualParamGroup getGroup() const { return mInfo->mGroup; }
- F32 getMinWeight() const { return mInfo->mMinWeight; }
- F32 getMaxWeight() const { return mInfo->mMaxWeight; }
- F32 getDefaultWeight() const { return mInfo->mDefaultWeight; }
- ESex getSex() const { return mInfo->mSex; }
-
- F32 getWeight() const { return mIsAnimating ? mTargetWeight : mCurWeight; }
- F32 getCurrentWeight() const { return mCurWeight; }
- F32 getLastWeight() const { return mLastWeight; }
- void setLastWeight(F32 val) { mLastWeight = val; }
- bool isAnimating() const { return mIsAnimating; }
- bool isTweakable() const { return (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) || (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT); }
-
- LLVisualParam* getNextParam() { return mNext; }
- void setNextParam( LLVisualParam *next );
- void clearNextParam();
-
- virtual void setAnimating(bool is_animating) { mIsAnimating = is_animating && !mIsDummy; }
- bool getAnimating() const { return mIsAnimating; }
-
- void setIsDummy(bool is_dummy) { mIsDummy = is_dummy; }
-
- void setParamLocation(EParamLocation loc);
- EParamLocation getParamLocation() const { return mParamLocation; }
-
-protected:
- LLVisualParam(const LLVisualParam& pOther);
-
- F32 mCurWeight; // current weight
- F32 mLastWeight; // last weight
- LLVisualParam* mNext; // next param in a shared chain
- F32 mTargetWeight; // interpolation target
- bool mIsAnimating; // this value has been given an interpolation target
- bool mIsDummy; // this is used to prevent dummy visual params from animating
-
-
- S32 mID; // id for storing weight/morphtarget compares compactly
- LLVisualParamInfo *mInfo;
- EParamLocation mParamLocation; // where does this visual param live?
-} LL_ALIGN_POSTFIX(16);
-
-#endif // LL_LLVisualParam_H
+/** + * @file llvisualparam.h + * @brief Implementation of LLPolyMesh class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVisualParam_H +#define LL_LLVisualParam_H + +#include "v3math.h" +#include "llstring.h" +#include "llxmltree.h" +#include <boost/function.hpp> + +class LLPolyMesh; +class LLXmlTreeNode; + +enum ESex +{ + SEX_FEMALE = 0x01, + SEX_MALE = 0x02, + SEX_BOTH = 0x03 // values chosen to allow use as a bit field. +}; + +enum EVisualParamGroup +{ + VISUAL_PARAM_GROUP_TWEAKABLE, + VISUAL_PARAM_GROUP_ANIMATABLE, + VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT, + VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE, // deprecated params that used to be tweakable. + NUM_VISUAL_PARAM_GROUPS +}; + +enum EParamLocation +{ + LOC_UNKNOWN, + LOC_AV_SELF, + LOC_AV_OTHER, + LOC_WEARABLE +}; + +const std::string param_location_name(const EParamLocation& loc); + +const S32 MAX_TRANSMITTED_VISUAL_PARAMS = 255; + +//----------------------------------------------------------------------------- +// LLVisualParamInfo +// Contains shared data for VisualParams +//----------------------------------------------------------------------------- +class LLVisualParamInfo +{ + friend class LLVisualParam; +public: + LLVisualParamInfo(); + virtual ~LLVisualParamInfo() {}; + + virtual bool parseXml(LLXmlTreeNode *node); + + S32 getID() const { return mID; } + + virtual void toStream(std::ostream &out); + +protected: + S32 mID; // ID associated with VisualParam + + std::string mName; // name (for internal purposes) + std::string mDisplayName; // name displayed to the user + std::string mMinName; // name associated with minimum value + std::string mMaxName; // name associated with maximum value + EVisualParamGroup mGroup; // morph group for separating UI controls + F32 mMinWeight; // minimum weight that can be assigned to this morph target + F32 mMaxWeight; // maximum weight that can be assigned to this morph target + F32 mDefaultWeight; + ESex mSex; // Which gender(s) this param applies to. +}; + +//----------------------------------------------------------------------------- +// LLVisualParam +// VIRTUAL CLASS +// An interface class for a generalized parametric modification of the avatar mesh +// Contains data that is specific to each Avatar +//----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) +class LLVisualParam +{ +public: + typedef boost::function<LLVisualParam*(S32)> visual_param_mapper; + + LLVisualParam(); + virtual ~LLVisualParam(); + + // Special: These functions are overridden by child classes + // (They can not be virtual because they use specific derived Info classes) + LLVisualParamInfo* getInfo() const { return mInfo; } + // This sets mInfo and calls initialization functions + bool setInfo(LLVisualParamInfo *info); + + // Virtual functions + // Pure virtuals + //virtual bool parseData( LLXmlTreeNode *node ) = 0; + virtual void apply( ESex avatar_sex ) = 0; + // Default functions + virtual void setWeight(F32 weight); + virtual void setAnimationTarget( F32 target_value); + virtual void animate(F32 delta); + virtual void stopAnimating(); + + virtual bool linkDrivenParams(visual_param_mapper mapper, bool only_cross_params); + virtual void resetDrivenParams(); + + // Interface methods + S32 getID() const { return mID; } + void setID(S32 id) { llassert(!mInfo); mID = id; } + + const std::string& getName() const { return mInfo->mName; } + const std::string& getDisplayName() const { return mInfo->mDisplayName; } + const std::string& getMaxDisplayName() const { return mInfo->mMaxName; } + const std::string& getMinDisplayName() const { return mInfo->mMinName; } + + void setDisplayName(const std::string& s) { mInfo->mDisplayName = s; } + void setMaxDisplayName(const std::string& s) { mInfo->mMaxName = s; } + void setMinDisplayName(const std::string& s) { mInfo->mMinName = s; } + + EVisualParamGroup getGroup() const { return mInfo->mGroup; } + F32 getMinWeight() const { return mInfo->mMinWeight; } + F32 getMaxWeight() const { return mInfo->mMaxWeight; } + F32 getDefaultWeight() const { return mInfo->mDefaultWeight; } + ESex getSex() const { return mInfo->mSex; } + + F32 getWeight() const { return mIsAnimating ? mTargetWeight : mCurWeight; } + F32 getCurrentWeight() const { return mCurWeight; } + F32 getLastWeight() const { return mLastWeight; } + void setLastWeight(F32 val) { mLastWeight = val; } + bool isAnimating() const { return mIsAnimating; } + bool isTweakable() const { return (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) || (getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT); } + + LLVisualParam* getNextParam() { return mNext; } + void setNextParam( LLVisualParam *next ); + void clearNextParam(); + + virtual void setAnimating(bool is_animating) { mIsAnimating = is_animating && !mIsDummy; } + bool getAnimating() const { return mIsAnimating; } + + void setIsDummy(bool is_dummy) { mIsDummy = is_dummy; } + + void setParamLocation(EParamLocation loc); + EParamLocation getParamLocation() const { return mParamLocation; } + +protected: + LLVisualParam(const LLVisualParam& pOther); + + F32 mCurWeight; // current weight + F32 mLastWeight; // last weight + LLVisualParam* mNext; // next param in a shared chain + F32 mTargetWeight; // interpolation target + bool mIsAnimating; // this value has been given an interpolation target + bool mIsDummy; // this is used to prevent dummy visual params from animating + + + S32 mID; // id for storing weight/morphtarget compares compactly + LLVisualParamInfo *mInfo; + EParamLocation mParamLocation; // where does this visual param live? +} LL_ALIGN_POSTFIX(16); + +#endif // LL_LLVisualParam_H |