1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "ecs_animation.h" 16 17#include <algorithm> 18#include <PropertyTools/property_api_impl.inl> 19#include <PropertyTools/property_data.h> 20 21#include <3d/ecs/systems/intf_animation_system.h> 22#include <3d/ecs/systems/intf_node_system.h> 23#include <core/intf_engine.h> 24 25#include <meta/api/make_callback.h> 26 27#include "ecs_util.h" 28 29using namespace BASE_NS; 30using namespace CORE_NS; 31using namespace CORE3D_NS; 32using namespace META_NS; 33 34SCENE_BEGIN_NAMESPACE() 35 36namespace { 37 38bool EndsWith(string_view str, string_view postfix) 39{ 40 return str.size() >= postfix.size() && 0 == str.compare(str.size() - postfix.size(), postfix.size(), postfix); 41} 42 43template<typename type> 44const BASE_NS::Uid GetArrayTypeUid() 45{ 46 return UidFromType<type[]>(); 47} 48 49PropertyData::PropertyOffset RLock(IPropertyHandle& targetHandle, string_view property) 50{ 51 PropertyData pData; 52 53 string path, name; 54 auto containerHandle = ResolveContainerProperty(targetHandle, string(property), path, name); 55 if (containerHandle) { 56 if (auto po = pData.RLock(*containerHandle, name); po) { 57 return po; 58 } 59 } 60 61 if (auto po = pData.RLock(targetHandle, property); po) { 62 return po; 63 } 64 65 return PropertyData::PropertyOffset(); 66} 67 68BASE_NS::string ResolvePathToAnimationRoot(IEcs& ecs, Entity root, Entity target) 69{ 70 BASE_NS::string result; 71 72 CORE3D_NS::INodeSystem* nodeSystem = GetSystem<INodeSystem>(ecs); 73 if (nodeSystem) { 74 auto rootNode = nodeSystem->GetNode(root); 75 auto node = nodeSystem->GetNode(target); 76 if (rootNode && node) { 77 if (rootNode->IsAncestorOf(*node)) { 78 auto current = node; 79 while (current) { 80 // Found root node, break. 81 if (current == rootNode) { 82 break; 83 } 84 85 // Add this to path. 86 if (result.empty()) { 87 result = current->GetName(); 88 } else { 89 result = current->GetName() + "/" + result; 90 } 91 92 // Process parent next. 93 current = current->GetParent(); 94 } 95 } 96 } 97 } 98 99 return result; 100} 101 102void UpdateTrackTargets(IEcs& ecs, Entity animationEntity, Entity rootNode) 103{ 104 auto& nameManager_ = *GetManager<INameComponentManager>(ecs); 105 auto animationManager = GetManager<IAnimationComponentManager>(ecs); 106 auto animationTrackManager = GetManager<IAnimationTrackComponentManager>(ecs); 107 auto& entityManager = ecs.GetEntityManager(); 108 109 auto* nodeSystem = GetSystem<INodeSystem>(ecs); 110 CORE_ASSERT(nodeSystem); 111 if (!nodeSystem) { 112 return; 113 } 114 auto* node = nodeSystem->GetNode(rootNode); 115 CORE_ASSERT(node); 116 if (!node) { 117 return; 118 } 119 120 if (const ScopedHandle<const AnimationComponent> animationData = animationManager->Read(animationEntity); 121 animationData) { 122 vector<Entity> targetEntities; 123 targetEntities.reserve(animationData->tracks.size()); 124 std::transform(animationData->tracks.begin(), animationData->tracks.end(), std::back_inserter(targetEntities), 125 [&nameManager = nameManager_, &node](const Entity& trackEntity) { 126 if (auto nameHandle = nameManager.Read(trackEntity); nameHandle) { 127 if (nameHandle->name.empty()) { 128 return node->GetEntity(); 129 } else { 130 if (auto targetNode = node->LookupNodeByPath(nameHandle->name); targetNode) { 131 return targetNode->GetEntity(); 132 } 133 } 134 } 135 return Entity {}; 136 }); 137 if (animationData->tracks.size() == targetEntities.size()) { 138 auto targetIt = targetEntities.begin(); 139 for (const auto& trackEntity : animationData->tracks) { 140 if (auto track = animationTrackManager->Write(trackEntity); track) { 141 if (track->target) { 142 CORE_LOG_D("AnimationTrack %s already targetted", 143 to_hex(static_cast<const Entity&>(track->target).id).data()); 144 } 145 track->target = entityManager.GetReferenceCounted(*targetIt); 146 } 147 ++targetIt; 148 } 149 } 150 } 151} 152} // namespace 153 154IProperty::Ptr EcsTrackAnimation::Keyframes() const 155{ 156 return keyframes_; 157} 158 159size_t EcsTrackAnimation::AddKeyframe(float timestamp, const META_NS::IAny::ConstPtr& from) 160{ 161 // TODO: Implement. 162 return {}; 163} 164 165bool EcsTrackAnimation::RemoveKeyframe(size_t index) 166{ 167 // TODO: Implement. 168 return false; 169} 170void EcsTrackAnimation::RemoveAllKeyframes() 171{ 172 // TODO: Implement. 173} 174 175bool EcsTrackAnimation::Build(const META_NS::IMetadata::Ptr&) 176{ 177 auto& registry = META_NS::GetObjectRegistry(); 178 179 auto arr = ConstructArrayProperty<float>("Keyframes", {}, META_NS::ObjectFlagBits::NONE); 180 keyframes_ = arr.GetProperty(); 181 if (!keyframes_) { 182 CORE_LOG_E("Invalid property type for EcsTrackAnimation: <float>"); 183 return false; 184 } 185 return true; 186} 187 188void EcsTrackAnimation::Step(const META_NS::IClock::ConstPtr& clock) 189{ 190 // TODO: Implement. 191} 192 193void EcsTrackAnimation::Start() 194{ 195 // TODO: Implement. 196 META_NS::Invoke<META_NS::IOnChanged>(OnStarted()); 197} 198 199void EcsTrackAnimation::Stop() 200{ 201} 202 203void EcsTrackAnimation::Pause() 204{ 205} 206 207void EcsTrackAnimation::Restart() 208{ 209 Stop(); 210 Start(); 211} 212 213void EcsTrackAnimation::Finish() 214{ 215 // TODO: Implement. 216} 217 218void EcsTrackAnimation::Seek(float position) 219{ 220 // TODO: Implement. 221} 222 223BASE_NS::string EcsAnimation::GetName() const 224{ 225 return Name()->GetValue(); 226} 227 228bool EcsAnimation::Build(const META_NS::IMetadata::Ptr& /*data*/) 229{ 230 GetSelf<META_NS::IRequiredInterfaces>()->SetRequiredInterfaces({ IEcsTrackAnimation::UID }); 231 232 // TODO: Loop count. 233 // TODO: Running. 234 Name()->OnChanged()->AddHandler(MakeCallback<IOnChanged>([this] { OnNamePropertyChanged(); })); 235 Duration()->OnChanged()->AddHandler(MakeCallback<IOnChanged>([this] { OnDurationPropertyChanged(); })); 236 Progress()->OnChanged()->AddHandler(MakeCallback<IOnChanged>([this] { OnProgressPropertyChanged(); })); 237 238 return true; 239} 240 241bool EcsAnimation::SetRootEntity(CORE_NS::Entity entity) 242{ 243 if (EntityUtil::IsValid(root_)) { 244 // Cannot change root entity, once set. 245 return entity == root_; 246 } 247 248 root_ = entity; 249 return true; 250} 251 252CORE_NS::Entity EcsAnimation::GetRootEntity() const 253{ 254 return root_; 255} 256 257bool EcsAnimation::Retarget(CORE_NS::Entity entity) 258{ 259 if (ecs_) { 260 UpdateTrackTargets(*ecs_, GetEntity(), entity); 261 root_ = entity; 262 263 return true; 264 } 265 return false; 266} 267 268void EcsAnimation::SetEntity(CORE_NS::IEcs& ecs, CORE_NS::Entity entity) 269{ 270 ecs_ = &ecs; 271 entity_ = ecs_->GetEntityManager().GetReferenceCounted(entity); 272 animationStateManager_ = nullptr; 273 274 for (auto manager : ecs.GetComponentManagers()) { 275 if (manager->GetName() == "AnimationStateComponent") { 276 animationStateManager_ = manager; 277 break; 278 } 279 } 280 281 animationManager_ = GetManager<IAnimationComponentManager>(*ecs_); 282 animationTrackManager_ = GetManager<IAnimationTrackComponentManager>(*ecs_); 283 animationInputManager_ = GetManager<IAnimationInputComponentManager>(*ecs_); 284 animationOutputManager_ = GetManager<IAnimationOutputComponentManager>(*ecs_); 285 nameManager_ = GetManager<INameComponentManager>(*ecs_); 286 287 OnAnimationNameChanged(IEcs::ComponentListener::EventType::MODIFIED); 288 OnAnimationChanged(IEcs::ComponentListener::EventType::MODIFIED); 289 290 if (auto ecsListener = ecsListener_.lock()) { 291 auto po = GetSelf<SCENE_NS::IEcsProxyObject>(); 292 ecsListener->AddEntity(entity_, po, *nameManager_); 293 ecsListener->AddEntity(entity_, po, *animationStateManager_); 294 ecsListener->AddEntity(entity_, po, *animationManager_); 295 ecsListener->AddEntity(entity_, po, *animationTrackManager_); 296 ecsListener->AddEntity(entity_, po, *animationInputManager_); 297 } 298 299 // If the animation root is not set, then try to resolve it. 300 if (!EntityUtil::IsValid(root_)) { 301 root_ = TryResolveAnimationRoot(); 302 } 303 304 META_ACCESS_PROPERTY(Valid)->SetValue(true); 305} 306 307CORE_NS::Entity EcsAnimation::TryResolveAnimationRoot() 308{ 309 if (!ecs_) { 310 return CORE_NS::Entity {}; 311 } 312 313 CORE3D_NS::INodeSystem* nodeSystem = GetSystem<INodeSystem>(*ecs_); 314 315 // We will try to resolve the animation root from the first animation track. 316 auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 317 if (tracks.empty()) { 318 // No way to resolve, no tracks. 319 return {}; 320 } 321 322 IEcsTrackAnimation::Ptr track = tracks.at(0); 323 324 BASE_NS::string path; 325 if (auto nameHandle = nameManager_->Read(track->GetEntity()); nameHandle) { 326 // The name of the track actually represents the path to the animated entity. 327 path = nameHandle->name; 328 } 329 330 ISceneNode* node = nullptr; 331 if (auto trackHandle = animationTrackManager_->Read(track->GetEntity()); trackHandle) { 332 // This is the node that is being animated by the path. 333 node = nodeSystem->GetNode(trackHandle->target); 334 if (!node) { 335 return {}; 336 } 337 338 // Resolve the path to parent. 339 while (!path.empty()) { 340 BASE_NS::string suffix = node->GetName(); 341 if (EndsWith(path, suffix)) { 342 // Remove name of this node from the path. 343 path = string(path.substr(0, path.length() - suffix.length())); 344 if (EndsWith(path, "/")) { 345 path = string(path.substr(0, path.length() - 1)); 346 } 347 // Go up the tree. 348 node = node->GetParent(); 349 } else { 350 // Error. 351 node = nullptr; 352 break; 353 } 354 } 355 } 356 357 if (node) { 358 SetRootEntity(node->GetEntity()); 359 } 360 361 return node ? node->GetEntity() : Entity {}; 362} 363 364void EcsAnimation::AddAnimation(const IAnimation::Ptr& animation) 365{ 366 GetSelf<META_NS::IContainer>()->Add(interface_pointer_cast<IObject>(animation)); 367 // ToDo: Can we rely that someone has added an listener for tracks 368} 369 370void EcsAnimation::RemoveAnimation(const IAnimation::Ptr& animation) 371{ 372 GetSelf<META_NS::IContainer>()->Remove(interface_pointer_cast<IObject>(animation)); 373 // ToDo: In principle, the tracks should deal common listener and removing parent, might be worth checking though 374} 375 376vector<IAnimation::Ptr> EcsAnimation::GetAnimations() const 377{ 378 return META_NS::GetAll<IAnimation>(GetSelf<META_NS::IContainer>()); 379} 380 381void EcsAnimation::DoComponentEvent( 382 IEcs::ComponentListener::EventType type, const IComponentManager& componentManager, const CORE_NS::Entity& entity) 383{ 384 bool isAnimationNameChange = componentManager.GetUid() == INameComponentManager::UID; 385 bool isAnimationChange = componentManager.GetUid() == IAnimationComponentManager::UID; 386 bool isAnimationStateChange = componentManager.GetUid() == animationStateManager_->GetUid(); 387 bool isAnimationInputChange = componentManager.GetUid() == IAnimationInputComponentManager::UID; 388 bool isAnimationTrackChange = componentManager.GetUid() == IAnimationTrackComponentManager::UID; 389 390 if (isAnimationChange || isAnimationStateChange) { 391 // For animation and animation state, we are interested about changes concerning entity_. 392 393 if (isAnimationChange) { 394 // Animation has changed for this entity. 395 OnAnimationChanged(type); 396 } else if (isAnimationStateChange) { 397 // Animation state has changed for this entity. 398 OnAnimationStateChanged(type); 399 } 400 } else if (isAnimationTrackChange) { 401 OnAnimationTracksChanged(type, entity); 402 } else if (isAnimationInputChange) { 403 OnAnimationInputsChanged(type, entity); 404 } else if (isAnimationNameChange) { 405 OnAnimationNameChanged(type); 406 } 407} 408 409void EcsAnimation::OnAnimationStateChanged(IEcs::ComponentListener::EventType event) 410{ 411 // This function is triggered when ECS dispatch changes at the end of the frame. 412 if (!ecs_ || event != IEcs::ComponentListener::EventType::MODIFIED) { 413 return; 414 } 415 416 // Propagate changes back to object's properties. 417 auto stateHandle = animationStateManager_->GetData(entity_); 418 const auto metaData = stateHandle->Owner()->MetaData(); 419 for (const auto& data : metaData) { 420 if (data.name == "time") { 421 auto* time = static_cast<const float*>( 422 static_cast<const void*>(static_cast<const uint8_t*>(stateHandle->RLock()) + data.offset)); 423 424 updateGuard_ = true; 425 auto duration = GetValue(TotalDuration()).ToSecondsFloat(); 426 if (duration > 0) { 427 SetProgress(*time / duration); 428 } else { 429 SetProgress(0); 430 } 431 updateGuard_ = false; 432 433 stateHandle->RUnlock(); 434 break; 435 } 436 } 437} 438 439void EcsAnimation::OnAnimationNameChanged(IEcs::ComponentListener::EventType event) 440{ 441 // This function is triggered when ECS dispatch changes at the end of the frame. 442 if (!ecs_ || event != IEcs::ComponentListener::EventType::MODIFIED) { 443 return; 444 } 445 446 if (nameManager_->HasComponent(GetEntity())) { 447 updateGuard_ = true; 448 SetValue(Name(), nameManager_->Get(GetEntity()).name); 449 updateGuard_ = false; 450 } 451} 452 453void EcsAnimation::OnAnimationChanged(IEcs::ComponentListener::EventType event) 454{ 455 // This function is triggered when ECS dispatch changes at the end of the frame. 456 if (!ecs_ || event == IEcs::ComponentListener::EventType::DESTROYED) { 457 return; 458 } 459 460 // Propagate changes back to object's properties. 461 auto handle = animationManager_->Read(entity_); 462 if (handle) { 463 updateGuard_ = true; 464 repeatCount_ = static_cast<int32_t>(handle->repeatCount); 465 // Update animation duration. 466 SetValue(META_ACCESS_PROPERTY(Duration), TimeSpan::Seconds(handle->duration)); 467 updateGuard_ = false; 468 469 // Update animation tracks, if needed. 470 if (IsAnimationTrackArrayModified()) { 471 GatherAnimationTracks(); 472 } 473 } 474} 475 476void EcsAnimation::OnAnimationTracksChanged(IEcs::ComponentListener::EventType event, CORE_NS::Entity entity) 477{ 478 bool animationHasNewOrRemovedTracks = false; 479 480 auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 481 482 // Go through all created / modified / destroyed track entities. 483 auto iterator = std::find_if( 484 tracks.begin(), tracks.end(), [entity](const auto& track) { return track->GetEntity() == entity; }); 485 if (iterator != tracks.end()) { 486 // Animation track was reported changed. 487 if (event == IEcs::ComponentListener::EventType::MODIFIED) { 488 // An animation track has been modified, so update it. 489 auto index = std::distance(tracks.begin(), iterator); 490 491 auto track = tracks.at(index); 492 OnAnimationTrackChanged(*track, entity); 493 494 } else { 495 // If we have new or removed tracks, we will simply update all. 496 animationHasNewOrRemovedTracks = true; 497 } 498 } 499 500 // If new or removed tracks, refresh all. 501 if (animationHasNewOrRemovedTracks) { 502 GatherAnimationTracks(); 503 } 504} 505 506void EcsAnimation::OnAnimationInputsChanged(IEcs::ComponentListener::EventType event, CORE_NS::Entity entity) 507{ 508 if (!ecs_) { 509 return; 510 } 511 512 auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 513 // Go through all created / modified / destroyed track entities. 514 for (size_t i = 0; i < tracks.size(); ++i) { 515 auto track = tracks.at(i); 516 if (auto trackHandle = animationTrackManager_->Read(track->GetEntity()); trackHandle) { 517 if (trackHandle->timestamps == entity) { 518 // Timestamps for this track have changed. 519 OnAnimationTimestampsChanged(*track, trackHandle->timestamps); 520 break; 521 } 522 } 523 } 524} 525 526bool EcsAnimation::IsAnimationTrackArrayModified() 527{ 528 if (!ecs_) { 529 return false; 530 } 531 532 auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 533 auto handle = animationManager_->Read(entity_); 534 if (handle) { 535 if (handle->tracks.size() != tracks.size()) { 536 // The amount of tracks is different. 537 return true; 538 } 539 540 for (size_t i = 0; i < handle->tracks.size(); ++i) { 541 if (tracks.at(i)->GetEntity() != handle->tracks[i]) { 542 // Track entity id has changed. 543 return true; 544 } 545 } 546 } 547 548 return false; 549} 550 551void EcsAnimation::GatherAnimationTracks() 552{ 553 if (!ecs_) { 554 return; 555 } 556 557 // Take copy of the animation tracks. 558 auto oldTracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 559 560 // Clear tracks. 561 GetSelf<META_NS::IContainer>()->RemoveAll(); 562 563 // Update animation tracks. 564 auto handle = animationManager_->Read(entity_); 565 if (handle) { 566 for (const auto& track : handle->tracks) { 567 // See if we have this track stored. 568 auto it = std::find_if(oldTracks.begin(), oldTracks.end(), [track](const auto& t) { 569 if (t->GetEntity() == track) { 570 return true; 571 } 572 return false; 573 }); 574 575 IEcsTrackAnimation::Ptr animationTrack; 576 if (it != oldTracks.end()) { 577 animationTrack = *it; 578 } else { 579 animationTrack = 580 META_NS::GetObjectRegistry().Create<IEcsTrackAnimation>(SCENE_NS::ClassId::EcsTrackAnimation); 581 interface_pointer_cast<SCENE_NS::IEcsProxyObject>(animationTrack) 582 ->SetCommonListener(ecsListener_.lock()); 583 } 584 585 OnAnimationTrackChanged(*animationTrack, track); 586 GetSelf<META_NS::IContainer>()->Add(interface_pointer_cast<IObject>(animationTrack)); 587 } 588 } 589} 590 591void EcsAnimation::OnAnimationTrackChanged(IEcsTrackAnimation& track, Entity trackEntity) 592{ 593 if (!ecs_ || updateGuard_) { 594 return; 595 } 596 597 if (auto trackHandle = animationTrackManager_->Read(trackEntity); trackHandle) { 598 auto nameComponent = nameManager_->Get(trackHandle->target.operator Entity()); 599 600 track.SetEntity(trackEntity); 601 602 auto named = interface_cast<INamed>(&track); 603 if (named) { 604 SetValue(named->Name(), nameComponent.name + '.' + trackHandle->property.data()); 605 } 606 OnAnimationTimestampsChanged(track, trackHandle->timestamps); 607 } 608} 609 610void EcsAnimation::UpdateTimestamps(IEcsTrackAnimation& track, Entity timestampEntity) 611{ 612 if (!ecs_) { 613 return; 614 } 615 616 if (animationInputManager_->HasComponent(timestampEntity)) { 617 const auto timestamps = animationInputManager_->Get(timestampEntity); 618 const auto trackAnimation = interface_cast<ITrackAnimation>(&track); 619 const auto timedAnimation = interface_cast<ITimedAnimation>(&track); 620 621 vector<float> times; 622 times.reserve(timestamps.timestamps.size()); 623 624 const auto duration = META_NS::GetValue(timedAnimation->Duration()).ToSecondsFloat(); 625 626 for (const auto timestamp : timestamps.timestamps) { 627 const auto offset = (duration > 0) ? (timestamp / duration) : 0.0f; 628 times.push_back(offset); 629 } 630 631 trackAnimation->Timestamps()->SetValue(times); 632 } 633} 634void EcsAnimation::OnAnimationTimestampsChanged(IEcsTrackAnimation& track, Entity timestampEntity) 635{ 636 if (!ecs_ || updateGuard_) { 637 return; 638 } 639 640 UpdateTimestamps(track, timestampEntity); 641 642 // If any of the tracks in this animation is sharing the same timestamps, then make all tracks read-only. 643 bool hasSharedTimestamps = false; 644 645 auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 646 for (const auto& other : tracks) { 647 if (other->GetEntity() != track.GetEntity()) { 648 if (auto trackHandle = animationTrackManager_->Read(other->GetEntity()); trackHandle) { 649 if (trackHandle->timestamps == timestampEntity) { 650 hasSharedTimestamps = true; 651 break; 652 } 653 } 654 } 655 } 656 657 if (GetValue(ReadOnly()) != hasSharedTimestamps) { 658 META_ACCESS_PROPERTY(ReadOnly)->SetValue(hasSharedTimestamps); 659 } 660} 661 662void EcsAnimation::SetDuration(uint32_t ms) 663{ 664 if (!ecs_) { 665 return; 666 } 667 668 const auto newDuration = TimeSpan::Milliseconds(ms); 669 const auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 670 for (const auto& track : tracks) { 671 if (const auto trackHandle = animationTrackManager_->Read(track->GetEntity()); trackHandle) { 672 interface_cast<META_NS::ITimedAnimation>(track)->Duration()->SetValue(newDuration); 673 UpdateTimestamps(*track, trackHandle->timestamps); 674 } 675 } 676 677 META_ACCESS_PROPERTY(Duration)->SetValue(newDuration); 678} 679 680void EcsAnimation::AddKey(IEcsTrackAnimation::Ptr track, float time) 681{ 682 if (!ecs_) { 683 return; 684 } 685 686 updateGuard_ = true; 687 688 auto handle = animationTrackManager_->Read(track->GetEntity()); 689 if (handle) { 690 auto propertyData = GetProperty(handle->component, handle->target, handle->property); 691 if (propertyData) { 692 SetKeyFrameData(track->GetEntity(), time, propertyData.data); 693 } 694 } 695 696 UpdateAnimationTrackDuration(track->GetEntity()); 697 698 updateGuard_ = false; 699 700 uint32_t timeMs = static_cast<uint32_t>(time * 1000.0f); 701 if (GetValue(Duration()).ToMilliseconds() < timeMs) { 702 META_ACCESS_PROPERTY(Duration)->SetValue(TimeSpan::Milliseconds(timeMs)); 703 } 704 705 OnAnimationTrackChanged(*track, track->GetEntity()); 706} 707 708void EcsAnimation::RemoveKey(IEcsTrackAnimation::Ptr track, uint32_t index) 709{ 710 if (!ecs_) { 711 return; 712 } 713 714 updateGuard_ = true; 715 716 // remove timestamp at pos 717 if (auto animationTrack = animationTrackManager_->Read(track->GetEntity()); animationTrack) { 718 auto stampsEntity = animationTrack->timestamps.operator Entity(); 719 auto inputData = animationInputManager_->Write(stampsEntity); 720 vector<float>::iterator iit = inputData->timestamps.begin(); 721 inputData->timestamps.erase(iit + index); 722 // remove data at pos 723 auto dataEntity = animationTrack->data.operator Entity(); 724 if (auto outputData = animationOutputManager_->Write(dataEntity); outputData) { 725 auto targetEntity = animationTrack->target.operator Entity(); 726 727 auto manager = ecs_->GetComponentManager(animationTrack->component); 728 729 auto target = manager->GetData(targetEntity); 730 auto poffset = RLock(*target, animationTrack->property); 731 vector<uint8_t>::iterator oit = outputData->data.begin(); 732 outputData->data.erase(oit + (index * poffset.property->size), 733 oit + (index * poffset.property->size) + poffset.property->size); 734 } 735 } 736 737 updateGuard_ = false; 738 739 OnAnimationTrackChanged(*track, track->GetEntity()); 740} 741 742void EcsAnimation::UpdateKey(IEcsTrackAnimation::Ptr track, uint32_t oldKeyIndex, uint32_t newKeyIndex, float time) 743{ 744 if (!ecs_) { 745 return; 746 } 747 748 updateGuard_ = true; 749 750 { 751 auto animationTrack = animationTrackManager_->Read(track->GetEntity()); 752 auto stampsEntity = animationTrack->timestamps.operator Entity(); 753 auto inputData = animationInputManager_->Write(stampsEntity); 754 755 auto dataEntity = animationTrack->data.operator Entity(); 756 auto outputData = animationOutputManager_->Write(dataEntity); 757 auto targetEntity = animationTrack->target.operator Entity(); 758 759 vector<float>::iterator iit = inputData->timestamps.begin(); 760 inputData->timestamps.erase(iit + oldKeyIndex); 761 762 auto manager = ecs_->GetComponentManager(animationTrack->component); 763 764 auto target = manager->GetData(targetEntity); 765 auto poffset = RLock(*target, animationTrack->property); 766 if (poffset) { 767 vector<uint8_t>::iterator oit = outputData->data.begin(); 768 769 vector<uint8_t> moveData(oit + (oldKeyIndex * poffset.property->size), 770 oit + (oldKeyIndex * poffset.property->size) + poffset.property->size); 771 772 outputData->data.erase(oit + (oldKeyIndex * poffset.property->size), 773 oit + (oldKeyIndex * poffset.property->size) + poffset.property->size); 774 775 inputData->timestamps.insert(iit + newKeyIndex, time); 776 777 vector<uint8_t>::iterator noit = outputData->data.begin(); 778 outputData->data.insert( 779 noit + (newKeyIndex * poffset.property->size), std::begin(moveData), std::end(moveData)); 780 } 781 } 782 783 updateGuard_ = false; 784 785 uint32_t timeMs = static_cast<uint32_t>(time * 1000.0f); 786 if (GetValue(Duration()).ToMilliseconds() < timeMs) { 787 META_ACCESS_PROPERTY(Duration)->SetValue(TimeSpan::Milliseconds(timeMs)); 788 } 789 790 OnAnimationTrackChanged(*track, track->GetEntity()); 791} 792 793void EcsAnimation::OnDestroyAnimationTrack(IEcsTrackAnimation::Ptr track) 794{ 795 if (ecs_) { 796 if (auto trackHandle = animationTrackManager_->Read(track->GetEntity()); trackHandle) { 797 // Destroy timestamps and keys. 798 ecs_->GetEntityManager().Destroy(trackHandle->timestamps); 799 ecs_->GetEntityManager().Destroy(trackHandle->data); 800 } 801 802 { 803 // Remove track from animation. 804 const auto animationHandle = animationManager_->Write(GetEntity()); 805 auto it = std::find(animationHandle->tracks.begin(), animationHandle->tracks.end(), track->GetEntity()); 806 if (it != animationHandle->tracks.end()) { 807 animationHandle->tracks.erase(it); 808 } 809 } 810 811 // Destroy track. 812 ecs_->GetEntityManager().Destroy(track->GetEntity()); 813 } 814 815 GetSelf<META_NS::IContainer>()->Remove(interface_pointer_cast<IObject>(track)); 816} 817 818BASE_NS::vector<CORE_NS::EntityReference> EcsAnimation::GetAllRelatedEntities() const 819{ 820 BASE_NS::vector<CORE_NS::EntityReference> result; 821 822 if (animationManager_) { 823 auto animationHandle = animationManager_->Read(GetEntity()); 824 if (animationHandle) { 825 for (auto& track : animationHandle->tracks) { 826 const auto trackHandle = animationTrackManager_->Read(track); 827 if (trackHandle) { 828 if (EntityUtil::IsValid(trackHandle->timestamps)) { 829 result.push_back(ecs_->GetEntityManager().GetReferenceCounted(trackHandle->timestamps)); 830 } 831 832 if (EntityUtil::IsValid(trackHandle->data)) { 833 result.push_back(ecs_->GetEntityManager().GetReferenceCounted(trackHandle->data)); 834 } 835 836 result.push_back(ecs_->GetEntityManager().GetReferenceCounted(track)); 837 } 838 } 839 } 840 841 // Add self. 842 result.push_back(ecs_->GetEntityManager().GetReferenceCounted(GetEntity())); 843 } 844 845 return result; 846} 847 848IEcsTrackAnimation::Ptr EcsAnimation::CreateAnimationTrack( 849 CORE_NS::Entity rootEntity, CORE_NS::Entity targetEntity, BASE_NS::string_view fullPropertyPath) 850{ 851 // Extract property path. 852 auto separatorPosition = fullPropertyPath.find_first_of('.'); 853 if (!ecs_ || separatorPosition == BASE_NS::string::npos) { 854 return {}; 855 } 856 857 IComponentManager* componentManager { nullptr }; 858 auto componentManagerName = fullPropertyPath.substr(0, separatorPosition); 859 auto propertyPath = fullPropertyPath.substr(separatorPosition + 1); 860 861 for (const auto& manager : ecs_->GetComponentManagers()) { 862 if (manager->GetName() == componentManagerName) { 863 componentManager = manager; 864 break; 865 } 866 } 867 868 if (!componentManager) { 869 return {}; 870 } 871 872 updateGuard_ = true; 873 874 EntityReference animationTrack; 875 876 if (IPropertyHandle* targetHandle = componentManager->GetData(targetEntity); targetHandle) { 877 if (auto po = RLock(*targetHandle, propertyPath); po) { 878 BASE_NS::string targetName = "Unnamed"; 879 if (nameManager_->HasComponent(targetEntity)) { 880 targetName = nameManager_->Get(targetEntity).name; 881 } 882 883 const auto timeStamps = ecs_->GetEntityManager().CreateReferenceCounted(); 884 { 885 NameComponent nameComponent; 886 nameComponent.name = "TimeStamps - " + targetName + ":" + propertyPath; 887 nameManager_->Set(timeStamps, nameComponent); 888 889 animationInputManager_->Create(timeStamps); 890 } 891 892 const auto keys = ecs_->GetEntityManager().CreateReferenceCounted(); 893 { 894 NameComponent nameComponent; 895 nameComponent.name = "Keys - " + targetName + ":" + propertyPath; 896 nameManager_->Set(keys, nameComponent); 897 898 animationOutputManager_->Create(keys); 899 auto keysHandle = animationOutputManager_->Write(keys); 900 keysHandle->type = po.property->type; 901 } 902 903 const auto targetRef = ecs_->GetEntityManager().GetReferenceCounted(targetEntity); 904 animationTrack = ecs_->GetEntityManager().CreateReferenceCounted(); 905 { 906 NameComponent nameComponent; 907 nameComponent.name = ResolvePathToAnimationRoot(*ecs_, rootEntity, targetEntity); 908 nameManager_->Set(animationTrack, nameComponent); 909 910 animationTrackManager_->Create(animationTrack); 911 auto trackHandle = animationTrackManager_->Write(animationTrack); 912 trackHandle->component = componentManager->GetUid(); 913 trackHandle->property = propertyPath; 914 trackHandle->interpolationMode = AnimationTrackComponent::Interpolation::LINEAR; 915 trackHandle->timestamps = timeStamps; 916 trackHandle->data = keys; 917 trackHandle->target = targetRef; 918 } 919 920 const auto animationHandle = animationManager_->Write(GetEntity()); 921 animationHandle->tracks.emplace_back(animationTrack); 922 } 923 } 924 925 updateGuard_ = false; 926 927 IEcsTrackAnimation::Ptr track = 928 META_NS::GetObjectRegistry().Create<IEcsTrackAnimation>(SCENE_NS::ClassId::EcsTrackAnimation); 929 OnAnimationTrackChanged(*track, animationTrack); 930 931 GetSelf<META_NS::IContainer>()->Add(interface_pointer_cast<IObject>(track)); 932 933 return track; 934} 935 936IEcsTrackAnimation::Ptr EcsAnimation::GetAnimationTrack(CORE_NS::Entity target, BASE_NS::string_view fullPropertyPath) 937{ 938 // Extract property path. 939 auto separatorPosition = fullPropertyPath.find_first_of('.'); 940 if (!ecs_ || separatorPosition == BASE_NS::string::npos) { 941 return {}; 942 } 943 944 auto propertyPath = fullPropertyPath.substr(separatorPosition + 1); 945 946 auto tracks = META_NS::GetAll<IEcsTrackAnimation>(GetSelf<META_NS::IContainer>()); 947 for (auto& track : tracks) { 948 const auto trackHandle = animationTrackManager_->Read(track->GetEntity()); 949 if (trackHandle) { 950 if (trackHandle->target == target && trackHandle->property == propertyPath) { 951 return track; 952 } 953 } 954 } 955 956 return {}; 957} 958 959void EcsAnimation::DestroyAnimationTrack(IEcsTrackAnimation::Ptr track) 960{ 961 updateGuard_ = true; 962 OnDestroyAnimationTrack(track); 963 updateGuard_ = false; 964} 965 966void EcsAnimation::DestroyAllAnimationTracks() 967{ 968 updateGuard_ = true; 969 auto container = GetSelf<META_NS::IContainer>(); 970 while (container->GetSize() > 0) { 971 auto topmost = container->GetAt(0); 972 if (auto track = interface_pointer_cast<IEcsTrackAnimation>(topmost)) { 973 OnDestroyAnimationTrack(track); 974 } else { 975 container->Remove(topmost); 976 } 977 } 978 updateGuard_ = false; 979} 980 981void EcsAnimation::Destroy() 982{ 983 SCENE_PLUGIN_VERBOSE_LOG("Tearing down: %s", META_NS::GetValue(Name()).c_str()); 984 985 if (ecs_ && entity_) { 986 if (auto ecsListener = ecsListener_.lock()) { 987 auto po = GetSelf<SCENE_NS::IEcsProxyObject>(); 988 ecsListener->RemoveEntity(entity_, po, *nameManager_); 989 ecsListener->RemoveEntity(entity_, po, *animationStateManager_); 990 ecsListener->RemoveEntity(entity_, po, *animationManager_); 991 ecsListener->RemoveEntity(entity_, po, *animationTrackManager_); 992 ecsListener->RemoveEntity(entity_, po, *animationInputManager_); 993 } 994 } 995 996 root_ = {}; 997 entity_ = {}; 998} 999 1000void EcsAnimation::OnDurationPropertyChanged() 1001{ 1002 SetValue(META_ACCESS_PROPERTY(TotalDuration), GetValue(Duration()) * repeatCount_); 1003 if (!ecs_ || updateGuard_) { 1004 return; 1005 } 1006 1007 auto handle = animationManager_->Write(entity_); 1008 if (handle) { 1009 handle->duration = GetValue(Duration()).ToSecondsFloat(); 1010 } 1011} 1012 1013void EcsAnimation::OnNamePropertyChanged() 1014{ 1015 if (!ecs_ || updateGuard_) { 1016 return; 1017 } 1018 1019 auto handle = nameManager_->Write(entity_); 1020 if (handle) { 1021 handle->name = GetValue(Name()); 1022 } 1023} 1024 1025void EcsAnimation::OnProgressPropertyChanged() 1026{ 1027 if (updateGuard_) { 1028 return; 1029 } 1030 1031 auto progress = GetValue(Progress()); 1032 auto duration = GetValue(TotalDuration()).ToMilliseconds(); 1033 SetTime(uint32_t(progress * duration)); 1034} 1035 1036CORE_NS::Entity EcsAnimation::GetEntity() const 1037{ 1038 return entity_; 1039} 1040 1041void EcsAnimation::SetProgress(float progress) 1042{ 1043 META_ACCESS_PROPERTY(Progress)->SetValue(Base::Math::clamp(progress, 0.0f, 1.0f)); 1044} 1045 1046void EcsAnimation::SetTime(uint32_t value) 1047{ 1048 if (ecs_) { 1049 auto stateHandle = animationStateManager_->GetData(entity_); 1050 const auto metaData = stateHandle->Owner()->MetaData(); 1051 for (const auto& data : metaData) { 1052 if (data.name == "time") { 1053 auto* time = 1054 static_cast<float*>(static_cast<void*>(static_cast<uint8_t*>(stateHandle->WLock()) + data.offset)); 1055 *time = value / 1000.0f; 1056 stateHandle->WUnlock(); 1057 break; 1058 } 1059 } 1060 } 1061} 1062 1063void EcsAnimation::Step(const IClock::ConstPtr& clock) 1064{ 1065 auto duration = GetValue(TotalDuration()).ToSecondsFloat(); 1066 if (duration <= 0.0f) { 1067 return; 1068 } 1069 1070 if (!lastFrameTime_) { 1071 lastFrameTime_ = clock->GetTime(); 1072 } 1073 1074 auto step = (clock->GetTime() - *lastFrameTime_).ToSecondsFloat(); 1075 SetProgress(GetValue(Progress()) + (step / duration)); 1076 1077 lastFrameTime_ = clock->GetTime(); 1078} 1079 1080void EcsAnimation::Start() 1081{ 1082 auto loopAnimation_ = true; 1083 1084 if (animationManager_) { 1085 if (auto animation = animationManager_->Write(entity_); animation) { 1086 animation->state = AnimationComponent::PlaybackState::PAUSE; 1087 if (loopAnimation_) { 1088 animation->repeatCount = AnimationComponent::REPEAT_COUNT_INFINITE; 1089 } else { 1090 animation->repeatCount = 0; 1091 } 1092 } 1093 } 1094 1095 lastFrameTime_.reset(); 1096 META_ACCESS_PROPERTY(Running)->SetValue(true); 1097 META_NS::Invoke<META_NS::IOnChanged>(OnStarted()); 1098} 1099 1100void EcsAnimation::Stop() 1101{ 1102 if (animationManager_) { 1103 if (auto animation = animationManager_->Write(entity_); animation) { 1104 animation->state = AnimationComponent::PlaybackState::PAUSE; 1105 } 1106 } 1107 lastFrameTime_.reset(); 1108 META_ACCESS_PROPERTY(Running)->SetValue(false); 1109} 1110 1111void EcsAnimation::Pause() 1112{ 1113 if (animationManager_) { 1114 if (auto animation = animationManager_->Write(entity_); animation) { 1115 animation->state = AnimationComponent::PlaybackState::PAUSE; 1116 } 1117 } 1118 META_ACCESS_PROPERTY(Running)->SetValue(false); 1119} 1120 1121void EcsAnimation::Restart() 1122{ 1123 Stop(); 1124 Start(); 1125} 1126 1127void EcsAnimation::Finish() 1128{ 1129 Seek(1.0f); 1130} 1131 1132void EcsAnimation::Seek(float position) 1133{ 1134 // TODO: Implement. 1135 SetProgress(position); 1136} 1137 1138EcsAnimation::Data EcsAnimation::GetProperty(Uid componentUid, Entity entity, string property) const 1139{ 1140 Data data; 1141 if (ecs_) { 1142 auto cm = ecs_->GetComponentManager(componentUid); 1143 if (IPropertyHandle* targetHandle = cm->GetData(entity); targetHandle) { 1144 if (auto po = RLock(*targetHandle, property); po) { 1145 data.property = &(po.property->type); 1146 const uint8_t* src = reinterpret_cast<uint8_t*>(po.offset); 1147 data.data.resize(po.property->size); 1148 CloneData(data.data.data(), data.data.size(), src, po.property->size); 1149 } 1150 } 1151 } 1152 return data; 1153} 1154 1155void EcsAnimation::SetKeyFrameData(Entity animationTrack, float timeStamp, vector<uint8_t> valueData) 1156{ 1157 if (!ecs_) { 1158 return; 1159 } 1160 1161 BASE_ASSERT(EntityUtil::IsValid(animationTrack)); 1162 auto trackHandle = animationTrackManager_->Read(animationTrack); 1163 if (trackHandle) { 1164 const auto timeStamps = trackHandle->timestamps; 1165 const auto keys = trackHandle->data; 1166 BASE_ASSERT(EntityUtil::IsValid(timeStamps)); 1167 BASE_ASSERT(EntityUtil::IsValid(keys)); 1168 1169 size_t index = 0; 1170 bool replace = false; 1171 // insert/replace the timestamp 1172 // find out the position where keyframe belongs based on timestamp 1173 auto timeLineHandle = animationInputManager_->Write(timeStamps); 1174 if (timeLineHandle) { 1175 auto& data = timeLineHandle->timestamps; 1176 const size_t oldCount = data.size(); 1177 const size_t newCount = oldCount + 1; 1178 1179 for (vector<float>::iterator it = data.begin(); it < data.end(); it++) { 1180 if (*it == timeStamp) { 1181 replace = true; 1182 break; 1183 } 1184 if (*it > timeStamp) { 1185 break; 1186 } 1187 index++; 1188 } 1189 1190 if (!replace) { 1191 // reserve space for one more 1192 data.reserve(newCount); 1193 vector<float>::iterator insertIterator = data.begin() + index; 1194 data.insert(insertIterator, timeStamp); 1195 } 1196 } 1197 1198 auto keysHandle = animationOutputManager_->Write(keys); 1199 if (keysHandle) { 1200 auto& data = keysHandle->data; 1201 const size_t oldSize = data.size(); 1202 const size_t oldCount = oldSize / valueData.size(); 1203 1204 if (!replace) { 1205 const size_t newCount = oldCount + 1; 1206 const size_t newSize = newCount * valueData.size(); 1207 // reserve space for one more 1208 data.reserve(newSize); 1209 vector<unsigned char>::iterator insertIterator = data.begin() + (index * valueData.size()); 1210 data.insert(insertIterator, valueData.begin(), valueData.end()); 1211 } else { 1212 auto dst = data.data() + index * valueData.size(); 1213 CloneData(dst, valueData.size(), valueData.data(), valueData.size()); 1214 } 1215 } 1216 } 1217} 1218 1219void EcsAnimation::UpdateAnimationTrackDuration(Entity animationTrack) 1220{ 1221 if (ecs_) { 1222 auto duration = GetTrackDuration(animationTrack); 1223 auto animationTrackHandle = animationTrackManager_->Read(animationTrack); 1224 if (animationTrackHandle) { 1225 auto target = animationTrackHandle->target; 1226 if (EntityUtil::IsValid(target)) { 1227 if (IPropertyHandle* targetHandle = animationManager_->GetData(target); targetHandle) { 1228 PropertyData pData; 1229 if (auto po = pData.WLock(*targetHandle, "duration"); po) { 1230 float* dst = reinterpret_cast<float*>(po.offset); 1231 *dst = duration; 1232 } 1233 } 1234 } 1235 } 1236 } 1237} 1238 1239float EcsAnimation::GetTrackDuration(Entity animationTrack) 1240{ 1241 BASE_ASSERT(EntityUtil::IsValid(animationTrack)); 1242 1243 float duration = 0.0f; 1244 1245 if (ecs_) { 1246 auto trackHandle = animationTrackManager_->Read(animationTrack); 1247 if (trackHandle) { 1248 const auto timeStamps = trackHandle->timestamps; 1249 BASE_ASSERT(EntityUtil::IsValid(timeStamps)); 1250 1251 auto timeLineHandle = animationInputManager_->Read(timeStamps); 1252 if (timeLineHandle) { 1253 auto& stamps = timeLineHandle->timestamps; 1254 for (auto& t : stamps) { 1255 if (t > duration) { 1256 duration = t; 1257 } 1258 } 1259 } 1260 } 1261 } 1262 1263 return duration; 1264} 1265/* 1266bool EcsAnimation::Export(Serialization::IExportContext& context, Serialization::ClassPrimitive& value) const 1267{ 1268 return ObjectContainerFwd::Export(context, value); 1269} 1270 1271bool EcsAnimation::Import(Serialization::IImportContext& context, const Serialization::ClassPrimitive& value) 1272{ 1273 return ObjectContainerFwd::Import(context, value); 1274} 1275*/ 1276void RegisterEcsAnimationObjectType() 1277{ 1278 META_NS::GetObjectRegistry().RegisterObjectType<EcsTrackAnimation>(); 1279 META_NS::GetObjectRegistry().RegisterObjectType<EcsAnimation>(); 1280} 1281 1282void UnregisterEcsAnimationObjectType() 1283{ 1284 META_NS::GetObjectRegistry().UnregisterObjectType<EcsTrackAnimation>(); 1285 META_NS::GetObjectRegistry().UnregisterObjectType<EcsAnimation>(); 1286} 1287 1288SCENE_END_NAMESPACE() 1289