diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llcharacter | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/llcharacter')
45 files changed, 17279 insertions, 17276 deletions
diff --git a/indra/llcharacter/llanimationstates.cpp b/indra/llcharacter/llanimationstates.cpp index 604c68a225..11c396fa9f 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 1757ce07a1..9eea37a3c8 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/llbvhconsts.h b/indra/llcharacter/llbvhconsts.h index b06c279b8f..3f353fe2cc 100644 --- a/indra/llcharacter/llbvhconsts.h +++ b/indra/llcharacter/llbvhconsts.h @@ -1,25 +1,25 @@ -/** +/** * @file llbvhconsts.h * @brief Consts and types useful to BVH files and 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$ */ @@ -30,17 +30,17 @@ const F32 MAX_ANIM_DURATION = 60.f; typedef enum e_constraint_type - { - CONSTRAINT_TYPE_POINT, - CONSTRAINT_TYPE_PLANE, - NUM_CONSTRAINT_TYPES - } EConstraintType; + { + CONSTRAINT_TYPE_POINT, + CONSTRAINT_TYPE_PLANE, + NUM_CONSTRAINT_TYPES + } EConstraintType; typedef enum e_constraint_target_type - { - CONSTRAINT_TARGET_TYPE_BODY, - CONSTRAINT_TARGET_TYPE_GROUND, - NUM_CONSTRAINT_TARGET_TYPES - } EConstraintTargetType; + { + CONSTRAINT_TARGET_TYPE_BODY, + CONSTRAINT_TARGET_TYPE_GROUND, + NUM_CONSTRAINT_TARGET_TYPES + } EConstraintTargetType; #endif // LL_LLBVHCONSTS_H diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index a277014ca5..988e352fdb 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 1cad8561c3..472192d799 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 abb0495b31..2c66d6f336 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 d134c1cb5b..d845ead44d 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 0eed1ab39e..7ad0aefa6a 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 de78c47da6..0f350af20c 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 b36b83e75e..9dee01c1ee 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 22db9bc565..69b2946866 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 f74c8aa70c..f52530db33 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 828b4851be..7f1b65d48b 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 b327deca64..989c47b847 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 6bab1e8795..602bcb96ad 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 3597f3b63f..888980ac11 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 e1a378e4c3..101121c7cb 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 4b5d1c8894..c22e3cb70b 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 4eb814ee2b..db0a935fea 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 c01ec96450..7c4ded36ac 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 ed6dd69362..58fd99bc5c 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 1ca1ed4dec..e0a212bcc8 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 2706e2ed31..4eb0bc4410 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 be9f35d3e4..a2c3eacbe1 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 dfb6c1ec9f..e2f1602353 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 553d95dbbe..97118ab370 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 5e31d70216..26a4907a01 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 0932a837bd..c77bdacc71 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 1dd743e096..0dce80f0da 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 7539d84db1..0b89dfafa9 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 a0b599663e..c7fbe20dbf 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 d6d7267115..ba719eaac6 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 115606d863..e4dc066d58 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 dea470cbd3..422a038da7 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 73652a15b4..c6b2d84960 100644 --- a/indra/llcharacter/llmultigesture.cpp +++ b/indra/llcharacter/llmultigesture.cpp @@ -1,508 +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() -: mKey(), - mMask(), - mName(), - mTrigger(), - mReplaceText(), - mSteps(), - mPlaying(false), - mCurrentStep(0), - mDoneCallback(NULL), - mCallbackData(NULL) -{ - reset(); -} - -LLMultiGesture::~LLMultiGesture() -{ - std::for_each(mSteps.begin(), mSteps.end(), DeletePointer()); - mSteps.clear(); -} - -void LLMultiGesture::reset() -{ - mPlaying = false; - mCurrentStep = 0; - mWaitTimer.reset(); - mWaitingTimer = false; - mWaitingAnimations = 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 13acbc3f52..b166510721 100644 --- a/indra/llcharacter/llmultigesture.h +++ b/indra/llcharacter/llmultigesture.h @@ -1,235 +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; - MASK mMask; - - // 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; - - // "instruction pointer" for steps - S32 mCurrentStep; - - // We're waiting for triggered animations to stop playing - bool mWaitingAnimations; - - // We're waiting a fixed amount of time - bool mWaitingTimer; - - // Waiting after the last step played for all animations to complete - bool mWaitingAtEnd; - - // Timer for waiting - LLFrameTimer mWaitTimer; - - void (*mDoneCallback)(LLMultiGesture* gesture, void* data); - void* mCallbackData; - - // 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; - -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 1983607d47..0853655199 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 d43956e120..536ff26f1c 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 261eaf0350..1908819ac8 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 521da113e9..7ede949b35 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 87d61a2d36..1029ba40eb 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 b284dd2941..7317003497 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 5930a28ee8..7a5c2654be 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 9cbb3962f4..83f2269ea1 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
diff --git a/indra/llcharacter/tests/lljoint_test.cpp b/indra/llcharacter/tests/lljoint_test.cpp index 617f31b0e4..5a813bac4a 100644 --- a/indra/llcharacter/tests/lljoint_test.cpp +++ b/indra/llcharacter/tests/lljoint_test.cpp @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&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$ */ @@ -37,199 +37,199 @@ namespace tut { - struct lljoint_data - { - }; - typedef test_group<lljoint_data> lljoint_test; - typedef lljoint_test::object lljoint_object; - tut::lljoint_test lljoint_testcase("LLJoint"); - - template<> template<> - void lljoint_object::test<1>() - { - LLJoint lljoint; - LLJoint* jnt = lljoint.getParent(); - ensure("getParent() failed ", (NULL == jnt)); - ensure("getRoot() failed ", (&lljoint == lljoint.getRoot())); - } - - template<> template<> - void lljoint_object::test<2>() - { - std::string str = "LLJoint"; - LLJoint parent(str), child; - child.setup(str, &parent); - LLJoint* jnt = child.getParent(); - ensure("setup() failed ", (&parent == jnt)); - } - - template<> template<> - void lljoint_object::test<3>() - { - LLJoint parent, child; - std::string str = "LLJoint"; - child.setup(str, &parent); - LLJoint* jnt = parent.findJoint(str); - ensure("findJoint() failed ", (&child == jnt)); - } - - template<> template<> - void lljoint_object::test<4>() - { - LLJoint parent; - std::string str1 = "LLJoint", str2; - parent.setName(str1); - str2 = parent.getName(); - ensure("setName() failed ", (str1 == str2)); - } - - template<> template<> - void lljoint_object::test<5>() - { - LLJoint lljoint; - LLVector3 vec3(2.3f,30.f,10.f); - // SL-315 - lljoint.setPosition(vec3); - LLVector3 pos = lljoint.getPosition(); - ensure("setPosition()/getPosition() failed ", (vec3 == pos)); - } - - template<> template<> - void lljoint_object::test<6>() - { - LLJoint lljoint; - LLVector3 vec3(2.3f,30.f,10.f); - // SL-315 - lljoint.setWorldPosition(vec3); - LLVector3 pos = lljoint.getWorldPosition(); - ensure("1:setWorldPosition()/getWorldPosition() failed ", (vec3 == pos)); - LLVector3 lastPos = lljoint.getLastWorldPosition(); - ensure("2:getLastWorldPosition failed ", (vec3 == lastPos)); - } - - template<> template<> - void lljoint_object::test<7>() - { - LLJoint lljoint("LLJoint"); - LLQuaternion q(2.3f,30.f,10.f,1.f); - lljoint.setRotation(q); - LLQuaternion rot = lljoint.getRotation(); - ensure("setRotation()/getRotation() failed ", (q == rot)); - } - template<> template<> - void lljoint_object::test<8>() - { - LLJoint lljoint("LLJoint"); - LLQuaternion q(2.3f,30.f,10.f,1.f); - lljoint.setWorldRotation(q); - LLQuaternion rot = lljoint.getWorldRotation(); - ensure("1:setWorldRotation()/getWorldRotation() failed ", (q == rot)); - LLQuaternion lastRot = lljoint.getLastWorldRotation(); - ensure("2:getLastWorldRotation failed ", (q == lastRot)); - } - - template<> template<> - void lljoint_object::test<9>() - { - LLJoint lljoint; - LLVector3 vec3(2.3f,30.f,10.f); - lljoint.setScale(vec3); - LLVector3 scale = lljoint.getScale(); - ensure("setScale()/getScale failed ", (vec3 == scale)); - } - - template<> template<> - void lljoint_object::test<10>() - { - LLJoint lljoint("LLJoint"); - LLMatrix4 mat; - mat.setIdentity(); - lljoint.setWorldMatrix(mat);//giving warning setWorldMatrix not correctly implemented; - LLMatrix4 mat4 = lljoint.getWorldMatrix(); - ensure("setWorldMatrix()/getWorldMatrix failed ", (mat4 == mat)); - } - - template<> template<> - void lljoint_object::test<11>() - { - S32 joint_num = 12; - LLJoint lljoint(joint_num); - lljoint.setName("parent"); - S32 jointNum = lljoint.getJointNum(); - ensure("getJointNum failed ", (jointNum == joint_num)); - } - - template<> template<> - void lljoint_object::test<12>() - { - LLJoint lljoint; - LLVector3 vec3(2.3f,30.f,10.f); - lljoint.setSkinOffset(vec3); - LLVector3 offset = lljoint.getSkinOffset(); - ensure("1:setSkinOffset()/getSkinOffset() failed ", (vec3 == offset)); - } - - template<> template<> - void lljoint_object::test<13>() - { - LLJoint lljointgp("gparent"); - LLJoint lljoint("parent"); - LLJoint lljoint1("child1"); - lljoint.addChild(&lljoint1); - LLJoint lljoint2("child2"); - lljoint.addChild(&lljoint2); - LLJoint lljoint3("child3"); - lljoint.addChild(&lljoint3); - - LLJoint* jnt = NULL; - jnt = lljoint2.getParent(); - ensure("addChild() failed ", (&lljoint == jnt)); - LLJoint* jnt1 = lljoint.findJoint("child3"); - ensure("findJoint() failed ", (&lljoint3 == jnt1)); - lljoint.removeChild(&lljoint3); - LLJoint* jnt2 = lljoint.findJoint("child3"); - ensure("removeChild() failed ", (NULL == jnt2)); - - lljointgp.addChild(&lljoint); - ensure("GetParent() failed ", (&lljoint== lljoint2.getParent())); - ensure("getRoot() failed ", (&lljointgp == lljoint2.getRoot())); - - ensure("getRoot() failed ", &lljoint1 == lljoint.findJoint("child1")); - - lljointgp.removeAllChildren(); - // parent removed from grandparent - so should not be able to locate child - ensure("removeAllChildren() failed ", (NULL == lljointgp.findJoint("child1"))); - // it should still exist in parent though - ensure("removeAllChildren() failed ", (&lljoint1 == lljoint.findJoint("child1"))); - } - - template<> template<> - void lljoint_object::test<14>() - { - LLJoint lljointgp("gparent"); - - LLJoint llparent1("parent1"); - LLJoint llparent2("parent2"); - - LLJoint llchild("child1"); - LLJoint lladoptedchild("child2"); - llparent1.addChild(&llchild); - llparent1.addChild(&lladoptedchild); - - llparent2.addChild(&lladoptedchild); - ensure("1. addChild failed to remove prior parent", lladoptedchild.getParent() == &llparent2); - ensure("2. addChild failed to remove prior parent", llparent1.findJoint("child2") == NULL); - } - - - /* - Test cases for the following not added. They perform operations - on underlying LLXformMatrix and LLVector3 elements which have - been unit tested separately. - Unit Testing these functions will basically require re-implementing - logic of these function in the test case itself - - 1) void WorldMatrixChildren(); + struct lljoint_data + { + }; + typedef test_group<lljoint_data> lljoint_test; + typedef lljoint_test::object lljoint_object; + tut::lljoint_test lljoint_testcase("LLJoint"); + + template<> template<> + void lljoint_object::test<1>() + { + LLJoint lljoint; + LLJoint* jnt = lljoint.getParent(); + ensure("getParent() failed ", (NULL == jnt)); + ensure("getRoot() failed ", (&lljoint == lljoint.getRoot())); + } + + template<> template<> + void lljoint_object::test<2>() + { + std::string str = "LLJoint"; + LLJoint parent(str), child; + child.setup(str, &parent); + LLJoint* jnt = child.getParent(); + ensure("setup() failed ", (&parent == jnt)); + } + + template<> template<> + void lljoint_object::test<3>() + { + LLJoint parent, child; + std::string str = "LLJoint"; + child.setup(str, &parent); + LLJoint* jnt = parent.findJoint(str); + ensure("findJoint() failed ", (&child == jnt)); + } + + template<> template<> + void lljoint_object::test<4>() + { + LLJoint parent; + std::string str1 = "LLJoint", str2; + parent.setName(str1); + str2 = parent.getName(); + ensure("setName() failed ", (str1 == str2)); + } + + template<> template<> + void lljoint_object::test<5>() + { + LLJoint lljoint; + LLVector3 vec3(2.3f,30.f,10.f); + // SL-315 + lljoint.setPosition(vec3); + LLVector3 pos = lljoint.getPosition(); + ensure("setPosition()/getPosition() failed ", (vec3 == pos)); + } + + template<> template<> + void lljoint_object::test<6>() + { + LLJoint lljoint; + LLVector3 vec3(2.3f,30.f,10.f); + // SL-315 + lljoint.setWorldPosition(vec3); + LLVector3 pos = lljoint.getWorldPosition(); + ensure("1:setWorldPosition()/getWorldPosition() failed ", (vec3 == pos)); + LLVector3 lastPos = lljoint.getLastWorldPosition(); + ensure("2:getLastWorldPosition failed ", (vec3 == lastPos)); + } + + template<> template<> + void lljoint_object::test<7>() + { + LLJoint lljoint("LLJoint"); + LLQuaternion q(2.3f,30.f,10.f,1.f); + lljoint.setRotation(q); + LLQuaternion rot = lljoint.getRotation(); + ensure("setRotation()/getRotation() failed ", (q == rot)); + } + template<> template<> + void lljoint_object::test<8>() + { + LLJoint lljoint("LLJoint"); + LLQuaternion q(2.3f,30.f,10.f,1.f); + lljoint.setWorldRotation(q); + LLQuaternion rot = lljoint.getWorldRotation(); + ensure("1:setWorldRotation()/getWorldRotation() failed ", (q == rot)); + LLQuaternion lastRot = lljoint.getLastWorldRotation(); + ensure("2:getLastWorldRotation failed ", (q == lastRot)); + } + + template<> template<> + void lljoint_object::test<9>() + { + LLJoint lljoint; + LLVector3 vec3(2.3f,30.f,10.f); + lljoint.setScale(vec3); + LLVector3 scale = lljoint.getScale(); + ensure("setScale()/getScale failed ", (vec3 == scale)); + } + + template<> template<> + void lljoint_object::test<10>() + { + LLJoint lljoint("LLJoint"); + LLMatrix4 mat; + mat.setIdentity(); + lljoint.setWorldMatrix(mat);//giving warning setWorldMatrix not correctly implemented; + LLMatrix4 mat4 = lljoint.getWorldMatrix(); + ensure("setWorldMatrix()/getWorldMatrix failed ", (mat4 == mat)); + } + + template<> template<> + void lljoint_object::test<11>() + { + S32 joint_num = 12; + LLJoint lljoint(joint_num); + lljoint.setName("parent"); + S32 jointNum = lljoint.getJointNum(); + ensure("getJointNum failed ", (jointNum == joint_num)); + } + + template<> template<> + void lljoint_object::test<12>() + { + LLJoint lljoint; + LLVector3 vec3(2.3f,30.f,10.f); + lljoint.setSkinOffset(vec3); + LLVector3 offset = lljoint.getSkinOffset(); + ensure("1:setSkinOffset()/getSkinOffset() failed ", (vec3 == offset)); + } + + template<> template<> + void lljoint_object::test<13>() + { + LLJoint lljointgp("gparent"); + LLJoint lljoint("parent"); + LLJoint lljoint1("child1"); + lljoint.addChild(&lljoint1); + LLJoint lljoint2("child2"); + lljoint.addChild(&lljoint2); + LLJoint lljoint3("child3"); + lljoint.addChild(&lljoint3); + + LLJoint* jnt = NULL; + jnt = lljoint2.getParent(); + ensure("addChild() failed ", (&lljoint == jnt)); + LLJoint* jnt1 = lljoint.findJoint("child3"); + ensure("findJoint() failed ", (&lljoint3 == jnt1)); + lljoint.removeChild(&lljoint3); + LLJoint* jnt2 = lljoint.findJoint("child3"); + ensure("removeChild() failed ", (NULL == jnt2)); + + lljointgp.addChild(&lljoint); + ensure("GetParent() failed ", (&lljoint== lljoint2.getParent())); + ensure("getRoot() failed ", (&lljointgp == lljoint2.getRoot())); + + ensure("getRoot() failed ", &lljoint1 == lljoint.findJoint("child1")); + + lljointgp.removeAllChildren(); + // parent removed from grandparent - so should not be able to locate child + ensure("removeAllChildren() failed ", (NULL == lljointgp.findJoint("child1"))); + // it should still exist in parent though + ensure("removeAllChildren() failed ", (&lljoint1 == lljoint.findJoint("child1"))); + } + + template<> template<> + void lljoint_object::test<14>() + { + LLJoint lljointgp("gparent"); + + LLJoint llparent1("parent1"); + LLJoint llparent2("parent2"); + + LLJoint llchild("child1"); + LLJoint lladoptedchild("child2"); + llparent1.addChild(&llchild); + llparent1.addChild(&lladoptedchild); + + llparent2.addChild(&lladoptedchild); + ensure("1. addChild failed to remove prior parent", lladoptedchild.getParent() == &llparent2); + ensure("2. addChild failed to remove prior parent", llparent1.findJoint("child2") == NULL); + } + + + /* + Test cases for the following not added. They perform operations + on underlying LLXformMatrix and LLVector3 elements which have + been unit tested separately. + Unit Testing these functions will basically require re-implementing + logic of these function in the test case itself + + 1) void WorldMatrixChildren(); 2) void updateWorldMatrixParent(); 3) void updateWorldPRSParent(); 4) void updateWorldMatrix(); @@ -237,6 +237,6 @@ namespace tut 6) void setConstraintSilhouette(LLDynamicArray<LLVector3>& silhouette); 7) void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot); - */ + */ } |