/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "pch.h" #include "AnimationContent.h" #include "EditorCompressionPresetTable.h" #include "EditorDBATable.h" #include "Shared/AnimationFilter.h" #include "CharacterDocument.h" #include #include "Serialization.h" #include "Serialization/Decorators/EditorActionButton.h" #include "EntryList.h" #include #include #include "CharacterDefinition.h" #include "CharacterToolSystem.h" #include #include namespace CharacterTool { AnimationContent::AnimationContent() : type(ANIMATION) , size(-1) , importState(NOT_SET) , loadedInEngine(false) , loadedAsAdditive(false) , animationId(-1) , delayApplyUntilStart(false) , system(nullptr) { } bool AnimationContent::HasAudioEvents() const { for (size_t i = 0; i < events.size(); ++i) { if (IsAudioEventType(events[i].type.c_str())) { return true; } } return false; } void AnimationContent::ApplyToCharacter(bool* triggerPreview, ICharacterInstance* characterInstance, const char* animationPath, bool startingAnimation) { if (startingAnimation) { if (!delayApplyUntilStart) { return; } } IAnimEvents* animEvents = gEnv->pCharacterManager->GetIAnimEvents(); if (IAnimEventList* animEventList = animEvents->GetAnimEventList(animationPath)) { animEventList->Clear(); for (size_t i = 0; i < events.size(); ++i) { CAnimEventData animEvent; events[i].ToData(&animEvent); animEventList->Append(animEvent); } delayApplyUntilStart = false; } else { delayApplyUntilStart = !startingAnimation; } animEvents->InitializeSegmentationDataFromAnimEvents(animationPath); if (type == BLEND_SPACE) { XmlNodeRef xml = blendSpace.SaveToXml(); _smart_ptr content = xml->getXMLData(); gEnv->pCharacterManager->InjectBSPACE(animationPath, content->GetString(), content->GetStringLength()); gEnv->pCharacterManager->ReloadLMG(animationPath); gEnv->pCharacterManager->ClearBSPACECache(); if (triggerPreview) { *triggerPreview = true; } } if (type == COMBINED_BLEND_SPACE) { XmlNodeRef xml = combinedBlendSpace.SaveToXml(); _smart_ptr content = xml->getXMLData(); gEnv->pCharacterManager->InjectBSPACE(animationPath, content->GetString(), content->GetStringLength()); gEnv->pCharacterManager->ReloadLMG(animationPath); gEnv->pCharacterManager->ClearBSPACECache(); if (triggerPreview) { *triggerPreview = true; } } } void AnimationContent::UpdateBlendSpaceMotionParameters(IAnimationSet* animationSet, IDefaultSkeleton* skeleton) { for (size_t i = 0; i < blendSpace.m_examples.size(); ++i) { BlendSpaceExample& e = blendSpace.m_examples[i]; Vec4 v; if (animationSet->GetMotionParameters(animationId, i, skeleton, v)) { if (!e.specified[0]) { e.parameters.x = v.x; } if (!e.specified[1]) { e.parameters.y = v.y; } if (!e.specified[2]) { e.parameters.z = v.z; } if (!e.specified[3]) { e.parameters.w = v.w; } } } } bool IsSkeletonProductFromAssetImporterSource(const char* skeletonPath) { bool fullPathfound = false; AZStd::string assetSourcePath; AZStd::string assetProductPath(skeletonPath); AzFramework::StringFunc::Strip(assetProductPath, '.', true, true); EBUS_EVENT_RESULT(fullPathfound, AzToolsFramework::AssetSystemRequestBus, GetFullSourcePathFromRelativeProductPath, assetProductPath, assetSourcePath); if (fullPathfound) { AZStd::unordered_set extensions; EBUS_EVENT(AZ::SceneAPI::Events::AssetImportRequestBus, GetSupportedFileExtensions, extensions); for (const AZStd::string& extension : extensions) { return AzFramework::StringFunc::Find(assetSourcePath.c_str(), extension.c_str(), 0, true, false) != AZStd::string::npos; } } return false; } void AnimationContent::Serialize(Serialization::IArchive& ar) { if (type == ANIMATION && importState == COMPILED_BUT_NO_ANIMSETTINGS) { if (system && IsSkeletonProductFromAssetImporterSource(system->document->GetLoadedCharacterDefinition()->skeleton.c_str())) { ar.Warning(*this, "Compression settings not available for animations generated from an fbx file."); } else { ar.Warning(*this, "AnimSettings file used to compile the animation is missing. You may need to obtain it from version control.\n\nAlternatively you can create a new AnimSettings file."); bool createNewAnimSettings = false; ar(Serialization::ToggleButton(createNewAnimSettings), "createButton", "()) { SAnimationFilterItem item; item.path = entryBase->path; item.skeletonAlias = settings.build.skeletonAlias; item.tags = settings.build.tags; if (EditorCompressionPresetTable* presetTable = ar.FindContext()) { const EditorCompressionPreset* preset = presetTable->FindPresetForAnimation(item); if (preset) { presetApplied = true; if (ar.OpenBlock("automaticCompressionSettings", "+!Compression Preset")) { ar(preset->entry.name, "preset", "!^"); const_cast(preset)->entry.settings.Serialize(ar); ar.CloseBlock(); } } } if (EditorDBATable* dbaTable = ar.FindContext()) { int dbaIndex = dbaTable->FindDBAForAnimation(item); if (dbaIndex >= 0) { string dbaName = dbaTable->GetEntryByIndex(dbaIndex)->entry.path; ar(dbaName, "dbaName", "()) { UpdateBlendSpaceMotionParameters(characterInstance->GetIAnimationSet(), &characterInstance->GetIDefaultSkeleton()); } } blendSpace.Serialize(ar); } if (type == COMBINED_BLEND_SPACE) { combinedBlendSpace.Serialize(ar); } if (type == ANM) { string msg = "Contains no properties."; ar(msg, "msg", "