Files
2025-05-18 13:04:45 +08:00

241 lines
6.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#ifdef NEW_DIRECTLINK_PLUGIN
#include "DatasmithMaxDirectLink.h"
#include "DatasmithSceneFactory.h"
#include "Windows/AllowWindowsPlatformTypes.h"
MAX_INCLUDES_START
#include "impexp.h"
#include "max.h"
MAX_INCLUDES_END
#if WITH_ITOO_INTERFACE
#pragma warning( push )
#pragma warning( disable: 4238 )
//#include "itoo/forestitreesinterface.h"
#include "itreesinterface.H"
#pragma warning( pop )
#include "ircinterface.H"
#endif // WITH_ITOO_INTERFACE
namespace DatasmithMaxDirectLink
{
namespace GeomUtils
{
bool ConvertRailClone(ISceneTracker& SceneTracker, FNodeTracker& NodeTracker)
{
INode* RailCloneNode = NodeTracker.Node;
if (RailCloneNode == nullptr)
{
return false;
}
TimeValue CurrentTime = GetCOREInterface()->GetTime();
IRCStaticInterface* RCStaticInterface = GetRCStaticInterface();
if (!RCStaticInterface)
{
return false;
}
RCStaticInterface->IRCRegisterEngine();
Interval ObjectValidity = RailCloneNode->GetObjectRef()->ObjectValidity(CurrentTime);
NodeTracker.Validity.NarrowValidityToInterval(ObjectValidity);
IRCInterface* RCInterface = GetRCInterface(RailCloneNode->GetObjectRef());
if (!RCInterface)
{
return false;
}
TRCEngineFeatures RCFeatures;
RCFeatures.rcAPIversion;
RCFeatures.renderAPIversion;
RCFeatures.supportNoGeomObjects = false; // todo: support non-mesh objects
RCFeatures.disableMaterialBaking; // todo: might handle this ourselves
if (RCStaticInterface->functions.Count() > 2) // Check that RC version is at least 3(see SDK)
{
RCStaticInterface->IRCSetEngineFeatures(INT_PTR(&RCFeatures)); // fills rcAPIversion
}
LogDebug(FString::Printf(TEXT("RCEngine: sdk version=%d, runtime version:%d"), RCFeatures.renderAPIversion, RCFeatures.rcAPIversion));
RCInterface->IRCRenderBegin(CurrentTime);
int NumInstances;
TRCInstance* RCInstance = RCGetInstances(RCInterface, RCFeatures, NumInstances);
if (RCInstance && NumInstances > 0) // Required to check for null by the SDK
{
// todo: materials
// MaterialEnum(RailCloneNode->GetMtl(), true);
int32 NextMeshIndex = 0;
struct FHismInstances
{
// todo: for forest - custom mesh node
TUniquePtr<Mesh> MaxMesh;
TArray<Matrix3> Transforms;
};
TArray<FHismInstances> InstancesForMesh;
InstancesForMesh.Reserve(NumInstances);
TMap<Mesh*, int32> RenderableNodeIndicesMap;
for (int j = 0; j < NumInstances; j++, RCInstance = RCGetNextInstance(RCInstance, RCFeatures))
{
if (RCInstance && RCInstance->mesh)
{
if (int32* RenderableNodeIndexPtr = RenderableNodeIndicesMap.Find(RCInstance->mesh))
{
InstancesForMesh[*RenderableNodeIndexPtr].Transforms.Emplace(RCInstance->tm);
}
else
{
RenderableNodeIndicesMap.Add(RCInstance->mesh, InstancesForMesh.Num());
FHismInstances& RenderableNode = InstancesForMesh.Emplace_GetRef();
RenderableNode.MaxMesh = MakeUnique<Mesh>(*RCInstance->mesh);
RenderableNode.Transforms.Emplace(RCInstance->tm);
}
}
}
// note: this is how baseline exporter derives names
FString UniqueName = FString::FromInt(NodeTracker.Node->GetHandle());
NodeTracker.CreateConverted().DatasmithActorElement = FDatasmithSceneFactory::CreateActor((const TCHAR*)*UniqueName);
SceneTracker.SetupActor(NodeTracker);
int32 MeshIndex = 0;
for (FHismInstances& Instances: InstancesForMesh)
{
FMeshConverterSource MeshSource = {
NodeTracker.Node, TEXT(""),
FRenderMeshForConversion(NodeTracker.Node, Instances.MaxMesh.Get(), false), false,
FRenderMeshForConversion()
};
SceneTracker.SetupDatasmithHISMForNode(NodeTracker, MeshSource, NodeTracker.Node->GetMtl(), MeshIndex, Instances.Transforms);
MeshIndex++;
}
}
RCInterface->IRCClearInstances();
RCInterface->IRCClearMeshes();
RCInterface->IRCRenderEnd(CurrentTime);
return true;
}
bool ConvertForest(ISceneTracker& Scene, FNodeTracker& NodeTracker)
{
INode* ForestNode = NodeTracker.Node;
TimeValue CurrentTime = GetCOREInterface()->GetTime();
IForestPackInterface* ForestPackInterface = GetForestPackInterface();
ForestPackInterface->IForestRegisterEngine();
TForestEngineFeatures EngineFeatures;
EngineFeatures.edgeMode = FALSE;
EngineFeatures.meshesSupport = FALSE;
ForestPackInterface->IForestSetEngineFeatures((INT_PTR) &EngineFeatures);
ITreesInterface* ITrees = GetTreesInterface(ForestNode->GetObjectRef());
ITrees->IForestRenderBegin(CurrentTime);
int NumInstances;
TForestInstance* ForestInstance = (TForestInstance*)ITrees->IForestGetRenderNodes(NumInstances);
ulong ForestHandle = ForestNode->GetHandle();
FString ForestName = ForestNode->GetName();
Matrix3 ForestMatrix = ForestNode->GetNodeTM(CurrentTime);
if (ForestInstance && NumInstances)
{
struct FHismInstances
{
INode* GeometryNode;
TMap<Mtl*, TArray<Matrix3>> InstancesTransformsForMaterial;
};
TArray<FHismInstances> InstancesForMesh;
InstancesForMesh.Reserve(NumInstances); // Reserve to avoid reallocations
TMap<int, int32> RenderableNodeIndicesMap;
for (int i = 0; i < NumInstances; i++, ForestInstance++)
{
if (ForestInstance->node != NULL)
{
int VirtualMaster = ITrees->IForestGetSpecID(i);
if (int32* RenderableNodeIndexPtr = RenderableNodeIndicesMap.Find(VirtualMaster))
{
InstancesForMesh[*RenderableNodeIndexPtr].InstancesTransformsForMaterial.FindOrAdd(ForestInstance->mtl).Emplace(ForestInstance->tm);
}
else
{
RenderableNodeIndicesMap.Add(VirtualMaster, InstancesForMesh.Num());
FHismInstances& RenderableNode = InstancesForMesh.Emplace_GetRef();
RenderableNode.GeometryNode = ForestInstance->node;
RenderableNode.InstancesTransformsForMaterial.FindOrAdd(ForestInstance->mtl).Emplace(ForestInstance->tm);
}
}
}
// note: this is how baseline exporter derives names
FString UniqueName = FString::FromInt(NodeTracker.Node->GetHandle());
NodeTracker.CreateConverted().DatasmithActorElement = FDatasmithSceneFactory::CreateActor((const TCHAR*)*UniqueName);
Scene.SetupActor(NodeTracker);
int32 MeshIndex = 0;
for (FHismInstances& Instances: InstancesForMesh)
{
INode* GeometryNode = Instances.GeometryNode;
FMeshConverterSource MeshSource = {
GeometryNode, TEXT(""),
GetMeshForGeomObject(CurrentTime, GeometryNode), false,
FRenderMeshForConversion()
};
if (MeshSource.IsValid())
{
for(const TPair<Mtl*, TArray<Matrix3>>& MaterialAndTransforms: Instances.InstancesTransformsForMaterial)
{
Scene.SetupDatasmithHISMForNode(NodeTracker, MeshSource, MaterialAndTransforms.Key, MeshIndex, MaterialAndTransforms.Value);
}
MeshIndex ++;
}
}
}
ITrees->IForestClearRenderNodes();
ITrees->IForestRenderEnd(CurrentTime);
return true;
}
}
}
#include "Windows/HideWindowsPlatformTypes.h"
#endif // NEW_DIRECTLINK_PLUGIN