152 lines
3.5 KiB
C++
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) {});
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|