Files
UnrealEngine/Engine/Source/Runtime/StateStream/Private/TransformStateStreamImpl.cpp
2025-05-18 13:04:45 +08:00

152 lines
3.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "TransformStateStreamImpl.h"
#include "StateStreamCreator.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
FTransformObject::~FTransformObject()
{
if (Parent)
{
Parent->RemoveListener(this);
Parent = nullptr;
}
check(!First);
}
FTransformObject::Info FTransformObject::GetInfo()
{
// TODO: Race condition safe
if (bDirty)
{
WorldTransform = LocalState->GetLocalTransform();
bVisible = LocalState->GetVisible();
if (Parent)
{
Info ParentInfo = Parent->GetInfo();
WorldTransform *= ParentInfo.WorldTransform;
bVisible |= ParentInfo.bVisible;
}
bDirty = false;
}
return { WorldTransform, LocalState->GetBoneTransforms(), bVisible };
}
void FTransformObject::AddListener(FTransformObjectListener* Listener)
{
if (!First)
{
First = Listener;
}
else
{
Listener->Next = First;
First->Prev = Listener;
First = Listener;
}
}
void FTransformObject::RemoveListener(FTransformObjectListener* Listener)
{
if (Listener->Prev)
{
Listener->Prev->Next = Listener->Next;
}
else
{
First = Listener->Next;
}
if (Listener->Next)
{
Listener->Next->Prev = Listener->Prev;
}
Listener->Next = nullptr;
Listener->Prev = nullptr;
}
void FTransformObject::CallListeners()
{
for (FTransformObjectListener* It = First; It; It = It->Next)
{
It->OnTransformObjectDirty();
}
}
void FTransformObject::OnTransformObjectDirty()
{
bDirty = true;
CallListeners();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FTransformStateStreamImpl::SetParent(FTransformObject* Object, const FTransformDynamicState& Ds)
{
const FTransformHandle& ParentHandle = Ds.GetParent();
if (!ParentHandle.IsValid() || Object->Parent)
{
return;
}
FTransformObject*& ParentUserData = Render_GetUserData(ParentHandle);
FTransformObject* ParentObject = ParentUserData;
if (!ParentObject)
{
ParentObject = new FTransformObject();
ParentObject->AddRef();
ParentUserData = ParentObject;
SetParent(ParentObject, Render_GetDynamicState(ParentHandle));
}
ParentObject->AddListener(Object);
Object->Parent = ParentObject;
}
void FTransformStateStreamImpl::Render_OnCreate(const FTransformStaticState& Ss, const FTransformDynamicState& Ds, FTransformObject*& UserData, bool IsDestroyedInSameFrame)
{
FTransformObject* Object = UserData;
if (!Object)
{
Object = new FTransformObject();
Object->AddRef();
Object->LocalState = &Ds;
UserData = Object;
}
SetParent(Object, Ds);
}
void FTransformStateStreamImpl::Render_OnUpdate(const FTransformStaticState& Ss, const FTransformDynamicState& Ds, FTransformObject*& UserData)
{
FTransformObject* Object = UserData;
if (Ds.LocalTransformModified() || Ds.VisibleModified() || Ds.BoneTransformsModified())
{
Object->OnTransformObjectDirty();
}
if (Ds.ParentModified())
{
SetParent(Object, Ds);
}
}
void FTransformStateStreamImpl::Render_OnDestroy(const FTransformStaticState& Ss, const FTransformDynamicState& Ds, FTransformObject*& UserData)
{
UserData->Release();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FStateStreamCreator TransformStateStreamCreator(TransformStateStreamId,
[](const FStateStreamRegisterContext& Context) { Context.Register(*new FTransformStateStreamImpl(), true); },
[](const FStateStreamUnregisterContext& Context) {});
////////////////////////////////////////////////////////////////////////////////////////////////////