Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+72
View File
@@ -0,0 +1,72 @@
# -*- cmake -*-
project(llcharacter)
include(00-Common)
include(LLCommon)
set(llcharacter_SOURCE_FILES
llanimationstates.cpp
llbvhloader.cpp
llcharacter.cpp
lleditingmotion.cpp
llgesture.cpp
llhandmotion.cpp
llheadrotmotion.cpp
lljoint.cpp
lljointsolverrp3.cpp
llkeyframefallmotion.cpp
llkeyframemotion.cpp
llkeyframemotionparam.cpp
llkeyframestandmotion.cpp
llkeyframewalkmotion.cpp
llmotioncontroller.cpp
llmotion.cpp
llmultigesture.cpp
llpose.cpp
llstatemachine.cpp
lltargetingmotion.cpp
llvisualparam.cpp
)
set(llcharacter_HEADER_FILES
CMakeLists.txt
llanimationstates.h
llbvhloader.h
llbvhconsts.h
llcharacter.h
lleditingmotion.h
llgesture.h
llhandmotion.h
llheadrotmotion.h
lljoint.h
lljointsolverrp3.h
lljointstate.h
llkeyframefallmotion.h
llkeyframemotion.h
llkeyframemotionparam.h
llkeyframestandmotion.h
llkeyframewalkmotion.h
llmotion.h
llmotioncontroller.h
llmultigesture.h
llpose.h
llstatemachine.h
lltargetingmotion.h
llvisualparam.h
)
list(APPEND llcharacter_SOURCE_FILES ${llcharacter_HEADER_FILES})
add_library (llcharacter ${llcharacter_SOURCE_FILES})
target_include_directories( llcharacter INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(
llcharacter
llcommon
llmath
llmessage
llfilesystem
llxml
)
+497
View File
@@ -0,0 +1,497 @@
/**
* @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);
// <FS:Zi> Run Prio 0 default bento pose in the background to fix splayed hands, open mouths, etc.
LLUUID const ANIM_AGENT_BENTO_IDLE ("0e720142-0d4b-cf1d-cae5-277f58299604");
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
+265
View File
@@ -0,0 +1,265 @@
/**
* @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;
// <FS:Zi> Run Prio 0 default bento pose in the background to fix splayed hands, open mouths, etc.
extern const LLUUID ANIM_AGENT_BENTO_IDLE;
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
+46
View File
@@ -0,0 +1,46 @@
/**
* @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$
*/
#ifndef LL_LLBVHCONSTS_H
#define LL_LLBVHCONSTS_H
const F32 MAX_ANIM_DURATION = 60.f;
typedef enum e_constraint_type
{
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;
#endif // LL_LLBVHCONSTS_H
File diff suppressed because it is too large Load Diff
+347
View File
@@ -0,0 +1,347 @@
/**
* @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, std::less<>>& 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; }
// <FS:Sei> FIRE-17277: Allow entering Loop In/Loop Out as frames
S32 getNumFrames() const { return mNumFrames; }
// </FS:Sei>
protected:
// Consumes one line of input from file.
// <FS:ND> Remove LLVolatileAPRPool/apr_file_t and use FILE* instead
// bool getLine(apr_file_t *fp);
bool getLine(LLAPRFile::tFiletype *fp);
// </FS:ND>
// 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
+505
View File
@@ -0,0 +1,505 @@
/**
* @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::list< 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) ;
mMotionController.setCharacter( this );
mPauseRequest = new LLPauseRequestHandle();
}
//-----------------------------------------------------------------------------
// ~LLCharacter()
// Class Destructor
//-----------------------------------------------------------------------------
LLCharacter::~LLCharacter()
{
for (const auto& it : mVisualParamIndexMap)
{
delete it.second;
}
llassert_always(sAllowInstancesChange) ;
}
//-----------------------------------------------------------------------------
// getJoint()
//-----------------------------------------------------------------------------
//<FS:Ansariel> Joint-lookup improvements
//LLJoint *LLCharacter::getJoint( const std::string &name )
LLJoint* LLCharacter::getJoint(std::string_view name)
{
LLJoint* joint = NULL;
LLJoint *root = getRootJoint();
if (root)
{
joint = root->findJoint(name);
}
if (!joint)
{
LL_WARNS() << "Failed to find joint: " << name << 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()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//bool LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight)
bool LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, bool upload_bake)
{
S32 index = which_param->getID();
visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
if (index_iter != mVisualParamIndexMap.end())
{
// <FS:Ansariel> [Legacy Bake]
//index_iter->second->setWeight(weight);
index_iter->second->setWeight(weight, upload_bake);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// setVisualParamWeight()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//bool LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
bool LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, bool upload_bake)
{
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())
{
// <FS:Ansariel> [Legacy Bake]
//name_iter->second->setWeight(weight);
name_iter->second->setWeight(weight, upload_bake);
return true;
}
LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL;
return false;
}
//-----------------------------------------------------------------------------
// setVisualParamWeight()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//bool LLCharacter::setVisualParamWeight(S32 index, F32 weight)
bool LLCharacter::setVisualParamWeight(S32 index, F32 weight, bool upload_bake)
{
visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
if (index_iter != mVisualParamIndexMap.end())
{
// <FS:Ansariel> [Legacy Bake]
//index_iter->second->setWeight(weight);
index_iter->second->setWeight(weight, upload_bake);
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())
{
// <FS:Ansariel> [Legacy Bake]
//param->setWeight( param->getDefaultWeight());
param->setWeight( param->getDefaultWeight(), false);
}
}
}
//-----------------------------------------------------------------------------
// getVisualParam()
//-----------------------------------------------------------------------------
LLVisualParam* LLCharacter::getVisualParam(const char *param_name)
{
std::string tname(param_name);
LLStringUtil::toLower(tname);
char *tableptr = sVisualParamNames.checkString(tname);
// <FS:ND> Protect against crashes later on
if( !tableptr )
return 0;
// </FS:ND>
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;
}
+320
View File
@@ -0,0 +1,320 @@
/**
* @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.
//<FS:Ansariel> Joint-lookup improvements
// virtual LLJoint *getJoint( const std::string &name );
virtual LLJoint* getJoint(std::string_view 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);
// <FS:Ansariel> [Legacy Bake]
//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);
virtual bool setVisualParamWeight(const LLVisualParam *which_param, F32 weight, bool upload_bake = false );
virtual bool setVisualParamWeight(const char* param_name, F32 weight, bool upload_bake = false );
virtual bool setVisualParamWeight(S32 index, F32 weight, bool upload_bake = false );
// </FS:Ansariel> [Legacy Bake]
// 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);
// <FS:Ansariel> [Legacy Bake]
//void animateTweakableVisualParams(F32 delta)
void animateTweakableVisualParams(F32 delta, bool upload_bake)
{
for (auto& it : mVisualParamIndexMap)
{
if (it.second->isTweakable())
{
// <FS:Ansariel> [Legacy Bake]
//it.second->animate(delta);
it.second->animate(delta, upload_bake);
}
}
}
void applyAllVisualParams(ESex avatar_sex)
{
for (auto& it : mVisualParamIndexMap)
{
it.second->apply(avatar_sex);
}
}
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::list< 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
+264
View File
@@ -0,0 +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
+135
View File
@@ -0,0 +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
+348
View File
@@ -0,0 +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
auto 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());
}
+113
View File
@@ -0,0 +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 static_cast<S32>(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
+271
View File
@@ -0,0 +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
+139
View File
@@ -0,0 +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
+578
View File
@@ -0,0 +1,578 @@
/**
* @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);
// <FS:ND> Guess we should take the return value of that llclamp...
// llclamp(vergence, -F_PI_BY_TWO, 0.f);
vergence = llclamp(vergence, -F_PI_BY_TWO, 0.f);
// </FS:ND>
}
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
+216
View File
@@ -0,0 +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 diff suppressed because it is too large Load Diff
+309
View File
@@ -0,0 +1,309 @@
/**
* @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
//<FS:Ansariel> Joint-lookup improvements
//LLJoint *findJoint( const std::string &name );
LLJoint* findJoint(std::string_view 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
+395
View File
@@ -0,0 +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
+176
View File
@@ -0,0 +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
+124
View File
@@ -0,0 +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
+150
View File
@@ -0,0 +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
+78
View File
@@ -0,0 +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 diff suppressed because it is too large Load Diff
+464
View File
@@ -0,0 +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 static_cast<U32>(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
+444
View File
@@ -0,0 +1,444 @@
/**
* @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);
// <FS> Fix copy paste error
//if (motion->getDuration() > mEaseInDuration)
if (motion->getEaseInDuration() > mEaseInDuration)
// </FS>
{
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 = &paramMotion;
}
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 = &paramMotion;
}
//...or, if we've seen no other motion so far, make sure we blend to this only
else if (!firstMotion)
{
firstMotion = &paramMotion;
secondMotion = &paramMotion;
}
}
}
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);
// <FS:ND> Remove LLVolatileAPRPool/apr_file_t and use FILE* instead
// apr_file_t* fp = infile.getFileHandle() ;
LLAPRFile::tFiletype* fp = infile.getFileHandle() ;
// </FS:ND>
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
+169
View File
@@ -0,0 +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
+342
View File
@@ -0,0 +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
+118
View File
@@ -0,0 +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
+396
View File
@@ -0,0 +1,396 @@
/**
* @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);
// <FS:CR> Prevent slow walking animation bug
if(foot_speed < 0.0f) foot_speed = 0.0f;
// </FS:CR>
// 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, F32Milliseconds(100.f));
LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
mPelvisState->setRotation(roll);
return true;
}
+174
View File
@@ -0,0 +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
+178
View File
@@ -0,0 +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
+267
View File
@@ -0,0 +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 diff suppressed because it is too large Load Diff
+245
View File
@@ -0,0 +1,245 @@
/**
* @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; }
// <FS:Ansariel> Fix impostered animation speed based on a fix by Henri Beauchamp
void setUpdateFactor(F32 update_factor) { mUpdateFactor = update_factor; }
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
F32 mUpdateFactor; // <FS:Ansariel> Fix impostered animation speed based on a fix by Henri Beauchamp
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
+501
View File
@@ -0,0 +1,501 @@
/**
* @file llmultigesture.cpp
* @brief Gestures that are asset-based and can have multiple steps.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include <algorithm>
#include "stdio.h"
#include "llmultigesture.h"
#include "llerror.h"
#include "lldatapacker.h"
#include "llstl.h"
const S32 GESTURE_VERSION = 2;
//---------------------------------------------------------------------------
// LLMultiGesture
//---------------------------------------------------------------------------
LLMultiGesture::LLMultiGesture()
{
reset();
}
LLMultiGesture::~LLMultiGesture()
{
std::for_each(mSteps.begin(), mSteps.end(), DeletePointer());
mSteps.clear();
}
void LLMultiGesture::reset()
{
mPlaying = false;
mCurrentStep = 0;
mWaitTimer.reset();
mWaitingAnimations = false;
mWaitingKeyRelease = false;
mWaitingTimer = false;
mTriggeredByKey = false;
mKeyReleased = false;
mWaitingAtEnd = false;
mRequestedAnimIDs.clear();
mPlayingAnimIDs.clear();
}
S32 LLMultiGesture::getMaxSerialSize() const
{
S32 max_size = 0;
// ascii format, being very conservative about possible
// label lengths.
max_size += 64; // version S32
max_size += 64; // key U8
max_size += 64; // mask U32
max_size += 256; // trigger string
max_size += 256; // replace string
max_size += 64; // step count S32
for (LLGestureStep* step : mSteps)
{
max_size += 64; // type S32
max_size += step->getMaxSerialSize();
}
/* binary format
max_size += sizeof(S32); // version
max_size += sizeof(mKey);
max_size += sizeof(mMask);
max_size += mTrigger.length() + 1; // for null
max_size += sizeof(S32); // step count
std::vector<LLGestureStep*>::const_iterator it;
for (it = mSteps.begin(); it != mSteps.end(); ++it)
{
LLGestureStep* step = *it;
max_size += sizeof(S32); // type
max_size += step->getMaxSerialSize();
}
*/
return max_size;
}
bool LLMultiGesture::serialize(LLDataPacker& dp) const
{
dp.packS32(GESTURE_VERSION, "version");
dp.packU8(mKey, "key");
dp.packU32(mMask, "mask");
dp.packString(mTrigger, "trigger");
dp.packString(mReplaceText, "replace");
S32 count = (S32)mSteps.size();
dp.packS32(count, "step_count");
S32 i;
for (i = 0; i < count; ++i)
{
LLGestureStep* step = mSteps[i];
dp.packS32(step->getType(), "step_type");
bool ok = step->serialize(dp);
if (!ok)
{
return false;
}
}
return true;
}
bool LLMultiGesture::deserialize(LLDataPacker& dp)
{
S32 version;
dp.unpackS32(version, "version");
if (version != GESTURE_VERSION)
{
LL_WARNS() << "Bad LLMultiGesture version " << version
<< " should be " << GESTURE_VERSION
<< LL_ENDL;
return false;
}
dp.unpackU8(mKey, "key");
dp.unpackU32(mMask, "mask");
dp.unpackString(mTrigger, "trigger");
dp.unpackString(mReplaceText, "replace");
S32 count;
dp.unpackS32(count, "step_count");
if (count < 0)
{
LL_WARNS() << "Bad LLMultiGesture step count " << count << LL_ENDL;
return false;
}
S32 i;
for (i = 0; i < count; ++i)
{
S32 type;
dp.unpackS32(type, "step_type");
EStepType step_type = (EStepType)type;
switch(step_type)
{
case STEP_ANIMATION:
{
LLGestureStepAnimation* step = new LLGestureStepAnimation();
bool ok = step->deserialize(dp);
if (!ok) return false;
mSteps.push_back(step);
break;
}
case STEP_SOUND:
{
LLGestureStepSound* step = new LLGestureStepSound();
bool ok = step->deserialize(dp);
if (!ok) return false;
mSteps.push_back(step);
break;
}
case STEP_CHAT:
{
LLGestureStepChat* step = new LLGestureStepChat();
bool ok = step->deserialize(dp);
if (!ok) return false;
mSteps.push_back(step);
break;
}
case STEP_WAIT:
{
LLGestureStepWait* step = new LLGestureStepWait();
bool ok = step->deserialize(dp);
if (!ok) return false;
mSteps.push_back(step);
break;
}
default:
{
LL_WARNS() << "Bad LLMultiGesture step type " << type << LL_ENDL;
return false;
}
}
}
return true;
}
void LLMultiGesture::dump()
{
LL_INFOS() << "key " << S32(mKey) << " mask " << U32(mMask)
<< " trigger " << mTrigger
<< " replace " << mReplaceText
<< LL_ENDL;
U32 i;
for (i = 0; i < mSteps.size(); ++i)
{
LLGestureStep* step = mSteps[i];
step->dump();
}
}
//---------------------------------------------------------------------------
// LLGestureStepAnimation
//---------------------------------------------------------------------------
LLGestureStepAnimation::LLGestureStepAnimation()
: LLGestureStep(),
mAnimName("None"),
mAnimAssetID(),
mFlags(0x0)
{ }
LLGestureStepAnimation::~LLGestureStepAnimation()
{ }
S32 LLGestureStepAnimation::getMaxSerialSize() const
{
S32 max_size = 0;
// ascii
max_size += 256; // anim name
max_size += 64; // anim asset id
max_size += 64; // flags
/* binary
max_size += mAnimName.length() + 1;
max_size += sizeof(mAnimAssetID);
max_size += sizeof(mFlags);
*/
return max_size;
}
bool LLGestureStepAnimation::serialize(LLDataPacker& dp) const
{
dp.packString(mAnimName, "anim_name");
dp.packUUID(mAnimAssetID, "asset_id");
dp.packU32(mFlags, "flags");
return true;
}
bool LLGestureStepAnimation::deserialize(LLDataPacker& dp)
{
dp.unpackString(mAnimName, "anim_name");
// Apparently an earlier version of the gesture code added \r to the end
// of the animation names. Get rid of it. JC
if (!mAnimName.empty() && mAnimName[mAnimName.length() - 1] == '\r')
{
// chop the last character
mAnimName.resize(mAnimName.length() - 1);
}
dp.unpackUUID(mAnimAssetID, "asset_id");
dp.unpackU32(mFlags, "flags");
return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector<std::string> LLGestureStepAnimation::getLabel() const
{
std::vector<std::string> strings;
// std::string label;
if (mFlags & ANIM_FLAG_STOP)
{
strings.push_back( "AnimFlagStop");
// label = "Stop Animation: ";
}
else
{
strings.push_back( "AnimFlagStart");
// label = "Start Animation: ";
}
strings.push_back( mAnimName);
// label += mAnimName;
return strings;
}
void LLGestureStepAnimation::dump()
{
LL_INFOS() << "step animation " << mAnimName
<< " id " << mAnimAssetID
<< " flags " << mFlags
<< LL_ENDL;
}
//---------------------------------------------------------------------------
// LLGestureStepSound
//---------------------------------------------------------------------------
LLGestureStepSound::LLGestureStepSound()
: LLGestureStep(),
mSoundName("None"),
mSoundAssetID(),
mFlags(0x0)
{ }
LLGestureStepSound::~LLGestureStepSound()
{ }
S32 LLGestureStepSound::getMaxSerialSize() const
{
S32 max_size = 0;
max_size += 256; // sound name
max_size += 64; // sound asset id
max_size += 64; // flags
/* binary
max_size += mSoundName.length() + 1;
max_size += sizeof(mSoundAssetID);
max_size += sizeof(mFlags);
*/
return max_size;
}
bool LLGestureStepSound::serialize(LLDataPacker& dp) const
{
dp.packString(mSoundName, "sound_name");
dp.packUUID(mSoundAssetID, "asset_id");
dp.packU32(mFlags, "flags");
return true;
}
bool LLGestureStepSound::deserialize(LLDataPacker& dp)
{
dp.unpackString(mSoundName, "sound_name");
dp.unpackUUID(mSoundAssetID, "asset_id");
dp.unpackU32(mFlags, "flags");
return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector<std::string> LLGestureStepSound::getLabel() const
{
std::vector<std::string> strings;
strings.push_back( "Sound");
strings.push_back( mSoundName);
// std::string label("Sound: ");
// label += mSoundName;
return strings;
}
void LLGestureStepSound::dump()
{
LL_INFOS() << "step sound " << mSoundName
<< " id " << mSoundAssetID
<< " flags " << mFlags
<< LL_ENDL;
}
//---------------------------------------------------------------------------
// LLGestureStepChat
//---------------------------------------------------------------------------
LLGestureStepChat::LLGestureStepChat()
: LLGestureStep(),
mChatText(),
mFlags(0x0)
{ }
LLGestureStepChat::~LLGestureStepChat()
{ }
S32 LLGestureStepChat::getMaxSerialSize() const
{
S32 max_size = 0;
max_size += 256; // chat text
max_size += 64; // flags
/* binary
max_size += mChatText.length() + 1;
max_size += sizeof(mFlags);
*/
return max_size;
}
bool LLGestureStepChat::serialize(LLDataPacker& dp) const
{
dp.packString(mChatText, "chat_text");
dp.packU32(mFlags, "flags");
return true;
}
bool LLGestureStepChat::deserialize(LLDataPacker& dp)
{
dp.unpackString(mChatText, "chat_text");
dp.unpackU32(mFlags, "flags");
return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector<std::string> LLGestureStepChat::getLabel() const
{
std::vector<std::string> strings;
strings.push_back("Chat");
strings.push_back(mChatText);
return strings;
}
void LLGestureStepChat::dump()
{
LL_INFOS() << "step chat " << mChatText
<< " flags " << mFlags
<< LL_ENDL;
}
//---------------------------------------------------------------------------
// LLGestureStepWait
//---------------------------------------------------------------------------
LLGestureStepWait::LLGestureStepWait()
: LLGestureStep(),
mWaitSeconds(0.f),
mFlags(0x0)
{ }
LLGestureStepWait::~LLGestureStepWait()
{ }
S32 LLGestureStepWait::getMaxSerialSize() const
{
S32 max_size = 0;
max_size += 64; // wait seconds
max_size += 64; // flags
/* binary
max_size += sizeof(mWaitSeconds);
max_size += sizeof(mFlags);
*/
return max_size;
}
bool LLGestureStepWait::serialize(LLDataPacker& dp) const
{
dp.packF32(mWaitSeconds, "wait_seconds");
dp.packU32(mFlags, "flags");
return true;
}
bool LLGestureStepWait::deserialize(LLDataPacker& dp)
{
dp.unpackF32(mWaitSeconds, "wait_seconds");
dp.unpackU32(mFlags, "flags");
return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector<std::string> LLGestureStepWait::getLabel() const
{
std::vector<std::string> strings;
strings.push_back( "Wait" );
// std::string label("--- Wait: ");
if (mFlags & WAIT_FLAG_TIME)
{
char buffer[64]; /* Flawfinder: ignore */
snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */
strings.push_back(buffer);
// label += buffer;
}
else if (mFlags & WAIT_FLAG_ALL_ANIM)
{
strings.push_back("until animations are done");
// label += "until animations are done";
}
else
{
strings.push_back("");
}
return strings;
}
void LLGestureStepWait::dump()
{
LL_INFOS() << "step wait " << mWaitSeconds
<< " flags " << mFlags
<< LL_ENDL;
}
+245
View File
@@ -0,0 +1,245 @@
/**
* @file llmultigesture.h
* @brief Gestures that are asset-based and can have multiple steps.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLMULTIGESTURE_H
#define LL_LLMULTIGESTURE_H
#include <set>
#include <string>
#include <vector>
#include "lluuid.h"
#include "llframetimer.h"
class LLDataPacker;
class LLGestureStep;
class LLMultiGesture
{
public:
LLMultiGesture();
virtual ~LLMultiGesture();
// Maximum number of bytes this could hold once serialized.
S32 getMaxSerialSize() const;
bool serialize(LLDataPacker& dp) const;
bool deserialize(LLDataPacker& dp);
void dump();
void reset();
const std::string& getTrigger() const { return mTrigger; }
protected:
LLMultiGesture(const LLMultiGesture& gest);
const LLMultiGesture& operator=(const LLMultiGesture& rhs);
public:
KEY mKey { 0 };
MASK mMask { 0 };
// This name can be empty if the inventory item is not around and
// the gesture manager has not yet set the name
std::string mName;
// String, like "/foo" or "hello" that makes it play
std::string mTrigger;
// Replaces the trigger substring with this text
std::string mReplaceText;
std::vector<LLGestureStep*> mSteps;
// Is the gesture currently playing?
bool mPlaying { false };
// "instruction pointer" for steps
S32 mCurrentStep { 0 };
// We're waiting for triggered animations to stop playing
bool mWaitingAnimations { false };
// We're waiting for key release
bool mWaitingKeyRelease { false };
// We're waiting a fixed amount of time
bool mWaitingTimer { false };
// We're waiting for triggered animations to stop playing
bool mTriggeredByKey { false };
// Has the key been released?
bool mKeyReleased { false };
// Waiting after the last step played for all animations to complete
bool mWaitingAtEnd { false };
// Timer for waiting
LLFrameTimer mWaitTimer;
void (*mDoneCallback)(LLMultiGesture* gesture, void* data) { NULL };
void* mCallbackData { NULL };
// Animations that we requested to start
std::set<LLUUID> mRequestedAnimIDs;
// Once the animation starts playing (sim says to start playing)
// the ID is moved from mRequestedAnimIDs to here.
std::set<LLUUID> mPlayingAnimIDs;
};
// Order must match the library_list in floater_preview_gesture.xml!
enum EStepType
{
STEP_ANIMATION = 0,
STEP_SOUND = 1,
STEP_CHAT = 2,
STEP_WAIT = 3,
STEP_EOF = 4
};
class LLGestureStep
{
public:
LLGestureStep() {}
virtual ~LLGestureStep() {}
virtual EStepType getType() = 0;
// Return a user-readable label for this step
virtual std::vector<std::string> getLabel() const = 0;
virtual S32 getMaxSerialSize() const = 0;
virtual bool serialize(LLDataPacker& dp) const = 0;
virtual bool deserialize(LLDataPacker& dp) = 0;
virtual void dump() = 0;
};
// By default, animation steps start animations.
// If the least significant bit is 1, it will stop animations.
const U32 ANIM_FLAG_STOP = 0x01;
class LLGestureStepAnimation : public LLGestureStep
{
public:
LLGestureStepAnimation();
virtual ~LLGestureStepAnimation();
virtual EStepType getType() { return STEP_ANIMATION; }
virtual std::vector<std::string> getLabel() const;
virtual S32 getMaxSerialSize() const;
virtual bool serialize(LLDataPacker& dp) const;
virtual bool deserialize(LLDataPacker& dp);
virtual void dump();
public:
std::string mAnimName;
LLUUID mAnimAssetID;
U32 mFlags;
};
class LLGestureStepSound : public LLGestureStep
{
public:
LLGestureStepSound();
virtual ~LLGestureStepSound();
virtual EStepType getType() { return STEP_SOUND; }
virtual std::vector<std::string> getLabel() const;
virtual S32 getMaxSerialSize() const;
virtual bool serialize(LLDataPacker& dp) const;
virtual bool deserialize(LLDataPacker& dp);
virtual void dump();
public:
std::string mSoundName;
LLUUID mSoundAssetID;
U32 mFlags;
};
class LLGestureStepChat : public LLGestureStep
{
public:
LLGestureStepChat();
virtual ~LLGestureStepChat();
virtual EStepType getType() { return STEP_CHAT; }
virtual std::vector<std::string> getLabel() const;
virtual S32 getMaxSerialSize() const;
virtual bool serialize(LLDataPacker& dp) const;
virtual bool deserialize(LLDataPacker& dp);
virtual void dump();
public:
std::string mChatText;
U32 mFlags;
};
const U32 WAIT_FLAG_TIME = 0x01;
const U32 WAIT_FLAG_ALL_ANIM = 0x02;
const U32 WAIT_FLAG_KEY_RELEASE = 0x04;
class LLGestureStepWait : public LLGestureStep
{
public:
LLGestureStepWait();
virtual ~LLGestureStepWait();
virtual EStepType getType() { return STEP_WAIT; }
virtual std::vector<std::string> getLabel() const;
virtual S32 getMaxSerialSize() const;
virtual bool serialize(LLDataPacker& dp) const;
virtual bool deserialize(LLDataPacker& dp);
virtual void dump();
public:
F32 mWaitSeconds;
U32 mFlags;
};
#endif
+569
View File
@@ -0,0 +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();
}
+141
View File
@@ -0,0 +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
+388
View File
@@ -0,0 +1,388 @@
/**
* @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);
// <FS:ND> Remove LLVolatileAPRPool/apr_file_t and use FILE* instead
// apr_file_t* dot_file = outfile.getFileHandle() ;
LLAPRFile::tFiletype* dot_file = outfile.getFileHandle() ;
// </FS:ND>
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;
}
+147
View File
@@ -0,0 +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
+170
View File
@@ -0,0 +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
+116
View File
@@ -0,0 +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
+394
View File
@@ -0,0 +1,394 @@
/**
* @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()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLVisualParam::setWeight(F32 weight)
void LLVisualParam::setWeight(F32 weight, bool upload_bake)
{
if (mIsAnimating)
{
//RN: allow overshoot
mCurWeight = weight;
}
else if (mInfo)
{
mCurWeight = llclamp(weight, mInfo->mMinWeight, mInfo->mMaxWeight);
}
else
{
mCurWeight = weight;
}
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->setWeight(weight);
mNext->setWeight(weight, upload_bake);
}
}
//-----------------------------------------------------------------------------
// setAnimationTarget()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLVisualParam::setAnimationTarget(F32 target_value)
void LLVisualParam::setAnimationTarget(F32 target_value, bool upload_bake)
{
// don't animate dummy parameters
if (mIsDummy)
{
// <FS:Ansariel> [Legacy Bake]
//setWeight(target_value);
setWeight(target_value, upload_bake);
mTargetWeight = mCurWeight;
return;
}
if (mInfo)
{
if (isTweakable())
{
mTargetWeight = llclamp(target_value, mInfo->mMinWeight, mInfo->mMaxWeight);
}
}
else
{
mTargetWeight = target_value;
}
mIsAnimating = true;
if (mNext)
{
// <FS:Ansariel> [Legacy Bake]
//mNext->setAnimationTarget(target_value);
mNext->setAnimationTarget(target_value, upload_bake);
}
}
//-----------------------------------------------------------------------------
// 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()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLVisualParam::animate( F32 delta)
void LLVisualParam::animate( F32 delta, bool upload_bake)
{
if (mIsAnimating)
{
F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight;
// <FS:Ansariel> [Legacy Bake]
//setWeight(new_weight);
setWeight(new_weight, upload_bake);
}
}
//-----------------------------------------------------------------------------
// stopAnimating()
//-----------------------------------------------------------------------------
// <FS:Ansariel> [Legacy Bake]
//void LLVisualParam::stopAnimating()
void LLVisualParam::stopAnimating(bool upload_bake)
{
if (mIsAnimating && isTweakable())
{
mIsAnimating = false;
// <FS:Ansariel> [Legacy Bake]
//setWeight(mTargetWeight);
setWeight(mTargetWeight, upload_bake);
}
}
//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;
}
}
+191
View File
@@ -0,0 +1,191 @@
/**
* @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
// <FS:Ansariel> [Legacy Bake]
//virtual void setWeight(F32 weight);
//virtual void setAnimationTarget( F32 target_value);
//virtual void animate(F32 delta);
//virtual void stopAnimating();
virtual void setWeight(F32 weight, bool upload_bake);
virtual void setAnimationTarget( F32 target_value, bool upload_bake);
virtual void animate(F32 delta, bool upload_bake);
virtual void stopAnimating(bool upload_bake);
// </FS:Ansariel> [Legacy Bake]
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
+242
View File
@@ -0,0 +1,242 @@
/**
* @file lljoint_test.cpp
* @author Adroit
* @date 2007-03
* @brief lljoint test cases.
*
* $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$
*/
#include "linden_common.h"
#include "m4math.h"
#include "v3math.h"
#include "../lljoint.h"
#include "../test/lltut.h"
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();
2) void updateWorldMatrixParent();
3) void updateWorldPRSParent();
4) void updateWorldMatrix();
5) LLXformMatrix *getXform() { return &mXform; }
6) void setConstraintSilhouette(LLDynamicArray<LLVector3>& silhouette);
7) void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot);
*/
}