From cd82296908540a5661f0602690c63960576b645c Mon Sep 17 00:00:00 2001 From: Damien Pernuit Date: Wed, 20 Sep 2023 16:49:11 -0400 Subject: [PATCH] HoudiniNiagara: - Update 2.5 of the plugin. - Adds support for Unreal 5.3. --- HoudiniNiagara.uplugin | 80 +- README.md | 98 +- .../Classes/NiagaraDataInterfaceHoudini.h | 790 +- .../Private/HoudiniPointCache.cpp | 94 +- .../Private/HoudiniPointCacheLoader.cpp | 213 +- .../Private/HoudiniPointCacheLoaderBJSON.cpp | 846 +- .../Private/HoudiniPointCacheLoaderCSV.cpp | 1161 +-- .../Private/HoudiniPointCacheLoaderJSON.cpp | 455 +- .../HoudiniPointCacheLoaderJSONBase.cpp | 682 +- .../Private/NiagaraDataInterfaceHoudini.cpp | 8197 +++++++++-------- .../HoudiniNiagara/Public/HoudiniPointCache.h | 983 +- .../Private/HoudiniPointCacheAssetActions.cpp | 506 +- .../Private/HoudiniPointCacheExporterBase.cpp | 179 +- .../Private/HoudiniPointCacheExporterBase.h | 91 +- .../HoudiniPointCacheExporterHBJSON.cpp | 89 +- .../Private/HoudiniPointCacheExporterHCSV.cpp | 89 +- .../HoudiniPointCacheExporterHJSON.cpp | 92 +- .../Private/HoudiniPointCacheExporterHJSON.h | 79 +- .../Private/HoudiniPointCacheFactory.cpp | 401 +- 19 files changed, 7716 insertions(+), 7409 deletions(-) diff --git a/HoudiniNiagara.uplugin b/HoudiniNiagara.uplugin index 837e3ab..65b284a 100644 --- a/HoudiniNiagara.uplugin +++ b/HoudiniNiagara.uplugin @@ -1,40 +1,40 @@ -{ - "FileVersion": 3, - "Version": 2, - "VersionName": "2.4.0", - "EngineVersion" : "5.2", - "FriendlyName": "Houdini Niagara", - "Description": "Import Houdini point cloud data into UE5 to drive Niagara particle systems.", - "Category": "FX", - "CreatedBy": "Side Effects Software Inc.", - "CreatedByURL": "http://www.sidefx.com", - "DocsURL": "https://www.sidefx.com/docs/unreal/_niagara.html", - "MarketplaceURL" : "com.epicgames.launcher://ue/marketplace/product/79d2dd58387c4696a0f3458275f739d6", - "SupportURL": "https://www.sidefx.com/bugs/submit/", - "EnabledByDefault": false, - "CanContainContent": true, - "IsBetaVersion": false, - "Installed": false, - - "Modules": - [ - { - "Name": "HoudiniNiagara", - "Type": "Runtime", - "LoadingPhase": "Default" - }, - { - "Name": "HoudiniNiagaraEditor", - "Type": "Editor", - "LoadingPhase": "Default" - } - ], - - "Plugins": - [ - { - "Name": "Niagara", - "Enabled": true - } - ] -} +{ + "FileVersion": 3, + "Version": 2, + "VersionName": "2.5.0", + "EngineVersion" : "5.3", + "FriendlyName": "Houdini Niagara", + "Description": "Import Houdini point cloud data into UE5 to drive Niagara particle systems.", + "Category": "FX", + "CreatedBy": "Side Effects Software Inc.", + "CreatedByURL": "http://www.sidefx.com", + "DocsURL": "https://www.sidefx.com/docs/unreal/_niagara.html", + "MarketplaceURL" : "com.epicgames.launcher://ue/marketplace/product/79d2dd58387c4696a0f3458275f739d6", + "SupportURL": "https://www.sidefx.com/bugs/submit/", + "EnabledByDefault": false, + "CanContainContent": true, + "IsBetaVersion": false, + "Installed": false, + + "Modules": + [ + { + "Name": "HoudiniNiagara", + "Type": "Runtime", + "LoadingPhase": "Default" + }, + { + "Name": "HoudiniNiagaraEditor", + "Type": "Editor", + "LoadingPhase": "Default" + } + ], + + "Plugins": + [ + { + "Name": "Niagara", + "Enabled": true + } + ] +} diff --git a/README.md b/README.md index 97e2e8f..77670bc 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,49 @@ -# Houdini Niagara plug-in for Unreal - -This plug-in adds a new "Houdini Data Interface" to Niagara. -This version of the plugin is currently updated for UE5.2. - -The data interface allows importing and processing Houdini Point Cache assets in Niagara. -The point cache files can be exported using the Niagara ROP, available via the SideFXLabs tools. -https://www.sidefx.com/tutorials/sidefx-labs-installation/ - -Supported file types for the point caches are: -- *.hjson: Houdini JSON point cache (ascii) -- *.hbjson: Houdini JSON point cache (binary) -- *.hcsv: Houdini CSV point cache (legacy CSV, used by previous version of this plugin) - -### To build it: -- Copy the plug-in files to your UE5 source directory. (in Engine/Plugins/FX) -- Build UE5 - -Alternatively, you can also download the prebuilt binaries in the "releases" section of this repo. -1. Unzip the downloaded files. -2. Copy the HoudiniNiagara folder into __Your_Unreal_Project/Plugins__. - -You will now have access to the Houdini Niagara plug-in (under the Project/FX Category). - -Once enabled, the plug-in will give you access to a new Houdini Point Cache Data Interface in the Niagara Script Editor. The Data Interface will allow you to use multiples nodes and functions to access and parse data from the exported point cache. - -The Niagara plug-in must be enabled as well, as the Houdini Niagara plug-in depends on it too. - -### For more information: -#### Quick Start Videos: -https://www.sidefx.com/tutorials/houdini-to-ue4s-niagara/ - -#### Documentation for the plugin can be found here: -https://www.sidefx.com/docs/unreal/_niagara.html - -#### Demo Content: -[Example hip files and a content plugin can be found here.](https://drive.google.com/open?id=1yvTNEq-kaPeecJzP3C34xxGq2h_eQERX) - -To install the content plugin: -1. Create a new ue5 project (if you don't have one already) -2. Copy HoudiniNiagaraDemo2020 into the Plugins folder of your Unreal project. - -#### Additional info and links to video tutorials here: -https://www.sidefx.com/forum/topic/73075/ - -#### Programmable VFX with Unreal Engine's Niagara | GDC 2018 -https://youtu.be/mNPYdfRVPtM?t=2269 - - +# Houdini Niagara plug-in for Unreal + +This plug-in adds a new "Houdini Data Interface" to Niagara. +This version of the plugin is currently updated for UE5.3. + +The data interface allows importing and processing Houdini Point Cache assets in Niagara. +The point cache files can be exported using the Niagara ROP, available via the SideFXLabs tools. +https://www.sidefx.com/tutorials/sidefx-labs-installation/ + +Supported file types for the point caches are: +- *.hjson: Houdini JSON point cache (ascii) +- *.hbjson: Houdini JSON point cache (binary) +- *.hcsv: Houdini CSV point cache (legacy CSV, used by previous version of this plugin) + +### To build it: +- Copy the plug-in files to your UE5 source directory. (in Engine/Plugins/FX) +- Build UE5 + +Alternatively, you can also download the prebuilt binaries in the "releases" section of this repo. +1. Unzip the downloaded files. +2. Copy the HoudiniNiagara folder into __Your_Unreal_Project/Plugins__. + +You will now have access to the Houdini Niagara plug-in (under the Project/FX Category). + +Once enabled, the plug-in will give you access to a new Houdini Point Cache Data Interface in the Niagara Script Editor. The Data Interface will allow you to use multiples nodes and functions to access and parse data from the exported point cache. + +The Niagara plug-in must be enabled as well, as the Houdini Niagara plug-in depends on it too. + +### For more information: +#### Quick Start Videos: +https://www.sidefx.com/tutorials/houdini-to-ue4s-niagara/ + +#### Documentation for the plugin can be found here: +https://www.sidefx.com/docs/unreal/_niagara.html + +#### Demo Content: +[Example hip files and a content plugin can be found here.](https://drive.google.com/open?id=1yvTNEq-kaPeecJzP3C34xxGq2h_eQERX) + +To install the content plugin: +1. Create a new ue5 project (if you don't have one already) +2. Copy HoudiniNiagaraDemo2020 into the Plugins folder of your Unreal project. + +#### Additional info and links to video tutorials here: +https://www.sidefx.com/forum/topic/73075/ + +#### Programmable VFX with Unreal Engine's Niagara | GDC 2018 +https://youtu.be/mNPYdfRVPtM?t=2269 + + diff --git a/Source/HoudiniNiagara/Classes/NiagaraDataInterfaceHoudini.h b/Source/HoudiniNiagara/Classes/NiagaraDataInterfaceHoudini.h index cc5d855..07dfb73 100644 --- a/Source/HoudiniNiagara/Classes/NiagaraDataInterfaceHoudini.h +++ b/Source/HoudiniNiagara/Classes/NiagaraDataInterfaceHoudini.h @@ -1,378 +1,414 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "NiagaraCommon.h" -#include "NiagaraShared.h" -#include "VectorVM.h" -#include "HoudiniPointCache.h" -#include "NiagaraDataInterface.h" - -#include "NiagaraDataInterfaceHoudini.generated.h" - -USTRUCT() -struct FHoudiniEvent -{ - GENERATED_USTRUCT_BODY() - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - FVector Position; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - FVector Normal; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - float Impulse; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - FVector Velocity; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - int32 PointID; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - float Time; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - float Life; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - FLinearColor Color; - - UPROPERTY(EditAnywhere, Category = "Houdini Event") - int32 Type; - - FHoudiniEvent() - : Position(FVector::ZeroVector) - , Normal(FVector::ZeroVector) - , Impulse(0.0f) - , Velocity( FVector::ZeroVector) - , PointID(0) - , Time(0.0f) - , Life(0.0f) - , Color(FLinearColor::White) - , Type(0) - { - } - - inline bool operator==(const FHoudiniEvent& Other) const - { - if ( (Other.Position != Position) || (Other.Normal != Normal) - || (Other.Velocity != Velocity) || (Other.Impulse != Impulse) - || (Other.PointID != PointID) || (Other.Time != Time) - || (Other.Life != Life) || (Other.Color != Color) - || (Other.Type != Type) ) - return false; - - return true; - } - - inline bool operator!=(const FHoudiniEvent& Other) const - { - return !(*this == Other); - } -}; - - -/** Data Interface allowing sampling of UHoudiniPointCache assets (CSV, .json (binary) files) files. */ -UCLASS(EditInlineNew, Category = "Houdini Niagara", meta = (DisplayName = "Houdini Point Cache Info")) -class HOUDININIAGARA_API UNiagaraDataInterfaceHoudini : public UNiagaraDataInterface -{ - GENERATED_UCLASS_BODY() - - BEGIN_SHADER_PARAMETER_STRUCT(FShaderParameters, ) - SHADER_PARAMETER(int32, NumberOfSamples) - SHADER_PARAMETER(int32, NumberOfAttributes) - SHADER_PARAMETER(int32, NumberOfPoints) - SHADER_PARAMETER(int32, MaxNumberOfIndexesPerPoint) - SHADER_PARAMETER(int32, LastSpawnedPointId) - SHADER_PARAMETER(float, LastSpawnTime) - SHADER_PARAMETER(float, LastSpawnTimeRequest) - SHADER_PARAMETER_SRV(Buffer, FloatValuesBuffer) - SHADER_PARAMETER_SRV(Buffer, SpecialAttributeIndexesBuffer) - SHADER_PARAMETER_SRV(Buffer, SpawnTimesBuffer) - SHADER_PARAMETER_SRV(Buffer, LifeValuesBuffer) - SHADER_PARAMETER_SRV(Buffer, PointTypesBuffer) - SHADER_PARAMETER_SRV(Buffer, PointValueIndexesBuffer) - SHADER_PARAMETER_SRV(Buffer, FunctionIndexToAttributeIndexBuffer) - END_SHADER_PARAMETER_STRUCT() - -public: - - //DECLARE_NIAGARA_DI_PARAMETER(); - - // Houdini Point Cache Asset to sample - UPROPERTY( EditAnywhere, Category = "Houdini Niagara", meta = (DisplayName = "Houdini Point Cache Asset" ) ) - TObjectPtr HoudiniPointCacheAsset; - - //---------------------------------------------------------------------------- - // UObject Interface - virtual void PostInitProperties() override; - virtual void PostLoad() override; -#if WITH_EDITOR - virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; -#endif - //---------------------------------------------------------------------------- - // UNiagaraDataInterface Interface - - // Returns the DI's functions signatures - virtual void GetFunctions(TArray& OutFunctions)override; - - // Returns the delegate for the passed function signature. - virtual void GetVMExternalFunction(const FVMExternalFunctionBindingInfo& BindingInfo, void* InstanceData, FVMExternalFunction &OutFunc) override; - - virtual bool Equals(const UNiagaraDataInterface* Other) const override; - - //---------------------------------------------------------------------------- - // EXPOSED FUNCTIONS - - // Returns the float value at a given sample index and attribute index in the point cache - void GetFloatValue(FVectorVMExternalFunctionContext& Context); - - // Returns a float value for a given sample index and attribute name in the point cache - void GetFloatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Vector3 value for a given sample index in the point cache - void GetVectorValue(FVectorVMExternalFunctionContext& Context); - - // Returns a Vector3 value for a given sample index in the point cache by attribute - void GetVectorValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Vector3 value for a given sample index in the point cache - void GetVectorValueEx(FVectorVMExternalFunctionContext& Context); - - // Returns a Vector3 value for a given sample index in the point cache by attribute - void GetVectorValueExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Vector4 value for a given sample index in the point cache - void GetVector4Value(FVectorVMExternalFunctionContext& Context); - - // Returns a Vector4 value for a given sample index in the point cache by attribute - void GetVector4ValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Quat value for a given sample index in the point cache - void GetQuatValue(FVectorVMExternalFunctionContext& Context); - - // Returns a Quat value for a given sample index in the point cache by attribute - void GetQuatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns the positions for a given sample index in the point cache - void GetPosition(FVectorVMExternalFunctionContext& Context); - - // Returns the normals for a given sample index in the point cache - void GetNormal(FVectorVMExternalFunctionContext& Context); - - // Returns the time for a given sample index in the point cache - void GetTime(FVectorVMExternalFunctionContext& Context); - - // Returns the velocity for a given sample index in the point cache - void GetVelocity(FVectorVMExternalFunctionContext& Context); - - // Returns the color for a given sample index in the point cache - void GetColor(FVectorVMExternalFunctionContext& Context); - - // Returns the impulse value for a given sample index in the point cache - void GetImpulse(FVectorVMExternalFunctionContext& Context); - - // Returns the position and time for a given sample index in the point cache - void GetPositionAndTime(FVectorVMExternalFunctionContext& Context); - - // Returns the number of samples found in the point cache - void GetNumberOfSamples(FVectorVMExternalFunctionContext& Context); - - // Returns the number of attributes in the point cache - void GetNumberOfAttributes(FVectorVMExternalFunctionContext& Context); - - // Returns the number of unique points (by id) in the point cache - void GetNumberOfPoints(FVectorVMExternalFunctionContext& Context); - - // Returns the last sample index of the points that should be spawned at time t - void GetLastSampleIndexAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns the indexes (min, max) and number of points that should be spawned at time t - void GetPointIDsToSpawnAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns the position for a given point at a given time - void GetPointPositionAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns a float value for a given point at a given time - void GetPointValueAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns a float value by attribute name for a given point at a given time - void GetPointValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Vector value for a given point at a given time - void GetPointVectorValueAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns a Vector value by attribute name for a given point at a given time - void GetPointVectorValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Vector value for a given point at a given time - void GetPointVectorValueAtTimeEx(FVectorVMExternalFunctionContext& Context); - - // Returns a Vector value by attribute name for a given point at a given time - void GetPointVectorValueAtTimeExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Vector4 value for a given point at a given time - void GetPointVector4ValueAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns a Vector4 value by attribute name for a given point at a given time - void GetPointVector4ValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns a Quat value for a given point at a given time - void GetPointQuatValueAtTime(FVectorVMExternalFunctionContext& Context); - - // Returns a Quat value by attribute name for a given point at a given time - void GetPointQuatValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); - - // Returns the sample indexes (previous, next) for reading values for a given point at a given time - void GetSampleIndexesForPointAtTime(FVectorVMExternalFunctionContext& Context); - - // Return the life value for a given point - void GetPointLife(FVectorVMExternalFunctionContext& Context); - - // Return the life of a given point at a given time - //template - void GetPointLifeAtTime(FVectorVMExternalFunctionContext& Context); - - // Return the type value for a given point - void GetPointType(FVectorVMExternalFunctionContext& Context); - - //---------------------------------------------------------------------------- - // Standard attribute accessor as a stopgap. These can be removed when - // string-based attribute lookups work on both the CPU and GPU. - - // Sample a vector attribute value for a given point at a given time - void GetPointGenericVectorAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context, bool DoSwap, bool DoScale); - - // Sample a float attribute value for a given point at a given time - void GetPointGenericFloatAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context); - - // Sample a float attribute value for a given point at a given time - void GetPointGenericInt32AttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context); - - void GetPointNormalAtTime(FVectorVMExternalFunctionContext& Context); - - void GetPointColorAtTime(FVectorVMExternalFunctionContext& Context); - - void GetPointAlphaAtTime(FVectorVMExternalFunctionContext& Context); - - void GetPointVelocityAtTime(FVectorVMExternalFunctionContext& Context); - - void GetPointImpulseAtTime(FVectorVMExternalFunctionContext& Context); - - void GetPointTypeAtTime(FVectorVMExternalFunctionContext& Context); - - //---------------------------------------------------------------------------- - // GPU / HLSL Functions - virtual bool GetFunctionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, const FNiagaraDataInterfaceGeneratedFunction& FunctionInfo, int FunctionInstanceIndex, FString& OutHLSL) override; - virtual bool AppendCompileHash(FNiagaraCompileHashVisitor* InVisitor) const override; - virtual void GetParameterDefinitionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, FString& OutHLSL) override; - virtual void GetCommonHLSL(FString& OutHLSL) override; - - - //virtual bool UseLegacyShaderBindings() const override { return false; } - virtual void BuildShaderParameters(FNiagaraShaderParametersBuilder& ShaderParametersBuilder) const override; - virtual void SetShaderParameters(const FNiagaraDataInterfaceSetShaderParametersContext& Context) const override; - virtual FNiagaraDataInterfaceParametersCS* CreateShaderStorage(const FNiagaraDataInterfaceGPUParamInfo& ParameterInfo, const FShaderParameterMap& ParameterMap) const override; - virtual const FTypeLayoutDesc* GetShaderStorageType() const override; - - virtual bool CanExecuteOnTarget(ENiagaraSimTarget Target)const override { return true; } - - // Members for GPU compatibility - - // Buffer and member variables base name - static const FString NumberOfSamplesBaseName; - static const FString NumberOfAttributesBaseName; - static const FString NumberOfPointsBaseName; - static const FString FloatValuesBufferBaseName; - static const FString SpecialAttributeIndexesBufferBaseName; - static const FString SpawnTimesBufferBaseName; - static const FString LifeValuesBufferBaseName; - static const FString PointTypesBufferBaseName; - static const FString MaxNumberOfIndexesPerPointBaseName; - static const FString PointValueIndexesBufferBaseName; - static const FString LastSpawnedPointIdBaseName; - static const FString LastSpawnTimeBaseName; - static const FString LastSpawnTimeRequestBaseName; - static const FString FunctionIndexToAttributeIndexBufferBaseName; - - // Member variables accessors - FORCEINLINE int32 GetNumberOfSamples()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfSamples() : 0; } - FORCEINLINE int32 GetNumberOfAttributes()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfAttributes() : 0; } - FORCEINLINE int32 GetNumberOfPoints()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfPoints() : 0; } - FORCEINLINE int32 GetMaxNumberOfIndexesPerPoints()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetMaxNumberOfPointValueIndexes() + 1 : 0; } - - // GPU Buffers accessors - /*FRWBuffer& GetFloatValuesGPUBuffer(); - FRWBuffer& GetSpecialAttributesColumnIndexesGPUBuffer(); - FRWBuffer& GetSpawnTimesGPUBuffer(); - FRWBuffer& GetLifeValuesGPUBuffer(); - FRWBuffer& GetPointTypesGPUBuffer(); - FRWBuffer& GetPointValueIndexesGPUBuffer();*/ - -protected: - virtual void PushToRenderThreadImpl() override; - - // Get the index of the function at InFunctionIndex in InGenerationFunctions if we only count functions with - // the Attribute function specifier. - // Return false if the function itself does not have the Attribute specifier, or if InGeneratedFunctions is empty. - bool GetAttributeFunctionIndex(const TArray& InGeneratedFunctions, int InFunctionIndex, int &OutColTitleFunctionIndex) const; - - virtual bool CopyToInternal(UNiagaraDataInterface* Destination) const override; - - // The following state variables are now stored in Niagara on the emitter itself - // as opposed to being stored internally. - // // Last Spawned PointID - // UPROPERTY() - // int32 LastSpawnedPointID; - // // Last Spawn time - // UPROPERTY() - // float LastSpawnTime; - - // // Float to track last desired time of GetPointIDsToSpawnAtTime and GetLastPointIDToSpawnAtTime(). - // // This is used to detect emitter loops - // UPROPERTY() - // float LastSpawnTimeRequest; -}; - -struct FNiagaraDataInterfaceProxyHoudini : public FNiagaraDataInterfaceProxy -{ - FHoudiniPointCacheResource* Resource; - - TArray FunctionIndexToAttributeIndex; - bool bFunctionIndexToAttributeIndexHasBeenBuilt; - FRWBuffer FunctionIndexToAttributeIndexGPUBuffer; - - FNiagaraDataInterfaceProxyHoudini(); - virtual ~FNiagaraDataInterfaceProxyHoudini(); - - virtual int32 PerInstanceDataPassedToRenderThreadSize() const override - { - return 0; - } - - void UpdateFunctionIndexToAttributeIndexBuffer(const TMemoryImageArray& FunctionIndexToAttribute, bool bForceUpdate = false); +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "NiagaraCommon.h" +#include "NiagaraShared.h" +#include "VectorVM.h" +#include "HoudiniPointCache.h" +#include "NiagaraDataInterface.h" +#include "Runtime/Launch/Resources/Version.h" +#include "NiagaraDataInterfaceHoudini.generated.h" + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 2 +#if WITH_EDITORONLY_DATA +#define HOUDINI_COMPILE_NIAGARA +#endif +#else +#define HOUDINI_COMPILE_NIAGARA +#endif + +USTRUCT() +struct FHoudiniEvent +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + FVector Position; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + FVector Normal; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + float Impulse; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + FVector Velocity; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + int32 PointID; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + float Time; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + float Life; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + FLinearColor Color; + + UPROPERTY(EditAnywhere, Category = "Houdini Event") + int32 Type; + + FHoudiniEvent() + : Position(FVector::ZeroVector) + , Normal(FVector::ZeroVector) + , Impulse(0.0f) + , Velocity( FVector::ZeroVector) + , PointID(0) + , Time(0.0f) + , Life(0.0f) + , Color(FLinearColor::White) + , Type(0) + { + } + + inline bool operator==(const FHoudiniEvent& Other) const + { + if ( (Other.Position != Position) || (Other.Normal != Normal) + || (Other.Velocity != Velocity) || (Other.Impulse != Impulse) + || (Other.PointID != PointID) || (Other.Time != Time) + || (Other.Life != Life) || (Other.Color != Color) + || (Other.Type != Type) ) + return false; + + return true; + } + + inline bool operator!=(const FHoudiniEvent& Other) const + { + return !(*this == Other); + } +}; + + +/** Data Interface allowing sampling of UHoudiniPointCache assets (CSV, .json (binary) files) files. */ +UCLASS(EditInlineNew, Category = "Houdini Niagara", meta = (DisplayName = "Houdini Point Cache Info")) +class HOUDININIAGARA_API UNiagaraDataInterfaceHoudini : public UNiagaraDataInterface +{ + GENERATED_UCLASS_BODY() + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +public: + DECLARE_NIAGARA_DI_PARAMETER(); + +#else + BEGIN_SHADER_PARAMETER_STRUCT(FShaderParameters, ) + SHADER_PARAMETER(int32, NumberOfSamples) + SHADER_PARAMETER(int32, NumberOfAttributes) + SHADER_PARAMETER(int32, NumberOfPoints) + SHADER_PARAMETER(int32, MaxNumberOfIndexesPerPoint) + SHADER_PARAMETER(int32, LastSpawnedPointId) + SHADER_PARAMETER(float, LastSpawnTime) + SHADER_PARAMETER(float, LastSpawnTimeRequest) + SHADER_PARAMETER_SRV(Buffer, FloatValuesBuffer) + SHADER_PARAMETER_SRV(Buffer, SpecialAttributeIndexesBuffer) + SHADER_PARAMETER_SRV(Buffer, SpawnTimesBuffer) + SHADER_PARAMETER_SRV(Buffer, LifeValuesBuffer) + SHADER_PARAMETER_SRV(Buffer, PointTypesBuffer) + SHADER_PARAMETER_SRV(Buffer, PointValueIndexesBuffer) + SHADER_PARAMETER_SRV(Buffer, FunctionIndexToAttributeIndexBuffer) + END_SHADER_PARAMETER_STRUCT() +public: + +#endif + + UPROPERTY(EditAnywhere, Category = "Houdini Niagara", meta = (DisplayName = "Houdini Point Cache Asset")) + TObjectPtr HoudiniPointCacheAsset; +//#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +// UHoudiniPointCache* HoudiniPointCacheAsset; +//#else +// // Houdini Point Cache Asset to sample +// TObjectPtr HoudiniPointCacheAsset; +//#endif + + + //---------------------------------------------------------------------------- + // UObject Interface + virtual void PostInitProperties() override; + virtual void PostLoad() override; +#if WITH_EDITOR + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; +#endif + //---------------------------------------------------------------------------- + // UNiagaraDataInterface Interface + + // Returns the DI's functions signatures + virtual void GetFunctions(TArray& OutFunctions)override; + + // Returns the delegate for the passed function signature. + virtual void GetVMExternalFunction(const FVMExternalFunctionBindingInfo& BindingInfo, void* InstanceData, FVMExternalFunction &OutFunc) override; + + virtual bool Equals(const UNiagaraDataInterface* Other) const override; + + //---------------------------------------------------------------------------- + // EXPOSED FUNCTIONS + + // Returns the float value at a given sample index and attribute index in the point cache + void GetFloatValue(FVectorVMExternalFunctionContext& Context); + + // Returns a float value for a given sample index and attribute name in the point cache + void GetFloatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Vector3 value for a given sample index in the point cache + void GetVectorValue(FVectorVMExternalFunctionContext& Context); + + // Returns a Vector3 value for a given sample index in the point cache by attribute + void GetVectorValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Vector3 value for a given sample index in the point cache + void GetVectorValueEx(FVectorVMExternalFunctionContext& Context); + + // Returns a Vector3 value for a given sample index in the point cache by attribute + void GetVectorValueExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Vector4 value for a given sample index in the point cache + void GetVector4Value(FVectorVMExternalFunctionContext& Context); + + // Returns a Vector4 value for a given sample index in the point cache by attribute + void GetVector4ValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Quat value for a given sample index in the point cache + void GetQuatValue(FVectorVMExternalFunctionContext& Context); + + // Returns a Quat value for a given sample index in the point cache by attribute + void GetQuatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns the positions for a given sample index in the point cache + void GetPosition(FVectorVMExternalFunctionContext& Context); + + // Returns the normals for a given sample index in the point cache + void GetNormal(FVectorVMExternalFunctionContext& Context); + + // Returns the time for a given sample index in the point cache + void GetTime(FVectorVMExternalFunctionContext& Context); + + // Returns the velocity for a given sample index in the point cache + void GetVelocity(FVectorVMExternalFunctionContext& Context); + + // Returns the color for a given sample index in the point cache + void GetColor(FVectorVMExternalFunctionContext& Context); + + // Returns the impulse value for a given sample index in the point cache + void GetImpulse(FVectorVMExternalFunctionContext& Context); + + // Returns the position and time for a given sample index in the point cache + void GetPositionAndTime(FVectorVMExternalFunctionContext& Context); + + // Returns the number of samples found in the point cache + void GetNumberOfSamples(FVectorVMExternalFunctionContext& Context); + + // Returns the number of attributes in the point cache + void GetNumberOfAttributes(FVectorVMExternalFunctionContext& Context); + + // Returns the number of unique points (by id) in the point cache + void GetNumberOfPoints(FVectorVMExternalFunctionContext& Context); + + // Returns the last sample index of the points that should be spawned at time t + void GetLastSampleIndexAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns the indexes (min, max) and number of points that should be spawned at time t + void GetPointIDsToSpawnAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns the position for a given point at a given time + void GetPointPositionAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns a float value for a given point at a given time + void GetPointValueAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns a float value by attribute name for a given point at a given time + void GetPointValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Vector value for a given point at a given time + void GetPointVectorValueAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns a Vector value by attribute name for a given point at a given time + void GetPointVectorValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Vector value for a given point at a given time + void GetPointVectorValueAtTimeEx(FVectorVMExternalFunctionContext& Context); + + // Returns a Vector value by attribute name for a given point at a given time + void GetPointVectorValueAtTimeExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Vector4 value for a given point at a given time + void GetPointVector4ValueAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns a Vector4 value by attribute name for a given point at a given time + void GetPointVector4ValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns a Quat value for a given point at a given time + void GetPointQuatValueAtTime(FVectorVMExternalFunctionContext& Context); + + // Returns a Quat value by attribute name for a given point at a given time + void GetPointQuatValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute); + + // Returns the sample indexes (previous, next) for reading values for a given point at a given time + void GetSampleIndexesForPointAtTime(FVectorVMExternalFunctionContext& Context); + + // Return the life value for a given point + void GetPointLife(FVectorVMExternalFunctionContext& Context); + + // Return the life of a given point at a given time + //template + void GetPointLifeAtTime(FVectorVMExternalFunctionContext& Context); + + // Return the type value for a given point + void GetPointType(FVectorVMExternalFunctionContext& Context); + + //---------------------------------------------------------------------------- + // Standard attribute accessor as a stopgap. These can be removed when + // string-based attribute lookups work on both the CPU and GPU. + + // Sample a vector attribute value for a given point at a given time + void GetPointGenericVectorAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context, bool DoSwap, bool DoScale); + + // Sample a float attribute value for a given point at a given time + void GetPointGenericFloatAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context); + + // Sample a float attribute value for a given point at a given time + void GetPointGenericInt32AttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context); + + void GetPointNormalAtTime(FVectorVMExternalFunctionContext& Context); + + void GetPointColorAtTime(FVectorVMExternalFunctionContext& Context); + + void GetPointAlphaAtTime(FVectorVMExternalFunctionContext& Context); + + void GetPointVelocityAtTime(FVectorVMExternalFunctionContext& Context); + + void GetPointImpulseAtTime(FVectorVMExternalFunctionContext& Context); + + void GetPointTypeAtTime(FVectorVMExternalFunctionContext& Context); + + //---------------------------------------------------------------------------- + // GPU / HLSL Functions + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +#if WITH_EDITORONLY_DATA + virtual bool GetFunctionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, const FNiagaraDataInterfaceGeneratedFunction& FunctionInfo, int FunctionInstanceIndex, FString& OutHLSL) override; + virtual void GetParameterDefinitionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, FString& OutHLSL) override; + virtual void GetCommonHLSL(FString& OutHLSL) override; +#endif +#else + +#if WITH_EDITORONLY_DATA + virtual bool GetFunctionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, const FNiagaraDataInterfaceGeneratedFunction& FunctionInfo, int FunctionInstanceIndex, FString& OutHLSL) override; + virtual bool AppendCompileHash(FNiagaraCompileHashVisitor* InVisitor) const override; + virtual void GetParameterDefinitionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, FString& OutHLSL) override; + virtual void GetCommonHLSL(FString& OutHLSL) override; +#endif + + + //virtual bool UseLegacyShaderBindings() const override { return false; } + virtual void BuildShaderParameters(FNiagaraShaderParametersBuilder& ShaderParametersBuilder) const override; + virtual void SetShaderParameters(const FNiagaraDataInterfaceSetShaderParametersContext& Context) const override; + virtual FNiagaraDataInterfaceParametersCS* CreateShaderStorage(const FNiagaraDataInterfaceGPUParamInfo& ParameterInfo, const FShaderParameterMap& ParameterMap) const override; + virtual const FTypeLayoutDesc* GetShaderStorageType() const override; + +#endif + + virtual bool CanExecuteOnTarget(ENiagaraSimTarget Target)const override { return true; } + + // Members for GPU compatibility + + // Buffer and member variables base name + static const FString NumberOfSamplesBaseName; + static const FString NumberOfAttributesBaseName; + static const FString NumberOfPointsBaseName; + static const FString FloatValuesBufferBaseName; + static const FString SpecialAttributeIndexesBufferBaseName; + static const FString SpawnTimesBufferBaseName; + static const FString LifeValuesBufferBaseName; + static const FString PointTypesBufferBaseName; + static const FString MaxNumberOfIndexesPerPointBaseName; + static const FString PointValueIndexesBufferBaseName; + static const FString LastSpawnedPointIdBaseName; + static const FString LastSpawnTimeBaseName; + static const FString LastSpawnTimeRequestBaseName; + static const FString FunctionIndexToAttributeIndexBufferBaseName; + + // Member variables accessors + FORCEINLINE int32 GetNumberOfSamples()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfSamples() : 0; } + FORCEINLINE int32 GetNumberOfAttributes()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfAttributes() : 0; } + FORCEINLINE int32 GetNumberOfPoints()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfPoints() : 0; } + FORCEINLINE int32 GetMaxNumberOfIndexesPerPoints()const { return HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetMaxNumberOfPointValueIndexes() + 1 : 0; } + + // GPU Buffers accessors + /*FRWBuffer& GetFloatValuesGPUBuffer(); + FRWBuffer& GetSpecialAttributesColumnIndexesGPUBuffer(); + FRWBuffer& GetSpawnTimesGPUBuffer(); + FRWBuffer& GetLifeValuesGPUBuffer(); + FRWBuffer& GetPointTypesGPUBuffer(); + FRWBuffer& GetPointValueIndexesGPUBuffer();*/ + +protected: + virtual void PushToRenderThreadImpl() override; + + // Get the index of the function at InFunctionIndex in InGenerationFunctions if we only count functions with + // the Attribute function specifier. + // Return false if the function itself does not have the Attribute specifier, or if InGeneratedFunctions is empty. + bool GetAttributeFunctionIndex(const TArray& InGeneratedFunctions, int InFunctionIndex, int &OutColTitleFunctionIndex) const; + + virtual bool CopyToInternal(UNiagaraDataInterface* Destination) const override; + + // The following state variables are now stored in Niagara on the emitter itself + // as opposed to being stored internally. + // // Last Spawned PointID + // UPROPERTY() + // int32 LastSpawnedPointID; + // // Last Spawn time + // UPROPERTY() + // float LastSpawnTime; + + // // Float to track last desired time of GetPointIDsToSpawnAtTime and GetLastPointIDToSpawnAtTime(). + // // This is used to detect emitter loops + // UPROPERTY() + // float LastSpawnTimeRequest; +}; + +struct FNiagaraDataInterfaceProxyHoudini : public FNiagaraDataInterfaceProxy +{ + FHoudiniPointCacheResource* Resource; + + TArray FunctionIndexToAttributeIndex; + bool bFunctionIndexToAttributeIndexHasBeenBuilt; + FRWBuffer FunctionIndexToAttributeIndexGPUBuffer; + + FNiagaraDataInterfaceProxyHoudini(); + virtual ~FNiagaraDataInterfaceProxyHoudini(); + + virtual int32 PerInstanceDataPassedToRenderThreadSize() const override + { + return 0; + } + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 + void UpdateFunctionIndexToAttributeIndexBuffer(const TMemoryImageArray& FunctionIndexToAttribute, bool bForceUpdate = false); +#else + void UpdateFunctionIndexToAttributeIndexBuffer(const TMemoryImageArray& FunctionIndexToAttribute, bool bForceUpdate = false); +#endif + }; \ No newline at end of file diff --git a/Source/HoudiniNiagara/Private/HoudiniPointCache.cpp b/Source/HoudiniNiagara/Private/HoudiniPointCache.cpp index a5be76a..7df7b34 100644 --- a/Source/HoudiniNiagara/Private/HoudiniPointCache.cpp +++ b/Source/HoudiniNiagara/Private/HoudiniPointCache.cpp @@ -22,14 +22,17 @@ */ #include "HoudiniPointCache.h" -#include "HoudiniPointCacheLoaderCSV.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" #include "HoudiniPointCacheLoaderBJSON.h" -#include "HoudiniPointCacheLoaderJSON.h" - #include "Misc/FileHelper.h" -#include "Misc/Paths.h" +#include "CoreMinimal.h" +#include "HoudiniPointCacheLoaderCSV.h" +#include "HoudiniPointCacheLoaderJSON.h" #include "Math/NumericLimits.h" -#include "RHI.h" #include "PixelFormat.h" #include "RenderingThread.h" @@ -1139,7 +1142,11 @@ void UHoudiniPointCache::RequestPushToGPU() if (ThisResource) { ThisResource->AcceptStaticDataUpdate(RTDataToPass); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + ThisResource->InitResource(CmdList); +#else ThisResource->InitResource(); +#endif } } ); @@ -1150,7 +1157,11 @@ void FHoudiniPointCacheResource::AcceptStaticDataUpdate(TUniquePtr= 3 +void FHoudiniPointCacheResource::InitRHI(FRHICommandListBase& RHICmdList) +#else void FHoudiniPointCacheResource::InitRHI() +#endif { if (!CachedData.IsValid()) return; @@ -1159,14 +1170,26 @@ void FHoudiniPointCacheResource::InitRHI() { int32 NumElements = CachedData->FloatData.Num(); FloatValuesGPUBuffer.Release(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + FloatValuesGPUBuffer.Initialize(RHICmdList, TEXT("HoudiniGPUBufferFloat"), sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +#else FloatValuesGPUBuffer.Initialize(TEXT("HoudiniGPUBufferFloat"), sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +#endif uint32 BufferSize = NumElements * sizeof(float); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + float* BufferData = static_cast(RHICmdList.LockBuffer(FloatValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#else float* BufferData = static_cast(RHILockBuffer(FloatValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#endif FPlatformMemory::Memcpy(BufferData, CachedData->FloatData.GetData(), BufferSize); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + RHICmdList.UnlockBuffer(FloatValuesGPUBuffer.Buffer); +#else RHIUnlockBuffer(FloatValuesGPUBuffer.Buffer); +#endif } if (CachedData->SpecialAttributeIndexes.Num()) @@ -1174,14 +1197,26 @@ void FHoudiniPointCacheResource::InitRHI() uint32 NumElements = CachedData->SpecialAttributeIndexes.Num(); SpecialAttributeIndexesGPUBuffer.Release(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + SpecialAttributeIndexesGPUBuffer.Initialize(RHICmdList, TEXT("HoudiniGPUBufferSpecialAttributeIndexes"), sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +#else SpecialAttributeIndexesGPUBuffer.Initialize(TEXT("HoudiniGPUBufferSpecialAttributeIndexes"), sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +#endif uint32 BufferSize = NumElements * sizeof(int32); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + float* BufferData = static_cast(RHICmdList.LockBuffer(SpecialAttributeIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#else float* BufferData = static_cast(RHILockBuffer(SpecialAttributeIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#endif FPlatformMemory::Memcpy(BufferData, CachedData->SpecialAttributeIndexes.GetData(), BufferSize); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + RHICmdList.UnlockBuffer(SpecialAttributeIndexesGPUBuffer.Buffer); +#else RHIUnlockBuffer(SpecialAttributeIndexesGPUBuffer.Buffer); +#endif } if (CachedData->SpawnTimes.Num()) @@ -1189,14 +1224,25 @@ void FHoudiniPointCacheResource::InitRHI() uint32 NumElements = CachedData->SpawnTimes.Num(); SpawnTimesGPUBuffer.Release(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + SpawnTimesGPUBuffer.Initialize(RHICmdList, TEXT("HoudiniGPUBufferSpawnTimes"), sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +#else SpawnTimesGPUBuffer.Initialize(TEXT("HoudiniGPUBufferSpawnTimes"), sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +#endif uint32 BufferSize = NumElements * sizeof(float); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + float* BufferData = static_cast(RHICmdList.LockBuffer(SpawnTimesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#else float* BufferData = static_cast(RHILockBuffer(SpawnTimesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#endif FPlatformMemory::Memcpy(BufferData, CachedData->SpawnTimes.GetData(), BufferSize); - +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + RHICmdList.UnlockBuffer(SpawnTimesGPUBuffer.Buffer); +#else RHIUnlockBuffer(SpawnTimesGPUBuffer.Buffer); +#endif } if (CachedData->LifeValues.Num()) @@ -1204,14 +1250,26 @@ void FHoudiniPointCacheResource::InitRHI() uint32 NumElements = CachedData->LifeValues.Num(); LifeValuesGPUBuffer.Release(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + LifeValuesGPUBuffer.Initialize(RHICmdList, TEXT("HoudiniGPUBufferLifeValues"), sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +#else LifeValuesGPUBuffer.Initialize(TEXT("HoudiniGPUBufferLifeValues"), sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +#endif uint32 BufferSize = NumElements * sizeof(float); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + float* BufferData = static_cast(RHICmdList.LockBuffer(LifeValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#else float* BufferData = static_cast(RHILockBuffer(LifeValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#endif FPlatformMemory::Memcpy(BufferData, CachedData->LifeValues.GetData(), BufferSize); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + RHICmdList.UnlockBuffer(LifeValuesGPUBuffer.Buffer); +#else RHIUnlockBuffer(LifeValuesGPUBuffer.Buffer); +#endif } if (CachedData->PointTypes.Num()) @@ -1219,14 +1277,26 @@ void FHoudiniPointCacheResource::InitRHI() uint32 NumElements = CachedData->PointTypes.Num(); PointTypesGPUBuffer.Release(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + PointTypesGPUBuffer.Initialize(RHICmdList, TEXT("HoudiniGPUBufferPointTypes"), sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +#else PointTypesGPUBuffer.Initialize(TEXT("HoudiniGPUBufferPointTypes"), sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +#endif uint32 BufferSize = NumElements * sizeof(int32); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + int32* BufferData = static_cast(RHICmdList.LockBuffer(PointTypesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#else int32* BufferData = static_cast(RHILockBuffer(PointTypesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#endif FPlatformMemory::Memcpy(BufferData, CachedData->PointTypes.GetData(), BufferSize); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + RHICmdList.UnlockBuffer(PointTypesGPUBuffer.Buffer); +#else RHIUnlockBuffer(PointTypesGPUBuffer.Buffer); +#endif } if (CachedData->PointValueIndexes.Num()) @@ -1234,12 +1304,24 @@ void FHoudiniPointCacheResource::InitRHI() uint32 NumElements = CachedData->PointValueIndexes.Num(); PointValueIndexesGPUBuffer.Release(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + PointValueIndexesGPUBuffer.Initialize(RHICmdList, TEXT("HoudiniGPUBufferPointValuesIndexes"), sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +#else PointValueIndexesGPUBuffer.Initialize(TEXT("HoudiniGPUBufferPointValuesIndexes"), sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +#endif uint32 BufferSize = NumElements * sizeof(int32); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + int32* BufferData = static_cast(RHICmdList.LockBuffer(PointValueIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#else int32* BufferData = static_cast(RHILockBuffer(PointValueIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +#endif FPlatformMemory::Memcpy(BufferData, CachedData->PointValueIndexes.GetData(), BufferSize); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + RHICmdList.UnlockBuffer(PointValueIndexesGPUBuffer.Buffer); +#else RHIUnlockBuffer(PointValueIndexesGPUBuffer.Buffer); +#endif } if (CachedData->Attributes.Num()) diff --git a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoader.cpp b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoader.cpp index a935709..275a04e 100644 --- a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoader.cpp +++ b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoader.cpp @@ -1,105 +1,108 @@ -#include "HoudiniPointCacheLoader.h" -#include "HoudiniPointCache.h" -#include "Misc/FileHelper.h" - - -FHoudiniPointCacheSortPredicate::FHoudiniPointCacheSortPredicate(const int32 &InTimeAttrIndex, const int32 &InAgeAttrIndex, const int32 &InIDAttrIndex ) - : TimeAttributeIndex( InTimeAttrIndex ), AgeAttributeIndex(InAgeAttrIndex), IDAttributeIndex( InIDAttrIndex ) -{ - -} - -bool FHoudiniPointCacheSortPredicate::operator()( const TArray& A, const TArray& B ) const -{ - float ATime = TNumericLimits< float >::Lowest(); - if ( A.IsValidIndex( TimeAttributeIndex ) ) - ATime = FCString::Atof( *A[ TimeAttributeIndex ] ); - - float BTime = TNumericLimits< float >::Lowest(); - if ( B.IsValidIndex( TimeAttributeIndex ) ) - BTime = FCString::Atof( *B[ TimeAttributeIndex ] ); - - if ( ATime != BTime ) - { - return ATime < BTime; - } - else - { - float AAge = TNumericLimits< float >::Lowest(); - if (A.IsValidIndex(AgeAttributeIndex)) - AAge = FCString::Atof(*A[AgeAttributeIndex]); - - float BAge = TNumericLimits< float >::Lowest(); - if (B.IsValidIndex(AgeAttributeIndex)) - BAge = FCString::Atof(*B[AgeAttributeIndex]); - - if (AAge != BAge) - { - return BAge < AAge; - } - else - { - float AID = TNumericLimits< float >::Lowest(); - if (A.IsValidIndex(IDAttributeIndex)) - AID = FCString::Atof(*A[IDAttributeIndex]); - - float BID = TNumericLimits< float >::Lowest(); - if (B.IsValidIndex(IDAttributeIndex)) - BID = FCString::Atof(*B[IDAttributeIndex]); - - return AID <= BID; - } - } -} - -FHoudiniPointCacheLoader::FHoudiniPointCacheLoader(const FString& InFilePath) - : FilePath(InFilePath) -{ - -} - -FHoudiniPointCacheLoader::~FHoudiniPointCacheLoader() -{ - -} - -#if WITH_EDITOR -bool FHoudiniPointCacheLoader::LoadRawPointCacheData(UHoudiniPointCache* InAsset, const FString& InFilePath) const -{ - InAsset->Modify(); - return FFileHelper::LoadFileToArray( InAsset->RawDataCompressed, *InFilePath ); -} -#endif - - -#if WITH_EDITOR -void FHoudiniPointCacheLoader::CompressRawData(UHoudiniPointCache* InAsset) const -{ - constexpr ECompressionFlags CompressFlags = COMPRESS_BiasMemory; - const uint32 UncompressedSize = InAsset->RawDataCompressed.Num(); - - const FName CompressionName = NAME_Oodle; - int32 CompressedSize = FCompression::CompressMemoryBound(CompressionName, UncompressedSize, CompressFlags); - TArray CompressedData; - - CompressedData.SetNum(CompressedSize); - - if (FCompression::CompressMemory( - CompressionName, - CompressedData.GetData(), - CompressedSize, - InAsset->RawDataCompressed.GetData(), - UncompressedSize, - CompressFlags)) - { - CompressedData.SetNum(CompressedSize); - CompressedData.Shrink(); - - InAsset->RawDataCompressed = MoveTemp(CompressedData); - InAsset->RawDataCompressionMethod = CompressionName; - } - - InAsset->RawDataUncompressedSize = UncompressedSize; - InAsset->RawDataFormatID = GetFormatID(); -} -#endif +#include "HoudiniPointCacheLoader.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "HoudiniPointCache.h" +#include "Misc/FileHelper.h" + +FHoudiniPointCacheSortPredicate::FHoudiniPointCacheSortPredicate(const int32 &InTimeAttrIndex, const int32 &InAgeAttrIndex, const int32 &InIDAttrIndex ) + : TimeAttributeIndex( InTimeAttrIndex ), AgeAttributeIndex(InAgeAttrIndex), IDAttributeIndex( InIDAttrIndex ) +{ + +} + +bool FHoudiniPointCacheSortPredicate::operator()( const TArray& A, const TArray& B ) const +{ + float ATime = TNumericLimits< float >::Lowest(); + if ( A.IsValidIndex( TimeAttributeIndex ) ) + ATime = FCString::Atof( *A[ TimeAttributeIndex ] ); + + float BTime = TNumericLimits< float >::Lowest(); + if ( B.IsValidIndex( TimeAttributeIndex ) ) + BTime = FCString::Atof( *B[ TimeAttributeIndex ] ); + + if ( ATime != BTime ) + { + return ATime < BTime; + } + else + { + float AAge = TNumericLimits< float >::Lowest(); + if (A.IsValidIndex(AgeAttributeIndex)) + AAge = FCString::Atof(*A[AgeAttributeIndex]); + + float BAge = TNumericLimits< float >::Lowest(); + if (B.IsValidIndex(AgeAttributeIndex)) + BAge = FCString::Atof(*B[AgeAttributeIndex]); + + if (AAge != BAge) + { + return BAge < AAge; + } + else + { + float AID = TNumericLimits< float >::Lowest(); + if (A.IsValidIndex(IDAttributeIndex)) + AID = FCString::Atof(*A[IDAttributeIndex]); + + float BID = TNumericLimits< float >::Lowest(); + if (B.IsValidIndex(IDAttributeIndex)) + BID = FCString::Atof(*B[IDAttributeIndex]); + + return AID <= BID; + } + } +} + +FHoudiniPointCacheLoader::FHoudiniPointCacheLoader(const FString& InFilePath) + : FilePath(InFilePath) +{ + +} + +FHoudiniPointCacheLoader::~FHoudiniPointCacheLoader() +{ + +} + +#if WITH_EDITOR +bool FHoudiniPointCacheLoader::LoadRawPointCacheData(UHoudiniPointCache* InAsset, const FString& InFilePath) const +{ + InAsset->Modify(); + return FFileHelper::LoadFileToArray( InAsset->RawDataCompressed, *InFilePath ); +} +#endif + + +#if WITH_EDITOR +void FHoudiniPointCacheLoader::CompressRawData(UHoudiniPointCache* InAsset) const +{ + constexpr ECompressionFlags CompressFlags = COMPRESS_BiasMemory; + const uint32 UncompressedSize = InAsset->RawDataCompressed.Num(); + + const FName CompressionName = NAME_Oodle; + int32 CompressedSize = FCompression::CompressMemoryBound(CompressionName, UncompressedSize, CompressFlags); + TArray CompressedData; + + CompressedData.SetNum(CompressedSize); + + if (FCompression::CompressMemory( + CompressionName, + CompressedData.GetData(), + CompressedSize, + InAsset->RawDataCompressed.GetData(), + UncompressedSize, + CompressFlags)) + { + CompressedData.SetNum(CompressedSize); + CompressedData.Shrink(); + + InAsset->RawDataCompressed = MoveTemp(CompressedData); + InAsset->RawDataCompressionMethod = CompressionName; + } + + InAsset->RawDataUncompressedSize = UncompressedSize; + InAsset->RawDataFormatID = GetFormatID(); +} +#endif diff --git a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderBJSON.cpp b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderBJSON.cpp index 631959f..230e413 100644 --- a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderBJSON.cpp +++ b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderBJSON.cpp @@ -1,422 +1,424 @@ -#include "HoudiniPointCacheLoaderBJSON.h" -#include "HoudiniPointCache.h" - -#include "HAL/FileManager.h" -#include "Misc/FileHelper.h" -#include "Serialization/MemoryReader.h" - -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeChar; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt8; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt8; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeBool; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt16; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt16; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt32; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt32; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt64; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt64; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeFloat32; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeFloat64; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeString; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerObjectStart; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerObjectEnd; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerArrayStart; -const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerArrayEnd; - -FHoudiniPointCacheLoaderBJSON::FHoudiniPointCacheLoaderBJSON(const FString& InFilePath) : - FHoudiniPointCacheLoaderJSONBase(InFilePath) -{ - -} - -#if WITH_EDITOR -bool FHoudiniPointCacheLoaderBJSON::LoadToAsset(UHoudiniPointCache *InAsset) -{ - const FString& InFilePath = GetFilePath(); - FScopedLoadingState ScopedLoadingState(*InFilePath); - - // Reset the reader and load the whole file into raw buffer - if (!LoadRawPointCacheData(InAsset, InFilePath)) - { - UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to read file '%s' error."), *InFilePath); - return false; - } - - // Pre-allocate and reset buffer - Buffer.SetNumZeroed(1024); - - // Construct reader to read from the (currently) uncompressed data buffer in memory. - Reader = MakeUnique(InAsset->RawDataCompressed); - if (!Reader) - { - UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to reader data from raw data buffer.")); - return false; - } - - // Read start of root object - unsigned char Marker = '\0'; - if (!ReadMarker(Marker) || Marker != MarkerObjectStart) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Expected root object start.")); - return false; - } - - FString ObjectKey; - if (!ReadNonContainerValue(ObjectKey, false)) - return false; - if (ObjectKey != TEXT("header")) - return false; - - // Found header - FHoudiniPointCacheJSONHeader Header; - if (!ReadHeader(Header)) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not read header.")); - return false; - } - - // Set up the Attribute and SpecialAttributeIndexes arrays in the asset, - // expanding attributes with size > 1 - // If time was not an attribute in the file, we add it as an attribute - // but we always set time to the frame's time, irrespective of the existence of a time - // attribute in the file - uint32 NumAttributesPerFileSample = Header.NumAttributeComponents; - ParseAttributesAndInitAsset(InAsset, Header); - - // Get Age attribute index, we'll use this to ensure we sort point spawn time correctly - int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); - int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); - - // Due to the way that some of the DI functions work, - // we expect that the point IDs start at zero, and increment as the points are spawned - // Make sure this is the case by converting the point IDs as we read them - int32 NextPointID = 0; - TMap HoudiniIDToNiagaraIDMap; - - // Expect cache_data key, object start, frames key - if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("cache_data")) - return false; - - if (!ReadMarker(Marker) || Marker != MarkerObjectStart) - return false; - - if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("frames")) - return false; - - // Read the frames array, each entry contains a 'frame' object - // Expect array start - if (!ReadMarker(Marker) || Marker != MarkerArrayStart) - return false; - - uint32 NumFramesRead = 0; - uint32 FrameStartSampleIndex = 0; - TArray> TempFrameData; - while (!Reader->AtEnd() && !IsNext(MarkerArrayEnd)) - { - // Expect object start - if (!ReadMarker(Marker) || Marker != MarkerObjectStart) - return false; - - float FrameNumber = 0.0f; - float Time = 0; - uint32 NumPointsInFrame = 0; - - // Read 'number' (frame number) - if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("number")) - return false; - if (!ReadNonContainerValue(FrameNumber, false, MarkerTypeUInt32)) - return false; - - // Read 'time' - if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("time")) - return false; - if (!ReadNonContainerValue(Time, false, MarkerTypeFloat32)) - return false; - - // Read 'num_points' (number of points in frame) - if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("num_points")) - return false; - if (!ReadNonContainerValue(NumPointsInFrame, false, MarkerTypeUInt32)) - return false; - - // Expect 'frame_data' key - if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("frame_data")) - return false; - - // Expect array start marker - if (!ReadMarker(Marker) || Marker != MarkerArrayStart) - return false; - - // Ensure we have enough space in our FrameData array to read the samples for this frame - TempFrameData.SetNum(NumPointsInFrame); - float PreviousAge = 0.0f; - bool bNeedToSort = false; - for (uint32 SampleIndex = 0; SampleIndex < NumPointsInFrame; ++SampleIndex) - { - // Initialize attributes for this sample - TempFrameData[SampleIndex].Init(0, NumAttributesPerFileSample); - - // Expect array start marker - if (!ReadMarker(Marker) || Marker != MarkerArrayStart) - return false; - - for (uint32 AttrIndex = 0; AttrIndex < NumAttributesPerFileSample; ++AttrIndex) - { - float& Value = TempFrameData[SampleIndex][AttrIndex]; - // Read a value - if (!ReadNonContainerValue(Value, false, Header.AttributeComponentDataTypes[AttrIndex])) - return false; - - if (AgeAttributeIndex != INDEX_NONE && AttrIndex == AgeAttributeIndex) - { - if (SampleIndex == 0) - { - PreviousAge = Value; - } - else if (PreviousAge < Value) - { - bNeedToSort = true; - } - } - } - - // Expect array end marker - if (!ReadMarker(Marker) || Marker != MarkerArrayEnd) - return false; - } - - // Sort this frame's data by age - if (bNeedToSort) - { - TempFrameData.Sort(FHoudiniPointCacheSortPredicate(INDEX_NONE, AgeAttributeIndex, IDAttributeIndex)); - } - - ProcessFrame(InAsset, FrameNumber, TempFrameData, Time, FrameStartSampleIndex, NumPointsInFrame, NumAttributesPerFileSample, Header, HoudiniIDToNiagaraIDMap, NextPointID); - - // Expect array end marker - if (!ReadMarker(Marker) || Marker != MarkerArrayEnd) - return false; - - // Expect object end - if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) - return false; - - FrameStartSampleIndex += NumPointsInFrame; - NumFramesRead++; - } - - if (NumFramesRead != Header.NumFrames) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent num_frames in header vs body: %d vs %d"), Header.NumFrames, NumFramesRead); - return false; - } - - // Expect array end - frames - if (!ReadMarker(Marker) || Marker != MarkerArrayEnd) - return false; - - // Expect object end - cache_data - if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) - return false; - - // Expect object end - root - if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) - return false; - - // We have finished ingesting the data. - // Finalize data loading by compressing raw data. - CompressRawData(InAsset); - - return true; -} -#endif - -bool FHoudiniPointCacheLoaderBJSON::ReadMarker(unsigned char &OutMarker) -{ - if (!CheckReader()) - return false; - - // Read TYPE (1 byte) - Reader->Serialize(Buffer.GetData(), 1); - OutMarker = Buffer[0]; - return true; -} - -bool FHoudiniPointCacheLoaderBJSON::ReadHeader(FHoudiniPointCacheJSONHeader &OutHeader) -{ - // Expect object start - unsigned char Marker = '\0'; - if (!ReadMarker(Marker) || Marker != MarkerObjectStart) - return false; - - // Attempt to reach each key and value of the header, return false if any value is missing or - // not of the expected type - FString HeaderKey; - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("version")) - return false; - if (!ReadNonContainerValue(OutHeader.Version, false, MarkerTypeString)) - return false; - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_samples")) - return false; - if (!ReadNonContainerValue(OutHeader.NumSamples, false, MarkerTypeUInt32)) - return false; - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_frames")) - return false; - if (!ReadNonContainerValue(OutHeader.NumFrames, false, MarkerTypeUInt32)) - return false; - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_points")) - return false; - if (!ReadNonContainerValue(OutHeader.NumPoints, false, MarkerTypeUInt32)) - return false; - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_attrib")) - return false; - if (!ReadNonContainerValue(OutHeader.NumAttributes, false, MarkerTypeUInt16)) - return false; - - // Preallocate Attribute arrays from NumAttributes - OutHeader.Attributes.Empty(OutHeader.NumAttributes); - OutHeader.AttributeSizes.Empty(OutHeader.NumAttributes); - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("attrib_name")) - return false; - if (!ReadArray(OutHeader.Attributes, MarkerTypeString)) - return false; - - // Check that attrib_name was the expected size - if (OutHeader.Attributes.Num() != OutHeader.NumAttributes) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_name array size mismatch: %d vs %d"), OutHeader.Attributes.Num(), OutHeader.NumAttributes); - return false; - } - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("attrib_size")) - return false; - if (!ReadArray(OutHeader.AttributeSizes, MarkerTypeUInt8)) - return false; - - // Check that attrib_size was the expected size - if (OutHeader.AttributeSizes.Num() != OutHeader.NumAttributes) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_size array size mismatch: %d vs %d"), OutHeader.AttributeSizes.Num(), OutHeader.NumAttributes); - return false; - } - - // Calculate the number of attribute components (sum of attribute size over all attributes) - OutHeader.NumAttributeComponents = 0; - for (uint32 AttrSize : OutHeader.AttributeSizes) - { - OutHeader.NumAttributeComponents += AttrSize; - } - OutHeader.AttributeComponentDataTypes.Empty(OutHeader.NumAttributeComponents); - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("attrib_data_type")) - return false; - if (!ReadArray(OutHeader.AttributeComponentDataTypes, MarkerTypeChar)) - return false; - - // Check that attrib_data_type was the expected size - if (OutHeader.AttributeComponentDataTypes.Num() != OutHeader.NumAttributeComponents) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_data_type array size mismatch: %d vs %d"), OutHeader.AttributeComponentDataTypes.Num(), OutHeader.NumAttributeComponents); - return false; - } - - if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("data_type")) - return false; - if (!ReadNonContainerValue(OutHeader.DataType, false, MarkerTypeString)) - return false; - - // Expect object end - if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) - return false; - return true; -} - -bool FHoudiniPointCacheLoaderBJSON::ReadNonContainerValue(FString &OutValue, bool bInReadMarkerType, unsigned char InMarkerType) -{ - if (!CheckReader()) - return false; - - uint32 Size = 0; - unsigned char MarkerType = '\0'; - if (bInReadMarkerType) - { - // Read TYPE (1 byte) - Reader->Serialize(Buffer.GetData(), 1); - MarkerType = Buffer[0]; - } - else - { - MarkerType = InMarkerType; - } - - if (MarkerType != MarkerTypeString && MarkerType != MarkerTypeChar) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Expected string or char, found type %c"), MarkerType); - return false; - } - - if (MarkerType == MarkerTypeString) - { - // Get the number of characters in the string as Size - if (!ReadNonContainerValue(Size, true)) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not determine string size.")); - return false; - } - // Strings are encoded with utf-8, calculate number of bytes to read - Size = Size * sizeof(UTF8CHAR); - } - else - { - // char 1 byte - Size = 1; - } - Reader->Serialize(Buffer.GetData(), Size); - if (Size >= static_cast(Buffer.Num())) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Buffer too small to read string with size %d"), Size) - return false; - } - Buffer[Size] = '\0'; - OutValue = UTF8_TO_TCHAR(Buffer.GetData()); - - return true; -} - -bool FHoudiniPointCacheLoaderBJSON::Peek(int32 InSize) -{ - if (!CheckReader()) - return false; - - int64 Position = Reader->Tell(); - if (Reader->TotalSize() - Position < InSize) - { - return false; - } - Reader->ByteOrderSerialize(Buffer.GetData(), InSize); - Reader->Seek(Position); - - return true; -} - -bool FHoudiniPointCacheLoaderBJSON::CheckReader(bool bInCheckAtEnd) const -{ - if (!Reader || !Reader.IsValid()) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Binary JSON reader is not valid.")) - return false; - } - // Check that we are not at the end of the archive - if (bInCheckAtEnd && Reader->AtEnd()) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Binary JSON reader reach EOF early.")) - return false; - } - - return true; -} + +#include "HoudiniPointCacheLoaderBJSON.h" +#include "CoreMinimal.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "HoudiniPointCache.h" +#include "Serialization/MemoryReader.h" + + +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeChar; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt8; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt8; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeBool; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt16; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt16; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt32; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt32; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeInt64; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeUInt64; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeFloat32; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeFloat64; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerTypeString; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerObjectStart; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerObjectEnd; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerArrayStart; +const unsigned char FHoudiniPointCacheLoaderBJSON::MarkerArrayEnd; + +FHoudiniPointCacheLoaderBJSON::FHoudiniPointCacheLoaderBJSON(const FString& InFilePath) : + FHoudiniPointCacheLoaderJSONBase(InFilePath) +{ + +} + +#if WITH_EDITOR +bool FHoudiniPointCacheLoaderBJSON::LoadToAsset(UHoudiniPointCache *InAsset) +{ + const FString& InFilePath = GetFilePath(); + FScopedLoadingState ScopedLoadingState(*InFilePath); + + // Reset the reader and load the whole file into raw buffer + if (!LoadRawPointCacheData(InAsset, InFilePath)) + { + UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to read file '%s' error."), *InFilePath); + return false; + } + + // Pre-allocate and reset buffer + Buffer.SetNumZeroed(1024); + + // Construct reader to read from the (currently) uncompressed data buffer in memory. + Reader = MakeUnique(InAsset->RawDataCompressed); + if (!Reader) + { + UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to reader data from raw data buffer.")); + return false; + } + + // Read start of root object + unsigned char Marker = '\0'; + if (!ReadMarker(Marker) || Marker != MarkerObjectStart) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Expected root object start.")); + return false; + } + + FString ObjectKey; + if (!ReadNonContainerValue(ObjectKey, false)) + return false; + if (ObjectKey != TEXT("header")) + return false; + + // Found header + FHoudiniPointCacheJSONHeader Header; + if (!ReadHeader(Header)) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not read header.")); + return false; + } + + // Set up the Attribute and SpecialAttributeIndexes arrays in the asset, + // expanding attributes with size > 1 + // If time was not an attribute in the file, we add it as an attribute + // but we always set time to the frame's time, irrespective of the existence of a time + // attribute in the file + uint32 NumAttributesPerFileSample = Header.NumAttributeComponents; + ParseAttributesAndInitAsset(InAsset, Header); + + // Get Age attribute index, we'll use this to ensure we sort point spawn time correctly + int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); + int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); + + // Due to the way that some of the DI functions work, + // we expect that the point IDs start at zero, and increment as the points are spawned + // Make sure this is the case by converting the point IDs as we read them + int32 NextPointID = 0; + TMap HoudiniIDToNiagaraIDMap; + + // Expect cache_data key, object start, frames key + if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("cache_data")) + return false; + + if (!ReadMarker(Marker) || Marker != MarkerObjectStart) + return false; + + if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("frames")) + return false; + + // Read the frames array, each entry contains a 'frame' object + // Expect array start + if (!ReadMarker(Marker) || Marker != MarkerArrayStart) + return false; + + uint32 NumFramesRead = 0; + uint32 FrameStartSampleIndex = 0; + TArray> TempFrameData; + while (!Reader->AtEnd() && !IsNext(MarkerArrayEnd)) + { + // Expect object start + if (!ReadMarker(Marker) || Marker != MarkerObjectStart) + return false; + + float FrameNumber = 0.0f; + float Time = 0; + uint32 NumPointsInFrame = 0; + + // Read 'number' (frame number) + if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("number")) + return false; + if (!ReadNonContainerValue(FrameNumber, false, MarkerTypeUInt32)) + return false; + + // Read 'time' + if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("time")) + return false; + if (!ReadNonContainerValue(Time, false, MarkerTypeFloat32)) + return false; + + // Read 'num_points' (number of points in frame) + if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("num_points")) + return false; + if (!ReadNonContainerValue(NumPointsInFrame, false, MarkerTypeUInt32)) + return false; + + // Expect 'frame_data' key + if (!ReadNonContainerValue(ObjectKey, false, MarkerTypeString) || ObjectKey != TEXT("frame_data")) + return false; + + // Expect array start marker + if (!ReadMarker(Marker) || Marker != MarkerArrayStart) + return false; + + // Ensure we have enough space in our FrameData array to read the samples for this frame + TempFrameData.SetNum(NumPointsInFrame); + float PreviousAge = 0.0f; + bool bNeedToSort = false; + for (uint32 SampleIndex = 0; SampleIndex < NumPointsInFrame; ++SampleIndex) + { + // Initialize attributes for this sample + TempFrameData[SampleIndex].Init(0, NumAttributesPerFileSample); + + // Expect array start marker + if (!ReadMarker(Marker) || Marker != MarkerArrayStart) + return false; + + for (uint32 AttrIndex = 0; AttrIndex < NumAttributesPerFileSample; ++AttrIndex) + { + float& Value = TempFrameData[SampleIndex][AttrIndex]; + // Read a value + if (!ReadNonContainerValue(Value, false, Header.AttributeComponentDataTypes[AttrIndex])) + return false; + + if (AgeAttributeIndex != INDEX_NONE && AttrIndex == AgeAttributeIndex) + { + if (SampleIndex == 0) + { + PreviousAge = Value; + } + else if (PreviousAge < Value) + { + bNeedToSort = true; + } + } + } + + // Expect array end marker + if (!ReadMarker(Marker) || Marker != MarkerArrayEnd) + return false; + } + + // Sort this frame's data by age + if (bNeedToSort) + { + TempFrameData.Sort(FHoudiniPointCacheSortPredicate(INDEX_NONE, AgeAttributeIndex, IDAttributeIndex)); + } + + ProcessFrame(InAsset, FrameNumber, TempFrameData, Time, FrameStartSampleIndex, NumPointsInFrame, NumAttributesPerFileSample, Header, HoudiniIDToNiagaraIDMap, NextPointID); + + // Expect array end marker + if (!ReadMarker(Marker) || Marker != MarkerArrayEnd) + return false; + + // Expect object end + if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) + return false; + + FrameStartSampleIndex += NumPointsInFrame; + NumFramesRead++; + } + + if (NumFramesRead != Header.NumFrames) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent num_frames in header vs body: %d vs %d"), Header.NumFrames, NumFramesRead); + return false; + } + + // Expect array end - frames + if (!ReadMarker(Marker) || Marker != MarkerArrayEnd) + return false; + + // Expect object end - cache_data + if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) + return false; + + // Expect object end - root + if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) + return false; + + // We have finished ingesting the data. + // Finalize data loading by compressing raw data. + CompressRawData(InAsset); + + return true; +} +#endif + +bool FHoudiniPointCacheLoaderBJSON::ReadMarker(unsigned char &OutMarker) +{ + if (!CheckReader()) + return false; + + // Read TYPE (1 byte) + Reader->Serialize(Buffer.GetData(), 1); + OutMarker = Buffer[0]; + return true; +} + +bool FHoudiniPointCacheLoaderBJSON::ReadHeader(FHoudiniPointCacheJSONHeader &OutHeader) +{ + // Expect object start + unsigned char Marker = '\0'; + if (!ReadMarker(Marker) || Marker != MarkerObjectStart) + return false; + + // Attempt to reach each key and value of the header, return false if any value is missing or + // not of the expected type + FString HeaderKey; + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("version")) + return false; + if (!ReadNonContainerValue(OutHeader.Version, false, MarkerTypeString)) + return false; + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_samples")) + return false; + if (!ReadNonContainerValue(OutHeader.NumSamples, false, MarkerTypeUInt32)) + return false; + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_frames")) + return false; + if (!ReadNonContainerValue(OutHeader.NumFrames, false, MarkerTypeUInt32)) + return false; + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_points")) + return false; + if (!ReadNonContainerValue(OutHeader.NumPoints, false, MarkerTypeUInt32)) + return false; + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("num_attrib")) + return false; + if (!ReadNonContainerValue(OutHeader.NumAttributes, false, MarkerTypeUInt16)) + return false; + + // Preallocate Attribute arrays from NumAttributes + OutHeader.Attributes.Empty(OutHeader.NumAttributes); + OutHeader.AttributeSizes.Empty(OutHeader.NumAttributes); + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("attrib_name")) + return false; + if (!ReadArray(OutHeader.Attributes, MarkerTypeString)) + return false; + + // Check that attrib_name was the expected size + if (OutHeader.Attributes.Num() != OutHeader.NumAttributes) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_name array size mismatch: %d vs %d"), OutHeader.Attributes.Num(), OutHeader.NumAttributes); + return false; + } + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("attrib_size")) + return false; + if (!ReadArray(OutHeader.AttributeSizes, MarkerTypeUInt8)) + return false; + + // Check that attrib_size was the expected size + if (OutHeader.AttributeSizes.Num() != OutHeader.NumAttributes) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_size array size mismatch: %d vs %d"), OutHeader.AttributeSizes.Num(), OutHeader.NumAttributes); + return false; + } + + // Calculate the number of attribute components (sum of attribute size over all attributes) + OutHeader.NumAttributeComponents = 0; + for (uint32 AttrSize : OutHeader.AttributeSizes) + { + OutHeader.NumAttributeComponents += AttrSize; + } + OutHeader.AttributeComponentDataTypes.Empty(OutHeader.NumAttributeComponents); + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("attrib_data_type")) + return false; + if (!ReadArray(OutHeader.AttributeComponentDataTypes, MarkerTypeChar)) + return false; + + // Check that attrib_data_type was the expected size + if (OutHeader.AttributeComponentDataTypes.Num() != OutHeader.NumAttributeComponents) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_data_type array size mismatch: %d vs %d"), OutHeader.AttributeComponentDataTypes.Num(), OutHeader.NumAttributeComponents); + return false; + } + + if (!ReadNonContainerValue(HeaderKey, false, MarkerTypeString) || HeaderKey != TEXT("data_type")) + return false; + if (!ReadNonContainerValue(OutHeader.DataType, false, MarkerTypeString)) + return false; + + // Expect object end + if (!ReadMarker(Marker) || Marker != MarkerObjectEnd) + return false; + return true; +} + +bool FHoudiniPointCacheLoaderBJSON::ReadNonContainerValue(FString &OutValue, bool bInReadMarkerType, unsigned char InMarkerType) +{ + if (!CheckReader()) + return false; + + uint32 Size = 0; + unsigned char MarkerType = '\0'; + if (bInReadMarkerType) + { + // Read TYPE (1 byte) + Reader->Serialize(Buffer.GetData(), 1); + MarkerType = Buffer[0]; + } + else + { + MarkerType = InMarkerType; + } + + if (MarkerType != MarkerTypeString && MarkerType != MarkerTypeChar) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Expected string or char, found type %c"), MarkerType); + return false; + } + + if (MarkerType == MarkerTypeString) + { + // Get the number of characters in the string as Size + if (!ReadNonContainerValue(Size, true)) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not determine string size.")); + return false; + } + // Strings are encoded with utf-8, calculate number of bytes to read + Size = Size * sizeof(UTF8CHAR); + } + else + { + // char 1 byte + Size = 1; + } + Reader->Serialize(Buffer.GetData(), Size); + if (Size >= static_cast(Buffer.Num())) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Buffer too small to read string with size %d"), Size) + return false; + } + Buffer[Size] = '\0'; + OutValue = UTF8_TO_TCHAR(Buffer.GetData()); + + return true; +} + +bool FHoudiniPointCacheLoaderBJSON::Peek(int32 InSize) +{ + if (!CheckReader()) + return false; + + int64 Position = Reader->Tell(); + if (Reader->TotalSize() - Position < InSize) + { + return false; + } + Reader->ByteOrderSerialize(Buffer.GetData(), InSize); + Reader->Seek(Position); + + return true; +} + +bool FHoudiniPointCacheLoaderBJSON::CheckReader(bool bInCheckAtEnd) const +{ + if (!Reader || !Reader.IsValid()) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Binary JSON reader is not valid.")) + return false; + } + // Check that we are not at the end of the archive + if (bInCheckAtEnd && Reader->AtEnd()) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Binary JSON reader reach EOF early.")) + return false; + } + + return true; +} diff --git a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderCSV.cpp b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderCSV.cpp index 1f79e0e..c066fc3 100644 --- a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderCSV.cpp +++ b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderCSV.cpp @@ -1,579 +1,584 @@ -#include "HoudiniPointCacheLoaderCSV.h" -#include "HoudiniPointCache.h" -#include "Misc/FileHelper.h" - -FHoudiniPointCacheLoaderCSV::FHoudiniPointCacheLoaderCSV(const FString& InFilePath) - : FHoudiniPointCacheLoader(InFilePath) -{ - -} - -#if WITH_EDITOR -bool FHoudiniPointCacheLoaderCSV::LoadToAsset(UHoudiniPointCache *InAsset) -{ - // Parse the file to a string array - TArray StringArray; - if (!FFileHelper::LoadFileToStringArray(StringArray, *GetFilePath())) - return false; - - if (!UpdateFromStringArray(InAsset, StringArray)) - { - return false; - } - - // Load uncompressed raw data into asset. - if (!LoadRawPointCacheData(InAsset, *GetFilePath())) - { - return false; - } - // Finalize load by compressing raw data. - CompressRawData(InAsset); - - return true; -} -#endif - -#if WITH_EDITOR -bool FHoudiniPointCacheLoaderCSV::UpdateFromStringArray(UHoudiniPointCache *InAsset, TArray& InStringArray) -{ - if (!InAsset) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Cannot load CSV file to HoudiniPointCache, InAsset is NULL.")); - return false; - } - - // Reset the CSV sizes - InAsset->NumberOfAttributes = 0; - InAsset->NumberOfSamples = 0; - InAsset->NumberOfPoints = 0; - - // Get references to point cache data arrays - TArray &FloatSampleData = InAsset->GetFloatSampleData(); - TArray &SpawnTimes = InAsset->GetSpawnTimes(); - TArray &LifeValues = InAsset->GetLifeValues(); - TArray &PointTypes = InAsset->GetPointTypes(); - TArray &SpecialAttributeIndexes = InAsset->GetSpecialAttributeIndexes(); - TArray &PointValueIndexes = InAsset->GetPointValueIndexes(); - - // Reset the column indexes of the special attributes - SpecialAttributeIndexes.Init( INDEX_NONE, EHoudiniAttributes::HOUDINI_ATTR_SIZE ); - - if ( InStringArray.Num() <= 0 ) - { - UE_LOG( LogHoudiniNiagara, Error, TEXT( "Could not load the CSV file, error: not enough rows in the file." ) ); - return false; - } - - // Remove empty rows from the CSV - InStringArray.RemoveAll( [&]( const FString& InString ) { return InString.IsEmpty(); } ); - - // Number of rows in the CSV (ignoring the title row) - InAsset->NumberOfSamples = InStringArray.Num() - 1; - if ( InAsset->NumberOfSamples < 1 ) - { - UE_LOG( LogHoudiniNiagara, Error, TEXT( "Could not load the CSV file, error: not enough rows in the file." ) ); - return false; - } - - // See if we need to use a custom title row - // The custom title row will be ignored if it is empty or only composed of spaces - FString TitleRow = InAsset->SourceCSVTitleRow; - TitleRow.ReplaceInline(TEXT(" "), TEXT("")); - if ( TitleRow.IsEmpty() ) - InAsset->SetUseCustomCSVTitleRow(false); - - if ( !InAsset->GetUseCustomCSVTitleRow() ) - InAsset->SourceCSVTitleRow = InStringArray[0]; - - // Parses the CSV file's title row to update the column indexes of special values we're interested in - // Also look for packed vectors in the first row and update the indexes accordingly - bool HasPackedVectors = false; - if ( !ParseCSVTitleRow( InAsset, InAsset->SourceCSVTitleRow, InStringArray[1], HasPackedVectors ) ) - return false; - - // Remove the title row now that it's been processed - InStringArray.RemoveAt( 0 ); - - // Parses each string of the csv file to a string array - TArray< TArray< FString > > ParsedStringArrays; - ParsedStringArrays.SetNum( InAsset->NumberOfSamples ); - for ( int32 rowIdx = 0; rowIdx < InAsset->NumberOfSamples; rowIdx++ ) - { - // Get the current row - FString CurrentRow = InStringArray[ rowIdx ]; - if ( HasPackedVectors ) - { - // Clean up the packing characters: ()" from the row so it can be parsed properly - CurrentRow.ReplaceInline( TEXT("("), TEXT("") ); - CurrentRow.ReplaceInline( TEXT(")"), TEXT("") ); - CurrentRow.ReplaceInline( TEXT("\""), TEXT("") ); - } - - // Parse the current row to an array - TArray CurrentParsedRow; - CurrentRow.ParseIntoArray( CurrentParsedRow, TEXT(",") ); - - // Check that the parsed row and number of columns match - if ( InAsset->NumberOfAttributes != CurrentParsedRow.Num() ) - UE_LOG( LogHoudiniNiagara, Warning, - TEXT("Error while parsing the CSV File. Row %d has %d values instead of the expected %d!"), - rowIdx + 1, CurrentParsedRow.Num(), InAsset->NumberOfAttributes ); - - // Store the parsed row - ParsedStringArrays[ rowIdx ] = CurrentParsedRow; - } - - // If we have time and/or age values, we have to make sure the csv rows are sorted by time and/or age - int32 TimeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TIME); - int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); - int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); - if ( TimeAttributeIndex != INDEX_NONE ) - { - // First check if we need to sort the array - bool NeedToSort = false; - float PreviousTimeValue = 0.0f; - float PreviousAgeValue = 0.0f; - for ( int32 rowIdx = 0; rowIdx < ParsedStringArrays.Num(); rowIdx++ ) - { - if ( !ParsedStringArrays[ rowIdx ].IsValidIndex( TimeAttributeIndex ) && - !ParsedStringArrays[ rowIdx ].IsValidIndex( AgeAttributeIndex ) ) - continue; - - // Get the current time value - float CurrentTimeValue = PreviousTimeValue; - if (ParsedStringArrays[rowIdx].IsValidIndex(TimeAttributeIndex)) - { - CurrentTimeValue = FCString::Atof(*(ParsedStringArrays[rowIdx][TimeAttributeIndex])); - } - - // Get the current age value - float CurrentAgeValue = PreviousAgeValue; - if (ParsedStringArrays[rowIdx].IsValidIndex(AgeAttributeIndex)) - { - CurrentAgeValue = FCString::Atof(*(ParsedStringArrays[rowIdx][AgeAttributeIndex])); - } - - if ( rowIdx == 0 ) - { - PreviousTimeValue = CurrentTimeValue; - PreviousAgeValue = CurrentAgeValue; - continue; - } - - // Time values arent sorted properly - if ( PreviousTimeValue > CurrentTimeValue || (PreviousTimeValue == CurrentTimeValue && PreviousAgeValue < CurrentAgeValue ) ) - { - NeedToSort = true; - break; - } - } - - if ( NeedToSort ) - { - // We need to sort the CSV rows by their time values - ParsedStringArrays.Sort( FHoudiniPointCacheSortPredicate( TimeAttributeIndex, AgeAttributeIndex, IDAttributeIndex ) ); - } - } - - // Initialize our different buffers - FloatSampleData.Empty(); - FloatSampleData.SetNumZeroed( InAsset->NumberOfSamples * InAsset->NumberOfAttributes ); - - /* - StringCSVData.Empty(); - StringCSVData.SetNumZeroed( NumberOfSamples * NumberOfAttributes ); - */ - // Due to the way that some of the DI functions work, - // we expect that the point IDs start at zero, and increment as the points are spawned - // Make sure this is the case by converting the point IDs as we read them - int32 NextPointID = 0; - TMap HoudiniIDToNiagaraIDMap; - - - // We also keep track of the row indexes for each time values - //float lastTimeValue = 0.0; - //TimeValuesIndexes.Empty(); - - // And the row indexes for each point - PointValueIndexes.Empty(); - - // Extract all the values from the table to the float & string buffers - TArray CurrentParsedRow; - for ( int rowIdx = 0; rowIdx < ParsedStringArrays.Num(); rowIdx++ ) - { - CurrentParsedRow = ParsedStringArrays[ rowIdx ]; - - // Store the CSV Data in the buffers - // The data is stored transposed in those buffers - int32 CurrentID = -1; - for ( int colIdx = 0; colIdx < InAsset->NumberOfAttributes; colIdx++ ) - { - // Get the string value for the current column - FString CurrentVal = TEXT("0"); - if ( CurrentParsedRow.IsValidIndex( colIdx ) ) - { - CurrentVal = CurrentParsedRow[ colIdx ]; - } - else - { - UE_LOG( LogHoudiniNiagara, Warning, - TEXT("Error while parsing the CSV File. Row %d has an invalid value for column %d!"), - rowIdx + 1, colIdx + 1 ); - } - - // Convert the string value to a float - float FloatValue = FCString::Atof( *CurrentVal ); - - // Handle point IDs here - if ( colIdx == IDAttributeIndex ) - { - // If the point ID doesn't exist in the Houdini/Niagara mapping, create a new a entry. - // Otherwise, replace the point ID with the Niagara ID. - - int32 PointID = FMath::FloorToInt(FloatValue); - // The point ID may need to be replaced - if ( !HoudiniIDToNiagaraIDMap.Contains( PointID ) ) - { - // We found a new point, so we add it to the ID map - HoudiniIDToNiagaraIDMap.Add( PointID, NextPointID++ ); - - // Add a new array for that point's indexes - PointValueIndexes.Add( FPointIndexes() ); - } - - // Get the Niagara ID from the Houdini ID - CurrentID = HoudiniIDToNiagaraIDMap[ PointID ]; - FloatValue = (float)CurrentID; - - // Add the current row to this point's row index list - PointValueIndexes[ CurrentID ].SampleIndexes.Add( rowIdx ); - } - - // Store the Value in the buffer - FloatSampleData[ rowIdx + ( colIdx * InAsset->NumberOfSamples ) ] = FloatValue; - } - - // If we dont have Point ID informations, we still want to fill the PointValueIndexes array - if ( !InAsset->IsValidAttributeAttributeIndex( EHoudiniAttributes::POINTID ) ) - { - // Each row is considered its own point - PointValueIndexes.Add(FPointIndexes()); - PointValueIndexes[ rowIdx ].SampleIndexes.Add( rowIdx ); - } - } - - InAsset->NumberOfPoints = HoudiniIDToNiagaraIDMap.Num(); - if ( InAsset->NumberOfPoints <= 0 ) - InAsset->NumberOfPoints = InAsset->NumberOfSamples; - - // Look for point specific attributes to build some helper arrays - int32 LifeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::LIFE); - //int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); - int32 TypeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TYPE); - - SpawnTimes.Empty(); - SpawnTimes.Init( -FLT_MAX, InAsset->NumberOfPoints ); - - LifeValues.Empty(); - LifeValues.Init( -FLT_MAX, InAsset->NumberOfPoints ); - - PointTypes.Empty(); - PointTypes.Init( -1, InAsset->NumberOfPoints ); - - const float SpawnBias = 0.001f; - for ( int rowIdx = 0; rowIdx < InAsset->NumberOfSamples; rowIdx++ ) - { - // Get the point ID - int32 CurrentID = rowIdx; - if ( IDAttributeIndex != INDEX_NONE ) - { - // Remap the external point ID to the expected Niagara particle ID. - CurrentID = (int32)FloatSampleData[ rowIdx + ( IDAttributeIndex * InAsset->NumberOfSamples ) ]; - CurrentID = HoudiniIDToNiagaraIDMap[CurrentID]; - } - - // Get the time value for the current row - float CurrentTime = 0.0f; - if ( TimeAttributeIndex != INDEX_NONE ) - CurrentTime = FloatSampleData[ rowIdx + ( TimeAttributeIndex * InAsset->NumberOfSamples ) ]; - - if ( FMath::IsNearlyEqual(SpawnTimes[ CurrentID ], -FLT_MAX) ) - { - // We have detected a new particle. - - // Calculate spawn and life from attributes. - // Spawn time is when the point is first seen - if (AgeAttributeIndex != INDEX_NONE) - { - // If we have an age attribute we can more accurately calculate the particle's spawn time. - SpawnTimes[ CurrentID ] = CurrentTime - FloatSampleData [rowIdx + (AgeAttributeIndex * InAsset->NumberOfSamples) ]; - } - else - { - // We don't have an age attribute. Simply use the current time as the spawn time. - // Note that we bias the value slightly to that the particle is already spawned at the CurrentTime. - SpawnTimes[ CurrentID ] = CurrentTime; - } - - if ( LifeAttributeIndex != INDEX_NONE ) - { - LifeValues[ CurrentID ] = FloatSampleData [rowIdx + (LifeAttributeIndex * InAsset->NumberOfSamples) ]; - } - } - - // If we don't have a life attribute, keep setting the life attribute for the particle - // so that when the particle is no longer present we have recorded its last observed time - if ( LifeAttributeIndex == INDEX_NONE && LifeValues[ CurrentID ] < CurrentTime) - { - // Life is the difference between spawn time and time of death - // Note that the particle should still be alive at this timestep. Since we don't - // have access to a frame rate here we will workaround this for now by adding - // a small value such that the particle dies *after* this timestep. - LifeValues[ CurrentID ] = CurrentTime - SpawnTimes[ CurrentID ]; - } - - // Keep track of the point type at spawn - if ( PointTypes[ CurrentID ] < 0 ) - { - float CurrentType = 0.0f; - if (TypeAttributeIndex != INDEX_NONE) - InAsset->GetFloatValue( rowIdx, TypeAttributeIndex, CurrentType ); - - PointTypes[ CurrentID ] = (int32)CurrentType; - } - - } - return true; -} -#endif - -#if WITH_EDITOR -bool FHoudiniPointCacheLoaderCSV::ParseCSVTitleRow( UHoudiniPointCache *InAsset, const FString& TitleRow, const FString& FirstValueRow, bool& HasPackedVectors ) -{ - // Get the relevant point cache asset data arrays - TArray &AttributeArray = InAsset->AttributeArray; - TArray &SpecialAttributeIndexes = InAsset->GetSpecialAttributeIndexes(); - - // Get the number of values per row via the title row - AttributeArray.Empty(); - TitleRow.ParseIntoArray( AttributeArray, TEXT(",") ); - InAsset->NumberOfAttributes = AttributeArray.Num(); - if ( InAsset->NumberOfAttributes < 1 ) - { - UE_LOG( LogHoudiniNiagara, Error, TEXT( "Could not load the CSV file, error: not enough columns." ) ); - return false; - } - - // Look for the position, normal and time attributes indexes - for ( int32 n = 0; n < AttributeArray.Num(); n++ ) - { - // Remove spaces from the title row - AttributeArray[ n ].ReplaceInline( TEXT(" "), TEXT("") ); - - FString CurrentTitle = AttributeArray[ n ]; - if ( CurrentTitle.Equals( TEXT("P.x"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("P"), ESearchCase::IgnoreCase ) ) - { - if ( !InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POSITION)) - SpecialAttributeIndexes[EHoudiniAttributes::POSITION] = n; - } - else if ( CurrentTitle.Equals( TEXT("N.x"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("N"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::NORMAL)) - SpecialAttributeIndexes[EHoudiniAttributes::NORMAL] = n; - } - else if ( CurrentTitle.Contains( TEXT("time"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TIME)) - SpecialAttributeIndexes[EHoudiniAttributes::TIME] = n; - } - else if ( CurrentTitle.Equals( TEXT("id"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POINTID)) - SpecialAttributeIndexes[EHoudiniAttributes::POINTID] = n; - } - else if ( CurrentTitle.Equals( TEXT("life"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::LIFE)) - SpecialAttributeIndexes[EHoudiniAttributes::LIFE] = n; - } - else if ( CurrentTitle.Equals( TEXT("age"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::AGE)) - SpecialAttributeIndexes[EHoudiniAttributes::AGE] = n; - } - else if ( CurrentTitle.Equals( TEXT("Cd.r"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("Cd"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::COLOR)) - SpecialAttributeIndexes[EHoudiniAttributes::COLOR] = n; - } - else if ( CurrentTitle.Equals( TEXT("alpha"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::ALPHA)) - SpecialAttributeIndexes[EHoudiniAttributes::ALPHA] = n; - } - else if ( CurrentTitle.Equals( TEXT("v.x"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("v"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::VELOCITY)) - SpecialAttributeIndexes[EHoudiniAttributes::VELOCITY] = n; - } - else if ( CurrentTitle.Equals(TEXT("type"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TYPE)) - SpecialAttributeIndexes[EHoudiniAttributes::TYPE] = n; - } - else if ( CurrentTitle.Equals(TEXT("impulse"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::IMPULSE)) - SpecialAttributeIndexes[EHoudiniAttributes::IMPULSE] = n; - } - } - - // Read the first row of the CSV file, and look for packed vectors value (X,Y,Z) - // We'll have to expand them in the title row to match the parsed data - HasPackedVectors = false; - int32 FoundPackedVectorCharIndex = 0; - while ( FoundPackedVectorCharIndex != INDEX_NONE ) - { - // Try to find ( in the row - FoundPackedVectorCharIndex = FirstValueRow.Find( TEXT("("), ESearchCase::IgnoreCase, ESearchDir::FromStart, FoundPackedVectorCharIndex ); - if ( FoundPackedVectorCharIndex == INDEX_NONE ) - break; - - // We want to know which column this char belong to - int32 FoundPackedVectorAttributeIndex = INDEX_NONE; - { - // Chop the first row up to the found character - FString FirstRowLeft = FirstValueRow.Left( FoundPackedVectorCharIndex ); - - // ReplaceInLine returns the number of occurences of ",", that's what we want! - FoundPackedVectorAttributeIndex = FirstRowLeft.ReplaceInline(TEXT(","), TEXT("")); - } - - if ( !AttributeArray.IsValidIndex( FoundPackedVectorAttributeIndex ) ) - { - UE_LOG( LogHoudiniNiagara, Warning, - TEXT( "Error while parsing the CSV File. Couldn't unpack vector found at character %d in the first row!" ), - FoundPackedVectorCharIndex + 1 ); - continue; - } - - // We found a packed vector, get its size - int32 FoundVectorSize = 0; - { - // Extract the vector string - int32 FoundPackedVectorEndCharIndex = FirstValueRow.Find( TEXT(")"), ESearchCase::IgnoreCase, ESearchDir::FromStart, FoundPackedVectorCharIndex ); - FString VectorString = FirstValueRow.Mid( FoundPackedVectorCharIndex + 1, FoundPackedVectorEndCharIndex - FoundPackedVectorCharIndex - 1 ); - - // Use ReplaceInLine to count the number of , to get the vector's size! - FoundVectorSize = VectorString.ReplaceInline( TEXT(","), TEXT("") ) + 1; - } - - if ( FoundVectorSize < 2 ) - continue; - - // Increment the number of columns - InAsset->NumberOfAttributes += ( FoundVectorSize - 1 ); - - // Extract the special attributes column indexes we found - int32 PositionAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POSITION); - int32 NormalAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::NORMAL); - int32 ColorAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::COLOR); - int32 AlphaAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::ALPHA); - int32 VelocityAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::VELOCITY); - - // Expand TitleRowArray - if ( ( FoundPackedVectorAttributeIndex == PositionAttributeIndex ) && ( FoundVectorSize == 3 ) ) - { - // Expand P to Px,Py,Pz - AttributeArray[ PositionAttributeIndex ] = TEXT("P.x"); - AttributeArray.Insert( TEXT( "P.y" ), PositionAttributeIndex + 1 ); - AttributeArray.Insert( TEXT( "P.z" ), PositionAttributeIndex + 2 ); - } - else if ( ( FoundPackedVectorAttributeIndex == NormalAttributeIndex ) && ( FoundVectorSize == 3 ) ) - { - // Expand N to Nx,Ny,Nz - AttributeArray[ NormalAttributeIndex ] = TEXT("N.x"); - AttributeArray.Insert( TEXT("N.y"), NormalAttributeIndex + 1 ); - AttributeArray.Insert( TEXT("N.z"), NormalAttributeIndex + 2 ); - } - else if ( ( FoundPackedVectorAttributeIndex == VelocityAttributeIndex ) && ( FoundVectorSize == 3 ) ) - { - // Expand V to Vx,Vy,Vz - AttributeArray[ VelocityAttributeIndex ] = TEXT("v.x"); - AttributeArray.Insert( TEXT("v.y"), VelocityAttributeIndex + 1 ); - AttributeArray.Insert( TEXT("v.z"), VelocityAttributeIndex + 2 ); - } - else if ( ( FoundPackedVectorAttributeIndex == ColorAttributeIndex ) && ( ( FoundVectorSize == 3 ) || ( FoundVectorSize == 4 ) ) ) - { - // Expand Cd to R, G, B - AttributeArray[ ColorAttributeIndex ] = TEXT("Cd.r"); - AttributeArray.Insert( TEXT("Cd.g"), ColorAttributeIndex + 1 ); - AttributeArray.Insert( TEXT("Cd.b"), ColorAttributeIndex + 2 ); - - if ( FoundVectorSize == 4 ) - { - // Insert A if we had RGBA - AttributeArray.Insert( TEXT("Cd.a"), ColorAttributeIndex + 3 ); - if ( AlphaAttributeIndex == INDEX_NONE ) - AlphaAttributeIndex = ColorAttributeIndex + 3; - } - } - else - { - // Expand the vector's title from V to V, V1, V2, V3 ... - FString FoundPackedVectortTitle = AttributeArray[ FoundPackedVectorAttributeIndex ]; - for ( int32 n = 0; n < FoundVectorSize; n++ ) - { - FString CurrentTitle = FString::Printf( TEXT( "%s.%d" ), *FoundPackedVectortTitle, n ); - if (n == 0) - AttributeArray[FoundPackedVectorAttributeIndex] = CurrentTitle; - else - AttributeArray.Insert( CurrentTitle, FoundPackedVectorAttributeIndex + n ); - } - } - - // We have inserted new column titles because of the packed vector, - // so we need to offset all the special attributes column indexes after the inserted values - for ( int32 AttrIdx = EHoudiniAttributes::HOUDINI_ATTR_BEGIN; AttrIdx < EHoudiniAttributes::HOUDINI_ATTR_SIZE; AttrIdx++ ) - { - if ( SpecialAttributeIndexes[AttrIdx] == INDEX_NONE ) - continue; - - if ( SpecialAttributeIndexes[AttrIdx] > FoundPackedVectorAttributeIndex ) - SpecialAttributeIndexes[AttrIdx] += FoundVectorSize - 1; - } - - HasPackedVectors = true; - FoundPackedVectorCharIndex++; - } - - // For sanity, Check that the number of columns matches the title row and the first row - { - // Check the title row - if ( InAsset->NumberOfAttributes != AttributeArray.Num() ) - UE_LOG( LogHoudiniNiagara, Error, - TEXT( "Error while parsing the CSV File. Found %d columns but the Title string has %d values! Some values will have an offset!" ), - InAsset->NumberOfAttributes, AttributeArray.Num() ); - - // Use ReplaceInLine to count the number of columns in the first row and make sure it's correct - FString FirstValueRowCopy = FirstValueRow; - int32 FirstRowColumnCount = FirstValueRowCopy.ReplaceInline( TEXT(","), TEXT("") ) + 1; - if ( InAsset->NumberOfAttributes != FirstRowColumnCount ) - UE_LOG( LogHoudiniNiagara, Error, - TEXT("Error while parsing the CSV File. Found %d columns but found %d values in the first row! Some values will have an offset!" ), - InAsset->NumberOfAttributes, FirstRowColumnCount ); - } - /* - // Update the TitleRow uproperty - TitleRow.Empty(); - for (int32 n = 0; n < TitleRowArray.Num(); n++) - { - TitleRow += TitleRowArray[n]; - if ( n < TitleRowArray.Num() - 1 ) - TitleRow += TEXT(","); - } - */ - - return true; -} +#include "HoudiniPointCacheLoaderCSV.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "HoudiniPointCache.h" +#include "Misc/FileHelper.h" + +FHoudiniPointCacheLoaderCSV::FHoudiniPointCacheLoaderCSV(const FString& InFilePath) + : FHoudiniPointCacheLoader(InFilePath) +{ + +} + +#if WITH_EDITOR +bool FHoudiniPointCacheLoaderCSV::LoadToAsset(UHoudiniPointCache *InAsset) +{ + // Parse the file to a string array + TArray StringArray; + if (!FFileHelper::LoadFileToStringArray(StringArray, *GetFilePath())) + return false; + + if (!UpdateFromStringArray(InAsset, StringArray)) + { + return false; + } + + // Load uncompressed raw data into asset. + if (!LoadRawPointCacheData(InAsset, *GetFilePath())) + { + return false; + } + // Finalize load by compressing raw data. + CompressRawData(InAsset); + + return true; +} +#endif + +#if WITH_EDITOR +bool FHoudiniPointCacheLoaderCSV::UpdateFromStringArray(UHoudiniPointCache *InAsset, TArray& InStringArray) +{ + if (!InAsset) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Cannot load CSV file to HoudiniPointCache, InAsset is NULL.")); + return false; + } + + // Reset the CSV sizes + InAsset->NumberOfAttributes = 0; + InAsset->NumberOfSamples = 0; + InAsset->NumberOfPoints = 0; + + // Get references to point cache data arrays + TArray &FloatSampleData = InAsset->GetFloatSampleData(); + TArray &SpawnTimes = InAsset->GetSpawnTimes(); + TArray &LifeValues = InAsset->GetLifeValues(); + TArray &PointTypes = InAsset->GetPointTypes(); + TArray &SpecialAttributeIndexes = InAsset->GetSpecialAttributeIndexes(); + TArray &PointValueIndexes = InAsset->GetPointValueIndexes(); + + // Reset the column indexes of the special attributes + SpecialAttributeIndexes.Init( INDEX_NONE, EHoudiniAttributes::HOUDINI_ATTR_SIZE ); + + if ( InStringArray.Num() <= 0 ) + { + UE_LOG( LogHoudiniNiagara, Error, TEXT( "Could not load the CSV file, error: not enough rows in the file." ) ); + return false; + } + + // Remove empty rows from the CSV + InStringArray.RemoveAll( [&]( const FString& InString ) { return InString.IsEmpty(); } ); + + // Number of rows in the CSV (ignoring the title row) + InAsset->NumberOfSamples = InStringArray.Num() - 1; + if ( InAsset->NumberOfSamples < 1 ) + { + UE_LOG( LogHoudiniNiagara, Error, TEXT( "Could not load the CSV file, error: not enough rows in the file." ) ); + return false; + } + + // See if we need to use a custom title row + // The custom title row will be ignored if it is empty or only composed of spaces + FString TitleRow = InAsset->SourceCSVTitleRow; + TitleRow.ReplaceInline(TEXT(" "), TEXT("")); + if ( TitleRow.IsEmpty() ) + InAsset->SetUseCustomCSVTitleRow(false); + + if ( !InAsset->GetUseCustomCSVTitleRow() ) + InAsset->SourceCSVTitleRow = InStringArray[0]; + + // Parses the CSV file's title row to update the column indexes of special values we're interested in + // Also look for packed vectors in the first row and update the indexes accordingly + bool HasPackedVectors = false; + if ( !ParseCSVTitleRow( InAsset, InAsset->SourceCSVTitleRow, InStringArray[1], HasPackedVectors ) ) + return false; + + // Remove the title row now that it's been processed + InStringArray.RemoveAt( 0 ); + + // Parses each string of the csv file to a string array + TArray< TArray< FString > > ParsedStringArrays; + ParsedStringArrays.SetNum( InAsset->NumberOfSamples ); + for ( int32 rowIdx = 0; rowIdx < InAsset->NumberOfSamples; rowIdx++ ) + { + // Get the current row + FString CurrentRow = InStringArray[ rowIdx ]; + if ( HasPackedVectors ) + { + // Clean up the packing characters: ()" from the row so it can be parsed properly + CurrentRow.ReplaceInline( TEXT("("), TEXT("") ); + CurrentRow.ReplaceInline( TEXT(")"), TEXT("") ); + CurrentRow.ReplaceInline( TEXT("\""), TEXT("") ); + } + + // Parse the current row to an array + TArray CurrentParsedRow; + CurrentRow.ParseIntoArray( CurrentParsedRow, TEXT(",") ); + + // Check that the parsed row and number of columns match + if ( InAsset->NumberOfAttributes != CurrentParsedRow.Num() ) + UE_LOG( LogHoudiniNiagara, Warning, + TEXT("Error while parsing the CSV File. Row %d has %d values instead of the expected %d!"), + rowIdx + 1, CurrentParsedRow.Num(), InAsset->NumberOfAttributes ); + + // Store the parsed row + ParsedStringArrays[ rowIdx ] = CurrentParsedRow; + } + + // If we have time and/or age values, we have to make sure the csv rows are sorted by time and/or age + int32 TimeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TIME); + int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); + int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); + if ( TimeAttributeIndex != INDEX_NONE ) + { + // First check if we need to sort the array + bool NeedToSort = false; + float PreviousTimeValue = 0.0f; + float PreviousAgeValue = 0.0f; + for ( int32 rowIdx = 0; rowIdx < ParsedStringArrays.Num(); rowIdx++ ) + { + if ( !ParsedStringArrays[ rowIdx ].IsValidIndex( TimeAttributeIndex ) && + !ParsedStringArrays[ rowIdx ].IsValidIndex( AgeAttributeIndex ) ) + continue; + + // Get the current time value + float CurrentTimeValue = PreviousTimeValue; + if (ParsedStringArrays[rowIdx].IsValidIndex(TimeAttributeIndex)) + { + CurrentTimeValue = FCString::Atof(*(ParsedStringArrays[rowIdx][TimeAttributeIndex])); + } + + // Get the current age value + float CurrentAgeValue = PreviousAgeValue; + if (ParsedStringArrays[rowIdx].IsValidIndex(AgeAttributeIndex)) + { + CurrentAgeValue = FCString::Atof(*(ParsedStringArrays[rowIdx][AgeAttributeIndex])); + } + + if ( rowIdx == 0 ) + { + PreviousTimeValue = CurrentTimeValue; + PreviousAgeValue = CurrentAgeValue; + continue; + } + + // Time values arent sorted properly + if ( PreviousTimeValue > CurrentTimeValue || (PreviousTimeValue == CurrentTimeValue && PreviousAgeValue < CurrentAgeValue ) ) + { + NeedToSort = true; + break; + } + } + + if ( NeedToSort ) + { + // We need to sort the CSV rows by their time values + ParsedStringArrays.Sort( FHoudiniPointCacheSortPredicate( TimeAttributeIndex, AgeAttributeIndex, IDAttributeIndex ) ); + } + } + + // Initialize our different buffers + FloatSampleData.Empty(); + FloatSampleData.SetNumZeroed( InAsset->NumberOfSamples * InAsset->NumberOfAttributes ); + + /* + StringCSVData.Empty(); + StringCSVData.SetNumZeroed( NumberOfSamples * NumberOfAttributes ); + */ + // Due to the way that some of the DI functions work, + // we expect that the point IDs start at zero, and increment as the points are spawned + // Make sure this is the case by converting the point IDs as we read them + int32 NextPointID = 0; + TMap HoudiniIDToNiagaraIDMap; + + + // We also keep track of the row indexes for each time values + //float lastTimeValue = 0.0; + //TimeValuesIndexes.Empty(); + + // And the row indexes for each point + PointValueIndexes.Empty(); + + // Extract all the values from the table to the float & string buffers + TArray CurrentParsedRow; + for ( int rowIdx = 0; rowIdx < ParsedStringArrays.Num(); rowIdx++ ) + { + CurrentParsedRow = ParsedStringArrays[ rowIdx ]; + + // Store the CSV Data in the buffers + // The data is stored transposed in those buffers + int32 CurrentID = -1; + for ( int colIdx = 0; colIdx < InAsset->NumberOfAttributes; colIdx++ ) + { + // Get the string value for the current column + FString CurrentVal = TEXT("0"); + if ( CurrentParsedRow.IsValidIndex( colIdx ) ) + { + CurrentVal = CurrentParsedRow[ colIdx ]; + } + else + { + UE_LOG( LogHoudiniNiagara, Warning, + TEXT("Error while parsing the CSV File. Row %d has an invalid value for column %d!"), + rowIdx + 1, colIdx + 1 ); + } + + // Convert the string value to a float + float FloatValue = FCString::Atof( *CurrentVal ); + + // Handle point IDs here + if ( colIdx == IDAttributeIndex ) + { + // If the point ID doesn't exist in the Houdini/Niagara mapping, create a new a entry. + // Otherwise, replace the point ID with the Niagara ID. + + int32 PointID = FMath::FloorToInt(FloatValue); + // The point ID may need to be replaced + if ( !HoudiniIDToNiagaraIDMap.Contains( PointID ) ) + { + // We found a new point, so we add it to the ID map + HoudiniIDToNiagaraIDMap.Add( PointID, NextPointID++ ); + + // Add a new array for that point's indexes + PointValueIndexes.Add( FPointIndexes() ); + } + + // Get the Niagara ID from the Houdini ID + CurrentID = HoudiniIDToNiagaraIDMap[ PointID ]; + FloatValue = (float)CurrentID; + + // Add the current row to this point's row index list + PointValueIndexes[ CurrentID ].SampleIndexes.Add( rowIdx ); + } + + // Store the Value in the buffer + FloatSampleData[ rowIdx + ( colIdx * InAsset->NumberOfSamples ) ] = FloatValue; + } + + // If we dont have Point ID informations, we still want to fill the PointValueIndexes array + if ( !InAsset->IsValidAttributeAttributeIndex( EHoudiniAttributes::POINTID ) ) + { + // Each row is considered its own point + PointValueIndexes.Add(FPointIndexes()); + PointValueIndexes[ rowIdx ].SampleIndexes.Add( rowIdx ); + } + } + + InAsset->NumberOfPoints = HoudiniIDToNiagaraIDMap.Num(); + if ( InAsset->NumberOfPoints <= 0 ) + InAsset->NumberOfPoints = InAsset->NumberOfSamples; + + // Look for point specific attributes to build some helper arrays + int32 LifeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::LIFE); + //int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); + int32 TypeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TYPE); + + SpawnTimes.Empty(); + SpawnTimes.Init( -FLT_MAX, InAsset->NumberOfPoints ); + + LifeValues.Empty(); + LifeValues.Init( -FLT_MAX, InAsset->NumberOfPoints ); + + PointTypes.Empty(); + PointTypes.Init( -1, InAsset->NumberOfPoints ); + + const float SpawnBias = 0.001f; + for ( int rowIdx = 0; rowIdx < InAsset->NumberOfSamples; rowIdx++ ) + { + // Get the point ID + int32 CurrentID = rowIdx; + if ( IDAttributeIndex != INDEX_NONE ) + { + // Remap the external point ID to the expected Niagara particle ID. + CurrentID = (int32)FloatSampleData[ rowIdx + ( IDAttributeIndex * InAsset->NumberOfSamples ) ]; + CurrentID = HoudiniIDToNiagaraIDMap[CurrentID]; + } + + // Get the time value for the current row + float CurrentTime = 0.0f; + if ( TimeAttributeIndex != INDEX_NONE ) + CurrentTime = FloatSampleData[ rowIdx + ( TimeAttributeIndex * InAsset->NumberOfSamples ) ]; + + if ( FMath::IsNearlyEqual(SpawnTimes[ CurrentID ], -FLT_MAX) ) + { + // We have detected a new particle. + + // Calculate spawn and life from attributes. + // Spawn time is when the point is first seen + if (AgeAttributeIndex != INDEX_NONE) + { + // If we have an age attribute we can more accurately calculate the particle's spawn time. + SpawnTimes[ CurrentID ] = CurrentTime - FloatSampleData [rowIdx + (AgeAttributeIndex * InAsset->NumberOfSamples) ]; + } + else + { + // We don't have an age attribute. Simply use the current time as the spawn time. + // Note that we bias the value slightly to that the particle is already spawned at the CurrentTime. + SpawnTimes[ CurrentID ] = CurrentTime; + } + + if ( LifeAttributeIndex != INDEX_NONE ) + { + LifeValues[ CurrentID ] = FloatSampleData [rowIdx + (LifeAttributeIndex * InAsset->NumberOfSamples) ]; + } + } + + // If we don't have a life attribute, keep setting the life attribute for the particle + // so that when the particle is no longer present we have recorded its last observed time + if ( LifeAttributeIndex == INDEX_NONE && LifeValues[ CurrentID ] < CurrentTime) + { + // Life is the difference between spawn time and time of death + // Note that the particle should still be alive at this timestep. Since we don't + // have access to a frame rate here we will workaround this for now by adding + // a small value such that the particle dies *after* this timestep. + LifeValues[ CurrentID ] = CurrentTime - SpawnTimes[ CurrentID ]; + } + + // Keep track of the point type at spawn + if ( PointTypes[ CurrentID ] < 0 ) + { + float CurrentType = 0.0f; + if (TypeAttributeIndex != INDEX_NONE) + InAsset->GetFloatValue( rowIdx, TypeAttributeIndex, CurrentType ); + + PointTypes[ CurrentID ] = (int32)CurrentType; + } + + } + return true; +} +#endif + +#if WITH_EDITOR +bool FHoudiniPointCacheLoaderCSV::ParseCSVTitleRow( UHoudiniPointCache *InAsset, const FString& TitleRow, const FString& FirstValueRow, bool& HasPackedVectors ) +{ + // Get the relevant point cache asset data arrays + TArray &AttributeArray = InAsset->AttributeArray; + TArray &SpecialAttributeIndexes = InAsset->GetSpecialAttributeIndexes(); + + // Get the number of values per row via the title row + AttributeArray.Empty(); + TitleRow.ParseIntoArray( AttributeArray, TEXT(",") ); + InAsset->NumberOfAttributes = AttributeArray.Num(); + if ( InAsset->NumberOfAttributes < 1 ) + { + UE_LOG( LogHoudiniNiagara, Error, TEXT( "Could not load the CSV file, error: not enough columns." ) ); + return false; + } + + // Look for the position, normal and time attributes indexes + for ( int32 n = 0; n < AttributeArray.Num(); n++ ) + { + // Remove spaces from the title row + AttributeArray[ n ].ReplaceInline( TEXT(" "), TEXT("") ); + + FString CurrentTitle = AttributeArray[ n ]; + if ( CurrentTitle.Equals( TEXT("P.x"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("P"), ESearchCase::IgnoreCase ) ) + { + if ( !InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POSITION)) + SpecialAttributeIndexes[EHoudiniAttributes::POSITION] = n; + } + else if ( CurrentTitle.Equals( TEXT("N.x"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("N"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::NORMAL)) + SpecialAttributeIndexes[EHoudiniAttributes::NORMAL] = n; + } + else if ( CurrentTitle.Contains( TEXT("time"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TIME)) + SpecialAttributeIndexes[EHoudiniAttributes::TIME] = n; + } + else if ( CurrentTitle.Equals( TEXT("id"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POINTID)) + SpecialAttributeIndexes[EHoudiniAttributes::POINTID] = n; + } + else if ( CurrentTitle.Equals( TEXT("life"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::LIFE)) + SpecialAttributeIndexes[EHoudiniAttributes::LIFE] = n; + } + else if ( CurrentTitle.Equals( TEXT("age"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::AGE)) + SpecialAttributeIndexes[EHoudiniAttributes::AGE] = n; + } + else if ( CurrentTitle.Equals( TEXT("Cd.r"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("Cd"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::COLOR)) + SpecialAttributeIndexes[EHoudiniAttributes::COLOR] = n; + } + else if ( CurrentTitle.Equals( TEXT("alpha"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::ALPHA)) + SpecialAttributeIndexes[EHoudiniAttributes::ALPHA] = n; + } + else if ( CurrentTitle.Equals( TEXT("v.x"), ESearchCase::IgnoreCase ) || CurrentTitle.Equals(TEXT("v"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::VELOCITY)) + SpecialAttributeIndexes[EHoudiniAttributes::VELOCITY] = n; + } + else if ( CurrentTitle.Equals(TEXT("type"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TYPE)) + SpecialAttributeIndexes[EHoudiniAttributes::TYPE] = n; + } + else if ( CurrentTitle.Equals(TEXT("impulse"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::IMPULSE)) + SpecialAttributeIndexes[EHoudiniAttributes::IMPULSE] = n; + } + } + + // Read the first row of the CSV file, and look for packed vectors value (X,Y,Z) + // We'll have to expand them in the title row to match the parsed data + HasPackedVectors = false; + int32 FoundPackedVectorCharIndex = 0; + while ( FoundPackedVectorCharIndex != INDEX_NONE ) + { + // Try to find ( in the row + FoundPackedVectorCharIndex = FirstValueRow.Find( TEXT("("), ESearchCase::IgnoreCase, ESearchDir::FromStart, FoundPackedVectorCharIndex ); + if ( FoundPackedVectorCharIndex == INDEX_NONE ) + break; + + // We want to know which column this char belong to + int32 FoundPackedVectorAttributeIndex = INDEX_NONE; + { + // Chop the first row up to the found character + FString FirstRowLeft = FirstValueRow.Left( FoundPackedVectorCharIndex ); + + // ReplaceInLine returns the number of occurences of ",", that's what we want! + FoundPackedVectorAttributeIndex = FirstRowLeft.ReplaceInline(TEXT(","), TEXT("")); + } + + if ( !AttributeArray.IsValidIndex( FoundPackedVectorAttributeIndex ) ) + { + UE_LOG( LogHoudiniNiagara, Warning, + TEXT( "Error while parsing the CSV File. Couldn't unpack vector found at character %d in the first row!" ), + FoundPackedVectorCharIndex + 1 ); + continue; + } + + // We found a packed vector, get its size + int32 FoundVectorSize = 0; + { + // Extract the vector string + int32 FoundPackedVectorEndCharIndex = FirstValueRow.Find( TEXT(")"), ESearchCase::IgnoreCase, ESearchDir::FromStart, FoundPackedVectorCharIndex ); + FString VectorString = FirstValueRow.Mid( FoundPackedVectorCharIndex + 1, FoundPackedVectorEndCharIndex - FoundPackedVectorCharIndex - 1 ); + + // Use ReplaceInLine to count the number of , to get the vector's size! + FoundVectorSize = VectorString.ReplaceInline( TEXT(","), TEXT("") ) + 1; + } + + if ( FoundVectorSize < 2 ) + continue; + + // Increment the number of columns + InAsset->NumberOfAttributes += ( FoundVectorSize - 1 ); + + // Extract the special attributes column indexes we found + int32 PositionAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POSITION); + int32 NormalAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::NORMAL); + int32 ColorAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::COLOR); + int32 AlphaAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::ALPHA); + int32 VelocityAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::VELOCITY); + + // Expand TitleRowArray + if ( ( FoundPackedVectorAttributeIndex == PositionAttributeIndex ) && ( FoundVectorSize == 3 ) ) + { + // Expand P to Px,Py,Pz + AttributeArray[ PositionAttributeIndex ] = TEXT("P.x"); + AttributeArray.Insert( TEXT( "P.y" ), PositionAttributeIndex + 1 ); + AttributeArray.Insert( TEXT( "P.z" ), PositionAttributeIndex + 2 ); + } + else if ( ( FoundPackedVectorAttributeIndex == NormalAttributeIndex ) && ( FoundVectorSize == 3 ) ) + { + // Expand N to Nx,Ny,Nz + AttributeArray[ NormalAttributeIndex ] = TEXT("N.x"); + AttributeArray.Insert( TEXT("N.y"), NormalAttributeIndex + 1 ); + AttributeArray.Insert( TEXT("N.z"), NormalAttributeIndex + 2 ); + } + else if ( ( FoundPackedVectorAttributeIndex == VelocityAttributeIndex ) && ( FoundVectorSize == 3 ) ) + { + // Expand V to Vx,Vy,Vz + AttributeArray[ VelocityAttributeIndex ] = TEXT("v.x"); + AttributeArray.Insert( TEXT("v.y"), VelocityAttributeIndex + 1 ); + AttributeArray.Insert( TEXT("v.z"), VelocityAttributeIndex + 2 ); + } + else if ( ( FoundPackedVectorAttributeIndex == ColorAttributeIndex ) && ( ( FoundVectorSize == 3 ) || ( FoundVectorSize == 4 ) ) ) + { + // Expand Cd to R, G, B + AttributeArray[ ColorAttributeIndex ] = TEXT("Cd.r"); + AttributeArray.Insert( TEXT("Cd.g"), ColorAttributeIndex + 1 ); + AttributeArray.Insert( TEXT("Cd.b"), ColorAttributeIndex + 2 ); + + if ( FoundVectorSize == 4 ) + { + // Insert A if we had RGBA + AttributeArray.Insert( TEXT("Cd.a"), ColorAttributeIndex + 3 ); + if ( AlphaAttributeIndex == INDEX_NONE ) + AlphaAttributeIndex = ColorAttributeIndex + 3; + } + } + else + { + // Expand the vector's title from V to V, V1, V2, V3 ... + FString FoundPackedVectortTitle = AttributeArray[ FoundPackedVectorAttributeIndex ]; + for ( int32 n = 0; n < FoundVectorSize; n++ ) + { + FString CurrentTitle = FString::Printf( TEXT( "%s.%d" ), *FoundPackedVectortTitle, n ); + if (n == 0) + AttributeArray[FoundPackedVectorAttributeIndex] = CurrentTitle; + else + AttributeArray.Insert( CurrentTitle, FoundPackedVectorAttributeIndex + n ); + } + } + + // We have inserted new column titles because of the packed vector, + // so we need to offset all the special attributes column indexes after the inserted values + for ( int32 AttrIdx = EHoudiniAttributes::HOUDINI_ATTR_BEGIN; AttrIdx < EHoudiniAttributes::HOUDINI_ATTR_SIZE; AttrIdx++ ) + { + if ( SpecialAttributeIndexes[AttrIdx] == INDEX_NONE ) + continue; + + if ( SpecialAttributeIndexes[AttrIdx] > FoundPackedVectorAttributeIndex ) + SpecialAttributeIndexes[AttrIdx] += FoundVectorSize - 1; + } + + HasPackedVectors = true; + FoundPackedVectorCharIndex++; + } + + // For sanity, Check that the number of columns matches the title row and the first row + { + // Check the title row + if ( InAsset->NumberOfAttributes != AttributeArray.Num() ) + UE_LOG( LogHoudiniNiagara, Error, + TEXT( "Error while parsing the CSV File. Found %d columns but the Title string has %d values! Some values will have an offset!" ), + InAsset->NumberOfAttributes, AttributeArray.Num() ); + + // Use ReplaceInLine to count the number of columns in the first row and make sure it's correct + FString FirstValueRowCopy = FirstValueRow; + int32 FirstRowColumnCount = FirstValueRowCopy.ReplaceInline( TEXT(","), TEXT("") ) + 1; + if ( InAsset->NumberOfAttributes != FirstRowColumnCount ) + UE_LOG( LogHoudiniNiagara, Error, + TEXT("Error while parsing the CSV File. Found %d columns but found %d values in the first row! Some values will have an offset!" ), + InAsset->NumberOfAttributes, FirstRowColumnCount ); + } + /* + // Update the TitleRow uproperty + TitleRow.Empty(); + for (int32 n = 0; n < TitleRowArray.Num(); n++) + { + TitleRow += TitleRowArray[n]; + if ( n < TitleRowArray.Num() - 1 ) + TitleRow += TEXT(","); + } + */ + + return true; +} #endif \ No newline at end of file diff --git a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSON.cpp b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSON.cpp index 556e037..acfe1e3 100644 --- a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSON.cpp +++ b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSON.cpp @@ -1,226 +1,229 @@ -#include "HoudiniPointCacheLoaderJSON.h" -#include "HoudiniPointCache.h" - -#include "HAL/FileManager.h" -#include "Misc/FileHelper.h" -#include "Serialization/JsonReader.h" -#include "Serialization/JsonSerializer.h" - - -FHoudiniPointCacheLoaderJSON::FHoudiniPointCacheLoaderJSON(const FString& InFilePath) : - FHoudiniPointCacheLoaderJSONBase(InFilePath) -{ - -} - -#if WITH_EDITOR -bool FHoudiniPointCacheLoaderJSON::LoadToAsset(UHoudiniPointCache *InAsset) -{ - const FString& InFilePath = GetFilePath(); - FScopedLoadingState ScopedLoadingState(*InFilePath); - - FString JsonString; - if (!FFileHelper::LoadFileToString(JsonString, *InFilePath)) - { - UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to read file '%s'."), *InFilePath); - return false; - } - - const TSharedRef>& Reader = TJsonReaderFactory<>::Create(JsonString); - - // Attempt to deserialize the JSON file to a FJsonObject - TSharedPtr PointCacheObject; - if (!FJsonSerializer::Deserialize(Reader, PointCacheObject) || !PointCacheObject.IsValid()) - { - UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to deserialize file '%s'."), *InFilePath); - return false; - } - - // Populate the header struct from 'header' JSON object - FHoudiniPointCacheJSONHeader Header; - if (!ReadHeader(*PointCacheObject, Header)) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not read header.")); - return false; - } - - // Set up the Attribute and SpecialAttributeIndexes arrays in the asset, - // expanding attributes with size > 1 - // If time was not an attribute in the file, we add it as an attribute - // but we always set time to the frame's time, irrespective of the existence of a time - // attribute in the file - uint32 NumAttributesPerFileSample = Header.NumAttributeComponents; - ParseAttributesAndInitAsset(InAsset, Header); - - // Get Age attribute index, we'll use this to ensure we sort point spawn time correctly - int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); - int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); - - // Due to the way that some of the DI functions work, - // we expect that the point IDs start at zero, and increment as the points are spawned - // Make sure this is the case by converting the point IDs as we read them - int32 NextPointID = 0; - TMap HoudiniIDToNiagaraIDMap; - - // Expect cache_data key, object start, frames key - const TSharedPtr &CacheDataObject = PointCacheObject->GetObjectField("cache_data"); - if (!CacheDataObject.IsValid()) - return false; - - const TArray> &Frames = CacheDataObject->GetArrayField("frames"); - - if (Frames.Num() != Header.NumFrames) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent num_frames in header vs body: %d vs %d"), Header.NumFrames, Frames.Num()); - return false; - } - - uint32 FrameStartSampleIndex = 0; - TArray> TempFrameData; - for (const TSharedPtr &FrameEntryAsValue : Frames) - { - const TSharedPtr &FrameEntryObject = FrameEntryAsValue->AsObject(); - if (!FrameEntryObject.IsValid()) - return false; - - float FrameNumber = FrameEntryObject->GetNumberField("number"); - float Time = FrameEntryObject->GetNumberField("time"); - uint32 NumPointsInFrame = FrameEntryObject->GetNumberField("num_points"); - - const TArray> FrameData = FrameEntryObject->GetArrayField("frame_data"); - - // Ensure we have enough space in our FrameData array to read the samples for this frame - TempFrameData.SetNum(NumPointsInFrame); - float PreviousAge = 0.0f; - bool bNeedToSort = false; - uint32 SampleIndex = 0; - for (const TSharedPtr &SampleAsValue : FrameData) - { - if (SampleIndex >= NumPointsInFrame) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Found more samples in frame %d as specified %d"), FrameNumber, NumPointsInFrame) - return false; - } - - // Initialize attributes for this sample - TempFrameData[SampleIndex].Init(0, NumAttributesPerFileSample); - uint32 AttrIndex = 0; - for (const TSharedPtr &AttrEntryAsValue : SampleAsValue->AsArray()) - { - if (AttrIndex >= NumAttributesPerFileSample) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Found more attributes in frame %d, sample %d as specified %d"), FrameNumber, SampleIndex, NumAttributesPerFileSample) - return false; - } - - float& Value = TempFrameData[SampleIndex][AttrIndex]; - Value = AttrEntryAsValue->AsNumber(); - - if (AgeAttributeIndex != INDEX_NONE && AttrIndex == AgeAttributeIndex) - { - if (SampleIndex == 0) - { - PreviousAge = Value; - } - else if (PreviousAge < Value) - { - bNeedToSort = true; - } - } - AttrIndex++; - } - - SampleIndex++; - } - - // Sort this frame's data by age - if (bNeedToSort) - { - TempFrameData.Sort(FHoudiniPointCacheSortPredicate(INDEX_NONE, AgeAttributeIndex, IDAttributeIndex)); - } - - ProcessFrame(InAsset, FrameNumber, TempFrameData, Time, FrameStartSampleIndex, NumPointsInFrame, NumAttributesPerFileSample, Header, HoudiniIDToNiagaraIDMap, NextPointID); - - FrameStartSampleIndex += NumPointsInFrame; - } - - // Load uncompressed raw data into asset. - // TODO: Rebuild JSON string from this buffer to avoid loading data twice. - if (!LoadRawPointCacheData(InAsset, *GetFilePath())) - { - return false; - } - - // Finalize load by compressing raw data. - CompressRawData(InAsset); - - return true; -} -#endif - -bool FHoudiniPointCacheLoaderJSON::ReadHeader(const FJsonObject &InPointCacheObject, FHoudiniPointCacheJSONHeader &OutHeader) const -{ - TSharedPtr HeaderObject = InPointCacheObject.GetObjectField("header"); - if (!HeaderObject.IsValid()) - return false; - - OutHeader.Version = HeaderObject->GetStringField("version"); - OutHeader.NumSamples = HeaderObject->GetNumberField("num_samples"); - OutHeader.NumFrames = HeaderObject->GetNumberField("num_frames"); - OutHeader.NumPoints = HeaderObject->GetNumberField("num_points"); - OutHeader.NumAttributes = HeaderObject->GetNumberField("num_attrib"); - - // Preallocate Attribute arrays from NumAttributes - OutHeader.Attributes.Empty(OutHeader.NumAttributes); - OutHeader.AttributeSizes.Empty(OutHeader.NumAttributes); - - for (const TSharedPtr &ArrayValue : HeaderObject->GetArrayField("attrib_name")) - { - OutHeader.Attributes.Add(ArrayValue->AsString()); - } - - // Check that attrib_name was the expected size - if (OutHeader.Attributes.Num() != OutHeader.NumAttributes) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_name array size mismatch: %d vs %d"), OutHeader.Attributes.Num(), OutHeader.NumAttributes); - return false; - } - - // Read attribute sizes and calculate the number of attribute components (sum of attribute size over all attributes) - OutHeader.NumAttributeComponents = 0; - for (const TSharedPtr &ArrayValue : HeaderObject->GetArrayField("attrib_size")) - { - uint8 AttrSize = ArrayValue->AsNumber(); - OutHeader.AttributeSizes.Add(AttrSize); - OutHeader.NumAttributeComponents += AttrSize; - } - - // Check that attrib_size was the expected size - if (OutHeader.AttributeSizes.Num() != OutHeader.NumAttributes) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_size array size mismatch: %d vs %d"), OutHeader.AttributeSizes.Num(), OutHeader.NumAttributes); - return false; - } - - OutHeader.AttributeComponentDataTypes.Empty(OutHeader.NumAttributeComponents); - - for (const TSharedPtr &ArrayValue : HeaderObject->GetArrayField("attrib_data_type")) - { - const FString& DataType = ArrayValue->AsString(); - if (DataType.Len() > 0) - OutHeader.AttributeComponentDataTypes.Add(DataType[0]); - else - OutHeader.AttributeComponentDataTypes.Add('\0'); - } - - // Check that attrib_data_type was the expected size - if (OutHeader.AttributeComponentDataTypes.Num() != OutHeader.NumAttributeComponents) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_data_type array size mismatch: %d vs %d"), OutHeader.AttributeComponentDataTypes.Num(), OutHeader.NumAttributeComponents); - return false; - } - - OutHeader.DataType = HeaderObject->GetStringField("data_type"); - - return true; -} +#include "HoudiniPointCacheLoaderJSON.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "HoudiniPointCache.h" +#include "Misc/FileHelper.h" +#include "Serialization/JsonReader.h" +#include "Serialization/JsonSerializer.h" + + +FHoudiniPointCacheLoaderJSON::FHoudiniPointCacheLoaderJSON(const FString& InFilePath) : + FHoudiniPointCacheLoaderJSONBase(InFilePath) +{ + +} + +#if WITH_EDITOR +bool FHoudiniPointCacheLoaderJSON::LoadToAsset(UHoudiniPointCache *InAsset) +{ + const FString& InFilePath = GetFilePath(); + FScopedLoadingState ScopedLoadingState(*InFilePath); + + FString JsonString; + if (!FFileHelper::LoadFileToString(JsonString, *InFilePath)) + { + UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to read file '%s'."), *InFilePath); + return false; + } + + const TSharedRef>& Reader = TJsonReaderFactory<>::Create(JsonString); + + // Attempt to deserialize the JSON file to a FJsonObject + TSharedPtr PointCacheObject; + if (!FJsonSerializer::Deserialize(Reader, PointCacheObject) || !PointCacheObject.IsValid()) + { + UE_LOG(LogHoudiniNiagara, Warning, TEXT("Failed to deserialize file '%s'."), *InFilePath); + return false; + } + + // Populate the header struct from 'header' JSON object + FHoudiniPointCacheJSONHeader Header; + if (!ReadHeader(*PointCacheObject, Header)) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not read header.")); + return false; + } + + // Set up the Attribute and SpecialAttributeIndexes arrays in the asset, + // expanding attributes with size > 1 + // If time was not an attribute in the file, we add it as an attribute + // but we always set time to the frame's time, irrespective of the existence of a time + // attribute in the file + uint32 NumAttributesPerFileSample = Header.NumAttributeComponents; + ParseAttributesAndInitAsset(InAsset, Header); + + // Get Age attribute index, we'll use this to ensure we sort point spawn time correctly + int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); + int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); + + // Due to the way that some of the DI functions work, + // we expect that the point IDs start at zero, and increment as the points are spawned + // Make sure this is the case by converting the point IDs as we read them + int32 NextPointID = 0; + TMap HoudiniIDToNiagaraIDMap; + + // Expect cache_data key, object start, frames key + const TSharedPtr &CacheDataObject = PointCacheObject->GetObjectField("cache_data"); + if (!CacheDataObject.IsValid()) + return false; + + const TArray> &Frames = CacheDataObject->GetArrayField("frames"); + + if (Frames.Num() != Header.NumFrames) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent num_frames in header vs body: %d vs %d"), Header.NumFrames, Frames.Num()); + return false; + } + + uint32 FrameStartSampleIndex = 0; + TArray> TempFrameData; + for (const TSharedPtr &FrameEntryAsValue : Frames) + { + const TSharedPtr &FrameEntryObject = FrameEntryAsValue->AsObject(); + if (!FrameEntryObject.IsValid()) + return false; + + float FrameNumber = FrameEntryObject->GetNumberField("number"); + float Time = FrameEntryObject->GetNumberField("time"); + uint32 NumPointsInFrame = FrameEntryObject->GetNumberField("num_points"); + + const TArray> FrameData = FrameEntryObject->GetArrayField("frame_data"); + + // Ensure we have enough space in our FrameData array to read the samples for this frame + TempFrameData.SetNum(NumPointsInFrame); + float PreviousAge = 0.0f; + bool bNeedToSort = false; + uint32 SampleIndex = 0; + for (const TSharedPtr &SampleAsValue : FrameData) + { + if (SampleIndex >= NumPointsInFrame) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Found more samples in frame %d as specified %d"), FrameNumber, NumPointsInFrame) + return false; + } + + // Initialize attributes for this sample + TempFrameData[SampleIndex].Init(0, NumAttributesPerFileSample); + uint32 AttrIndex = 0; + for (const TSharedPtr &AttrEntryAsValue : SampleAsValue->AsArray()) + { + if (AttrIndex >= NumAttributesPerFileSample) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Found more attributes in frame %d, sample %d as specified %d"), FrameNumber, SampleIndex, NumAttributesPerFileSample) + return false; + } + + float& Value = TempFrameData[SampleIndex][AttrIndex]; + Value = AttrEntryAsValue->AsNumber(); + + if (AgeAttributeIndex != INDEX_NONE && AttrIndex == AgeAttributeIndex) + { + if (SampleIndex == 0) + { + PreviousAge = Value; + } + else if (PreviousAge < Value) + { + bNeedToSort = true; + } + } + AttrIndex++; + } + + SampleIndex++; + } + + // Sort this frame's data by age + if (bNeedToSort) + { + TempFrameData.Sort(FHoudiniPointCacheSortPredicate(INDEX_NONE, AgeAttributeIndex, IDAttributeIndex)); + } + + ProcessFrame(InAsset, FrameNumber, TempFrameData, Time, FrameStartSampleIndex, NumPointsInFrame, NumAttributesPerFileSample, Header, HoudiniIDToNiagaraIDMap, NextPointID); + + FrameStartSampleIndex += NumPointsInFrame; + } + + // Load uncompressed raw data into asset. + // TODO: Rebuild JSON string from this buffer to avoid loading data twice. + if (!LoadRawPointCacheData(InAsset, *GetFilePath())) + { + return false; + } + + // Finalize load by compressing raw data. + CompressRawData(InAsset); + + return true; +} +#endif + +bool FHoudiniPointCacheLoaderJSON::ReadHeader(const FJsonObject &InPointCacheObject, FHoudiniPointCacheJSONHeader &OutHeader) const +{ + TSharedPtr HeaderObject = InPointCacheObject.GetObjectField("header"); + if (!HeaderObject.IsValid()) + return false; + + OutHeader.Version = HeaderObject->GetStringField("version"); + OutHeader.NumSamples = HeaderObject->GetNumberField("num_samples"); + OutHeader.NumFrames = HeaderObject->GetNumberField("num_frames"); + OutHeader.NumPoints = HeaderObject->GetNumberField("num_points"); + OutHeader.NumAttributes = HeaderObject->GetNumberField("num_attrib"); + + // Preallocate Attribute arrays from NumAttributes + OutHeader.Attributes.Empty(OutHeader.NumAttributes); + OutHeader.AttributeSizes.Empty(OutHeader.NumAttributes); + + for (const TSharedPtr &ArrayValue : HeaderObject->GetArrayField("attrib_name")) + { + OutHeader.Attributes.Add(ArrayValue->AsString()); + } + + // Check that attrib_name was the expected size + if (OutHeader.Attributes.Num() != OutHeader.NumAttributes) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_name array size mismatch: %d vs %d"), OutHeader.Attributes.Num(), OutHeader.NumAttributes); + return false; + } + + // Read attribute sizes and calculate the number of attribute components (sum of attribute size over all attributes) + OutHeader.NumAttributeComponents = 0; + for (const TSharedPtr &ArrayValue : HeaderObject->GetArrayField("attrib_size")) + { + uint8 AttrSize = ArrayValue->AsNumber(); + OutHeader.AttributeSizes.Add(AttrSize); + OutHeader.NumAttributeComponents += AttrSize; + } + + // Check that attrib_size was the expected size + if (OutHeader.AttributeSizes.Num() != OutHeader.NumAttributes) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_size array size mismatch: %d vs %d"), OutHeader.AttributeSizes.Num(), OutHeader.NumAttributes); + return false; + } + + OutHeader.AttributeComponentDataTypes.Empty(OutHeader.NumAttributeComponents); + + for (const TSharedPtr &ArrayValue : HeaderObject->GetArrayField("attrib_data_type")) + { + const FString& DataType = ArrayValue->AsString(); + if (DataType.Len() > 0) + OutHeader.AttributeComponentDataTypes.Add(DataType[0]); + else + OutHeader.AttributeComponentDataTypes.Add('\0'); + } + + // Check that attrib_data_type was the expected size + if (OutHeader.AttributeComponentDataTypes.Num() != OutHeader.NumAttributeComponents) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Header inconsistent: attrib_data_type array size mismatch: %d vs %d"), OutHeader.AttributeComponentDataTypes.Num(), OutHeader.NumAttributeComponents); + return false; + } + + OutHeader.DataType = HeaderObject->GetStringField("data_type"); + + return true; +} diff --git a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSONBase.cpp b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSONBase.cpp index 2d2fd96..4a1471b 100644 --- a/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSONBase.cpp +++ b/Source/HoudiniNiagara/Private/HoudiniPointCacheLoaderJSONBase.cpp @@ -1,340 +1,344 @@ -#include "HoudiniPointCacheLoaderJSONBase.h" -#include "HoudiniPointCache.h" - - -FHoudiniPointCacheLoaderJSONBase::FHoudiniPointCacheLoaderJSONBase(const FString& InFilePath) : - FHoudiniPointCacheLoader(InFilePath) -{ - -} - - -FHoudiniPointCacheLoaderJSONBase::~FHoudiniPointCacheLoaderJSONBase() -{ - -} - - -bool FHoudiniPointCacheLoaderJSONBase::ParseAttributesAndInitAsset(UHoudiniPointCache *InAsset, const FHoudiniPointCacheJSONHeader &InHeader) -{ - // Get the relevant point cache asset data arrays - TArray &AttributeArray = InAsset->AttributeArray; - TArray &SpecialAttributeIndexes = InAsset->GetSpecialAttributeIndexes(); - - // Reset the indexes of the special attributes - SpecialAttributeIndexes.Init(INDEX_NONE, EHoudiniAttributes::HOUDINI_ATTR_SIZE); - - InAsset->NumberOfAttributes = InHeader.NumAttributeComponents; - InAsset->AttributeArray.Empty(InAsset->NumberOfAttributes); - - // Look for the position, normal and time attributes indexes - uint32 AttrIndex = 0; - for (uint32 HeaderAttrIndex = 0; HeaderAttrIndex < InHeader.NumAttributes; ++HeaderAttrIndex) - { - uint32 AttrSize = InHeader.AttributeSizes[HeaderAttrIndex]; - // Remove spaces from the attribute name - FString AttrName = InHeader.Attributes[HeaderAttrIndex]; - AttrName.ReplaceInline( TEXT(" "), TEXT("") ); - - bool bIsVector = false; - bool bIsColor = false; - if (AttrName.Equals(TEXT("P"), ESearchCase::IgnoreCase)) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POSITION)) - SpecialAttributeIndexes[EHoudiniAttributes::POSITION] = AttrIndex; - bIsVector = true; - } - else if ( AttrName.Equals(TEXT("N"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::NORMAL)) - SpecialAttributeIndexes[EHoudiniAttributes::NORMAL] = AttrIndex; - bIsVector = true; - } - else if ( AttrName.Contains( TEXT("time"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TIME)) - SpecialAttributeIndexes[EHoudiniAttributes::TIME] = AttrIndex; - } - else if ( AttrName.Equals( TEXT("id"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POINTID)) - SpecialAttributeIndexes[EHoudiniAttributes::POINTID] = AttrIndex; - } - else if ( AttrName.Equals( TEXT("life"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::LIFE)) - SpecialAttributeIndexes[EHoudiniAttributes::LIFE] = AttrIndex; - } - else if ( AttrName.Equals( TEXT("age"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::AGE)) - SpecialAttributeIndexes[EHoudiniAttributes::AGE] = AttrIndex; - } - else if ( AttrName.Equals(TEXT("Cd"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::COLOR)) - SpecialAttributeIndexes[EHoudiniAttributes::COLOR] = AttrIndex; - bIsColor = true; - } - else if ( AttrName.Equals( TEXT("alpha"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::ALPHA)) - SpecialAttributeIndexes[EHoudiniAttributes::ALPHA] = AttrIndex; - } - else if ( AttrName.Equals(TEXT("v"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::VELOCITY)) - SpecialAttributeIndexes[EHoudiniAttributes::VELOCITY] = AttrIndex; - bIsVector = true; - } - else if ( AttrName.Equals(TEXT("type"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TYPE)) - SpecialAttributeIndexes[EHoudiniAttributes::TYPE] = AttrIndex; - } - else if ( AttrName.Equals(TEXT("impulse"), ESearchCase::IgnoreCase ) ) - { - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::IMPULSE)) - SpecialAttributeIndexes[EHoudiniAttributes::IMPULSE] = AttrIndex; - } - - if (AttrSize > 1) - { - const TCHAR VectorSuffixes[4] = {'x', 'y', 'z', 'w'}; - const TCHAR ColorSuffixes[4] = {'r', 'g', 'b', 'a'}; - for (uint32 ComponentIndex = 0; ComponentIndex < AttrSize; ++ComponentIndex) - { - if (bIsVector) - { - AttributeArray.Add(FString::Printf(TEXT("%s.%c"), *AttrName, VectorSuffixes[ComponentIndex])); - } - else if (bIsColor) - { - AttributeArray.Add(FString::Printf(TEXT("%s.%c"), *AttrName, ColorSuffixes[ComponentIndex])); - } - else - { - AttributeArray.Add(FString::Printf(TEXT("%s.%d"), *AttrName, ComponentIndex + 1)); - } - } - } - else - { - AttributeArray.Add(AttrName); - } - - AttrIndex += AttrSize; - } - - // If there was no time attribute in the file, add it - if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TIME)) - { - InAsset->AttributeArray.Add(TEXT("time")); - InAsset->NumberOfAttributes = InAsset->AttributeArray.Num(); - SpecialAttributeIndexes[EHoudiniAttributes::TIME] = InAsset->NumberOfAttributes - 1; - } - - // Get references to the various data arrays of the asset and initialize them - TArray &FloatSampleData = InAsset->GetFloatSampleData(); - TArray &SpawnTimes = InAsset->GetSpawnTimes(); - TArray &LifeValues = InAsset->GetLifeValues(); - TArray &PointTypes = InAsset->GetPointTypes(); - TArray &PointValueIndexes = InAsset->GetPointValueIndexes(); - - // Pre-allocate arrays in the point cache asset based off of the header - InAsset->NumberOfPoints = InHeader.NumPoints; - InAsset->NumberOfSamples = InHeader.NumSamples; - InAsset->NumberOfFrames = InHeader.NumFrames; - InAsset->FirstFrame = FLT_MAX; - InAsset->LastFrame = -FLT_MAX; - InAsset->MinSampleTime = FLT_MAX; - InAsset->MaxSampleTime = -FLT_MAX; - - FloatSampleData.Empty(InAsset->NumberOfSamples * InAsset->NumberOfAttributes); - FloatSampleData.Init(-FLT_MAX, InAsset->NumberOfSamples * InAsset->NumberOfAttributes); - SpawnTimes.Empty(InAsset->NumberOfPoints); - SpawnTimes.Init(-FLT_MAX, InAsset->NumberOfPoints); - LifeValues.Empty(InAsset->NumberOfPoints); - LifeValues.Init(-FLT_MAX, InAsset->NumberOfPoints); - PointTypes.Empty(InAsset->NumberOfPoints); - PointTypes.Init(-1, InAsset->NumberOfPoints); - PointValueIndexes.Empty(InAsset->NumberOfPoints); - PointValueIndexes.Init(FPointIndexes(), InAsset->NumberOfPoints); - - return true; -} - - -bool FHoudiniPointCacheLoaderJSONBase::ProcessFrame(UHoudiniPointCache *InAsset, float InFrameNumber, const TArray> &InFrameData, float InFrameTime, uint32 InFrameStartSampleIndex, uint32 InNumPointsInFrame, uint32 InNumAttributesPerPoint, const FHoudiniPointCacheJSONHeader &InHeader, TMap& InHoudiniIDToNiagaraIDMap, int32 &OutNextPointID) const -{ - // Get references to the various data arrays of the asset - TArray &FloatSampleData = InAsset->GetFloatSampleData(); - TArray &SpawnTimes = InAsset->GetSpawnTimes(); - TArray &LifeValues = InAsset->GetLifeValues(); - TArray &PointTypes = InAsset->GetPointTypes(); - TArray &PointValueIndexes = InAsset->GetPointValueIndexes(); - - // Set Min/Max Time seen in asset - if (InFrameTime < InAsset->MinSampleTime) - { - InAsset->MinSampleTime = InFrameTime; - } - if (InFrameTime > InAsset->MaxSampleTime) - { - InAsset->MaxSampleTime = InFrameTime; - } - if (InFrameNumber < InAsset->FirstFrame) - { - InAsset->FirstFrame = InFrameNumber; - } - if (InFrameNumber > InAsset->LastFrame) - { - InAsset->LastFrame = InFrameNumber; - } - - // Get Age attribute index, we'll use this to ensure we sort point spawn time correctly - int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); - int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); - int32 LifeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::LIFE); - int32 TypeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TYPE); - int32 TimeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TIME); - - if (InFrameData.Num() != InNumPointsInFrame) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent InFrameData size vs specified number of points in frame.")); - return false; - } - - // Copy the frame data into the FloatSampleData array, determine unique points IDs - // Also calculate SpawnTimes, LifeValues (if the life attribute exists) - int32 CurrentID = -1; - for (uint32 FrameSampleIndex = 0; FrameSampleIndex < InNumPointsInFrame; ++FrameSampleIndex) - { - uint32 SampleIndex = InFrameStartSampleIndex + FrameSampleIndex; - // Check Attribute sample array size - if (InFrameData[FrameSampleIndex].Num() != InNumAttributesPerPoint) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent InFrameData at SampleIndex %d: point attribute array size vs specified number of attributes per point."), SampleIndex); - return false; - } - for (uint32 AttrIndex = 0; AttrIndex < InNumAttributesPerPoint; ++AttrIndex) - { - // Get the float value for the attribute - float FloatValue = InFrameData[FrameSampleIndex][AttrIndex]; - - // Handle point IDs here - if (AttrIndex == IDAttributeIndex) - { - // If the point ID doesn't exist in the Houdini/Niagara mapping, create a new a entry. - // Otherwise, replace the point ID with the Niagara ID. - int32 PointID = FMath::FloorToInt(FloatValue); - - // The point ID may need to be replaced - if (!InHoudiniIDToNiagaraIDMap.Contains(PointID)) - { - // We found a new point, so we add it to the ID map - InHoudiniIDToNiagaraIDMap.Add(PointID, OutNextPointID++); - - // // Add a new array for that point's indexes - // PointValueIndexes.Add(FPointIndexes()); - } - - // Get the Niagara ID from the Houdini ID - CurrentID = InHoudiniIDToNiagaraIDMap[PointID]; - - // Check that CurrentID is still in the expected range - if (CurrentID < 0 || CurrentID >= InAsset->NumberOfPoints) - { - // ID is out of range - UE_LOG(LogHoudiniNiagara, Error, TEXT("Generated out of range point ID %d, expected max number of points %d"), CurrentID, InAsset->NumberOfPoints); - return false; - } - - FloatValue = static_cast(CurrentID); - - // Add the current sample index to this point's sample index list - PointValueIndexes[CurrentID].SampleIndexes.Add(SampleIndex); - } - - // Store the Value in the buffer - FloatSampleData[SampleIndex + (AttrIndex * InAsset->NumberOfSamples)] = FloatValue; - } - - // Always use the frame time, in other words, ignore a 'time' attribute - if (TimeAttributeIndex != INDEX_NONE) - { - FloatSampleData[SampleIndex + (TimeAttributeIndex * InAsset->NumberOfSamples)] = InFrameTime; - } - - // If we dont have Point ID information, we still want to fill the PointValueIndexes array - if (IDAttributeIndex == INDEX_NONE) - { - // Each sample is considered its own point - // PointValueIndexes.Add(FPointIndexes()); - PointValueIndexes[SampleIndex].SampleIndexes.Add(SampleIndex); - } - - // Calculate SpawnTimes, LifeValues and PointTypes - // Get the reconstructed point id - if (IDAttributeIndex != INDEX_NONE) - { - // Get remapped the external point ID to the expected Niagara particle ID. - CurrentID = static_cast(FloatSampleData[SampleIndex + (IDAttributeIndex * InAsset->NumberOfSamples)]); - // CurrentID = InHoudiniIDToNiagaraIDMap[CurrentID]; - } - else - { - CurrentID = SampleIndex; - } - - // The time value comes from the frame entry - const float CurrentTime = InFrameTime; - - if (FMath::IsNearlyEqual(SpawnTimes[CurrentID], -FLT_MAX)) - { - // We have detected a new particle. - - // Calculate spawn and life from attributes. - // Spawn time is when the point is first seen - if (AgeAttributeIndex != INDEX_NONE) - { - // If we have an age attribute we can more accurately calculate the particle's spawn time. - SpawnTimes[CurrentID] = CurrentTime - FloatSampleData[SampleIndex + (AgeAttributeIndex * InAsset->NumberOfSamples)]; - } - else - { - // We don't have an age attribute. Simply use the current time as the spawn time. - // Note that we bias the value slightly to that the particle is already spawned at the CurrentTime. - SpawnTimes[CurrentID] = CurrentTime; - } - - if (LifeAttributeIndex != INDEX_NONE) - { - LifeValues[CurrentID] = FloatSampleData[SampleIndex + (LifeAttributeIndex * InAsset->NumberOfSamples)]; - } - } - - // If we don't have a life attribute, keep setting the life attribute for the particle - // so that when the particle is no longer present we have recorded its last observed time - if (LifeAttributeIndex == INDEX_NONE && LifeValues[CurrentID] < CurrentTime) - { - // Life is the difference between spawn time and time of death - // Note that the particle should still be alive at this timestep. Since we don't - // have access to a frame rate here we will workaround this for now by adding - // a small value such that the particle dies *after* this timestep. - LifeValues[CurrentID] = CurrentTime - SpawnTimes[CurrentID]; - } - - // Keep track of the point type at spawn - if (PointTypes[CurrentID] < 0) - { - float CurrentType = 0.0f; - if (TypeAttributeIndex != INDEX_NONE) - CurrentType = FloatSampleData[SampleIndex + (TypeAttributeIndex * InAsset->NumberOfSamples)]; - - PointTypes[CurrentID] = static_cast(CurrentType); - } - } - - return true; +#include "HoudiniPointCacheLoaderJSONBase.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "HoudiniPointCache.h" + +FHoudiniPointCacheLoaderJSONBase::FHoudiniPointCacheLoaderJSONBase(const FString& InFilePath) : + FHoudiniPointCacheLoader(InFilePath) +{ + +} + + +FHoudiniPointCacheLoaderJSONBase::~FHoudiniPointCacheLoaderJSONBase() +{ + +} + + +bool FHoudiniPointCacheLoaderJSONBase::ParseAttributesAndInitAsset(UHoudiniPointCache *InAsset, const FHoudiniPointCacheJSONHeader &InHeader) +{ + // Get the relevant point cache asset data arrays + TArray &AttributeArray = InAsset->AttributeArray; + TArray &SpecialAttributeIndexes = InAsset->GetSpecialAttributeIndexes(); + + // Reset the indexes of the special attributes + SpecialAttributeIndexes.Init(INDEX_NONE, EHoudiniAttributes::HOUDINI_ATTR_SIZE); + + InAsset->NumberOfAttributes = InHeader.NumAttributeComponents; + InAsset->AttributeArray.Empty(InAsset->NumberOfAttributes); + + // Look for the position, normal and time attributes indexes + uint32 AttrIndex = 0; + for (uint32 HeaderAttrIndex = 0; HeaderAttrIndex < InHeader.NumAttributes; ++HeaderAttrIndex) + { + uint32 AttrSize = InHeader.AttributeSizes[HeaderAttrIndex]; + // Remove spaces from the attribute name + FString AttrName = InHeader.Attributes[HeaderAttrIndex]; + AttrName.ReplaceInline( TEXT(" "), TEXT("") ); + + bool bIsVector = false; + bool bIsColor = false; + if (AttrName.Equals(TEXT("P"), ESearchCase::IgnoreCase)) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POSITION)) + SpecialAttributeIndexes[EHoudiniAttributes::POSITION] = AttrIndex; + bIsVector = true; + } + else if ( AttrName.Equals(TEXT("N"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::NORMAL)) + SpecialAttributeIndexes[EHoudiniAttributes::NORMAL] = AttrIndex; + bIsVector = true; + } + else if ( AttrName.Contains( TEXT("time"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TIME)) + SpecialAttributeIndexes[EHoudiniAttributes::TIME] = AttrIndex; + } + else if ( AttrName.Equals( TEXT("id"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::POINTID)) + SpecialAttributeIndexes[EHoudiniAttributes::POINTID] = AttrIndex; + } + else if ( AttrName.Equals( TEXT("life"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::LIFE)) + SpecialAttributeIndexes[EHoudiniAttributes::LIFE] = AttrIndex; + } + else if ( AttrName.Equals( TEXT("age"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::AGE)) + SpecialAttributeIndexes[EHoudiniAttributes::AGE] = AttrIndex; + } + else if ( AttrName.Equals(TEXT("Cd"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::COLOR)) + SpecialAttributeIndexes[EHoudiniAttributes::COLOR] = AttrIndex; + bIsColor = true; + } + else if ( AttrName.Equals( TEXT("alpha"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::ALPHA)) + SpecialAttributeIndexes[EHoudiniAttributes::ALPHA] = AttrIndex; + } + else if ( AttrName.Equals(TEXT("v"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::VELOCITY)) + SpecialAttributeIndexes[EHoudiniAttributes::VELOCITY] = AttrIndex; + bIsVector = true; + } + else if ( AttrName.Equals(TEXT("type"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TYPE)) + SpecialAttributeIndexes[EHoudiniAttributes::TYPE] = AttrIndex; + } + else if ( AttrName.Equals(TEXT("impulse"), ESearchCase::IgnoreCase ) ) + { + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::IMPULSE)) + SpecialAttributeIndexes[EHoudiniAttributes::IMPULSE] = AttrIndex; + } + + if (AttrSize > 1) + { + const TCHAR VectorSuffixes[4] = {'x', 'y', 'z', 'w'}; + const TCHAR ColorSuffixes[4] = {'r', 'g', 'b', 'a'}; + for (uint32 ComponentIndex = 0; ComponentIndex < AttrSize; ++ComponentIndex) + { + if (bIsVector) + { + AttributeArray.Add(FString::Printf(TEXT("%s.%c"), *AttrName, VectorSuffixes[ComponentIndex])); + } + else if (bIsColor) + { + AttributeArray.Add(FString::Printf(TEXT("%s.%c"), *AttrName, ColorSuffixes[ComponentIndex])); + } + else + { + AttributeArray.Add(FString::Printf(TEXT("%s.%d"), *AttrName, ComponentIndex + 1)); + } + } + } + else + { + AttributeArray.Add(AttrName); + } + + AttrIndex += AttrSize; + } + + // If there was no time attribute in the file, add it + if (!InAsset->IsValidAttributeAttributeIndex(EHoudiniAttributes::TIME)) + { + InAsset->AttributeArray.Add(TEXT("time")); + InAsset->NumberOfAttributes = InAsset->AttributeArray.Num(); + SpecialAttributeIndexes[EHoudiniAttributes::TIME] = InAsset->NumberOfAttributes - 1; + } + + // Get references to the various data arrays of the asset and initialize them + TArray &FloatSampleData = InAsset->GetFloatSampleData(); + TArray &SpawnTimes = InAsset->GetSpawnTimes(); + TArray &LifeValues = InAsset->GetLifeValues(); + TArray &PointTypes = InAsset->GetPointTypes(); + TArray &PointValueIndexes = InAsset->GetPointValueIndexes(); + + // Pre-allocate arrays in the point cache asset based off of the header + InAsset->NumberOfPoints = InHeader.NumPoints; + InAsset->NumberOfSamples = InHeader.NumSamples; + InAsset->NumberOfFrames = InHeader.NumFrames; + InAsset->FirstFrame = FLT_MAX; + InAsset->LastFrame = -FLT_MAX; + InAsset->MinSampleTime = FLT_MAX; + InAsset->MaxSampleTime = -FLT_MAX; + + FloatSampleData.Empty(InAsset->NumberOfSamples * InAsset->NumberOfAttributes); + FloatSampleData.Init(-FLT_MAX, InAsset->NumberOfSamples * InAsset->NumberOfAttributes); + SpawnTimes.Empty(InAsset->NumberOfPoints); + SpawnTimes.Init(-FLT_MAX, InAsset->NumberOfPoints); + LifeValues.Empty(InAsset->NumberOfPoints); + LifeValues.Init(-FLT_MAX, InAsset->NumberOfPoints); + PointTypes.Empty(InAsset->NumberOfPoints); + PointTypes.Init(-1, InAsset->NumberOfPoints); + PointValueIndexes.Empty(InAsset->NumberOfPoints); + PointValueIndexes.Init(FPointIndexes(), InAsset->NumberOfPoints); + + return true; +} + + +bool FHoudiniPointCacheLoaderJSONBase::ProcessFrame(UHoudiniPointCache *InAsset, float InFrameNumber, const TArray> &InFrameData, float InFrameTime, uint32 InFrameStartSampleIndex, uint32 InNumPointsInFrame, uint32 InNumAttributesPerPoint, const FHoudiniPointCacheJSONHeader &InHeader, TMap& InHoudiniIDToNiagaraIDMap, int32 &OutNextPointID) const +{ + // Get references to the various data arrays of the asset + TArray &FloatSampleData = InAsset->GetFloatSampleData(); + TArray &SpawnTimes = InAsset->GetSpawnTimes(); + TArray &LifeValues = InAsset->GetLifeValues(); + TArray &PointTypes = InAsset->GetPointTypes(); + TArray &PointValueIndexes = InAsset->GetPointValueIndexes(); + + // Set Min/Max Time seen in asset + if (InFrameTime < InAsset->MinSampleTime) + { + InAsset->MinSampleTime = InFrameTime; + } + if (InFrameTime > InAsset->MaxSampleTime) + { + InAsset->MaxSampleTime = InFrameTime; + } + if (InFrameNumber < InAsset->FirstFrame) + { + InAsset->FirstFrame = InFrameNumber; + } + if (InFrameNumber > InAsset->LastFrame) + { + InAsset->LastFrame = InFrameNumber; + } + + // Get Age attribute index, we'll use this to ensure we sort point spawn time correctly + int32 IDAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::POINTID); + int32 AgeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::AGE); + int32 LifeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::LIFE); + int32 TypeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TYPE); + int32 TimeAttributeIndex = InAsset->GetAttributeAttributeIndex(EHoudiniAttributes::TIME); + + if (InFrameData.Num() != InNumPointsInFrame) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent InFrameData size vs specified number of points in frame.")); + return false; + } + + // Copy the frame data into the FloatSampleData array, determine unique points IDs + // Also calculate SpawnTimes, LifeValues (if the life attribute exists) + int32 CurrentID = -1; + for (uint32 FrameSampleIndex = 0; FrameSampleIndex < InNumPointsInFrame; ++FrameSampleIndex) + { + uint32 SampleIndex = InFrameStartSampleIndex + FrameSampleIndex; + // Check Attribute sample array size + if (InFrameData[FrameSampleIndex].Num() != InNumAttributesPerPoint) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Inconsistent InFrameData at SampleIndex %d: point attribute array size vs specified number of attributes per point."), SampleIndex); + return false; + } + for (uint32 AttrIndex = 0; AttrIndex < InNumAttributesPerPoint; ++AttrIndex) + { + // Get the float value for the attribute + float FloatValue = InFrameData[FrameSampleIndex][AttrIndex]; + + // Handle point IDs here + if (AttrIndex == IDAttributeIndex) + { + // If the point ID doesn't exist in the Houdini/Niagara mapping, create a new a entry. + // Otherwise, replace the point ID with the Niagara ID. + int32 PointID = FMath::FloorToInt(FloatValue); + + // The point ID may need to be replaced + if (!InHoudiniIDToNiagaraIDMap.Contains(PointID)) + { + // We found a new point, so we add it to the ID map + InHoudiniIDToNiagaraIDMap.Add(PointID, OutNextPointID++); + + // // Add a new array for that point's indexes + // PointValueIndexes.Add(FPointIndexes()); + } + + // Get the Niagara ID from the Houdini ID + CurrentID = InHoudiniIDToNiagaraIDMap[PointID]; + + // Check that CurrentID is still in the expected range + if (CurrentID < 0 || CurrentID >= InAsset->NumberOfPoints) + { + // ID is out of range + UE_LOG(LogHoudiniNiagara, Error, TEXT("Generated out of range point ID %d, expected max number of points %d"), CurrentID, InAsset->NumberOfPoints); + return false; + } + + FloatValue = static_cast(CurrentID); + + // Add the current sample index to this point's sample index list + PointValueIndexes[CurrentID].SampleIndexes.Add(SampleIndex); + } + + // Store the Value in the buffer + FloatSampleData[SampleIndex + (AttrIndex * InAsset->NumberOfSamples)] = FloatValue; + } + + // Always use the frame time, in other words, ignore a 'time' attribute + if (TimeAttributeIndex != INDEX_NONE) + { + FloatSampleData[SampleIndex + (TimeAttributeIndex * InAsset->NumberOfSamples)] = InFrameTime; + } + + // If we dont have Point ID information, we still want to fill the PointValueIndexes array + if (IDAttributeIndex == INDEX_NONE) + { + // Each sample is considered its own point + // PointValueIndexes.Add(FPointIndexes()); + PointValueIndexes[SampleIndex].SampleIndexes.Add(SampleIndex); + } + + // Calculate SpawnTimes, LifeValues and PointTypes + // Get the reconstructed point id + if (IDAttributeIndex != INDEX_NONE) + { + // Get remapped the external point ID to the expected Niagara particle ID. + CurrentID = static_cast(FloatSampleData[SampleIndex + (IDAttributeIndex * InAsset->NumberOfSamples)]); + // CurrentID = InHoudiniIDToNiagaraIDMap[CurrentID]; + } + else + { + CurrentID = SampleIndex; + } + + // The time value comes from the frame entry + const float CurrentTime = InFrameTime; + + if (FMath::IsNearlyEqual(SpawnTimes[CurrentID], -FLT_MAX)) + { + // We have detected a new particle. + + // Calculate spawn and life from attributes. + // Spawn time is when the point is first seen + if (AgeAttributeIndex != INDEX_NONE) + { + // If we have an age attribute we can more accurately calculate the particle's spawn time. + SpawnTimes[CurrentID] = CurrentTime - FloatSampleData[SampleIndex + (AgeAttributeIndex * InAsset->NumberOfSamples)]; + } + else + { + // We don't have an age attribute. Simply use the current time as the spawn time. + // Note that we bias the value slightly to that the particle is already spawned at the CurrentTime. + SpawnTimes[CurrentID] = CurrentTime; + } + + if (LifeAttributeIndex != INDEX_NONE) + { + LifeValues[CurrentID] = FloatSampleData[SampleIndex + (LifeAttributeIndex * InAsset->NumberOfSamples)]; + } + } + + // If we don't have a life attribute, keep setting the life attribute for the particle + // so that when the particle is no longer present we have recorded its last observed time + if (LifeAttributeIndex == INDEX_NONE && LifeValues[CurrentID] < CurrentTime) + { + // Life is the difference between spawn time and time of death + // Note that the particle should still be alive at this timestep. Since we don't + // have access to a frame rate here we will workaround this for now by adding + // a small value such that the particle dies *after* this timestep. + LifeValues[CurrentID] = CurrentTime - SpawnTimes[CurrentID]; + } + + // Keep track of the point type at spawn + if (PointTypes[CurrentID] < 0) + { + float CurrentType = 0.0f; + if (TypeAttributeIndex != INDEX_NONE) + CurrentType = FloatSampleData[SampleIndex + (TypeAttributeIndex * InAsset->NumberOfSamples)]; + + PointTypes[CurrentID] = static_cast(CurrentType); + } + } + + return true; } \ No newline at end of file diff --git a/Source/HoudiniNiagara/Private/NiagaraDataInterfaceHoudini.cpp b/Source/HoudiniNiagara/Private/NiagaraDataInterfaceHoudini.cpp index 07dcee0..18b2fcb 100644 --- a/Source/HoudiniNiagara/Private/NiagaraDataInterfaceHoudini.cpp +++ b/Source/HoudiniNiagara/Private/NiagaraDataInterfaceHoudini.cpp @@ -1,4022 +1,4175 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#include "NiagaraDataInterfaceHoudini.h" -#include "NiagaraTypes.h" -#include "Misc/FileHelper.h" -#include "NiagaraShader.h" -#include "NiagaraRenderer.h" -#include "NiagaraShaderParametersBuilder.h" -#include "ShaderParameterUtils.h" - -#define LOCTEXT_NAMESPACE "HoudiniNiagaraDataInterface" - -struct FNiagaraDataInterfaceParametersCS_Houdini : public FNiagaraDataInterfaceParametersCS -{ - DECLARE_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini, NonVirtual); - - LAYOUT_FIELD(TMemoryImageArray, FunctionIndexToAttribute); -}; - -IMPLEMENT_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini); - - - -// Base name for the member variables / buffers for GPU compatibility -const FString UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName(TEXT("_NumberOfSamples")); -const FString UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName(TEXT("_NumberOfAttributes")); -const FString UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName(TEXT("_NumberOfPoints")); -const FString UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName(TEXT("_FloatValuesBuffer")); -const FString UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName(TEXT("_SpecialAttributeIndexesBuffer")); -const FString UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName(TEXT("_SpawnTimesBuffer")); -const FString UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName(TEXT("_LifeValuesBuffer")); -const FString UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName(TEXT("_PointTypesBuffer")); -const FString UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName(TEXT("_MaxNumberOfIndexesPerPoint")); -const FString UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName(TEXT("_PointValueIndexesBuffer")); -const FString UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName(TEXT("_LastSpawnedPointId")); -const FString UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName(TEXT("_LastSpawnTime")); -const FString UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName(TEXT("_LastSpawnTimeRequest")); -const FString UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName(TEXT("_FunctionIndexToAttributeIndexBuffer")); - - -// Name of all the functions available in the data interface -static const FName GetFloatValueName("GetFloatValue"); -static const FName GetFloatValueByStringName("GetFloatValueByString"); -static const FName GetVectorValueName("GetVectorValue"); -static const FName GetVectorValueByStringName("GetVectorValueByString"); -static const FName GetVectorValueExName("GetVectorValueEx"); -static const FName GetVectorValueExByStringName("GetVectorValueExByString"); -static const FName GetVector4ValueName("GetVector4Value"); -static const FName GetVector4ValueByStringName("GetVector4ValueByString"); -static const FName GetQuatValueName("GetQuatValue"); -static const FName GetQuatValueByStringName("GetQuatValueByString"); - -static const FName GetPositionName("GetPosition"); -static const FName GetNormalName("GetNormal"); -static const FName GetTimeName("GetTime"); -static const FName GetVelocityName("GetVelocity"); -static const FName GetColorName("GetColor"); -static const FName GetImpulseName("GetImpulse"); -static const FName GetPositionAndTimeName("GetPositionAndTime"); - -static const FName GetNumberOfPointsName("GetNumberOfPoints"); -static const FName GetNumberOfSamplesName("GetNumberOfSamples"); -static const FName GetNumberOfAttributesName("GetNumberOfAttributes"); - -static const FName GetLastSampleIndexAtTimeName("GetLastSampleIndexAtTime"); -static const FName GetPointIDsToSpawnAtTimeName("GetPointIDsToSpawnAtTime"); -static const FName GetSampleIndexesForPointAtTimeName("GetSampleIndexesForPointAtTime"); - -static const FName GetPointPositionAtTimeName("GetPointPositionAtTime"); -static const FName GetPointValueAtTimeName("GetPointValueAtTime"); -static const FName GetPointValueAtTimeByStringName("GetPointValueAtTimeByString"); -static const FName GetPointVectorValueAtTimeName("GetPointVectorValueAtTime"); -static const FName GetPointVectorValueAtTimeByStringName("GetPointVectorValueAtTimeByString"); -static const FName GetPointVector4ValueAtTimeName("GetPointVector4ValueAtTime"); -static const FName GetPointVector4ValueAtTimeByStringName("GetPointVector4ValueAtTimeByString"); -static const FName GetPointVectorValueAtTimeExName("GetPointVectorValueAtTimeEx"); -static const FName GetPointVectorValueAtTimeExByStringName("GetPointVectorValueAtTimeExByString"); -static const FName GetPointQuatValueAtTimeName("GetPointQuatValueAtTime"); -static const FName GetPointQuatValueAtTimeByStringName("GetPointQuatValueAtTimeByString"); - -static const FName GetPointLifeName("GetPointLife"); -static const FName GetPointLifeAtTimeName("GetPointLifeAtTime"); -static const FName GetPointTypeName("GetPointType"); - -static const FName GetPointNormalAtTimeName("GetPointNormalAtTime"); -static const FName GetPointColorAtTimeName("GetPointColorAtTime"); -static const FName GetPointAlphaAtTimeName("GetPointAlphaAtTime"); -static const FName GetPointVelocityAtTimeName("GetPointVelocityAtTime"); -static const FName GetPointImpulseAtTimeName("GetPointImpulseAtTime"); -static const FName GetPointTypeAtTimeName("GetPointTypeAtTime"); - - - -UNiagaraDataInterfaceHoudini::UNiagaraDataInterfaceHoudini(FObjectInitializer const& ObjectInitializer) - : Super(ObjectInitializer) -{ - HoudiniPointCacheAsset = nullptr; - - Proxy.Reset(new FNiagaraDataInterfaceProxyHoudini()); -} - -void UNiagaraDataInterfaceHoudini::PostInitProperties() -{ - Super::PostInitProperties(); - - if (HasAnyFlags(RF_ClassDefaultObject)) - { - ENiagaraTypeRegistryFlags RegistryFlags = ENiagaraTypeRegistryFlags::AllowUserVariable - | ENiagaraTypeRegistryFlags::AllowSystemVariable - | ENiagaraTypeRegistryFlags::AllowEmitterVariable - | ENiagaraTypeRegistryFlags::AllowParameter; - - FNiagaraTypeRegistry::Register(FNiagaraTypeDefinition(GetClass()), RegistryFlags); - - RegistryFlags |= ENiagaraTypeRegistryFlags::AllowPayload; - FNiagaraTypeRegistry::Register(FHoudiniEvent::StaticStruct(), RegistryFlags); - } -} - -void UNiagaraDataInterfaceHoudini::PostLoad() -{ - Super::PostLoad(); - - MarkRenderDataDirty(); -} - -#if WITH_EDITOR - -void UNiagaraDataInterfaceHoudini::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) -{ - Super::PostEditChangeProperty(PropertyChangedEvent); - - if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UNiagaraDataInterfaceHoudini, HoudiniPointCacheAsset)) - { - Modify(); - if ( HoudiniPointCacheAsset ) - { - MarkRenderDataDirty(); - } - } -} - -#endif - -bool UNiagaraDataInterfaceHoudini::CopyToInternal(UNiagaraDataInterface* Destination) const -{ - if ( !Super::CopyToInternal( Destination ) ) - return false; - - UNiagaraDataInterfaceHoudini* CastedInterface = CastChecked( Destination ); - if ( !CastedInterface ) - return false; - - CastedInterface->HoudiniPointCacheAsset = HoudiniPointCacheAsset; - CastedInterface->MarkRenderDataDirty(); - - return true; -} - -bool UNiagaraDataInterfaceHoudini::Equals(const UNiagaraDataInterface* Other) const -{ - if ( !Super::Equals(Other) ) - return false; - - const UNiagaraDataInterfaceHoudini* OtherHN = CastChecked(Other); - - if ( OtherHN != nullptr && OtherHN->HoudiniPointCacheAsset != nullptr && HoudiniPointCacheAsset ) - { - // Just make sure the two interfaces point to the same file - return OtherHN->HoudiniPointCacheAsset->FileName.Equals( HoudiniPointCacheAsset->FileName ); - } - - return false; -} - -// Returns the signature of all the functions avaialable in the data interface -void UNiagaraDataInterfaceHoudini::GetFunctions(TArray& OutFunctions) -{ - { - // GetFloatValue - FNiagaraFunctionSignature Sig; - Sig.Name = GetFloatValueName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetFloatValue", - "Returns the float value in the point cache for a given Sample Index and Attribute Index.\n" ) ); - - OutFunctions.Add( Sig ); - } - - { - // GetFloatValueByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetFloatValueByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetFloatValueByString", - "Returns the float value in the point cache for a given Sample Index and Attribute name.\n" ) ); - - OutFunctions.Add(Sig); - } - - { - // GetVectorValue - FNiagaraFunctionSignature Sig; - Sig.Name = GetVectorValueName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetVectorValue", - "Returns a Vector3 in the point cache for a given Sample Index and Attribute Index.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetVectorValueByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetVectorValueByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueByString", - "Returns a Vector3 in the point cache for a given Sample Index and Attribute name.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetVectorValueEx - FNiagaraFunctionSignature Sig; - Sig.Name = GetVectorValueExName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueEx", - "Returns a Vector3 in the point cache for a given Sample Index and Attribute Index.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal).")); - - OutFunctions.Add(Sig); - } - - { - // GetVectorValueExByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetVectorValueExByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueExByString", - "Returns a Vector3 in the point cache for a given Sample Index and Attribute name.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal).")); - - OutFunctions.Add(Sig); - } - - { - // GetVector4Value - FNiagaraFunctionSignature Sig; - Sig.Name = GetVector4ValueName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetVectorValue", - "Returns a Vector4 in the point cache for a given Sample Index and Attribute Index.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetVector4ValueByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetVector4ValueByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueByString", - "Returns a Vector4 in the point cache for a given Sample Index and Attribute name.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetQuatValueEx - FNiagaraFunctionSignature Sig; - Sig.Name = GetQuatValueName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetQuatValue", - "Returns a Quat in the point cache for a given Sample Index and Attribute Index.\nThe DoHoudiniToUnrealConversion parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetQuatValueByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetQuatValueByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetQuatValueByString", - "Returns a Quat in the point cache for a given Sample Index and Attribute name.\nThe DoHoudiniToUnrealConversion parameter indicates if the quat should be converted from Houdini*s coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetPosition - FNiagaraFunctionSignature Sig; - Sig.Name = GetPositionName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Position"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPosition", - "Helper function returning the position value for a given sample index in the point cache file.\nThe returned Position vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPositionAndTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPositionAndTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Position"))); // Vector3 Out - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // float Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPositionAndTime", - "Helper function returning the position and time values for a given Sample Index in the point cache.\nThe returned Position vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetNormal - FNiagaraFunctionSignature Sig; - Sig.Name = GetNormalName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Normal"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNormal", - "Helper function returning the normal value for a given Sample Index in the point cache.\nThe returned Normal vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Float Out - - Sig.SetDescription( LOCTEXT("DataInterfaceHoudini_GetTime", - "Helper function returning the time value for a given Sample Index in the point cache.\n") ); - - OutFunctions.Add(Sig); - } - - { - // GetVelocity - FNiagaraFunctionSignature Sig; - Sig.Name = GetVelocityName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Velocity"))); // Vector3 Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVelocity", - "Helper function returning the velocity value for a given Sample Index in the point cache.\nThe returned velocity vector is converted from Houdini's coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetColor - FNiagaraFunctionSignature Sig; - Sig.Name = GetColorName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetColorDef(), TEXT("Color"))); // Color Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetColor", - "Helper function returning the color value for a given Sample Index in the point cache.")); - - OutFunctions.Add(Sig); - } - - { - // GetImpulse - FNiagaraFunctionSignature Sig; - Sig.Name = GetImpulseName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Impulse"))); // Float Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetImpulse", - "Helper function returning the impulse value for a given Sample Index in the point cache.\n")); - - OutFunctions.Add(Sig); - } - - { - // GetNumberOfPoints - FNiagaraFunctionSignature Sig; - Sig.Name = GetNumberOfPointsName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("NumberOfPoints"))); // Int Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNumberOfPoints", - "Returns the number of points (with different id values) in the point cache.\n" ) ); - - OutFunctions.Add(Sig); - } - - { - // GetNumberOfSamples - FNiagaraFunctionSignature Sig; - Sig.Name = GetNumberOfSamplesName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add( FNiagaraVariable( FNiagaraTypeDefinition( GetClass()), TEXT("PointCache") ) ); // PointCache in - Sig.Outputs.Add( FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("NumberOfSamples") ) ); // Int Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNumberOfSamples", - "Returns the number of samples in the point cache." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetNumberOfAttributes - FNiagaraFunctionSignature Sig; - Sig.Name = GetNumberOfAttributesName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add( FNiagaraVariable( FNiagaraTypeDefinition( GetClass()), TEXT("PointCache") ) ); // PointCache in - Sig.Outputs.Add( FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("NumberOfAttributes") ) ); // Int Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNumberOfAttributes", - "Returns the number of attributes in the point cache." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetLastSampleIndexAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetLastSampleIndexAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition(GetClass()), TEXT("PointCache") ) ); // PointCache in - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time") ) ); // Time in - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("LastSampleIndex") ) ); // Int Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetLastSampleIndexAtTime", - "Returns the index of the last sample in the point cache that has a time value lesser or equal to the Time parameter." ) ); - - OutFunctions.Add(Sig); - } - - { - //GetPointIDsToSpawnAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointIDsToSpawnAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition(GetClass()), TEXT("PointCache") ) ); // PointCache in - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time") ) ); // Time in - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTime") ) ); // Emitter state In - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTimeRequest") ) ); // Emitter state In - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("LastSpawnedPointID") ) ); // Emitter state In - Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetBoolDef(), TEXT("ResetSpawnState") ) ); // Emitter state In - - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("MinID") ) ); // Int Out - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("MaxID") ) ); // Int Out - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("Count") ) ); // Int Out - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTime") ) ); // Emitter state Out - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTimeRequest") ) ); // Emitter state Out - Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("LastSpawnedPointID") ) ); // Emitter state Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointIDsToSpawnAtTime", - "Returns the count and point IDs of the points that should spawn for a given time value." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetSampleIndexesForPointAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetSampleIndexesForPointAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PreviousSampleIndex"))); // Int Out - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("NextSampleIndex"))); // Int Out - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("PrevWeight"))); // Float Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetSampleIndexesForPointAtTime", - "Returns the sample indexes for a given point at a given time.\nThe previous index, next index and weight can then be used to Lerp between values.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointPositionAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointPositionAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Position"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointPositionAtTime", - "Helper function returning the linearly interpolated position for a given point at a given time.\nThe returned Position vector is converted from Houdini's coordinate system to Unreal's.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointValueAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointValueAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointValueAtTime", - "Returns the linearly interpolated value in the specified attribute for a given point at a given time." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPointValueAtTimeByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointValueAtTimeByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointValueAtTimeByString", - "Returns the linearly interpolated value in the specified attribute (by name) for a given point at a given time.")); - - OutFunctions.Add(Sig); - } - - { - // GetPointVectorValueAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVectorValueAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointVectorValueAtTime", - "Helper function returning the linearly interpolated Vector value in the specified Attribute Index for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPointVectorValueAtTimeByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVectorValueAtTimeByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVectorValueAtTimeByString", - "Helper function returning the linearly interpolated Vector value in the specified attribute (by name) for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetPointVector4ValueAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVector4ValueAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointVector4ValueAtTime", - "Helper function returning the linearly interpolated Vector4 value in the specified Attribute Index for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPointVectorValueAtTimeByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVector4ValueAtTimeByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVector4ValueAtTimeByString", - "Helper function returning the linearly interpolated Vector4 value in the specified attribute (by name) for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); - - OutFunctions.Add(Sig); - } - - { - // GetPointVectorValueAtTimeEx - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVectorValueAtTimeExName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVectorValueAtTime", - "Helper function returning the linearly interpolated Vector value in the specified attribute index for a given point at a given time.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal)." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPointVectorValueAtTimeExByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVectorValueAtTimeExByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVectorValueAtTimeByString", - "Helper function returning the linearly interpolated Vector value in the specified attribute (by name) for a given point at a given time.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal).")); - - OutFunctions.Add(Sig); - } - - { - // GetPointQuatValueAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointQuatValueAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointQuatValueAtTime", - "Helper function returning the linearly interpolated Quat value in the specified attribute index for a given point at a given time.\nThe DoHoudiniToUnrealConversion parameter indicates if the vector4 should be converted from Houdini*s coordinate system to Unreal's.\n" ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPointQuatValueAtTimeByString - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointQuatValueAtTimeByStringName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out - - Sig.FunctionSpecifiers.Add(FName("Attribute")); - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointQuatValueAtTimeByString", - "Helper function returning the linearly interpolated Quat value in the specified attribute (by name) for a given point at a given time.\nThe DoHoudiniToUnrealConversion parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\n")); - - OutFunctions.Add(Sig); - } - - { - // GetPointLife - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointLifeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Life"))); // Float Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointLife", - "Helper function returning the life value for a given point when spawned.\nThe life value is either calculated from the alive attribute or is the life attribute at spawn time.")); - - OutFunctions.Add(Sig); - } - - { - // GetPointLifeAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointLifeAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Life"))); // Float Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointLifeAtTime", - "Helper function returning the remaining life for a given point in the point cache at a given time." ) ); - - OutFunctions.Add(Sig); - } - - { - // GetPointType - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointTypeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("Type"))); // Int Out - - Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointType", - "Helper function returning the type value for a given point when spawned.\n")); - - OutFunctions.Add(Sig); - } - - { - // GetPointNormalAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointNormalAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Normal"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointNormalAtTime", - "Helper function returning the linearly interpolated normal for a given point at a given time.\nThe returned vector is converted from Houdini's coordinate system to Unreal's.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointColorAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointColorAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Color"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointColorAtTime", - "Helper function returning the linearly interpolated color for a given point at a given time.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointAlphaAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointAlphaAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Alpha"))); // Float Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointAlphaAtTime", - "Helper function returning the linearly interpolated alpha for a given point at a given time.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointVelocityAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointVelocityAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Velocity"))); // Vector3 Out - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointVelocityAtTime", - "Helper function returning the linearly interpolated velocity for a given point at a given time.\nThe returned vector is converted from Houdini's coordinate system to Unreal's.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointImpulseAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointImpulseAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Impulse"))); // Impulse - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointImpulseAtTime", - "Helper function returning the linearly interpolated impulse for a given point at a given time.") ); - - OutFunctions.Add(Sig); - } - - { - // GetPointTypeAtTime - FNiagaraFunctionSignature Sig; - Sig.Name = GetPointTypeAtTimeName; - Sig.bMemberFunction = true; - Sig.bRequiresContext = false; - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In - Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in - Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("Type"))); // Type - - Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointTypeAtTime", - "Helper function returning the integer type for a given point at a given time.") ); - - OutFunctions.Add(Sig); - } - -} - -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetFloatValue); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetFloatValueByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValue); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetVectorValueByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueEx); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetVectorValueExByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVector4Value); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetVector4ValueByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetQuatValue); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetQuatValueByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPosition); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetNormal); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetColor); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVelocity); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetImpulse); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPositionAndTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetLastSampleIndexAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointIDsToSpawnAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetSampleIndexesForPointAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointPositionAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointValueAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointValueAtTimeByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeEx); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeExByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTimeByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTimeByString); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLife); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLifeAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointType); - -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointNormalAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointColorAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointAlphaAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVelocityAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointImpulseAtTime); -DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointTypeAtTime); - -void UNiagaraDataInterfaceHoudini::GetVMExternalFunction(const FVMExternalFunctionBindingInfo& BindingInfo, void* InstanceData, FVMExternalFunction &OutFunc) -{ - static const FName NAME_Attribute("Attribute"); - - const FVMFunctionSpecifier* AttributeSpecifier = BindingInfo.FindSpecifier(NAME_Attribute); - bool bAttributeSpecifierRequiredButNotFound = false; - - if (BindingInfo.Name == GetFloatValueName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetFloatValue)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetFloatValueByStringName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetFloatValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetVectorValueName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValue)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetVectorValueByStringName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetVectorValueExName && BindingInfo.GetNumInputs() == 4 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueEx)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetVectorValueExByStringName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 3) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueExByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetVector4ValueName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 4) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVector4Value)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetVector4ValueByStringName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 4) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVector4ValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetQuatValueName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 4) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetQuatValue)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetQuatValueByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 4) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetQuatValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetPositionName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPosition)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetNormalName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetNormal)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetTimeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetVelocityName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVelocity)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetColorName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 4) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetColor)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetImpulseName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetImpulse)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPositionAndTimeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 4) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPositionAndTime)::Bind(this, OutFunc); - } - else if ( BindingInfo.Name == GetNumberOfPointsName && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1 ) - { - OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceHoudini::GetNumberOfPoints); - } - else if (BindingInfo.Name == GetNumberOfSamplesName && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1) - { - OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceHoudini::GetNumberOfSamples); - } - else if (BindingInfo.Name == GetNumberOfAttributesName && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1) - { - OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceHoudini::GetNumberOfAttributes); - } - else if (BindingInfo.Name == GetLastSampleIndexAtTimeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetLastSampleIndexAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointIDsToSpawnAtTimeName && BindingInfo.GetNumInputs() == 5 && BindingInfo.GetNumOutputs() == 6) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointIDsToSpawnAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetSampleIndexesForPointAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetSampleIndexesForPointAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointPositionAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointPositionAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointValueAtTimeName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointValueAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointValueAtTimeByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetPointVectorValueAtTimeName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointVectorValueAtTimeByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetPointVector4ValueAtTimeName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 4) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointVector4ValueAtTimeByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 4) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetPointVectorValueAtTimeExName && BindingInfo.GetNumInputs() == 5 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeEx)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointVectorValueAtTimeExByStringName && BindingInfo.GetNumInputs() == 4 && BindingInfo.GetNumOutputs() == 3) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeExByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetPointQuatValueAtTimeName && BindingInfo.GetNumInputs() == 4 && BindingInfo.GetNumOutputs() == 4) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointQuatValueAtTimeByStringName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 4) - { - if (AttributeSpecifier) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); - } - else - { - bAttributeSpecifierRequiredButNotFound = true; - } - } - else if (BindingInfo.Name == GetPointLifeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLife)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointLifeAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLifeAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointTypeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointType)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointNormalAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointNormalAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointColorAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointColorAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointAlphaAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointAlphaAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointVelocityAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVelocityAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointImpulseAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointImpulseAtTime)::Bind(this, OutFunc); - } - else if (BindingInfo.Name == GetPointTypeAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) - { - NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointTypeAtTime)::Bind(this, OutFunc); - } - else - { - UE_LOG( LogHoudiniNiagara, Error, - TEXT( "Could not find data interface function:\n\tName: %s\n\tInputs: %i\n\tOutputs: %i" ), - *BindingInfo.Name.ToString(), BindingInfo.GetNumInputs(), BindingInfo.GetNumOutputs() ); - OutFunc = FVMExternalFunction(); - } - - if (bAttributeSpecifierRequiredButNotFound) - { - // Attribute specifier was required but was not found - UE_LOG( - LogHoudiniNiagara, Error, - TEXT("Could not find specifier '%s' on function:\n\tName: %s\n\tInputs: %i\n\tOutputs: %i"), - *NAME_Attribute.ToString(), *BindingInfo.Name.ToString(), BindingInfo.GetNumInputs(), BindingInfo.GetNumOutputs() - ); - } -} - -void UNiagaraDataInterfaceHoudini::GetFloatValue(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for ( int32 i = 0; i < Context.GetNumInstances(); ++i ) - { - int32 SampleIndex = SampleIndexParam.Get(); - int32 AttributeIndex = AttributeIndexParam.Get(); - - float value = 0.0f; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetFloatValue( SampleIndex, AttributeIndex, value ); - - *OutValue.GetDest() = value; - SampleIndexParam.Advance(); - AttributeIndexParam.Advance(); - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVectorValue(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - int32 AttributeIndex = AttributeIndexParam.Get(); - - FVector V = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetVectorValue(SampleIndex, AttributeIndex, V); - - *OutVectorX.GetDest() = V.X; - *OutVectorY.GetDest() = V.Y; - *OutVectorZ.GetDest() = V.Z; - - SampleIndexParam.Advance(); - AttributeIndexParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVectorValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - FVector V = FVector::ZeroVector; - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetVectorValueForString(SampleIndex, Attribute, V); - - *OutVectorX.GetDest() = V.X; - *OutVectorY.GetDest() = V.Y; - *OutVectorZ.GetDest() = V.Z; - - SampleIndexParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVectorValueEx(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - VectorVM::FExternalFuncInputHandler DoSwapParam(Context); - VectorVM::FExternalFuncInputHandler DoScaleParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - int32 AttributeIndex = AttributeIndexParam.Get(); - - bool DoSwap = DoSwapParam.Get().GetValue(); - bool DoScale = DoScaleParam.Get().GetValue(); - - FVector V = FVector::ZeroVector; - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetVectorValue(SampleIndex, AttributeIndex, V, DoSwap, DoScale); - - *OutVectorX.GetDest() = V.X; - *OutVectorY.GetDest() = V.Y; - *OutVectorZ.GetDest() = V.Z; - - SampleIndexParam.Advance(); - AttributeIndexParam.Advance(); - DoSwapParam.Advance(); - DoScaleParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVectorValueExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler DoSwapParam(Context); - VectorVM::FExternalFuncInputHandler DoScaleParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - bool DoSwap = DoSwapParam.Get().GetValue(); - bool DoScale = DoScaleParam.Get().GetValue(); - - FVector V = FVector::ZeroVector; - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetVectorValueForString(SampleIndex, Attribute, V, DoSwap, DoScale); - - *OutVectorX.GetDest() = V.X; - *OutVectorY.GetDest() = V.Y; - *OutVectorZ.GetDest() = V.Z; - - SampleIndexParam.Advance(); - DoSwapParam.Advance(); - DoScaleParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVector4Value(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - int32 AttributeIndex = AttributeIndexParam.Get(); - - FVector4 V(FVector::ZeroVector, 0); - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetVector4Value(SampleIndex, AttributeIndex, V); - - *OutVectorX.GetDest() = V.X; - *OutVectorY.GetDest() = V.Y; - *OutVectorZ.GetDest() = V.Z; - *OutVectorW.GetDest() = V.W; - - SampleIndexParam.Advance(); - AttributeIndexParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - OutVectorW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVector4ValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - FVector4 V(FVector::ZeroVector, 0); - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetVector4ValueForString(SampleIndex, Attribute, V); - - *OutVectorX.GetDest() = V.X; - *OutVectorY.GetDest() = V.Y; - *OutVectorZ.GetDest() = V.Z; - *OutVectorW.GetDest() = V.W; - - SampleIndexParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - OutVectorW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetQuatValue(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - int32 AttributeIndex = AttributeIndexParam.Get(); - - bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); - - FQuat Q(0, 0, 0, 0); - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetQuatValue(SampleIndex, AttributeIndex, Q, DoHoudiniToUnrealConversion); - - *OutVectorX.GetDest() = Q.X; - *OutVectorY.GetDest() = Q.Y; - *OutVectorZ.GetDest() = Q.Z; - *OutVectorW.GetDest() = Q.W; - - SampleIndexParam.Advance(); - AttributeIndexParam.Advance(); - DoHoudiniToUnrealConversionParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - OutVectorW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetQuatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); - VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); - - FQuat Q(0, 0, 0, 0); - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetQuatValueForString(SampleIndex, Attribute, Q, DoHoudiniToUnrealConversion); - - *OutVectorX.GetDest() = Q.X; - *OutVectorY.GetDest() = Q.Y; - *OutVectorZ.GetDest() = Q.Z; - *OutVectorW.GetDest() = Q.W; - - SampleIndexParam.Advance(); - DoHoudiniToUnrealConversionParam.Advance(); - OutVectorX.Advance(); - OutVectorY.Advance(); - OutVectorZ.Advance(); - OutVectorW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetFloatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for ( int32 i = 0; i < Context.GetNumInstances(); ++i ) - { - int32 SampleIndex = SampleIndexParam.Get(); - - float value = 0.0f; - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetFloatValueForString(SampleIndex, Attribute, value); - - *OutValue.GetDest() = value; - SampleIndexParam.Advance(); - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPosition(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutSampleX(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleY(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - FVector V = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetPositionValue( SampleIndex, V ); - - *OutSampleX.GetDest() = V.X; - *OutSampleY.GetDest() = V.Y; - *OutSampleZ.GetDest() = V.Z; - SampleIndexParam.Advance(); - OutSampleX.Advance(); - OutSampleY.Advance(); - OutSampleZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetNormal(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutSampleX(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleY(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - FVector V = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetNormalValue( SampleIndex, V ); - - *OutSampleX.GetDest() = V.X; - *OutSampleY.GetDest() = V.Y; - *OutSampleZ.GetDest() = V.Z; - SampleIndexParam.Advance(); - OutSampleX.Advance(); - OutSampleY.Advance(); - OutSampleZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - float value = 0.0f; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetTimeValue( SampleIndex, value ); - - *OutValue.GetDest() = value; - SampleIndexParam.Advance(); - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetVelocity(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutSampleX(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleY(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - FVector V = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetVelocityValue( SampleIndex, V ); - - *OutSampleX.GetDest() = V.X; - *OutSampleY.GetDest() = V.Y; - *OutSampleZ.GetDest() = V.Z; - SampleIndexParam.Advance(); - OutSampleX.Advance(); - OutSampleY.Advance(); - OutSampleZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetColor(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutSampleR(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleG(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleB(Context); - VectorVM::FExternalFuncRegisterHandler OutSampleA(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - FLinearColor C = FLinearColor::White; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetColorValue( SampleIndex, C ); - - *OutSampleR.GetDest() = C.R; - *OutSampleG.GetDest() = C.G; - *OutSampleB.GetDest() = C.B; - *OutSampleA.GetDest() = C.A; - SampleIndexParam.Advance(); - OutSampleR.Advance(); - OutSampleG.Advance(); - OutSampleB.Advance(); - OutSampleA.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetImpulse(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - float value = 0.0f; - if (HoudiniPointCacheAsset) - HoudiniPointCacheAsset->GetImpulseValue(SampleIndex, value); - - *OutValue.GetDest() = value; - SampleIndexParam.Advance(); - OutValue.Advance(); - } -} - -// Returns the last index of the points that should be spawned at time t -void UNiagaraDataInterfaceHoudini::GetLastSampleIndexAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - float t = TimeParam.Get(); - - int32 value = 0; - if ( HoudiniPointCacheAsset ) - HoudiniPointCacheAsset->GetLastSampleIndexAtTime( t, value ); - - *OutValue.GetDest() = value; - TimeParam.Advance(); - OutValue.Advance(); - } -} - -// Returns the last index of the points that should be spawned at time t -void UNiagaraDataInterfaceHoudini::GetPointIDsToSpawnAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler TimeParam( Context ); - VectorVM::FExternalFuncInputHandler LastSpawnTimeParam( Context ); - VectorVM::FExternalFuncInputHandler LastSpawnTimeRequestParam( Context ); - VectorVM::FExternalFuncInputHandler LastSpawnedPointIDParam( Context ); - VectorVM::FExternalFuncInputHandler ResetSpawnStateParam( Context ); - - VectorVM::FExternalFuncRegisterHandler OutMinValue( Context ); - VectorVM::FExternalFuncRegisterHandler OutMaxValue( Context ); - VectorVM::FExternalFuncRegisterHandler OutCountValue( Context ); - VectorVM::FExternalFuncRegisterHandler OutLastSpawnTimeValue( Context ); - VectorVM::FExternalFuncRegisterHandler OutLastSpawnTimeRequestValue( Context ); - VectorVM::FExternalFuncRegisterHandler OutLastSpawnedPointIDValue( Context ); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - float t = TimeParam.Get(); - float LastSpawnTime = LastSpawnTimeParam.Get(); - float LastSpawnTimeRequest = LastSpawnTimeRequestParam.Get(); - int32 LastSpawnedPointID = LastSpawnedPointIDParam.Get(); - bool ResetSpawnState = ResetSpawnStateParam.Get(); - - if (ResetSpawnState) - { - LastSpawnTime = -FLT_MAX; - LastSpawnTimeRequest = -FLT_MAX; - LastSpawnedPointID = -1; - } - - - int32 value = 0; - int32 min = 0, max = 0, count = 0; - - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointIDsToSpawnAtTime(t, min, max, count, LastSpawnedPointID, LastSpawnTime, LastSpawnTimeRequest); - } - - *OutMinValue.GetDest() = min; - *OutMaxValue.GetDest() = max; - *OutCountValue.GetDest() = count; - - *OutLastSpawnTimeValue.GetDest() = LastSpawnTime; - *OutLastSpawnTimeRequestValue.GetDest() = LastSpawnTimeRequest; - *OutLastSpawnedPointIDValue.GetDest() = LastSpawnedPointID; - - - TimeParam.Advance(); - OutMinValue.Advance(); - OutMaxValue.Advance(); - OutCountValue.Advance(); - OutLastSpawnTimeValue.Advance(); - OutLastSpawnTimeRequestValue.Advance(); - OutLastSpawnedPointIDValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPositionAndTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - VectorVM::FExternalFuncRegisterHandler OutTime(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 SampleIndex = SampleIndexParam.Get(); - - float timeValue = 0.0f; - FVector posVector = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetTimeValue( SampleIndex, timeValue); - HoudiniPointCacheAsset->GetPositionValue( SampleIndex, posVector); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - - *OutTime.GetDest() = timeValue; - - SampleIndexParam.Advance(); - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - OutTime.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetSampleIndexesForPointAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPrevIndex(Context); - VectorVM::FExternalFuncRegisterHandler OutNextIndex(Context); - VectorVM::FExternalFuncRegisterHandler OutWeightValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - float weight = 0.0f; - int32 prevIdx = 0; - int32 nextIdx = 0; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetSampleIndexesForPointAtTime( PointID, time, prevIdx, nextIdx, weight ); - } - - *OutPrevIndex.GetDest() = prevIdx; - *OutNextIndex.GetDest() = nextIdx; - *OutWeightValue.GetDest() = weight; - - PointIDParam.Advance(); - TimeParam.Advance(); - OutPrevIndex.Advance(); - OutNextIndex.Advance(); - OutWeightValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointPositionAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - FVector posVector = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointPositionAtTime(PointID, time, posVector); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - - PointIDParam.Advance(); - TimeParam.Advance(); - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointValueAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - int32 AttrIndex = AttributeIndexParam.Get(); - float time = TimeParam.Get(); - - float Value = 0.0f; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointValueAtTime( PointID, AttrIndex, time, Value ); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - AttributeIndexParam.Advance(); - TimeParam.Advance(); - - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - float Value = 0.0f; - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointValueAtTimeForString(PointID, Attribute, time, Value); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - TimeParam.Advance(); - - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - int32 AttrIndex = AttributeIndexParam.Get(); - float time = TimeParam.Get(); - - FVector posVector = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointVectorValueAtTime( PointID, AttrIndex, time, posVector, true, true); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - - PointIDParam.Advance(); - AttributeIndexParam.Advance(); - TimeParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - FVector posVector = FVector::ZeroVector; - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointVectorValueAtTimeForString(PointID, Attribute, time, posVector, true, true); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - - PointIDParam.Advance(); - TimeParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTimeEx(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - VectorVM::FExternalFuncInputHandler DoSwapParam(Context); - VectorVM::FExternalFuncInputHandler DoScaleParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - int32 AttrIndex = AttributeIndexParam.Get(); - float time = TimeParam.Get(); - - bool DoSwap = DoSwapParam.Get().GetValue(); - bool DoScale = DoScaleParam.Get().GetValue(); - - FVector posVector = FVector::ZeroVector; - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointVectorValueAtTime(PointID, AttrIndex, time, posVector, DoSwap, DoScale); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - - PointIDParam.Advance(); - AttributeIndexParam.Advance(); - TimeParam.Advance(); - DoSwapParam.Advance(); - DoScaleParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTimeExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - VectorVM::FExternalFuncInputHandler DoSwapParam(Context); - VectorVM::FExternalFuncInputHandler DoScaleParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - bool DoSwap = DoSwapParam.Get().GetValue(); - bool DoScale = DoScaleParam.Get().GetValue(); - - FVector posVector = FVector::ZeroVector; - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointVectorValueAtTimeForString(PointID, Attribute, time, posVector, DoSwap, DoScale); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - - PointIDParam.Advance(); - TimeParam.Advance(); - DoSwapParam.Advance(); - DoScaleParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointVector4ValueAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - VectorVM::FExternalFuncRegisterHandler OutPosW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - int32 AttrIndex = AttributeIndexParam.Get(); - float time = TimeParam.Get(); - - FVector4 posVector(FVector::ZeroVector, 0); - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointVector4ValueAtTime( PointID, AttrIndex, time, posVector); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - *OutPosW.GetDest() = posVector.W; - - PointIDParam.Advance(); - AttributeIndexParam.Advance(); - TimeParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - OutPosW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointVector4ValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - VectorVM::FExternalFuncRegisterHandler OutPosW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - FVector4 posVector(FVector::ZeroVector, 0); - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointVector4ValueAtTimeForString(PointID, Attribute, time, posVector); - } - - *OutPosX.GetDest() = posVector.X; - *OutPosY.GetDest() = posVector.Y; - *OutPosZ.GetDest() = posVector.Z; - *OutPosW.GetDest() = posVector.W; - - PointIDParam.Advance(); - TimeParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - OutPosW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointQuatValueAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - VectorVM::FExternalFuncRegisterHandler OutPosW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - int32 AttrIndex = AttributeIndexParam.Get(); - float time = TimeParam.Get(); - - bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); - - FQuat Q(0, 0, 0, 0); - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointQuatValueAtTime(PointID, AttrIndex, time, Q, DoHoudiniToUnrealConversion); - } - - *OutPosX.GetDest() = Q.X; - *OutPosY.GetDest() = Q.Y; - *OutPosZ.GetDest() = Q.Z; - *OutPosW.GetDest() = Q.W; - - PointIDParam.Advance(); - AttributeIndexParam.Advance(); - TimeParam.Advance(); - DoHoudiniToUnrealConversionParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - OutPosW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointQuatValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutPosX(Context); - VectorVM::FExternalFuncRegisterHandler OutPosY(Context); - VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); - VectorVM::FExternalFuncRegisterHandler OutPosW(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); - - FQuat Q(0, 0, 0, 0); - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointQuatValueAtTimeForString(PointID, Attribute, time, Q, DoHoudiniToUnrealConversion); - } - - *OutPosX.GetDest() = Q.X; - *OutPosY.GetDest() = Q.Y; - *OutPosZ.GetDest() = Q.Z; - *OutPosW.GetDest() = Q.W; - - PointIDParam.Advance(); - TimeParam.Advance(); - DoHoudiniToUnrealConversionParam.Advance(); - - OutPosX.Advance(); - OutPosY.Advance(); - OutPosZ.Advance(); - OutPosW.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointLife(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - - float Value = 0.0f; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointLife(PointID, Value); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - - OutValue.Advance(); - } -} - -//template, typename VectorVM::FExternalFuncInputHandler> -void UNiagaraDataInterfaceHoudini::GetPointLifeAtTime(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float time = TimeParam.Get(); - - float Value = 0.0f; - if ( HoudiniPointCacheAsset ) - { - HoudiniPointCacheAsset->GetPointLifeAtTime(PointID, time, Value); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - TimeParam.Advance(); - - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointType(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - - int32 Value = 0; - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->GetPointType(PointID, Value); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointGenericVectorAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context, bool DoSwap, bool DoScale) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutVecX(Context); - VectorVM::FExternalFuncRegisterHandler OutVecY(Context); - VectorVM::FExternalFuncRegisterHandler OutVecZ(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float Time = TimeParam.Get(); - - FVector VectorValue = FVector::ZeroVector; - if ( HoudiniPointCacheAsset ) - { - int32 AttrIndex = HoudiniPointCacheAsset->GetAttributeAttributeIndex(Attribute); - HoudiniPointCacheAsset->GetPointVectorValueAtTime(PointID, AttrIndex, Time, VectorValue, DoSwap, DoScale); - } - - *OutVecX.GetDest() = VectorValue.X; - *OutVecY.GetDest() = VectorValue.Y; - *OutVecZ.GetDest() = VectorValue.Z; - - PointIDParam.Advance(); - TimeParam.Advance(); - OutVecX.Advance(); - OutVecY.Advance(); - OutVecZ.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointGenericFloatAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float Time = TimeParam.Get(); - - float Value = 0.0f; - if ( HoudiniPointCacheAsset ) - { - int32 AttrIndex = HoudiniPointCacheAsset->GetAttributeAttributeIndex(Attribute); - HoudiniPointCacheAsset->GetPointFloatValueAtTime(PointID, AttrIndex, Time, Value); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - TimeParam.Advance(); - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointGenericInt32AttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncInputHandler PointIDParam(Context); - VectorVM::FExternalFuncInputHandler TimeParam(Context); - - VectorVM::FExternalFuncRegisterHandler OutValue(Context); - - for (int32 i = 0; i < Context.GetNumInstances(); ++i) - { - int32 PointID = PointIDParam.Get(); - float Time = TimeParam.Get(); - - int32 Value = 0.0f; - if ( HoudiniPointCacheAsset ) - { - int32 AttrIndex = HoudiniPointCacheAsset->GetAttributeAttributeIndex(Attribute); - HoudiniPointCacheAsset->GetPointInt32ValueAtTime(PointID, AttrIndex, Time, Value); - } - - *OutValue.GetDest() = Value; - - PointIDParam.Advance(); - TimeParam.Advance(); - OutValue.Advance(); - } -} - -void UNiagaraDataInterfaceHoudini::GetPointNormalAtTime(FVectorVMExternalFunctionContext& Context) -{ - GetPointGenericVectorAttributeAtTime(EHoudiniAttributes::NORMAL, Context, true, false); -} - -void UNiagaraDataInterfaceHoudini::GetPointColorAtTime(FVectorVMExternalFunctionContext& Context) -{ - GetPointGenericVectorAttributeAtTime(EHoudiniAttributes::COLOR, Context, false, false); -} - -void UNiagaraDataInterfaceHoudini::GetPointAlphaAtTime(FVectorVMExternalFunctionContext& Context) -{ - GetPointGenericFloatAttributeAtTime(EHoudiniAttributes::ALPHA, Context); -} - -void UNiagaraDataInterfaceHoudini::GetPointVelocityAtTime(FVectorVMExternalFunctionContext& Context) -{ - GetPointGenericVectorAttributeAtTime(EHoudiniAttributes::VELOCITY, Context, true, true); -} - -void UNiagaraDataInterfaceHoudini::GetPointImpulseAtTime(FVectorVMExternalFunctionContext& Context) -{ - GetPointGenericFloatAttributeAtTime(EHoudiniAttributes::IMPULSE, Context); -} - -void UNiagaraDataInterfaceHoudini::GetPointTypeAtTime(FVectorVMExternalFunctionContext& Context) -{ - GetPointGenericInt32AttributeAtTime(EHoudiniAttributes::TYPE, Context); -} - - -void UNiagaraDataInterfaceHoudini::GetNumberOfSamples(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncRegisterHandler OutNumSamples(Context); - *OutNumSamples.GetDest() = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfSamples() : 0; - OutNumSamples.Advance(); -} - -void UNiagaraDataInterfaceHoudini::GetNumberOfAttributes(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncRegisterHandler OutNumAttributes(Context); - *OutNumAttributes.GetDest() = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfAttributes() : 0; - OutNumAttributes.Advance(); -} - -void UNiagaraDataInterfaceHoudini::GetNumberOfPoints(FVectorVMExternalFunctionContext& Context) -{ - VectorVM::FExternalFuncRegisterHandler OutNumPoints(Context); - *OutNumPoints.GetDest() = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfPoints() : 0; - OutNumPoints.Advance(); -} - -bool UNiagaraDataInterfaceHoudini::GetAttributeFunctionIndex(const TArray& InGeneratedFunctions, int InFunctionIndex, int &OutAttributeFunctionIndex) const -{ - const uint32 NumGeneratedFunctions = InGeneratedFunctions.Num(); - if (NumGeneratedFunctions == 0 || InFunctionIndex < 0) - return false; - - const FName NAME_Attribute(TEXT("Attribute")); - int AttributeFunctionIndex = 0; - for (uint32 FunctionIndex = 0; FunctionIndex < NumGeneratedFunctions; ++FunctionIndex) - { - const FNiagaraDataInterfaceGeneratedFunction& GeneratedFunction = InGeneratedFunctions[FunctionIndex]; - const FName *Attribute = GeneratedFunction.FindSpecifierValue(NAME_Attribute); - if (Attribute != nullptr) - { - if (FunctionIndex == InFunctionIndex) - { - OutAttributeFunctionIndex = AttributeFunctionIndex; - return true; - } - else - { - AttributeFunctionIndex++; - } - } - } - - return false; -} - - -void UNiagaraDataInterfaceHoudini::GetCommonHLSL(FString& OutHLSL) -{ - OutHLSL += TEXT("float4 q_slerp(in float4 Quat1, in float4 Quat2, float Slerp)\n" - "{\n" - "// Get cosine of angle between quats.\n" - "float RawCosom = \n" - "Quat1.x * Quat2.x +\n" - "Quat1.y * Quat2.y +\n" - "Quat1.z * Quat2.z +\n" - "Quat1.w * Quat2.w;\n" - "// Unaligned quats - compensate, results in taking shorter route.\n" - "float Cosom = RawCosom >= 0.f ? RawCosom : -RawCosom;\n" - - "float Scale0, Scale1;\n" - - "if( Cosom < 0.9999f )\n" - "{ \n" - "const float Omega = acos(Cosom);\n" - "const float InvSin = 1.f/sin(Omega);\n" - "Scale0 = sin( (1.f - Slerp) * Omega ) * InvSin;\n" - "Scale1 = sin( Slerp * Omega ) * InvSin;\n" - "}\n" - "else\n" - "{\n" - "// Use linear interpolation.\n" - "Scale0 = 1.0f - Slerp;\n" - "Scale1 = Slerp; \n" - "}\n" - - "// In keeping with our flipped Cosom:\n" - "Scale1 = RawCosom >= 0.f ? Scale1 : -Scale1;\n" - - "float4 Result;\n" - - "Result.x = Scale0 * Quat1.x + Scale1 * Quat2.x;\n" - "Result.y = Scale0 * Quat1.y + Scale1 * Quat2.y;\n" - "Result.z = Scale0 * Quat1.z + Scale1 * Quat2.z;\n" - "Result.w = Scale0 * Quat1.w + Scale1 * Quat2.w;\n" - - "return normalize(Result);\n" - "}\n" - ); -} - - -void UNiagaraDataInterfaceHoudini::BuildShaderParameters(FNiagaraShaderParametersBuilder& ShaderParametersBuilder) const -{ - ShaderParametersBuilder.AddNestedStruct(); -} - -void UNiagaraDataInterfaceHoudini::SetShaderParameters(const FNiagaraDataInterfaceSetShaderParametersContext& Context) const -{ - FNiagaraDataInterfaceProxyHoudini& DIProxy = Context.GetProxy(); - FShaderParameters* ShaderParameters = Context.GetParameterNestedStruct(); - - if (FHoudiniPointCacheResource* Resource = DIProxy.Resource) - { - ShaderParameters->NumberOfSamples = Resource->NumSamples; - ShaderParameters->NumberOfAttributes = Resource->NumAttributes; - ShaderParameters->NumberOfPoints = Resource->NumPoints; - ShaderParameters->MaxNumberOfIndexesPerPoint = Resource->MaxNumberOfIndexesPerPoint; - ShaderParameters->LastSpawnedPointId = -1; - ShaderParameters->LastSpawnTime = -FLT_MAX; - ShaderParameters->LastSpawnTimeRequest = -FLT_MAX; - ShaderParameters->FloatValuesBuffer = Resource->FloatValuesGPUBuffer.SRV; - ShaderParameters->SpecialAttributeIndexesBuffer = Resource->SpecialAttributeIndexesGPUBuffer.SRV; - ShaderParameters->SpawnTimesBuffer = Resource->SpawnTimesGPUBuffer.SRV; - ShaderParameters->LifeValuesBuffer = Resource->LifeValuesGPUBuffer.SRV; - ShaderParameters->PointTypesBuffer = Resource->PointTypesGPUBuffer.SRV; - ShaderParameters->PointValueIndexesBuffer = Resource->PointValueIndexesGPUBuffer.SRV; - - // Build the the function index to attribute index lookup table if it has not yet been built for this DI proxy - const FNiagaraDataInterfaceParametersCS_Houdini& ShaderStorage = Context.GetShaderStorage(); - DIProxy.UpdateFunctionIndexToAttributeIndexBuffer(ShaderStorage.FunctionIndexToAttribute); - if (DIProxy.FunctionIndexToAttributeIndexGPUBuffer.NumBytes > 0) - { - ShaderParameters->FunctionIndexToAttributeIndexBuffer = DIProxy.FunctionIndexToAttributeIndexGPUBuffer.SRV; - } - else - { - ShaderParameters->FunctionIndexToAttributeIndexBuffer = FNiagaraRenderer::GetDummyIntBuffer(); - } - } - else - { - ShaderParameters->NumberOfSamples = 0; - ShaderParameters->NumberOfAttributes = 0; - ShaderParameters->NumberOfPoints = 0; - ShaderParameters->MaxNumberOfIndexesPerPoint = 0; - ShaderParameters->LastSpawnedPointId = -1; - ShaderParameters->LastSpawnTime = -FLT_MAX; - ShaderParameters->LastSpawnTimeRequest = -FLT_MAX; - ShaderParameters->FloatValuesBuffer = FNiagaraRenderer::GetDummyFloatBuffer(); - ShaderParameters->SpecialAttributeIndexesBuffer = FNiagaraRenderer::GetDummyIntBuffer(); - ShaderParameters->SpawnTimesBuffer = FNiagaraRenderer::GetDummyFloatBuffer(); - ShaderParameters->LifeValuesBuffer = FNiagaraRenderer::GetDummyFloatBuffer(); - ShaderParameters->PointTypesBuffer = FNiagaraRenderer::GetDummyIntBuffer(); - ShaderParameters->PointValueIndexesBuffer = FNiagaraRenderer::GetDummyIntBuffer(); - ShaderParameters->FunctionIndexToAttributeIndexBuffer = FNiagaraRenderer::GetDummyIntBuffer(); - } -} - -FNiagaraDataInterfaceParametersCS* UNiagaraDataInterfaceHoudini::CreateShaderStorage(const FNiagaraDataInterfaceGPUParamInfo& ParameterInfo, const FShaderParameterMap& ParameterMap) const -{ - FNiagaraDataInterfaceParametersCS_Houdini* ShaderStorage = new FNiagaraDataInterfaceParametersCS_Houdini(); - - // Build an array of function index -> attribute name (for those functions with the Attribute specifier). If a function does not have the - // Attribute specifier, set to NAME_None - const uint32 NumGeneratedFunctions = ParameterInfo.GeneratedFunctions.Num(); - ShaderStorage->FunctionIndexToAttribute.Empty(NumGeneratedFunctions); - const FName NAME_Attribute("Attribute"); - for (const FNiagaraDataInterfaceGeneratedFunction& GeneratedFunction : ParameterInfo.GeneratedFunctions) - { - const FName* Attribute = GeneratedFunction.FindSpecifierValue(NAME_Attribute); - if (Attribute != nullptr) - { - ShaderStorage->FunctionIndexToAttribute.Add(*Attribute); - } - } - - ShaderStorage->FunctionIndexToAttribute.Shrink(); - - return ShaderStorage; -} - -const FTypeLayoutDesc* UNiagaraDataInterfaceHoudini::GetShaderStorageType() const -{ - return &StaticGetTypeLayoutDesc(); -} - -// Build the shader function HLSL Code. -bool UNiagaraDataInterfaceHoudini::GetFunctionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, const FNiagaraDataInterfaceGeneratedFunction& FunctionInfo, int FunctionInstanceIndex, FString& OutHLSL) -{ - // Build the buffer/variable names declared for this DI - FString NumberOfSamplesVar = ParamInfo.DataInterfaceHLSLSymbol + NumberOfSamplesBaseName; - FString NumberOfAttributesVar = ParamInfo.DataInterfaceHLSLSymbol + NumberOfAttributesBaseName; - FString NumberOfPointsVar = ParamInfo.DataInterfaceHLSLSymbol + NumberOfPointsBaseName; - FString FloatBufferVar = ParamInfo.DataInterfaceHLSLSymbol + FloatValuesBufferBaseName; - FString AttributeIndexesBuffer = ParamInfo.DataInterfaceHLSLSymbol + SpecialAttributeIndexesBufferBaseName; - FString SpawnTimeBuffer = ParamInfo.DataInterfaceHLSLSymbol + SpawnTimesBufferBaseName; - FString LifeValuesBuffer = ParamInfo.DataInterfaceHLSLSymbol + LifeValuesBufferBaseName; - FString PointTypesBuffer = ParamInfo.DataInterfaceHLSLSymbol + PointTypesBufferBaseName; - FString MaxNumberOfIndexesPerPointVar = ParamInfo.DataInterfaceHLSLSymbol + MaxNumberOfIndexesPerPointBaseName; - FString PointValueIndexesBuffer = ParamInfo.DataInterfaceHLSLSymbol + PointValueIndexesBufferBaseName; - FString FunctionIndexToAttributeIndexBuffer = ParamInfo.DataInterfaceHLSLSymbol + FunctionIndexToAttributeIndexBufferBaseName; - - // Lambda returning the HLSL code used for reading a Float value in the FloatBuffer - auto ReadFloatInBuffer = [&](const FString& OutFloatValue, const FString& FloatSampleIndex, const FString& FloatAttrIndex) - { - // \t OutValue = FloatBufferName[ (SampleIndex) + ( (AttrIndex) * (NumberOfSamplesName) ) ];\n - return TEXT("\t ") + OutFloatValue + TEXT(" = ") + FloatBufferVar + TEXT("[ (") + FloatSampleIndex + TEXT(") + ( (") + FloatAttrIndex + TEXT(") * (") + NumberOfSamplesVar + TEXT(") ) ];\n"); - }; - - // Lambda returning the HLSL code for reading a Vector value in the FloatBuffer - // It expects the In_DoSwap and In_DoScale bools to be defined before being called! - auto ReadVectorInBuffer = [&](const FString& OutVectorValue, const FString& VectorSampleIndex, const FString& VectorAttributeIndex) - { - FString OutHLSLCode; - OutHLSLCode += TEXT("\t// ReadVectorInBuffer\n"); - OutHLSLCode += TEXT("\t{\n"); - OutHLSLCode += TEXT("\t\tfloat3 temp_Value = float3(0.0, 0.0, 0.0);\n"); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.x"), VectorSampleIndex, VectorAttributeIndex); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.y"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 1")); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.z"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 2")); - OutHLSLCode += TEXT("\t\t") + OutVectorValue + TEXT(" = temp_Value;\n"); - OutHLSLCode += TEXT("\t\tif ( In_DoSwap )\n"); - OutHLSLCode += TEXT("\t\t{\n"); - OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".y= temp_Value.z;\n"); - OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".z= temp_Value.y;\n"); - OutHLSLCode += TEXT("\t\t}\n"); - OutHLSLCode += TEXT("\t\tif ( In_DoScale )\n"); - OutHLSLCode += TEXT("\t\t{\n"); - OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(" *= 100.0f;\n"); - OutHLSLCode += TEXT("\t\t}\n"); - OutHLSLCode += TEXT("\t}\n"); - return OutHLSLCode; - }; - - // Lambda returning the HLSL code for reading a Vector value in the FloatBuffer - // It expects the In_DoHoudiniToUnrealConversion bool to be defined before being called! - auto ReadVector4InBuffer = [&](const FString& OutVectorValue, const FString& VectorSampleIndex, const FString& VectorAttributeIndex) - { - FString OutHLSLCode; - OutHLSLCode += TEXT("\t// ReadVector4InBuffer\n"); - OutHLSLCode += TEXT("\t{\n"); - OutHLSLCode += TEXT("\t\tfloat4 temp_Value = float4(0.0, 0.0, 0.0, 0.0);\n"); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.x"), VectorSampleIndex, VectorAttributeIndex); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.y"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 1")); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.z"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 2")); - OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.w"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 3")); - OutHLSLCode += TEXT("\t\t") + OutVectorValue + TEXT(" = temp_Value;\n"); - OutHLSLCode += TEXT("\t\tif ( In_DoHoudiniToUnrealConversion )\n"); - OutHLSLCode += TEXT("\t\t{\n"); - OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".x= -temp_Value.x;\n"); - OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".y= -temp_Value.z;\n"); - OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".z= -temp_Value.y;\n"); - OutHLSLCode += TEXT("\t\t}\n"); - OutHLSLCode += TEXT("\t}\n"); - return OutHLSLCode; - }; - - // Lambda returning the HLSL code for reading a special attribute's index in the buffer - auto GetSpecAttributeIndex = [&](const EHoudiniAttributes& Attr) - { - FString OutHLSLCode; - OutHLSLCode += AttributeIndexesBuffer + TEXT("[") + FString::FromInt(Attr) + TEXT("]"); - return OutHLSLCode; - }; - - // Lambda returning an HLSL expression for testing if two floats are nearly equal - auto IsNearlyEqualExpression = [&](const FString& In_A, const FString& In_B, const FString& In_ErrorTolerance = "1.e-8f") - { - return FString::Printf(TEXT("( abs( %s - %s ) <= %s )"), *In_A, *In_B, *In_ErrorTolerance); - }; - - // Lambda returning the HLSL code for getting the previous and next sample indexes for a given particle at a given time - auto GetSampleIndexesForPointAtTime = [&](const FString& In_PointID, const FString& In_Time, const FString& Out_PreviousSampleIndex, const FString& Out_NextSampleIndex, const FString& Out_Weight) - { - FString OutHLSLCode; - OutHLSLCode += TEXT("\t// GetSampleIndexesForPointAtTime\n"); - OutHLSLCode += TEXT("\t{\n"); - - OutHLSLCode += TEXT("\t\tbool prev_time_valid = false;\n"); - OutHLSLCode += TEXT("\t\tfloat prev_time = -1.0f;\n"); - OutHLSLCode += TEXT("\t\tbool next_time_valid = false;\n"); - OutHLSLCode += TEXT("\t\tfloat next_time = -1.0f;\n"); - - // Look at all the values for this Point - OutHLSLCode += TEXT("\t\tfor( int n = 0; n < ") + MaxNumberOfIndexesPerPointVar + TEXT("; n++ )\n\t{\n"); - OutHLSLCode += TEXT("\t\t\tint current_sample_index = ") + PointValueIndexesBuffer + TEXT("[ (") + In_PointID + TEXT(") * ") + MaxNumberOfIndexesPerPointVar + TEXT(" + n ];\n"); - OutHLSLCode += TEXT("\t\t\tif ( current_sample_index < 0 ){ break; }\n"); - - OutHLSLCode += TEXT("\t\t\tfloat current_time = -1.0f;\n"); - OutHLSLCode += TEXT("\t\t\tint time_attr_index = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); - OutHLSLCode += TEXT("\t\t\tif ( time_attr_index < 0 || time_attr_index >= ") + NumberOfAttributesVar + TEXT(" )\n"); - OutHLSLCode += TEXT("\t\t\t\t{ current_time = 0.0f; }\n"); - OutHLSLCode += TEXT("\t\t\telse\n"); - OutHLSLCode += TEXT("\t\t\t{") + ReadFloatInBuffer(TEXT("current_time"), TEXT("current_sample_index"), TEXT("time_attr_index")) + TEXT(" }\n"); - - OutHLSLCode += TEXT("\t\t\tif ( ") + IsNearlyEqualExpression("current_time", In_Time) + TEXT(" )\n"); - OutHLSLCode += TEXT("\t\t\t\t{ ") + Out_PreviousSampleIndex + TEXT(" = current_sample_index; ") + Out_NextSampleIndex + TEXT(" = current_sample_index; ") + Out_Weight + TEXT(" = 1.0; break;}\n"); - OutHLSLCode += TEXT("\t\t\telse if ( current_time < (") + In_Time + TEXT(") ){\n"); - OutHLSLCode += TEXT("\t\t\t\tif ( !prev_time_valid || prev_time < current_time )\n"); - OutHLSLCode += TEXT("\t\t\t\t\t { ") + Out_PreviousSampleIndex + TEXT(" = current_sample_index; prev_time = current_time; prev_time_valid = true; }\n"); - OutHLSLCode += TEXT("\t\t\t}\n"); - OutHLSLCode += TEXT("\t\t\telse if ( !next_time_valid || next_time > current_time )\n"); - OutHLSLCode += TEXT("\t\t\t\t { ") + Out_NextSampleIndex + TEXT(" = current_sample_index; next_time = current_time; next_time_valid = true; break; }\n"); - OutHLSLCode += TEXT("\t\t}\n"); - - OutHLSLCode += TEXT("\t\tif ( ") + Out_PreviousSampleIndex + TEXT(" < 0 )\n"); - OutHLSLCode += TEXT("\t\t\t{ ") + Out_Weight + TEXT(" = 0.0f; ") + Out_PreviousSampleIndex + TEXT(" = ") + Out_NextSampleIndex + TEXT(";}\n"); - OutHLSLCode += TEXT("\t\tif ( ") + Out_NextSampleIndex + TEXT(" < 0 )\n"); - OutHLSLCode += TEXT("\t\t\t{ ") + Out_Weight + TEXT(" = 1.0f; ") + Out_NextSampleIndex + TEXT(" = ") + Out_PreviousSampleIndex + TEXT(";}\n"); - - // Calculate the weight - OutHLSLCode += TEXT("\t\t") + Out_Weight + TEXT(" = ( ( (") + In_Time + TEXT(") - prev_time ) / ( next_time - prev_time ) );\n"); - - OutHLSLCode += TEXT("\t}\n"); - return OutHLSLCode; - }; - - // Build each function's HLSL code - if (FunctionInfo.DefinitionName == GetFloatValueName) - { - // GetFloatValue(int In_SampleIndex, int In_AttributeIndex, out float Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, out float Out_Value) \n{\n"); - - OutHLSL += ReadFloatInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetVectorValueName) - { - // GetVectorValue(int In_SampleIndex, int In_AttributeIndex, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, out float3 Out_Value) \n{\n"); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = true;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetVectorValueExName) - { - // GetVectorValueEx(int In_SampleIndex, int In_AttributeIndex, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) \n{\n"); - - OutHLSL += ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetVector4ValueName) - { - // GetVector4Value(int In_SampleIndex, int In_AttributeIndex, out float4 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, out float4 Out_Value) \n{\n"); - - OutHLSL += TEXT("\tbool In_DoHoudiniToUnrealConversion = false;\n"); - OutHLSL += ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetQuatValueName) - { - // GetQuatValue(int In_SampleIndex, int In_AttributeIndex, bool In_DoHoudiniToUnrealConversion, out float4 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, bool In_DoHoudiniToUnrealConversion, out float4 Out_Value) \n{\n"); - - OutHLSL += ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPositionName) - { - // GetPosition(int In_SampleIndex, out float3 Out_Position) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Position) \n{\n"); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = true;\n"); - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex( EHoudiniAttributes::POSITION ) + TEXT(";\n"); - OutHLSL += ReadVectorInBuffer(TEXT("Out_Position"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPositionAndTimeName) - { - // GetPositionAndTime(int In_SampleIndex, out float3 Out_Position, out float Out_Time) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Position, out float Out_Time) \n{\n"); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = true;\n"); - OutHLSL += TEXT("\tint In_PosAttrIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::POSITION) + TEXT(";\n"); - OutHLSL += ReadVectorInBuffer(TEXT("Out_Position"), TEXT("In_SampleIndex"), TEXT("In_PosAttrIndex")); - - OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); - OutHLSL += ReadFloatInBuffer(TEXT("Out_Time"), TEXT("In_SampleIndex"), TEXT("In_TimeAttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetNormalName) - { - // GetNormal(int In_SampleIndex, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Normal) \n{\n"); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = false;\n"); - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::NORMAL) + TEXT(";\n"); - OutHLSL += ReadVectorInBuffer(TEXT("Out_Normal"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetTimeName) - { - // GetTime(int In_SampleIndex, out float Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float Out_Time) \n{\n"); - - OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); - OutHLSL += ReadFloatInBuffer(TEXT("Out_Time"), TEXT("In_SampleIndex"), TEXT("In_TimeAttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetVelocityName) - { - // GetVelocity(int In_SampleIndex, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Velocity) \n{\n"); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = false;\n"); - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::VELOCITY) + TEXT(";\n"); - OutHLSL += ReadVectorInBuffer(TEXT("Out_Velocity"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetImpulseName) - { - // GetImpulse(int In_SampleIndex, out float Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float Out_Impulse) \n{\n"); - - OutHLSL += TEXT("\tint In_ImpulseAttrIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::IMPULSE) + TEXT(";\n"); - OutHLSL += ReadFloatInBuffer(TEXT("Out_Impulse"), TEXT("In_SampleIndex"), TEXT("In_ImpulseAttrIndex")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetColorName) - { - // GetColor(int In_SampleIndex, out float4 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float4 Out_Color) \n{\n"); - - OutHLSL += TEXT("\tfloat3 temp_color = float3(1.0, 1.0, 1.0);\n"); - OutHLSL += TEXT("\tint In_ColorAttrIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::COLOR) + TEXT(";\n"); - OutHLSL += TEXT("\tbool In_DoSwap = false;\n"); - OutHLSL += TEXT("\tbool In_DoScale = false;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("temp_color"), TEXT("In_SampleIndex"), TEXT("In_ColorAttrIndex")); - - OutHLSL += TEXT("\tfloat temp_alpha = 1.0;\n"); - OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); - OutHLSL += ReadFloatInBuffer(TEXT("temp_alpha"), TEXT("In_SampleIndex"), TEXT("In_TimeAttributeIndex")); - - OutHLSL += TEXT("Out_Color.x = temp_color.x;\n"); - OutHLSL += TEXT("Out_Color.y = temp_color.y;\n"); - OutHLSL += TEXT("Out_Color.z = temp_color.z;\n"); - OutHLSL += TEXT("Out_Color.w = temp_alpha;\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetNumberOfPointsName) - { - // GetNumberOfPoints(out int Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(out int Out_NumPoints) \n{\n"); - OutHLSL += TEXT("\tOut_NumPoints = ") + NumberOfPointsVar + TEXT(";\n"); - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetNumberOfSamplesName) - { - // GetNumberOfSamples(out int Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(out int Out_NumSamples) \n{\n"); - OutHLSL += TEXT("\tOut_NumSamples = ") + NumberOfSamplesVar + TEXT(";\n"); - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetNumberOfAttributesName) - { - // GetNumberOfSamples(out int Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(out int Out_NumAttributes) \n{\n"); - OutHLSL += TEXT("\tOut_NumAttributes = ") + NumberOfAttributesVar + TEXT(";\n"); - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetLastSampleIndexAtTimeName) - { - // GetLastSampleIndexAtTime(float In_Time, out int Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(float In_Time, out int Out_Value) \n{\n"); - - OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex( EHoudiniAttributes::TIME ) + TEXT(";\n"); - OutHLSL += TEXT("\tfloat temp_time = 1.0;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("temp_time"), NumberOfSamplesVar + TEXT("- 1"), TEXT("In_TimeAttributeIndex")); - OutHLSL += TEXT("\tif ( temp_time < In_Time ) { Out_Value = ") + NumberOfSamplesVar + TEXT(" - 1; return; }\n"); - OutHLSL += TEXT("\tint lastSampleIndex = -1;\n"); - OutHLSL += TEXT("\tfor( int n = 0; n < ") + NumberOfSamplesVar + TEXT("; n++ )\n\t{\n"); - OutHLSL += TEXT("\t") + ReadFloatInBuffer(TEXT("temp_time"), TEXT("n"), TEXT("In_TimeAttributeIndex")); - OutHLSL += TEXT("\t\tif ( temp_time == In_Time ){ lastSampleIndex = n ;}"); - OutHLSL += TEXT("\t\telse if ( temp_time > In_Time ){ lastSampleIndex = n -1; return;}"); - OutHLSL += TEXT("\t\tif ( lastSampleIndex == -1 ){ lastSampleIndex = ") + NumberOfSamplesVar + TEXT(" - 1; }"); - OutHLSL += TEXT("\t}\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointIDsToSpawnAtTimeName) - { - // GetPointIDsToSpawnAtTime(float In_Time, float In_LastSpawnTime, float In_LastSpawnTimeRequest, int In_LastSpawnPointID, out int Out_MinID, out int Out_MaxID, out int Out_Count, out float Out_LastSpawnTime, out float Out_LastSpawnTimeRequest, out int Out_LastSpawnPointID) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(float In_Time, float In_LastSpawnTime, float In_LastSpawnTimeRequest, int In_LastSpawnedPointID, out int Out_MinID, out int Out_MaxID, out int Out_Count, out float Out_LastSpawnTime, out float Out_LastSpawnTimeRequest, out int Out_LastSpawnPointID) \n{\n"); - - OutHLSL += TEXT("\tint time_attr_index = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); - OutHLSL += TEXT("\tif( time_attr_index < 0 )\n"); - OutHLSL += TEXT("\t\t{ Out_Count = ") + NumberOfPointsVar +TEXT("; Out_MinID = 0; Out_MaxID = Out_Count - 1; In_LastSpawnTimeRequest = In_Time; return; }\n"); - - // GetLastPointIDToSpawnAtTime - OutHLSL += TEXT("\tint last_id = -1;\n"); - OutHLSL += TEXT("\tif ( ") + SpawnTimeBuffer + TEXT("[ ") + NumberOfPointsVar + TEXT(" - 1 ] < In_Time && In_Time > In_LastSpawnTimeRequest )\n"); - OutHLSL += TEXT("\t{\n"); - OutHLSL += TEXT("\t\tlast_id = ") + NumberOfPointsVar + TEXT(" - 1;\n"); - OutHLSL += TEXT("\t}\n"); - OutHLSL += TEXT("\telse\n"); - OutHLSL += TEXT("\t{\n"); - OutHLSL += TEXT("\t\tfloat temp_time = 0;\n"); - OutHLSL += TEXT("\t\tfor( int n = 0; n < ") + NumberOfPointsVar + TEXT("; n++ )\n\t\t{\n"); - OutHLSL += TEXT("\t\t\ttemp_time = ") + SpawnTimeBuffer + TEXT("[ n ];\n"); - OutHLSL += TEXT("\t\t\tif ( temp_time > In_Time )\n"); - OutHLSL += TEXT("\t\t\t\t{ break; }\n"); - OutHLSL += TEXT("\t\t\tlast_id = n;\n"); - OutHLSL += TEXT("\t\t}\n"); - OutHLSL += TEXT("\t}\n"); - - // First, detect if we need to reset LastSpawnedPointID (after a loop of the emitter) - OutHLSL += TEXT("\tif ( last_id < In_LastSpawnedPointID || In_Time <= In_LastSpawnTime || In_Time <= In_LastSpawnTimeRequest )\n"); - OutHLSL += TEXT("\t\t{ In_LastSpawnedPointID = -1; }\n"); - - OutHLSL += TEXT("\tif ( last_id < 0 )\n"); - OutHLSL += TEXT("\t{\n"); - // Nothing to spawn, t is lower than the point's time - OutHLSL += TEXT("\t\t In_LastSpawnedPointID = -1;\n"); - OutHLSL += TEXT("\t\tOut_MinID = last_id;\n"); - OutHLSL += TEXT("\t\tOut_MaxID = last_id;\n"); - OutHLSL += TEXT("\t\tOut_Count = 0;\n"); - OutHLSL += TEXT("\t}\n"); - OutHLSL += TEXT("\telse\n"); - OutHLSL += TEXT("\t{\n"); - - // The last time value in the CSV is lower than t, spawn everything if we didnt already! - OutHLSL += TEXT("\t\tif ( last_id >= In_LastSpawnedPointID )\n"); - OutHLSL += TEXT("\t\t{\n"); - OutHLSL += TEXT("\t\t\tlast_id = last_id - 1;\n"); - OutHLSL += TEXT("\t\t}\n"); - - OutHLSL += TEXT("\t\tif ( last_id == In_LastSpawnedPointID )\n"); - OutHLSL += TEXT("\t\t{\n"); - // We dont have any new point to spawn - OutHLSL += TEXT("\t\t\tOut_MinID = last_id;\n"); - OutHLSL += TEXT("\t\t\tOut_MaxID = last_id;\n"); - OutHLSL += TEXT("\t\t\tOut_Count = 0;\n"); - OutHLSL += TEXT("\t\t}\n"); - OutHLSL += TEXT("\t\telse\n"); - OutHLSL += TEXT("\t\t{\n"); - // We have points to spawn at time t - OutHLSL += TEXT("\t\t\tOut_MinID = In_LastSpawnedPointID + 1;\n"); - OutHLSL += TEXT("\t\t\tOut_MaxID = last_id;\n"); - OutHLSL += TEXT("\t\t\tOut_Count = Out_MaxID - Out_MinID + 1;\n"); - - OutHLSL += TEXT("\t\t\tIn_LastSpawnedPointID = Out_MaxID;\n"); - OutHLSL += TEXT("\t\t\tIn_LastSpawnTime = In_Time;\n"); - OutHLSL += TEXT("\t\t}\n"); - - OutHLSL += TEXT("\t}\n"); - - OutHLSL += TEXT("\tIn_LastSpawnTimeRequest = In_Time;\n"); - - // Output the sim state variables - OutHLSL += TEXT("\tOut_LastSpawnTimeRequest = In_LastSpawnTimeRequest;\n"); - OutHLSL += TEXT("\tOut_LastSpawnTime = In_LastSpawnTime;\n"); - OutHLSL += TEXT("\tIn_LastSpawnedPointID = In_LastSpawnedPointID;\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetSampleIndexesForPointAtTimeName) - { - // GetSampleIndexesForPointAtTime(int In_PointID, float In_Time, out int Out_PreviousSampleIndex, out int Out_NextSampleIndex, out float Out_Weight) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out int Out_PreviousSampleIndex, out int Out_NextSampleIndex, out float Out_Weight) \n{\n"); - - OutHLSL += TEXT("\tOut_PreviousSampleIndex = 0;\n\tOut_NextSampleIndex = 0;\n\tOut_Weight = 0;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("Out_PreviousSampleIndex"), TEXT("Out_NextSampleIndex"), TEXT("Out_Weight")); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointPositionAtTimeName) - { - // GetPointPositionAtTime(int In_PointID, float In_Time, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Value) \n{\n"); - OutHLSL += TEXT("Out_Value = float3( 0.0, 0.0, 0.0 );\n"); - OutHLSL += TEXT("\tint pos_attr_index = ") + GetSpecAttributeIndex(EHoudiniAttributes::POSITION) + TEXT(";\n"); - OutHLSL += TEXT("\tint prev_index = 0;int next_index = 0;float weight = 0.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = true;\n"); - - OutHLSL += TEXT("\tfloat3 prev_vector = float3( 0.0, 0.0, 0.0 );\n"); - OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("pos_attr_index")); - OutHLSL += TEXT("\tfloat3 next_vector = float3( 0.0, 0.0, 0.0 );\n"); - OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("pos_attr_index")); - - OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointValueAtTimeName) - { - // GetPointValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, out float Out_Value) \n{\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tfloat prev_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat next_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Value = lerp(prev_value, next_value, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeName) - { - // GetPointVectorValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) \n{\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = true;\n"); - - OutHLSL += TEXT("\tfloat3 prev_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeExName) - { - // GetPointVectorValueAtTimeEx(int In_PointID, int In_AttributeIndex, float In_Time, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) \n{\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tfloat3 prev_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - - return true; - } - else if (FunctionInfo.DefinitionName == GetPointVector4ValueAtTimeName) - { - // GetPointVector4ValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, out float4 Out_Value) \n{\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tbool In_DoHoudiniToUnrealConversion = false;\n"); - - OutHLSL += TEXT("\tfloat4 prev_vector;\n"); - OutHLSL += ReadVector4InBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat4 next_vector;\n"); - OutHLSL += ReadVector4InBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointQuatValueAtTimeName) - { - // GetPointQuatValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, bool In_DoHoudiniToUnrealConversion, out float4 Out_Value) \n{\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tfloat4 prev_quat;\n"); - OutHLSL += ReadVector4InBuffer(TEXT("prev_quat"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat4 next_quat;\n"); - OutHLSL += ReadVector4InBuffer(TEXT("next_quat"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Value = q_slerp(prev_quat, next_quat, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointLifeName) - { - // GetPointLife(int In_PointID, out float Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, out float Out_Value) \n{\n"); - - OutHLSL += TEXT("\tif ( ( In_PointID < 0 ) || ( In_PointID >= ") + NumberOfPointsVar + TEXT(") )\n"); - OutHLSL += TEXT("\t\t{Out_Value = -1.0f; return;}\n"); - OutHLSL += TEXT("\tOut_Value = ") + LifeValuesBuffer + TEXT("[ In_PointID ];\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointLifeAtTimeName) - { - // GetPointLifeAtTime(int In_PointID, float In_Time, out float Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float Out_Value) \n{\n"); - - OutHLSL += TEXT("\tif ( ( In_PointID < 0 ) || ( In_PointID >= ") + NumberOfPointsVar+ TEXT(") )\n"); - OutHLSL += TEXT("\t\t{Out_Value = -1; return;}\n"); - OutHLSL += TEXT("\telse if ( In_Time < ") + SpawnTimeBuffer + TEXT("[ In_PointID ] )\n"); - OutHLSL += TEXT("\t{\n"); - OutHLSL += TEXT("\t\tOut_Value = ") + LifeValuesBuffer + TEXT("[ In_PointID ];\n"); - OutHLSL += TEXT("\t}\n"); - OutHLSL += TEXT("\telse\n"); - OutHLSL += TEXT("\t{\n"); - OutHLSL += TEXT("\t\tOut_Value = ") + LifeValuesBuffer + TEXT("[ In_PointID ] - ( In_Time - ") + SpawnTimeBuffer + TEXT("[ In_PointID ] );\n"); - OutHLSL += TEXT("\t}\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointTypeName) - { - // GetPointType(int In_PointID, out int Out_Value) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, out int Out_Value) \n{\n"); - - OutHLSL += TEXT("\tif ( ( In_PointID < 0 ) || ( In_PointID >= ") + NumberOfPointsVar+ TEXT(") )\n"); - OutHLSL += TEXT("\t\t{Out_Value = -1; return;}\n"); - OutHLSL += TEXT("\tOut_Value = ") + PointTypesBuffer + TEXT("[ In_PointID ];\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - // BEGIN: helper GetPointAtTime functions, can potentially be removed once get attr by string functions are functional - else if (FunctionInfo.DefinitionName == GetPointNormalAtTimeName) - { - // GetPointNormalAtTime(int In_PointID, float In_Time, out float3 Out_Normal) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Normal) \n{\n"); - - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::NORMAL) + TEXT(";\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = false;\n"); - - OutHLSL += TEXT("\tfloat3 prev_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Normal = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointColorAtTimeName) - { - // GetPointColorAtTime(int In_PointID, float In_Time, out float3 Out_Color) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Color) \n{\n"); - - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::COLOR) + TEXT(";\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = false;\n"); - - OutHLSL += TEXT("\tfloat3 prev_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Color = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointAlphaAtTimeName) - { - // GetPointAlphaAtTime(int In_PointID, float In_Time, out float Out_Alpha) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float Out_Alpha) \n{\n"); - - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::ALPHA) + TEXT(";\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tfloat3 prev_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Alpha = lerp(prev_value, next_value, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointVelocityAtTimeName) - { - // GetPointVelocityAtTime(int In_PointID, float In_Time, out float3 Out_Velocity) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Velocity) \n{\n"); - - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::VELOCITY) + TEXT(";\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); - OutHLSL += TEXT("\tbool In_DoScale = true;\n"); - - OutHLSL += TEXT("\tfloat3 prev_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_vector;\n"); - OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Velocity = lerp(prev_vector, next_vector, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointImpulseAtTimeName) - { - // GetPointImpulseAtTime(int In_PointID, float In_Time, out float Out_Impulse) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float Out_Impulse) \n{\n"); - - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::ALPHA) + TEXT(";\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tfloat3 prev_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - OutHLSL += TEXT("\tfloat3 next_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Impulse = lerp(prev_value, next_value, weight);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointTypeAtTimeName) - { - // GetPointTypeAtTime(int In_PointID, float In_Time, out int Out_Type) - OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out int Out_Type) \n{\n"); - - OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TYPE) + TEXT(";\n"); - - OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); - OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - - OutHLSL += TEXT("\tfloat3 prev_value;\n"); - OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); - - OutHLSL += TEXT("\tOut_Type = floor(prev_value);\n"); - - OutHLSL += TEXT("\n}\n"); - return true; - // END: helper GetPointAtTime functions, can potentially be removed once get attr by string functions are functional - } - else if (FunctionInfo.DefinitionName == GetFloatValueByStringName || - FunctionInfo.DefinitionName == GetVectorValueByStringName || - FunctionInfo.DefinitionName == GetVectorValueExByStringName || - FunctionInfo.DefinitionName == GetVector4ValueByStringName || - FunctionInfo.DefinitionName == GetQuatValueByStringName) - { - static const TCHAR *FunctionBodyTemplate = TEXT( - "void {FunctionName}(int In_SampleIndex, {AdditionalFunctionArguments}out {AttributeType} Out_Value)\n" - "{\n" - " int AttributeIndex = {FunctionIndexToAttributeIndexVarName}[{AttributeFunctionIndex}];\n" - " {VectorExFunctionDefaults}\n" - " {ReadFromBufferSnippet}\n" - "}\n\n" - ); - - int AttributeFunctionIndex = -1; - const bool bFoundAttributeFunctionIndex = GetAttributeFunctionIndex(ParamInfo.GeneratedFunctions, FunctionInstanceIndex, AttributeFunctionIndex); - if (!bFoundAttributeFunctionIndex) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not determine index for function (counted by Attribute specifier) for '%s'."), *FunctionInfo.InstanceName); - return false; - } - - FString AttributeTypeName; - FString ReadFromBufferSnippet; - FString AdditionalFunctionArguments; - FString VectorExFunctionDefaults; - if (FunctionInfo.DefinitionName == GetFloatValueByStringName) - { - AttributeTypeName = "float"; - AdditionalFunctionArguments = ""; - VectorExFunctionDefaults = ""; - ReadFromBufferSnippet = ReadFloatInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); - } - else if (FunctionInfo.DefinitionName == GetVectorValueByStringName) - { - AttributeTypeName = "float3"; - AdditionalFunctionArguments = ""; - VectorExFunctionDefaults = TEXT( - " bool In_DoSwap = true;\n" - " bool In_DoScale = true;\n" - ); - ReadFromBufferSnippet = ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); - } - else if (FunctionInfo.DefinitionName == GetVectorValueExByStringName) - { - AttributeTypeName = "float3"; - AdditionalFunctionArguments = TEXT("bool In_DoSwap, bool In_DoScale, "); - VectorExFunctionDefaults = ""; - ReadFromBufferSnippet = ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); - } - else if (FunctionInfo.DefinitionName == GetVector4ValueByStringName) - { - AttributeTypeName = "float4"; - AdditionalFunctionArguments = ""; - VectorExFunctionDefaults = TEXT( - " bool In_DoHoudiniToUnrealConversion = false;\n" - ); - ReadFromBufferSnippet = ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); - } - else if (FunctionInfo.DefinitionName == GetQuatValueByStringName) - { - AttributeTypeName = "float4"; - AdditionalFunctionArguments = TEXT("bool In_DoHoudiniToUnrealConversion, "); - VectorExFunctionDefaults = ""; - ReadFromBufferSnippet = ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); - } - else - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Unexpected function definition name: '%s'"), *FunctionInfo.DefinitionName.ToString()); - return false; - } - - TMap FunctionTemplateArgs = { - {TEXT("FunctionName"), FunctionInfo.InstanceName}, - {TEXT("AttributeType"), AttributeTypeName}, - {TEXT("FunctionIndexToAttributeIndexVarName"), FunctionIndexToAttributeIndexBuffer}, - {TEXT("AttributeFunctionIndex"), AttributeFunctionIndex}, - {TEXT("AdditionalFunctionArguments"), AdditionalFunctionArguments}, - {TEXT("VectorExFunctionDefaults"), VectorExFunctionDefaults}, - {TEXT("ReadFromBufferSnippet"), ReadFromBufferSnippet}, - }; - - OutHLSL += FString::Format(FunctionBodyTemplate, FunctionTemplateArgs); - return true; - } - else if (FunctionInfo.DefinitionName == GetPointValueAtTimeByStringName || - FunctionInfo.DefinitionName == GetPointVectorValueAtTimeByStringName || - FunctionInfo.DefinitionName == GetPointVectorValueAtTimeExByStringName || - FunctionInfo.DefinitionName == GetPointVector4ValueAtTimeByStringName || - FunctionInfo.DefinitionName == GetPointQuatValueAtTimeByStringName) - { - static const TCHAR *FunctionBodyTemplate = TEXT( - "void {FunctionName}(int In_PointID, float In_Time, {AdditionalFunctionArguments}out {AttributeType} Out_Value)\n" - "{\n" - " int AttributeIndex = {FunctionIndexToAttributeIndexVarName}[{AttributeFunctionIndex}];\n" - " int prev_index = -1;\n" - " int next_index = -1;\n" - " float weight = 1.0f;\n" - " {GetSampleIndexesForPointAtTimeSnippet}\n" - "\n" - " {VectorExFunctionDefaults}\n" - " {AttributeType} prev_value;\n" - " {AttributeType} next_value;\n" - " {ReadPrevFromBufferSnippet}\n" - " {ReadNextFromBufferSnippet}\n" - - " Out_Value = {LerpFunctionName}(prev_value, next_value, weight);\n" - "}\n\n" - ); - - int AttributeFunctionIndex = -1; - const bool bFoundAttributeFunctionIndex = GetAttributeFunctionIndex(ParamInfo.GeneratedFunctions, FunctionInstanceIndex, AttributeFunctionIndex); - if (!bFoundAttributeFunctionIndex) - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not determine index for function (counted by Attribute specifier) for '%s'."), *FunctionInfo.InstanceName); - return false; - } - - FString AttributeTypeName; - FString AdditionalFunctionArguments; - FString GetSampleIndexesForPointAtTimeSnippet; - FString VectorExFunctionDefaults; - FString ReadPrevFromBufferSnippet; - FString ReadNextFromBufferSnippet; - FString LerpFunctionName; - if (FunctionInfo.DefinitionName == GetPointValueAtTimeByStringName) - { - AttributeTypeName = "float"; - GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - AdditionalFunctionArguments = ""; - VectorExFunctionDefaults = ""; - ReadPrevFromBufferSnippet = ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); - ReadNextFromBufferSnippet = ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); - LerpFunctionName = "lerp"; - } - else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeByStringName) - { - AttributeTypeName = "float3"; - GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - AdditionalFunctionArguments = ""; - VectorExFunctionDefaults = TEXT( - " bool In_DoSwap = true;\n" - " bool In_DoScale = true;\n" - ); - ReadPrevFromBufferSnippet = ReadVectorInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); - ReadNextFromBufferSnippet = ReadVectorInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); - LerpFunctionName = "lerp"; - } - else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeExByStringName) - { - AttributeTypeName = "float3"; - GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - AdditionalFunctionArguments = TEXT("bool In_DoSwap, bool In_DoScale, "); - VectorExFunctionDefaults = ""; - ReadPrevFromBufferSnippet = ReadVectorInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); - ReadNextFromBufferSnippet = ReadVectorInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); - LerpFunctionName = "lerp"; - } - else if (FunctionInfo.DefinitionName == GetPointVector4ValueAtTimeByStringName) - { - AttributeTypeName = "float4"; - GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - AdditionalFunctionArguments = ""; - VectorExFunctionDefaults = TEXT( - " bool In_DoHoudiniToUnrealConversion = false;\n" - ); - ReadPrevFromBufferSnippet = ReadVector4InBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); - ReadNextFromBufferSnippet = ReadVector4InBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); - LerpFunctionName = "lerp"; - } - else if (FunctionInfo.DefinitionName == GetPointQuatValueAtTimeByStringName) - { - AttributeTypeName = "float4"; - GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); - AdditionalFunctionArguments = TEXT("bool In_DoHoudiniToUnrealConversion, "); - VectorExFunctionDefaults = ""; - ReadPrevFromBufferSnippet = ReadVector4InBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); - ReadNextFromBufferSnippet = ReadVector4InBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); - LerpFunctionName = "q_slerp"; - } - else - { - UE_LOG(LogHoudiniNiagara, Error, TEXT("Unexpected function definition name: '%s'"), *FunctionInfo.DefinitionName.ToString()); - return false; - } - - TMap FunctionTemplateArgs = { - {TEXT("FunctionName"), FunctionInfo.InstanceName}, - {TEXT("AttributeType"), AttributeTypeName}, - {TEXT("FunctionIndexToAttributeIndexVarName"), FunctionIndexToAttributeIndexBuffer}, - {TEXT("AttributeFunctionIndex"), AttributeFunctionIndex}, - {TEXT("GetSampleIndexesForPointAtTimeSnippet"), GetSampleIndexesForPointAtTimeSnippet}, - {TEXT("AdditionalFunctionArguments"), AdditionalFunctionArguments}, - {TEXT("VectorExFunctionDefaults"), VectorExFunctionDefaults}, - {TEXT("ReadPrevFromBufferSnippet"), ReadPrevFromBufferSnippet}, - {TEXT("ReadNextFromBufferSnippet"), ReadNextFromBufferSnippet}, - {TEXT("LerpFunctionName"), LerpFunctionName}, - }; - - OutHLSL += FString::Format(FunctionBodyTemplate, FunctionTemplateArgs); - return true; - } - - // return !OutHLSL.IsEmpty(); - return false; -} - -bool UNiagaraDataInterfaceHoudini::AppendCompileHash(FNiagaraCompileHashVisitor* InVisitor) const -{ - bool bSuccess = Super::AppendCompileHash(InVisitor); - bSuccess &= InVisitor->UpdateShaderParameters(); - return bSuccess; -} - -// Build buffers and member variables HLSL definition -// Always use the BaseName + the DataInterfaceHLSL indentifier! - -void UNiagaraDataInterfaceHoudini::GetParameterDefinitionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, FString& OutHLSL) -{ - // int NumberOfSamples_XX; - FString BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName; - OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); - - // int NumberOfAttributes_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName; - OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); - - // int NumberOfPoints_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName; - OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); - - // Buffer FloatValuesBuffer_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); - - // Buffer SpecialAttributeIndexesBuffer_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); - - // Buffer SpawnTimesBuffer_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); - - // Buffer LifeValuesBuffer_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); - - // Buffer PointTypesBuffer_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); - - // int MaxNumberOfIndexesPerPoint_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName; - OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); - - // Buffer PointValueIndexesBuffer_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); - - // int LastSpawnedPointId_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName; - OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); - - // float LastSpawnTime_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName; - OutHLSL += TEXT("float ") + BufferName + TEXT(";\n"); - - // float LastSpawnTimeRequest_XX; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName; - OutHLSL += TEXT("float ") + BufferName + TEXT(";\n"); - - // int FunctionIndexToAttributeIndexBuffer_XX[#]; - BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName; - OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n\n"); -} - -//FRWBuffer& UNiagaraDataInterfaceHoudini::GetFloatValuesGPUBuffer() -//{ -// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. -// if ( FloatValuesGPUBufferDirty ) -// { -// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->FloatSampleData.Num() : 0; -// if (NumElements <= 0) -// return FloatValuesGPUBuffer; -// -// FloatValuesGPUBuffer.Release(); -// FloatValuesGPUBuffer.Initialize( sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); -// -// uint32 BufferSize = NumElements * sizeof( float ); -// float* BufferData = static_cast( RHILockVertexBuffer( FloatValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); -// -// if ( HoudiniPointCacheAsset ) -// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->FloatSampleData.GetData(), BufferSize ); -// -// RHIUnlockVertexBuffer( FloatValuesGPUBuffer.Buffer ); -// FloatValuesGPUBufferDirty = false; -// } -// -// return FloatValuesGPUBuffer; -//} - -//FRWBuffer& UNiagaraDataInterfaceHoudini::GetSpecialAttributeIndexesGPUBuffer() -//{ -// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. -// if ( SpecialAttributeIndexesGPUBufferDirty ) -// { -// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->SpecialAttributeIndexes.Num() : 0; -// if (NumElements <= 0) -// return SpecialAttributeIndexesGPUBuffer; -// -// SpecialAttributeIndexesGPUBuffer.Release(); -// SpecialAttributeIndexesGPUBuffer.Initialize(sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); -// -// uint32 BufferSize = NumElements * sizeof(int32); -// float* BufferData = static_cast(RHILockVertexBuffer(SpecialAttributeIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); -// -// if (HoudiniPointCacheAsset) -// FPlatformMemory::Memcpy(BufferData, HoudiniPointCacheAsset->SpecialAttributeIndexes.GetData(), BufferSize); -// -// RHIUnlockVertexBuffer(SpecialAttributeIndexesGPUBuffer.Buffer); -// SpecialAttributeIndexesGPUBufferDirty = false; -// } -// -// return SpecialAttributeIndexesGPUBuffer; -//} - -//FRWBuffer& UNiagaraDataInterfaceHoudini::GetSpawnTimesGPUBuffer() -//{ -// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. -// if ( SpawnTimesGPUBufferDirty ) -// { -// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->SpawnTimes.Num() : 0; -// if (NumElements <= 0) -// return SpawnTimesGPUBuffer; -// -// SpawnTimesGPUBuffer.Release(); -// SpawnTimesGPUBuffer.Initialize( sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); -// -// uint32 BufferSize = NumElements * sizeof( float ); -// float* BufferData = static_cast( RHILockVertexBuffer(SpawnTimesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); -// -// if ( HoudiniPointCacheAsset ) -// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->SpawnTimes.GetData(), BufferSize ); -// -// RHIUnlockVertexBuffer( SpawnTimesGPUBuffer.Buffer ); -// SpawnTimesGPUBufferDirty = false; -// } -// -// return SpawnTimesGPUBuffer; -//} - -//FRWBuffer& UNiagaraDataInterfaceHoudini::GetLifeValuesGPUBuffer() -//{ -// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. -// if ( LifeValuesGPUBufferDirty ) -// { -// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->LifeValues.Num() : 0; -// if (NumElements <= 0) -// return LifeValuesGPUBuffer; -// -// LifeValuesGPUBuffer.Release(); -// LifeValuesGPUBuffer.Initialize( sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); -// -// uint32 BufferSize = NumElements * sizeof( float ); -// float* BufferData = static_cast( RHILockVertexBuffer( LifeValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); -// -// if ( HoudiniPointCacheAsset ) -// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->LifeValues.GetData(), BufferSize ); -// -// RHIUnlockVertexBuffer(LifeValuesGPUBuffer.Buffer ); -// LifeValuesGPUBufferDirty = false; -// } -// -// return LifeValuesGPUBuffer; -//} - -//FRWBuffer& UNiagaraDataInterfaceHoudini::GetPointTypesGPUBuffer() -//{ -// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. -// if ( PointTypesGPUBufferDirty ) -// { -// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->PointTypes.Num() : 0; -// if (NumElements <= 0) -// return PointTypesGPUBuffer; -// -// PointTypesGPUBuffer.Release(); -// PointTypesGPUBuffer.Initialize( sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); -// -// uint32 BufferSize = NumElements * sizeof(int32); -// int32* BufferData = static_cast( RHILockVertexBuffer(PointTypesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); -// -// if ( HoudiniPointCacheAsset ) -// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->PointTypes.GetData(), BufferSize ); -// -// RHIUnlockVertexBuffer(PointTypesGPUBuffer.Buffer ); -// PointTypesGPUBufferDirty = false; -// } -// -// return PointTypesGPUBuffer; -//} - -//FRWBuffer& UNiagaraDataInterfaceHoudini::GetPointValueIndexesGPUBuffer() -//{ -// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. -// if ( PointValueIndexesGPUBufferDirty ) -// { -// uint32 NumPoints = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->PointValueIndexes.Num() : 0; -// // Add an extra to the max number so all indexes end by a -1 -// uint32 MaxNumIndexesPerPoint = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetMaxNumberOfPointValueIndexes() + 1: 0; -// uint32 NumElements = NumPoints * MaxNumIndexesPerPoint; -// -// if (NumElements <= 0) -// return PointValueIndexesGPUBuffer; -// -// TArray PointValueIndexes; -// PointValueIndexes.Init(-1, NumElements); -// if ( HoudiniPointCacheAsset ) -// { -// // We need to flatten the nested array for HLSL conversion -// for ( int32 PointID = 0; PointID < HoudiniPointCacheAsset->PointValueIndexes.Num(); PointID++ ) -// { -// TArray SampleIndexes = HoudiniPointCacheAsset->PointValueIndexes[PointID].SampleIndexes; -// for( int32 Idx = 0; Idx < SampleIndexes.Num(); Idx++ ) -// { -// PointValueIndexes[ PointID * MaxNumIndexesPerPoint + Idx ] = SampleIndexes[ Idx ]; -// } -// } -// } -// -// PointValueIndexesGPUBuffer.Release(); -// PointValueIndexesGPUBuffer.Initialize(sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); -// -// uint32 BufferSize = NumElements * sizeof(int32); -// int32* BufferData = static_cast( RHILockVertexBuffer( PointValueIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); -// FPlatformMemory::Memcpy( BufferData, PointValueIndexes.GetData(), BufferSize ); -// RHIUnlockVertexBuffer( PointValueIndexesGPUBuffer.Buffer ); -// -// PointValueIndexesGPUBufferDirty = false; -// } -// -// return PointValueIndexesGPUBuffer; -//} - -void UNiagaraDataInterfaceHoudini::PushToRenderThreadImpl() -{ - // Need to throw a ref count into the RHI buffer so that the resource is guaranteed to stay alive while in the queue. - FHoudiniPointCacheResource* ThisResource = nullptr; - check(Proxy); - if (HoudiniPointCacheAsset) - { - HoudiniPointCacheAsset->RequestPushToGPU(); - ThisResource = HoudiniPointCacheAsset->Resource.Get(); - } - - FNiagaraDataInterfaceProxyHoudini* ThisProxy = GetProxyAs(); - ENQUEUE_RENDER_COMMAND(FNiagaraDIHoudiniPointCache_ToRT) ( - [ThisProxy, ThisResource](FRHICommandListImmediate& CmdList) mutable - { - ThisProxy->bFunctionIndexToAttributeIndexHasBeenBuilt = false; - ThisProxy->Resource = ThisResource; - } - ); -} - -FNiagaraDataInterfaceProxyHoudini::FNiagaraDataInterfaceProxyHoudini() - : FNiagaraDataInterfaceProxy(), Resource(nullptr) -{ - bFunctionIndexToAttributeIndexHasBeenBuilt = false; -} - - -FNiagaraDataInterfaceProxyHoudini::~FNiagaraDataInterfaceProxyHoudini() -{ -} - -void FNiagaraDataInterfaceProxyHoudini::UpdateFunctionIndexToAttributeIndexBuffer(const TMemoryImageArray &FunctionIndexToAttribute, bool bForceUpdate) -{ - // Don't rebuild the lookup table if it has already been built and bForceUpdate is false - if (bFunctionIndexToAttributeIndexHasBeenBuilt && !bForceUpdate) - return; - - if (!Resource) - return; - - const uint32 NumFunctions = FunctionIndexToAttribute.Num(); - FunctionIndexToAttributeIndex.SetNum(NumFunctions); - // For each generated function that uses the Attribute specifier we want to set the attribute index it uses, - // or -1 if the Attribute is invalid or missing - for (uint32 FunctionIndex = 0; FunctionIndex < NumFunctions; ++FunctionIndex) - { - const FName &Attribute = FunctionIndexToAttribute[FunctionIndex]; - if (Attribute != NAME_None) - { - int32 AttributeIndex = INDEX_NONE; - if (UHoudiniPointCache::GetAttributeIndexInArrayFromString(Attribute.ToString(), Resource->Attributes, AttributeIndex)) - { - FunctionIndexToAttributeIndex[FunctionIndex] = AttributeIndex; - } - if (AttributeIndex == INDEX_NONE) - { - UE_LOG(LogHoudiniNiagara, Warning, TEXT("Trying to access an attribute that does not exist: %s"), *Attribute.ToString()); - } - } - else - { - FunctionIndexToAttributeIndex[FunctionIndex] = INDEX_NONE; - } - } - - const uint32 BufferSize = NumFunctions * sizeof(int32); - if (FunctionIndexToAttributeIndexGPUBuffer.NumBytes != BufferSize) - { - FunctionIndexToAttributeIndexGPUBuffer.Release(); - } - - if (BufferSize > 0) - { - FunctionIndexToAttributeIndexGPUBuffer.Initialize(TEXT("HoudiniGPUBufferIndexToAttributeIndex"), sizeof(int32), NumFunctions, EPixelFormat::PF_R32_SINT, BUF_Static); - int32* BufferData = static_cast(RHILockBuffer(FunctionIndexToAttributeIndexGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); - FPlatformMemory::Memcpy(BufferData, FunctionIndexToAttributeIndex.GetData(), BufferSize); - RHIUnlockBuffer(FunctionIndexToAttributeIndexGPUBuffer.Buffer); - } - - bFunctionIndexToAttributeIndexHasBeenBuilt = true; -} -// -//void UNiagaraDataInterfaceHoudini::BuildShaderParameters(FNiagaraShaderParametersBuilder& ShaderParametersBuilder) const -//{ -// ShaderParametersBuilder.AddNestedStruct(); -//} -// -//// This fills in the parameters to send to the GPU -//void UNiagaraDataInterfaceHoudini::SetShaderParameters(const FNiagaraDataInterfaceSetShaderParametersContext& Context) const -//{ -// FNDIMousePositionProxy& DataInterfaceProxy = Context.GetProxy(); -// FNDIMousePositionInstanceData& InstanceData = DataInterfaceProxy.SystemInstancesToInstanceData_RT.FindChecked(Context.GetSystemInstanceID()); -// -// FShaderParameters* ShaderParameters = Context.GetParameterNestedStruct(); -// ShaderParameters->MousePosition.X = InstanceData.MousePos.X; -// ShaderParameters->MousePosition.Y = InstanceData.MousePos.Y; -// ShaderParameters->MousePosition.Z = InstanceData.ScreenSize.X; -// ShaderParameters->MousePosition.W = InstanceData.ScreenSize.Y; -//} -// - -//// Parameters used for GPU sim compatibility -//struct FNiagaraDataInterfaceParametersCS_Houdini : public FNiagaraDataInterfaceParametersCS -//{ -// DECLARE_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini, NonVirtual); -//public: -// void Bind(const FNiagaraDataInterfaceGPUParamInfo& ParameterInfo, const class FShaderParameterMap& ParameterMap) -// { -// NumberOfSamples.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// NumberOfAttributes.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// NumberOfPoints.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// FloatValuesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// SpecialAttributeIndexesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// SpawnTimesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// LifeValuesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// PointTypesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// MaxNumberOfIndexesPerPoint.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// PointValueIndexesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// LastSpawnedPointId.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// LastSpawnTime.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// LastSpawnTimeRequest.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// FunctionIndexToAttributeIndexBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); -// -// // Build an array of function index -> attribute name (for those functions with the Attribute specifier). If a function does not have the -// // Attribute specifier, set to NAME_None -// const uint32 NumGeneratedFunctions = ParameterInfo.GeneratedFunctions.Num(); -// FunctionIndexToAttribute.Empty(NumGeneratedFunctions); -// const FName NAME_Attribute("Attribute"); -// for (const FNiagaraDataInterfaceGeneratedFunction& GeneratedFunction : ParameterInfo.GeneratedFunctions) -// { -// const FName *Attribute = GeneratedFunction.FindSpecifierValue(NAME_Attribute); -// if (Attribute != nullptr) -// { -// FunctionIndexToAttribute.Add(*Attribute); -// } -// } -// } -// -// void Set(FRHICommandList& RHICmdList, const FNiagaraDataInterfaceSetArgs& Context) const -// { -// check( IsInRenderingThread() ); -// -// FRHIComputeShader* ComputeShaderRHI = Context.Shader.GetComputeShader(); -// FNiagaraDataInterfaceProxyHoudini* HoudiniDI = static_cast(Context.DataInterface); -// if ( !HoudiniDI) -// { -// return; -// } -// -// FHoudiniPointCacheResource* Resource = HoudiniDI->Resource; -// if (!Resource) -// { -// return; -// } -// -// SetShaderValue(RHICmdList, ComputeShaderRHI, NumberOfSamples, Resource->NumSamples); -// SetShaderValue(RHICmdList, ComputeShaderRHI, NumberOfAttributes, Resource->NumAttributes); -// SetShaderValue(RHICmdList, ComputeShaderRHI, NumberOfPoints, Resource->NumPoints); -// -// SetSRVParameter(RHICmdList, ComputeShaderRHI, FloatValuesBuffer, Resource->FloatValuesGPUBuffer.SRV); -// -// SetSRVParameter(RHICmdList, ComputeShaderRHI, SpecialAttributeIndexesBuffer, Resource->SpecialAttributeIndexesGPUBuffer.SRV); -// -// SetSRVParameter(RHICmdList, ComputeShaderRHI, SpawnTimesBuffer, Resource->SpawnTimesGPUBuffer.SRV); -// SetSRVParameter(RHICmdList, ComputeShaderRHI, LifeValuesBuffer, Resource->LifeValuesGPUBuffer.SRV); -// SetSRVParameter(RHICmdList, ComputeShaderRHI, PointTypesBuffer, Resource->PointTypesGPUBuffer.SRV); -// -// SetShaderValue(RHICmdList, ComputeShaderRHI, MaxNumberOfIndexesPerPoint, Resource->MaxNumberOfIndexesPerPoint); -// -// SetSRVParameter(RHICmdList, ComputeShaderRHI, PointValueIndexesBuffer, Resource->PointValueIndexesGPUBuffer.SRV); -// -// SetShaderValue(RHICmdList, ComputeShaderRHI, LastSpawnedPointId, -1); -// SetShaderValue(RHICmdList, ComputeShaderRHI, LastSpawnTime, -FLT_MAX); -// SetShaderValue(RHICmdList, ComputeShaderRHI, LastSpawnTimeRequest, -FLT_MAX); -// -// // Build the the function index to attribute index lookup table if it has not yet been built for this DI proxy -// HoudiniDI->UpdateFunctionIndexToAttributeIndexBuffer(FunctionIndexToAttribute); -// -// if (HoudiniDI->FunctionIndexToAttributeIndexGPUBuffer.NumBytes > 0) -// { -// SetSRVParameter(RHICmdList, ComputeShaderRHI, FunctionIndexToAttributeIndexBuffer, HoudiniDI->FunctionIndexToAttributeIndexGPUBuffer.SRV); -// } -// else -// { -// SetSRVParameter(RHICmdList, ComputeShaderRHI, FunctionIndexToAttributeIndexBuffer, FNiagaraRenderer::GetDummyIntBuffer()); -// } -// } -// -//private: -// LAYOUT_FIELD(FShaderParameter, NumberOfSamples); -// LAYOUT_FIELD(FShaderParameter, NumberOfAttributes); -// LAYOUT_FIELD(FShaderParameter, NumberOfPoints); -// -// LAYOUT_FIELD(FShaderResourceParameter, FloatValuesBuffer); -// LAYOUT_FIELD(FShaderResourceParameter, SpecialAttributeIndexesBuffer); -// -// LAYOUT_FIELD(FShaderResourceParameter, SpawnTimesBuffer); -// LAYOUT_FIELD(FShaderResourceParameter, LifeValuesBuffer); -// LAYOUT_FIELD(FShaderResourceParameter, PointTypesBuffer); -// -// LAYOUT_FIELD(FShaderParameter, MaxNumberOfIndexesPerPoint); -// LAYOUT_FIELD(FShaderResourceParameter, PointValueIndexesBuffer); -// -// LAYOUT_FIELD(FShaderParameter, LastSpawnedPointId); -// LAYOUT_FIELD(FShaderParameter, LastSpawnTime); -// LAYOUT_FIELD(FShaderParameter, LastSpawnTimeRequest); -// -// LAYOUT_FIELD(FShaderResourceParameter, FunctionIndexToAttributeIndexBuffer); -// -// LAYOUT_FIELD(TMemoryImageArray, FunctionIndexToAttribute); -// -// LAYOUT_FIELD_INITIALIZED(uint32, Version, 1); -//}; -// -//IMPLEMENT_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini); -// -//IMPLEMENT_NIAGARA_DI_PARAMETER(UNiagaraDataInterfaceHoudini, FNiagaraDataInterfaceParametersCS_Houdini); - -#undef LOCTEXT_NAMESPACE +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include "NiagaraDataInterfaceHoudini.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "HoudiniPointCache.h" +#include "NiagaraTypes.h" +#include "NiagaraShader.h" +#include "NiagaraRenderer.h" +#include "ShaderParameterUtils.h" + +#define LOCTEXT_NAMESPACE "HoudiniNiagaraDataInterface" + + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 + +// Base name for the member variables / buffers for GPU compatibility +const FString UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName(TEXT("NumberOfSamples_")); +const FString UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName(TEXT("NumberOfAttributes_")); +const FString UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName(TEXT("NumberOfPoints_")); +const FString UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName(TEXT("FloatValuesBuffer_")); +const FString UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName(TEXT("SpecialAttributeIndexesBuffer_")); +const FString UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName(TEXT("SpawnTimesBuffer_")); +const FString UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName(TEXT("LifeValuesBuffer_")); +const FString UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName(TEXT("PointTypesBuffer_")); +const FString UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName(TEXT("MaxNumberOfIndexesPerPoint_")); +const FString UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName(TEXT("PointValueIndexesBuffer_")); +const FString UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName(TEXT("LastSpawnedPointId_")); +const FString UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName(TEXT("LastSpawnTime_")); +const FString UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName(TEXT("LastSpawnTimeRequest_")); +const FString UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName(TEXT("FunctionIndexToAttributeIndexBuffer_")); + +#else +#include "NiagaraShaderParametersBuilder.h" + +struct FNiagaraDataInterfaceParametersCS_Houdini : public FNiagaraDataInterfaceParametersCS +{ + DECLARE_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini, NonVirtual); + + LAYOUT_FIELD(TMemoryImageArray, FunctionIndexToAttribute); +}; + +IMPLEMENT_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini); + +// Base name for the member variables / buffers for GPU compatibility +const FString UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName(TEXT("_NumberOfSamples")); +const FString UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName(TEXT("_NumberOfAttributes")); +const FString UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName(TEXT("_NumberOfPoints")); +const FString UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName(TEXT("_FloatValuesBuffer")); +const FString UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName(TEXT("_SpecialAttributeIndexesBuffer")); +const FString UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName(TEXT("_SpawnTimesBuffer")); +const FString UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName(TEXT("_LifeValuesBuffer")); +const FString UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName(TEXT("_PointTypesBuffer")); +const FString UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName(TEXT("_MaxNumberOfIndexesPerPoint")); +const FString UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName(TEXT("_PointValueIndexesBuffer")); +const FString UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName(TEXT("_LastSpawnedPointId")); +const FString UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName(TEXT("_LastSpawnTime")); +const FString UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName(TEXT("_LastSpawnTimeRequest")); +const FString UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName(TEXT("_FunctionIndexToAttributeIndexBuffer")); + + +#endif + + + +// Name of all the functions available in the data interface +static const FName GetFloatValueName("GetFloatValue"); +static const FName GetFloatValueByStringName("GetFloatValueByString"); +static const FName GetVectorValueName("GetVectorValue"); +static const FName GetVectorValueByStringName("GetVectorValueByString"); +static const FName GetVectorValueExName("GetVectorValueEx"); +static const FName GetVectorValueExByStringName("GetVectorValueExByString"); +static const FName GetVector4ValueName("GetVector4Value"); +static const FName GetVector4ValueByStringName("GetVector4ValueByString"); +static const FName GetQuatValueName("GetQuatValue"); +static const FName GetQuatValueByStringName("GetQuatValueByString"); + +static const FName GetPositionName("GetPosition"); +static const FName GetNormalName("GetNormal"); +static const FName GetTimeName("GetTime"); +static const FName GetVelocityName("GetVelocity"); +static const FName GetColorName("GetColor"); +static const FName GetImpulseName("GetImpulse"); +static const FName GetPositionAndTimeName("GetPositionAndTime"); + +static const FName GetNumberOfPointsName("GetNumberOfPoints"); +static const FName GetNumberOfSamplesName("GetNumberOfSamples"); +static const FName GetNumberOfAttributesName("GetNumberOfAttributes"); + +static const FName GetLastSampleIndexAtTimeName("GetLastSampleIndexAtTime"); +static const FName GetPointIDsToSpawnAtTimeName("GetPointIDsToSpawnAtTime"); +static const FName GetSampleIndexesForPointAtTimeName("GetSampleIndexesForPointAtTime"); + +static const FName GetPointPositionAtTimeName("GetPointPositionAtTime"); +static const FName GetPointValueAtTimeName("GetPointValueAtTime"); +static const FName GetPointValueAtTimeByStringName("GetPointValueAtTimeByString"); +static const FName GetPointVectorValueAtTimeName("GetPointVectorValueAtTime"); +static const FName GetPointVectorValueAtTimeByStringName("GetPointVectorValueAtTimeByString"); +static const FName GetPointVector4ValueAtTimeName("GetPointVector4ValueAtTime"); +static const FName GetPointVector4ValueAtTimeByStringName("GetPointVector4ValueAtTimeByString"); +static const FName GetPointVectorValueAtTimeExName("GetPointVectorValueAtTimeEx"); +static const FName GetPointVectorValueAtTimeExByStringName("GetPointVectorValueAtTimeExByString"); +static const FName GetPointQuatValueAtTimeName("GetPointQuatValueAtTime"); +static const FName GetPointQuatValueAtTimeByStringName("GetPointQuatValueAtTimeByString"); + +static const FName GetPointLifeName("GetPointLife"); +static const FName GetPointLifeAtTimeName("GetPointLifeAtTime"); +static const FName GetPointTypeName("GetPointType"); + +static const FName GetPointNormalAtTimeName("GetPointNormalAtTime"); +static const FName GetPointColorAtTimeName("GetPointColorAtTime"); +static const FName GetPointAlphaAtTimeName("GetPointAlphaAtTime"); +static const FName GetPointVelocityAtTimeName("GetPointVelocityAtTime"); +static const FName GetPointImpulseAtTimeName("GetPointImpulseAtTime"); +static const FName GetPointTypeAtTimeName("GetPointTypeAtTime"); + + + +UNiagaraDataInterfaceHoudini::UNiagaraDataInterfaceHoudini(FObjectInitializer const& ObjectInitializer) + : Super(ObjectInitializer) +{ + HoudiniPointCacheAsset = nullptr; + + Proxy.Reset(new FNiagaraDataInterfaceProxyHoudini()); +} + +void UNiagaraDataInterfaceHoudini::PostInitProperties() +{ + Super::PostInitProperties(); + + if (HasAnyFlags(RF_ClassDefaultObject)) + { + ENiagaraTypeRegistryFlags RegistryFlags = ENiagaraTypeRegistryFlags::AllowUserVariable + | ENiagaraTypeRegistryFlags::AllowSystemVariable + | ENiagaraTypeRegistryFlags::AllowEmitterVariable + | ENiagaraTypeRegistryFlags::AllowParameter; + + FNiagaraTypeRegistry::Register(FNiagaraTypeDefinition(GetClass()), RegistryFlags); + + RegistryFlags |= ENiagaraTypeRegistryFlags::AllowPayload; + FNiagaraTypeRegistry::Register(FHoudiniEvent::StaticStruct(), RegistryFlags); + } +} + +void UNiagaraDataInterfaceHoudini::PostLoad() +{ + Super::PostLoad(); + + MarkRenderDataDirty(); +} + +#if WITH_EDITOR + +void UNiagaraDataInterfaceHoudini::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UNiagaraDataInterfaceHoudini, HoudiniPointCacheAsset)) + { + Modify(); + if ( HoudiniPointCacheAsset ) + { + MarkRenderDataDirty(); + } + } +} + +#endif + +bool UNiagaraDataInterfaceHoudini::CopyToInternal(UNiagaraDataInterface* Destination) const +{ + if ( !Super::CopyToInternal( Destination ) ) + return false; + + UNiagaraDataInterfaceHoudini* CastedInterface = CastChecked( Destination ); + if ( !CastedInterface ) + return false; + + CastedInterface->HoudiniPointCacheAsset = HoudiniPointCacheAsset; + CastedInterface->MarkRenderDataDirty(); + + return true; +} + +bool UNiagaraDataInterfaceHoudini::Equals(const UNiagaraDataInterface* Other) const +{ + if ( !Super::Equals(Other) ) + return false; + + const UNiagaraDataInterfaceHoudini* OtherHN = CastChecked(Other); + + if ( OtherHN != nullptr && OtherHN->HoudiniPointCacheAsset != nullptr && HoudiniPointCacheAsset ) + { + // Just make sure the two interfaces point to the same file + return OtherHN->HoudiniPointCacheAsset->FileName.Equals( HoudiniPointCacheAsset->FileName ); + } + + return false; +} + +// Returns the signature of all the functions avaialable in the data interface +void UNiagaraDataInterfaceHoudini::GetFunctions(TArray& OutFunctions) +{ + { + // GetFloatValue + FNiagaraFunctionSignature Sig; + Sig.Name = GetFloatValueName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetFloatValue", + "Returns the float value in the point cache for a given Sample Index and Attribute Index.\n" ) ); + + OutFunctions.Add( Sig ); + } + + { + // GetFloatValueByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetFloatValueByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetFloatValueByString", + "Returns the float value in the point cache for a given Sample Index and Attribute name.\n" ) ); + + OutFunctions.Add(Sig); + } + + { + // GetVectorValue + FNiagaraFunctionSignature Sig; + Sig.Name = GetVectorValueName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetVectorValue", + "Returns a Vector3 in the point cache for a given Sample Index and Attribute Index.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetVectorValueByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetVectorValueByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueByString", + "Returns a Vector3 in the point cache for a given Sample Index and Attribute name.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetVectorValueEx + FNiagaraFunctionSignature Sig; + Sig.Name = GetVectorValueExName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueEx", + "Returns a Vector3 in the point cache for a given Sample Index and Attribute Index.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal).")); + + OutFunctions.Add(Sig); + } + + { + // GetVectorValueExByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetVectorValueExByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueExByString", + "Returns a Vector3 in the point cache for a given Sample Index and Attribute name.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal).")); + + OutFunctions.Add(Sig); + } + + { + // GetVector4Value + FNiagaraFunctionSignature Sig; + Sig.Name = GetVector4ValueName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetVectorValue", + "Returns a Vector4 in the point cache for a given Sample Index and Attribute Index.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetVector4ValueByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetVector4ValueByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVectorValueByString", + "Returns a Vector4 in the point cache for a given Sample Index and Attribute name.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetQuatValueEx + FNiagaraFunctionSignature Sig; + Sig.Name = GetQuatValueName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetQuatValue", + "Returns a Quat in the point cache for a given Sample Index and Attribute Index.\nThe DoHoudiniToUnrealConversion parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetQuatValueByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetQuatValueByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetQuatValueByString", + "Returns a Quat in the point cache for a given Sample Index and Attribute name.\nThe DoHoudiniToUnrealConversion parameter indicates if the quat should be converted from Houdini*s coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetPosition + FNiagaraFunctionSignature Sig; + Sig.Name = GetPositionName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Position"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPosition", + "Helper function returning the position value for a given sample index in the point cache file.\nThe returned Position vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPositionAndTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPositionAndTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Position"))); // Vector3 Out + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // float Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPositionAndTime", + "Helper function returning the position and time values for a given Sample Index in the point cache.\nThe returned Position vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetNormal + FNiagaraFunctionSignature Sig; + Sig.Name = GetNormalName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Normal"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNormal", + "Helper function returning the normal value for a given Sample Index in the point cache.\nThe returned Normal vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Float Out + + Sig.SetDescription( LOCTEXT("DataInterfaceHoudini_GetTime", + "Helper function returning the time value for a given Sample Index in the point cache.\n") ); + + OutFunctions.Add(Sig); + } + + { + // GetVelocity + FNiagaraFunctionSignature Sig; + Sig.Name = GetVelocityName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Velocity"))); // Vector3 Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetVelocity", + "Helper function returning the velocity value for a given Sample Index in the point cache.\nThe returned velocity vector is converted from Houdini's coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetColor + FNiagaraFunctionSignature Sig; + Sig.Name = GetColorName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetColorDef(), TEXT("Color"))); // Color Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetColor", + "Helper function returning the color value for a given Sample Index in the point cache.")); + + OutFunctions.Add(Sig); + } + + { + // GetImpulse + FNiagaraFunctionSignature Sig; + Sig.Name = GetImpulseName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("SampleIndex"))); // SampleIndex In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Impulse"))); // Float Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetImpulse", + "Helper function returning the impulse value for a given Sample Index in the point cache.\n")); + + OutFunctions.Add(Sig); + } + + { + // GetNumberOfPoints + FNiagaraFunctionSignature Sig; + Sig.Name = GetNumberOfPointsName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("NumberOfPoints"))); // Int Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNumberOfPoints", + "Returns the number of points (with different id values) in the point cache.\n" ) ); + + OutFunctions.Add(Sig); + } + + { + // GetNumberOfSamples + FNiagaraFunctionSignature Sig; + Sig.Name = GetNumberOfSamplesName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add( FNiagaraVariable( FNiagaraTypeDefinition( GetClass()), TEXT("PointCache") ) ); // PointCache in + Sig.Outputs.Add( FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("NumberOfSamples") ) ); // Int Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNumberOfSamples", + "Returns the number of samples in the point cache." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetNumberOfAttributes + FNiagaraFunctionSignature Sig; + Sig.Name = GetNumberOfAttributesName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add( FNiagaraVariable( FNiagaraTypeDefinition( GetClass()), TEXT("PointCache") ) ); // PointCache in + Sig.Outputs.Add( FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("NumberOfAttributes") ) ); // Int Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetNumberOfAttributes", + "Returns the number of attributes in the point cache." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetLastSampleIndexAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetLastSampleIndexAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition(GetClass()), TEXT("PointCache") ) ); // PointCache in + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time") ) ); // Time in + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("LastSampleIndex") ) ); // Int Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetLastSampleIndexAtTime", + "Returns the index of the last sample in the point cache that has a time value lesser or equal to the Time parameter." ) ); + + OutFunctions.Add(Sig); + } + + { + //GetPointIDsToSpawnAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointIDsToSpawnAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition(GetClass()), TEXT("PointCache") ) ); // PointCache in + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time") ) ); // Time in + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTime") ) ); // Emitter state In + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTimeRequest") ) ); // Emitter state In + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("LastSpawnedPointID") ) ); // Emitter state In + Sig.Inputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetBoolDef(), TEXT("ResetSpawnState") ) ); // Emitter state In + + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("MinID") ) ); // Int Out + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("MaxID") ) ); // Int Out + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("Count") ) ); // Int Out + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTime") ) ); // Emitter state Out + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetFloatDef(), TEXT("LastSpawnTimeRequest") ) ); // Emitter state Out + Sig.Outputs.Add(FNiagaraVariable( FNiagaraTypeDefinition::GetIntDef(), TEXT("LastSpawnedPointID") ) ); // Emitter state Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointIDsToSpawnAtTime", + "Returns the count and point IDs of the points that should spawn for a given time value." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetSampleIndexesForPointAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetSampleIndexesForPointAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PreviousSampleIndex"))); // Int Out + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("NextSampleIndex"))); // Int Out + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("PrevWeight"))); // Float Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetSampleIndexesForPointAtTime", + "Returns the sample indexes for a given point at a given time.\nThe previous index, next index and weight can then be used to Lerp between values.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointPositionAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointPositionAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Position"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointPositionAtTime", + "Helper function returning the linearly interpolated position for a given point at a given time.\nThe returned Position vector is converted from Houdini's coordinate system to Unreal's.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointValueAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointValueAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointValueAtTime", + "Returns the linearly interpolated value in the specified attribute for a given point at a given time." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPointValueAtTimeByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointValueAtTimeByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Value"))); // Float Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointValueAtTimeByString", + "Returns the linearly interpolated value in the specified attribute (by name) for a given point at a given time.")); + + OutFunctions.Add(Sig); + } + + { + // GetPointVectorValueAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVectorValueAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointVectorValueAtTime", + "Helper function returning the linearly interpolated Vector value in the specified Attribute Index for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPointVectorValueAtTimeByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVectorValueAtTimeByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVectorValueAtTimeByString", + "Helper function returning the linearly interpolated Vector value in the specified attribute (by name) for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetPointVector4ValueAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVector4ValueAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointVector4ValueAtTime", + "Helper function returning the linearly interpolated Vector4 value in the specified Attribute Index for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPointVectorValueAtTimeByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVector4ValueAtTimeByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec4Def(), TEXT("Value"))); // Vector4 Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVector4ValueAtTimeByString", + "Helper function returning the linearly interpolated Vector4 value in the specified attribute (by name) for a given point at a given time.\nThe returned Vector is converted from Houdini's coordinate system to Unreal's.")); + + OutFunctions.Add(Sig); + } + + { + // GetPointVectorValueAtTimeEx + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVectorValueAtTimeExName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVectorValueAtTime", + "Helper function returning the linearly interpolated Vector value in the specified attribute index for a given point at a given time.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal)." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPointVectorValueAtTimeExByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVectorValueAtTimeExByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoSwap"))); // DoSwap in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoScale"))); // DoScale in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Value"))); // Vector3 Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointVectorValueAtTimeByString", + "Helper function returning the linearly interpolated Vector value in the specified attribute (by name) for a given point at a given time.\nThe DoSwap parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\nThe DoScale parameter decides if the Vector value should be converted from meters (Houdini) to centimeters (Unreal).")); + + OutFunctions.Add(Sig); + } + + { + // GetPointQuatValueAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointQuatValueAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("AttributeIndex"))); // AttributeIndex In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointQuatValueAtTime", + "Helper function returning the linearly interpolated Quat value in the specified attribute index for a given point at a given time.\nThe DoHoudiniToUnrealConversion parameter indicates if the vector4 should be converted from Houdini*s coordinate system to Unreal's.\n" ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPointQuatValueAtTimeByString + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointQuatValueAtTimeByStringName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point ID In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("DoHoudiniToUnrealConversion"))); // DoHoudiniToUnrealConversion in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetQuatDef(), TEXT("Value"))); // Quat Out + + Sig.FunctionSpecifiers.Add(FName("Attribute")); + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointQuatValueAtTimeByString", + "Helper function returning the linearly interpolated Quat value in the specified attribute (by name) for a given point at a given time.\nThe DoHoudiniToUnrealConversion parameter indicates if the vector should be converted from Houdini*s coordinate system to Unreal's.\n")); + + OutFunctions.Add(Sig); + } + + { + // GetPointLife + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointLifeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Life"))); // Float Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointLife", + "Helper function returning the life value for a given point when spawned.\nThe life value is either calculated from the alive attribute or is the life attribute at spawn time.")); + + OutFunctions.Add(Sig); + } + + { + // GetPointLifeAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointLifeAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Life"))); // Float Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointLifeAtTime", + "Helper function returning the remaining life for a given point in the point cache at a given time." ) ); + + OutFunctions.Add(Sig); + } + + { + // GetPointType + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointTypeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("Type"))); // Int Out + + Sig.SetDescription(LOCTEXT("DataInterfaceHoudini_GetPointType", + "Helper function returning the type value for a given point when spawned.\n")); + + OutFunctions.Add(Sig); + } + + { + // GetPointNormalAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointNormalAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Normal"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointNormalAtTime", + "Helper function returning the linearly interpolated normal for a given point at a given time.\nThe returned vector is converted from Houdini's coordinate system to Unreal's.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointColorAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointColorAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Color"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointColorAtTime", + "Helper function returning the linearly interpolated color for a given point at a given time.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointAlphaAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointAlphaAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Alpha"))); // Float Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointAlphaAtTime", + "Helper function returning the linearly interpolated alpha for a given point at a given time.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointVelocityAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointVelocityAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetVec3Def(), TEXT("Velocity"))); // Vector3 Out + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointVelocityAtTime", + "Helper function returning the linearly interpolated velocity for a given point at a given time.\nThe returned vector is converted from Houdini's coordinate system to Unreal's.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointImpulseAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointImpulseAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Impulse"))); // Impulse + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointImpulseAtTime", + "Helper function returning the linearly interpolated impulse for a given point at a given time.") ); + + OutFunctions.Add(Sig); + } + + { + // GetPointTypeAtTime + FNiagaraFunctionSignature Sig; + Sig.Name = GetPointTypeAtTimeName; + Sig.bMemberFunction = true; + Sig.bRequiresContext = false; + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition(GetClass()), TEXT("PointCache"))); // PointCache in + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("PointID"))); // Point Number In + Sig.Inputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetFloatDef(), TEXT("Time"))); // Time in + Sig.Outputs.Add(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("Type"))); // Type + + Sig.SetDescription( LOCTEXT( "DataInterfaceHoudini_GetPointTypeAtTime", + "Helper function returning the integer type for a given point at a given time.") ); + + OutFunctions.Add(Sig); + } + +} + +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetFloatValue); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetFloatValueByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValue); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetVectorValueByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueEx); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetVectorValueExByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVector4Value); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetVector4ValueByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetQuatValue); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetQuatValueByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPosition); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetNormal); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetColor); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVelocity); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetImpulse); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPositionAndTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetLastSampleIndexAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointIDsToSpawnAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetSampleIndexesForPointAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointPositionAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointValueAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointValueAtTimeByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeEx); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeExByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTimeByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER_WITH_PAYLOAD(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTimeByString); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLife); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLifeAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointType); + +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointNormalAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointColorAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointAlphaAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVelocityAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointImpulseAtTime); +DEFINE_NDI_DIRECT_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointTypeAtTime); + +void UNiagaraDataInterfaceHoudini::GetVMExternalFunction(const FVMExternalFunctionBindingInfo& BindingInfo, void* InstanceData, FVMExternalFunction &OutFunc) +{ + static const FName NAME_Attribute("Attribute"); + + const FVMFunctionSpecifier* AttributeSpecifier = BindingInfo.FindSpecifier(NAME_Attribute); + bool bAttributeSpecifierRequiredButNotFound = false; + + if (BindingInfo.Name == GetFloatValueName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetFloatValue)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetFloatValueByStringName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetFloatValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetVectorValueName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValue)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetVectorValueByStringName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetVectorValueExName && BindingInfo.GetNumInputs() == 4 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueEx)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetVectorValueExByStringName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 3) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVectorValueExByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetVector4ValueName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 4) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVector4Value)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetVector4ValueByStringName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 4) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVector4ValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetQuatValueName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 4) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetQuatValue)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetQuatValueByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 4) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetQuatValueByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetPositionName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPosition)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetNormalName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetNormal)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetTimeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetVelocityName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetVelocity)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetColorName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 4) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetColor)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetImpulseName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetImpulse)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPositionAndTimeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 4) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPositionAndTime)::Bind(this, OutFunc); + } + else if ( BindingInfo.Name == GetNumberOfPointsName && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1 ) + { + OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceHoudini::GetNumberOfPoints); + } + else if (BindingInfo.Name == GetNumberOfSamplesName && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1) + { + OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceHoudini::GetNumberOfSamples); + } + else if (BindingInfo.Name == GetNumberOfAttributesName && BindingInfo.GetNumInputs() == 0 && BindingInfo.GetNumOutputs() == 1) + { + OutFunc = FVMExternalFunction::CreateUObject(this, &UNiagaraDataInterfaceHoudini::GetNumberOfAttributes); + } + else if (BindingInfo.Name == GetLastSampleIndexAtTimeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetLastSampleIndexAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointIDsToSpawnAtTimeName && BindingInfo.GetNumInputs() == 5 && BindingInfo.GetNumOutputs() == 6) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointIDsToSpawnAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetSampleIndexesForPointAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetSampleIndexesForPointAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointPositionAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointPositionAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointValueAtTimeName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointValueAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointValueAtTimeByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetPointVectorValueAtTimeName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointVectorValueAtTimeByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetPointVector4ValueAtTimeName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 4) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointVector4ValueAtTimeByStringName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 4) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVector4ValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetPointVectorValueAtTimeExName && BindingInfo.GetNumInputs() == 5 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeEx)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointVectorValueAtTimeExByStringName && BindingInfo.GetNumInputs() == 4 && BindingInfo.GetNumOutputs() == 3) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVectorValueAtTimeExByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetPointQuatValueAtTimeName && BindingInfo.GetNumInputs() == 4 && BindingInfo.GetNumOutputs() == 4) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointQuatValueAtTimeByStringName && BindingInfo.GetNumInputs() == 3 && BindingInfo.GetNumOutputs() == 4) + { + if (AttributeSpecifier) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointQuatValueAtTimeByString)::Bind(this, OutFunc, AttributeSpecifier->Value.ToString()); + } + else + { + bAttributeSpecifierRequiredButNotFound = true; + } + } + else if (BindingInfo.Name == GetPointLifeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLife)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointLifeAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointLifeAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointTypeName && BindingInfo.GetNumInputs() == 1 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointType)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointNormalAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointNormalAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointColorAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointColorAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointAlphaAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointAlphaAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointVelocityAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 3) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointVelocityAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointImpulseAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointImpulseAtTime)::Bind(this, OutFunc); + } + else if (BindingInfo.Name == GetPointTypeAtTimeName && BindingInfo.GetNumInputs() == 2 && BindingInfo.GetNumOutputs() == 1) + { + NDI_FUNC_BINDER(UNiagaraDataInterfaceHoudini, GetPointTypeAtTime)::Bind(this, OutFunc); + } + else + { + UE_LOG( LogHoudiniNiagara, Error, + TEXT( "Could not find data interface function:\n\tName: %s\n\tInputs: %i\n\tOutputs: %i" ), + *BindingInfo.Name.ToString(), BindingInfo.GetNumInputs(), BindingInfo.GetNumOutputs() ); + OutFunc = FVMExternalFunction(); + } + + if (bAttributeSpecifierRequiredButNotFound) + { + // Attribute specifier was required but was not found + UE_LOG( + LogHoudiniNiagara, Error, + TEXT("Could not find specifier '%s' on function:\n\tName: %s\n\tInputs: %i\n\tOutputs: %i"), + *NAME_Attribute.ToString(), *BindingInfo.Name.ToString(), BindingInfo.GetNumInputs(), BindingInfo.GetNumOutputs() + ); + } +} + +void UNiagaraDataInterfaceHoudini::GetFloatValue(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for ( int32 i = 0; i < Context.GetNumInstances(); ++i ) + { + int32 SampleIndex = SampleIndexParam.Get(); + int32 AttributeIndex = AttributeIndexParam.Get(); + + float value = 0.0f; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetFloatValue( SampleIndex, AttributeIndex, value ); + + *OutValue.GetDest() = value; + SampleIndexParam.Advance(); + AttributeIndexParam.Advance(); + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVectorValue(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + int32 AttributeIndex = AttributeIndexParam.Get(); + + FVector V = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetVectorValue(SampleIndex, AttributeIndex, V); + + *OutVectorX.GetDest() = V.X; + *OutVectorY.GetDest() = V.Y; + *OutVectorZ.GetDest() = V.Z; + + SampleIndexParam.Advance(); + AttributeIndexParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVectorValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + FVector V = FVector::ZeroVector; + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetVectorValueForString(SampleIndex, Attribute, V); + + *OutVectorX.GetDest() = V.X; + *OutVectorY.GetDest() = V.Y; + *OutVectorZ.GetDest() = V.Z; + + SampleIndexParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVectorValueEx(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + VectorVM::FExternalFuncInputHandler DoSwapParam(Context); + VectorVM::FExternalFuncInputHandler DoScaleParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + int32 AttributeIndex = AttributeIndexParam.Get(); + + bool DoSwap = DoSwapParam.Get().GetValue(); + bool DoScale = DoScaleParam.Get().GetValue(); + + FVector V = FVector::ZeroVector; + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetVectorValue(SampleIndex, AttributeIndex, V, DoSwap, DoScale); + + *OutVectorX.GetDest() = V.X; + *OutVectorY.GetDest() = V.Y; + *OutVectorZ.GetDest() = V.Z; + + SampleIndexParam.Advance(); + AttributeIndexParam.Advance(); + DoSwapParam.Advance(); + DoScaleParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVectorValueExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler DoSwapParam(Context); + VectorVM::FExternalFuncInputHandler DoScaleParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + bool DoSwap = DoSwapParam.Get().GetValue(); + bool DoScale = DoScaleParam.Get().GetValue(); + + FVector V = FVector::ZeroVector; + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetVectorValueForString(SampleIndex, Attribute, V, DoSwap, DoScale); + + *OutVectorX.GetDest() = V.X; + *OutVectorY.GetDest() = V.Y; + *OutVectorZ.GetDest() = V.Z; + + SampleIndexParam.Advance(); + DoSwapParam.Advance(); + DoScaleParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVector4Value(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + int32 AttributeIndex = AttributeIndexParam.Get(); + + FVector4 V(FVector::ZeroVector, 0); + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetVector4Value(SampleIndex, AttributeIndex, V); + + *OutVectorX.GetDest() = V.X; + *OutVectorY.GetDest() = V.Y; + *OutVectorZ.GetDest() = V.Z; + *OutVectorW.GetDest() = V.W; + + SampleIndexParam.Advance(); + AttributeIndexParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + OutVectorW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVector4ValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + FVector4 V(FVector::ZeroVector, 0); + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetVector4ValueForString(SampleIndex, Attribute, V); + + *OutVectorX.GetDest() = V.X; + *OutVectorY.GetDest() = V.Y; + *OutVectorZ.GetDest() = V.Z; + *OutVectorW.GetDest() = V.W; + + SampleIndexParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + OutVectorW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetQuatValue(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + int32 AttributeIndex = AttributeIndexParam.Get(); + + bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); + + FQuat Q(0, 0, 0, 0); + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetQuatValue(SampleIndex, AttributeIndex, Q, DoHoudiniToUnrealConversion); + + *OutVectorX.GetDest() = Q.X; + *OutVectorY.GetDest() = Q.Y; + *OutVectorZ.GetDest() = Q.Z; + *OutVectorW.GetDest() = Q.W; + + SampleIndexParam.Advance(); + AttributeIndexParam.Advance(); + DoHoudiniToUnrealConversionParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + OutVectorW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetQuatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVectorX(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorY(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorZ(Context); + VectorVM::FExternalFuncRegisterHandler OutVectorW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); + + FQuat Q(0, 0, 0, 0); + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetQuatValueForString(SampleIndex, Attribute, Q, DoHoudiniToUnrealConversion); + + *OutVectorX.GetDest() = Q.X; + *OutVectorY.GetDest() = Q.Y; + *OutVectorZ.GetDest() = Q.Z; + *OutVectorW.GetDest() = Q.W; + + SampleIndexParam.Advance(); + DoHoudiniToUnrealConversionParam.Advance(); + OutVectorX.Advance(); + OutVectorY.Advance(); + OutVectorZ.Advance(); + OutVectorW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetFloatValueByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for ( int32 i = 0; i < Context.GetNumInstances(); ++i ) + { + int32 SampleIndex = SampleIndexParam.Get(); + + float value = 0.0f; + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetFloatValueForString(SampleIndex, Attribute, value); + + *OutValue.GetDest() = value; + SampleIndexParam.Advance(); + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPosition(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutSampleX(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleY(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + FVector V = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetPositionValue( SampleIndex, V ); + + *OutSampleX.GetDest() = V.X; + *OutSampleY.GetDest() = V.Y; + *OutSampleZ.GetDest() = V.Z; + SampleIndexParam.Advance(); + OutSampleX.Advance(); + OutSampleY.Advance(); + OutSampleZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetNormal(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutSampleX(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleY(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + FVector V = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetNormalValue( SampleIndex, V ); + + *OutSampleX.GetDest() = V.X; + *OutSampleY.GetDest() = V.Y; + *OutSampleZ.GetDest() = V.Z; + SampleIndexParam.Advance(); + OutSampleX.Advance(); + OutSampleY.Advance(); + OutSampleZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + float value = 0.0f; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetTimeValue( SampleIndex, value ); + + *OutValue.GetDest() = value; + SampleIndexParam.Advance(); + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetVelocity(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutSampleX(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleY(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + FVector V = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetVelocityValue( SampleIndex, V ); + + *OutSampleX.GetDest() = V.X; + *OutSampleY.GetDest() = V.Y; + *OutSampleZ.GetDest() = V.Z; + SampleIndexParam.Advance(); + OutSampleX.Advance(); + OutSampleY.Advance(); + OutSampleZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetColor(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutSampleR(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleG(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleB(Context); + VectorVM::FExternalFuncRegisterHandler OutSampleA(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + FLinearColor C = FLinearColor::White; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetColorValue( SampleIndex, C ); + + *OutSampleR.GetDest() = C.R; + *OutSampleG.GetDest() = C.G; + *OutSampleB.GetDest() = C.B; + *OutSampleA.GetDest() = C.A; + SampleIndexParam.Advance(); + OutSampleR.Advance(); + OutSampleG.Advance(); + OutSampleB.Advance(); + OutSampleA.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetImpulse(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + float value = 0.0f; + if (HoudiniPointCacheAsset) + HoudiniPointCacheAsset->GetImpulseValue(SampleIndex, value); + + *OutValue.GetDest() = value; + SampleIndexParam.Advance(); + OutValue.Advance(); + } +} + +// Returns the last index of the points that should be spawned at time t +void UNiagaraDataInterfaceHoudini::GetLastSampleIndexAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + float t = TimeParam.Get(); + + int32 value = 0; + if ( HoudiniPointCacheAsset ) + HoudiniPointCacheAsset->GetLastSampleIndexAtTime( t, value ); + + *OutValue.GetDest() = value; + TimeParam.Advance(); + OutValue.Advance(); + } +} + +// Returns the last index of the points that should be spawned at time t +void UNiagaraDataInterfaceHoudini::GetPointIDsToSpawnAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler TimeParam( Context ); + VectorVM::FExternalFuncInputHandler LastSpawnTimeParam( Context ); + VectorVM::FExternalFuncInputHandler LastSpawnTimeRequestParam( Context ); + VectorVM::FExternalFuncInputHandler LastSpawnedPointIDParam( Context ); + VectorVM::FExternalFuncInputHandler ResetSpawnStateParam( Context ); + + VectorVM::FExternalFuncRegisterHandler OutMinValue( Context ); + VectorVM::FExternalFuncRegisterHandler OutMaxValue( Context ); + VectorVM::FExternalFuncRegisterHandler OutCountValue( Context ); + VectorVM::FExternalFuncRegisterHandler OutLastSpawnTimeValue( Context ); + VectorVM::FExternalFuncRegisterHandler OutLastSpawnTimeRequestValue( Context ); + VectorVM::FExternalFuncRegisterHandler OutLastSpawnedPointIDValue( Context ); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + float t = TimeParam.Get(); + float LastSpawnTime = LastSpawnTimeParam.Get(); + float LastSpawnTimeRequest = LastSpawnTimeRequestParam.Get(); + int32 LastSpawnedPointID = LastSpawnedPointIDParam.Get(); + bool ResetSpawnState = ResetSpawnStateParam.Get(); + + if (ResetSpawnState) + { + LastSpawnTime = -FLT_MAX; + LastSpawnTimeRequest = -FLT_MAX; + LastSpawnedPointID = -1; + } + + + int32 value = 0; + int32 min = 0, max = 0, count = 0; + + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointIDsToSpawnAtTime(t, min, max, count, LastSpawnedPointID, LastSpawnTime, LastSpawnTimeRequest); + } + + *OutMinValue.GetDest() = min; + *OutMaxValue.GetDest() = max; + *OutCountValue.GetDest() = count; + + *OutLastSpawnTimeValue.GetDest() = LastSpawnTime; + *OutLastSpawnTimeRequestValue.GetDest() = LastSpawnTimeRequest; + *OutLastSpawnedPointIDValue.GetDest() = LastSpawnedPointID; + + + TimeParam.Advance(); + OutMinValue.Advance(); + OutMaxValue.Advance(); + OutCountValue.Advance(); + OutLastSpawnTimeValue.Advance(); + OutLastSpawnTimeRequestValue.Advance(); + OutLastSpawnedPointIDValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPositionAndTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler SampleIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + VectorVM::FExternalFuncRegisterHandler OutTime(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 SampleIndex = SampleIndexParam.Get(); + + float timeValue = 0.0f; + FVector posVector = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetTimeValue( SampleIndex, timeValue); + HoudiniPointCacheAsset->GetPositionValue( SampleIndex, posVector); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + + *OutTime.GetDest() = timeValue; + + SampleIndexParam.Advance(); + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + OutTime.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetSampleIndexesForPointAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPrevIndex(Context); + VectorVM::FExternalFuncRegisterHandler OutNextIndex(Context); + VectorVM::FExternalFuncRegisterHandler OutWeightValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + float weight = 0.0f; + int32 prevIdx = 0; + int32 nextIdx = 0; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetSampleIndexesForPointAtTime( PointID, time, prevIdx, nextIdx, weight ); + } + + *OutPrevIndex.GetDest() = prevIdx; + *OutNextIndex.GetDest() = nextIdx; + *OutWeightValue.GetDest() = weight; + + PointIDParam.Advance(); + TimeParam.Advance(); + OutPrevIndex.Advance(); + OutNextIndex.Advance(); + OutWeightValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointPositionAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + FVector posVector = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointPositionAtTime(PointID, time, posVector); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + + PointIDParam.Advance(); + TimeParam.Advance(); + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointValueAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + int32 AttrIndex = AttributeIndexParam.Get(); + float time = TimeParam.Get(); + + float Value = 0.0f; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointValueAtTime( PointID, AttrIndex, time, Value ); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + AttributeIndexParam.Advance(); + TimeParam.Advance(); + + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + float Value = 0.0f; + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointValueAtTimeForString(PointID, Attribute, time, Value); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + TimeParam.Advance(); + + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + int32 AttrIndex = AttributeIndexParam.Get(); + float time = TimeParam.Get(); + + FVector posVector = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointVectorValueAtTime( PointID, AttrIndex, time, posVector, true, true); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + + PointIDParam.Advance(); + AttributeIndexParam.Advance(); + TimeParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + FVector posVector = FVector::ZeroVector; + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointVectorValueAtTimeForString(PointID, Attribute, time, posVector, true, true); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + + PointIDParam.Advance(); + TimeParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTimeEx(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + VectorVM::FExternalFuncInputHandler DoSwapParam(Context); + VectorVM::FExternalFuncInputHandler DoScaleParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + int32 AttrIndex = AttributeIndexParam.Get(); + float time = TimeParam.Get(); + + bool DoSwap = DoSwapParam.Get().GetValue(); + bool DoScale = DoScaleParam.Get().GetValue(); + + FVector posVector = FVector::ZeroVector; + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointVectorValueAtTime(PointID, AttrIndex, time, posVector, DoSwap, DoScale); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + + PointIDParam.Advance(); + AttributeIndexParam.Advance(); + TimeParam.Advance(); + DoSwapParam.Advance(); + DoScaleParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointVectorValueAtTimeExByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + VectorVM::FExternalFuncInputHandler DoSwapParam(Context); + VectorVM::FExternalFuncInputHandler DoScaleParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + bool DoSwap = DoSwapParam.Get().GetValue(); + bool DoScale = DoScaleParam.Get().GetValue(); + + FVector posVector = FVector::ZeroVector; + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointVectorValueAtTimeForString(PointID, Attribute, time, posVector, DoSwap, DoScale); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + + PointIDParam.Advance(); + TimeParam.Advance(); + DoSwapParam.Advance(); + DoScaleParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointVector4ValueAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + VectorVM::FExternalFuncRegisterHandler OutPosW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + int32 AttrIndex = AttributeIndexParam.Get(); + float time = TimeParam.Get(); + + FVector4 posVector(FVector::ZeroVector, 0); + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointVector4ValueAtTime( PointID, AttrIndex, time, posVector); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + *OutPosW.GetDest() = posVector.W; + + PointIDParam.Advance(); + AttributeIndexParam.Advance(); + TimeParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + OutPosW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointVector4ValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + VectorVM::FExternalFuncRegisterHandler OutPosW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + FVector4 posVector(FVector::ZeroVector, 0); + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointVector4ValueAtTimeForString(PointID, Attribute, time, posVector); + } + + *OutPosX.GetDest() = posVector.X; + *OutPosY.GetDest() = posVector.Y; + *OutPosZ.GetDest() = posVector.Z; + *OutPosW.GetDest() = posVector.W; + + PointIDParam.Advance(); + TimeParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + OutPosW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointQuatValueAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler AttributeIndexParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + VectorVM::FExternalFuncRegisterHandler OutPosW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + int32 AttrIndex = AttributeIndexParam.Get(); + float time = TimeParam.Get(); + + bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); + + FQuat Q(0, 0, 0, 0); + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointQuatValueAtTime(PointID, AttrIndex, time, Q, DoHoudiniToUnrealConversion); + } + + *OutPosX.GetDest() = Q.X; + *OutPosY.GetDest() = Q.Y; + *OutPosZ.GetDest() = Q.Z; + *OutPosW.GetDest() = Q.W; + + PointIDParam.Advance(); + AttributeIndexParam.Advance(); + TimeParam.Advance(); + DoHoudiniToUnrealConversionParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + OutPosW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointQuatValueAtTimeByString(FVectorVMExternalFunctionContext& Context, const FString& Attribute) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + VectorVM::FExternalFuncInputHandler DoHoudiniToUnrealConversionParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutPosX(Context); + VectorVM::FExternalFuncRegisterHandler OutPosY(Context); + VectorVM::FExternalFuncRegisterHandler OutPosZ(Context); + VectorVM::FExternalFuncRegisterHandler OutPosW(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + bool DoHoudiniToUnrealConversion = DoHoudiniToUnrealConversionParam.Get().GetValue(); + + FQuat Q(0, 0, 0, 0); + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointQuatValueAtTimeForString(PointID, Attribute, time, Q, DoHoudiniToUnrealConversion); + } + + *OutPosX.GetDest() = Q.X; + *OutPosY.GetDest() = Q.Y; + *OutPosZ.GetDest() = Q.Z; + *OutPosW.GetDest() = Q.W; + + PointIDParam.Advance(); + TimeParam.Advance(); + DoHoudiniToUnrealConversionParam.Advance(); + + OutPosX.Advance(); + OutPosY.Advance(); + OutPosZ.Advance(); + OutPosW.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointLife(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + + float Value = 0.0f; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointLife(PointID, Value); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + + OutValue.Advance(); + } +} + +//template, typename VectorVM::FExternalFuncInputHandler> +void UNiagaraDataInterfaceHoudini::GetPointLifeAtTime(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float time = TimeParam.Get(); + + float Value = 0.0f; + if ( HoudiniPointCacheAsset ) + { + HoudiniPointCacheAsset->GetPointLifeAtTime(PointID, time, Value); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + TimeParam.Advance(); + + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointType(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + + int32 Value = 0; + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->GetPointType(PointID, Value); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointGenericVectorAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context, bool DoSwap, bool DoScale) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutVecX(Context); + VectorVM::FExternalFuncRegisterHandler OutVecY(Context); + VectorVM::FExternalFuncRegisterHandler OutVecZ(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float Time = TimeParam.Get(); + + FVector VectorValue = FVector::ZeroVector; + if ( HoudiniPointCacheAsset ) + { + int32 AttrIndex = HoudiniPointCacheAsset->GetAttributeAttributeIndex(Attribute); + HoudiniPointCacheAsset->GetPointVectorValueAtTime(PointID, AttrIndex, Time, VectorValue, DoSwap, DoScale); + } + + *OutVecX.GetDest() = VectorValue.X; + *OutVecY.GetDest() = VectorValue.Y; + *OutVecZ.GetDest() = VectorValue.Z; + + PointIDParam.Advance(); + TimeParam.Advance(); + OutVecX.Advance(); + OutVecY.Advance(); + OutVecZ.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointGenericFloatAttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float Time = TimeParam.Get(); + + float Value = 0.0f; + if ( HoudiniPointCacheAsset ) + { + int32 AttrIndex = HoudiniPointCacheAsset->GetAttributeAttributeIndex(Attribute); + HoudiniPointCacheAsset->GetPointFloatValueAtTime(PointID, AttrIndex, Time, Value); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + TimeParam.Advance(); + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointGenericInt32AttributeAtTime(EHoudiniAttributes Attribute, FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncInputHandler PointIDParam(Context); + VectorVM::FExternalFuncInputHandler TimeParam(Context); + + VectorVM::FExternalFuncRegisterHandler OutValue(Context); + + for (int32 i = 0; i < Context.GetNumInstances(); ++i) + { + int32 PointID = PointIDParam.Get(); + float Time = TimeParam.Get(); + + int32 Value = 0.0f; + if ( HoudiniPointCacheAsset ) + { + int32 AttrIndex = HoudiniPointCacheAsset->GetAttributeAttributeIndex(Attribute); + HoudiniPointCacheAsset->GetPointInt32ValueAtTime(PointID, AttrIndex, Time, Value); + } + + *OutValue.GetDest() = Value; + + PointIDParam.Advance(); + TimeParam.Advance(); + OutValue.Advance(); + } +} + +void UNiagaraDataInterfaceHoudini::GetPointNormalAtTime(FVectorVMExternalFunctionContext& Context) +{ + GetPointGenericVectorAttributeAtTime(EHoudiniAttributes::NORMAL, Context, true, false); +} + +void UNiagaraDataInterfaceHoudini::GetPointColorAtTime(FVectorVMExternalFunctionContext& Context) +{ + GetPointGenericVectorAttributeAtTime(EHoudiniAttributes::COLOR, Context, false, false); +} + +void UNiagaraDataInterfaceHoudini::GetPointAlphaAtTime(FVectorVMExternalFunctionContext& Context) +{ + GetPointGenericFloatAttributeAtTime(EHoudiniAttributes::ALPHA, Context); +} + +void UNiagaraDataInterfaceHoudini::GetPointVelocityAtTime(FVectorVMExternalFunctionContext& Context) +{ + GetPointGenericVectorAttributeAtTime(EHoudiniAttributes::VELOCITY, Context, true, true); +} + +void UNiagaraDataInterfaceHoudini::GetPointImpulseAtTime(FVectorVMExternalFunctionContext& Context) +{ + GetPointGenericFloatAttributeAtTime(EHoudiniAttributes::IMPULSE, Context); +} + +void UNiagaraDataInterfaceHoudini::GetPointTypeAtTime(FVectorVMExternalFunctionContext& Context) +{ + GetPointGenericInt32AttributeAtTime(EHoudiniAttributes::TYPE, Context); +} + + +void UNiagaraDataInterfaceHoudini::GetNumberOfSamples(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncRegisterHandler OutNumSamples(Context); + *OutNumSamples.GetDest() = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfSamples() : 0; + OutNumSamples.Advance(); +} + +void UNiagaraDataInterfaceHoudini::GetNumberOfAttributes(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncRegisterHandler OutNumAttributes(Context); + *OutNumAttributes.GetDest() = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfAttributes() : 0; + OutNumAttributes.Advance(); +} + +void UNiagaraDataInterfaceHoudini::GetNumberOfPoints(FVectorVMExternalFunctionContext& Context) +{ + VectorVM::FExternalFuncRegisterHandler OutNumPoints(Context); + *OutNumPoints.GetDest() = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetNumberOfPoints() : 0; + OutNumPoints.Advance(); +} + +bool UNiagaraDataInterfaceHoudini::GetAttributeFunctionIndex(const TArray& InGeneratedFunctions, int InFunctionIndex, int &OutAttributeFunctionIndex) const +{ + const uint32 NumGeneratedFunctions = InGeneratedFunctions.Num(); + if (NumGeneratedFunctions == 0 || InFunctionIndex < 0) + return false; + + const FName NAME_Attribute(TEXT("Attribute")); + int AttributeFunctionIndex = 0; + for (uint32 FunctionIndex = 0; FunctionIndex < NumGeneratedFunctions; ++FunctionIndex) + { + const FNiagaraDataInterfaceGeneratedFunction& GeneratedFunction = InGeneratedFunctions[FunctionIndex]; + const FName *Attribute = GeneratedFunction.FindSpecifierValue(NAME_Attribute); + if (Attribute != nullptr) + { + if (FunctionIndex == InFunctionIndex) + { + OutAttributeFunctionIndex = AttributeFunctionIndex; + return true; + } + else + { + AttributeFunctionIndex++; + } + } + } + + return false; +} + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +#if WITH_EDITORONLY_DATA +void UNiagaraDataInterfaceHoudini::GetCommonHLSL(FString& OutHLSL) +{ + OutHLSL += TEXT("float4 q_slerp(in float4 Quat1, in float4 Quat2, float Slerp)\n" + "{\n" + "// Get cosine of angle between quats.\n" + "float RawCosom = \n" + "Quat1.x * Quat2.x +\n" + "Quat1.y * Quat2.y +\n" + "Quat1.z * Quat2.z +\n" + "Quat1.w * Quat2.w;\n" + "// Unaligned quats - compensate, results in taking shorter route.\n" + "float Cosom = RawCosom >= 0.f ? RawCosom : -RawCosom;\n" + + "float Scale0, Scale1;\n" + + "if( Cosom < 0.9999f )\n" + "{ \n" + "const float Omega = acos(Cosom);\n" + "const float InvSin = 1.f/sin(Omega);\n" + "Scale0 = sin( (1.f - Slerp) * Omega ) * InvSin;\n" + "Scale1 = sin( Slerp * Omega ) * InvSin;\n" + "}\n" + "else\n" + "{\n" + "// Use linear interpolation.\n" + "Scale0 = 1.0f - Slerp;\n" + "Scale1 = Slerp; \n" + "}\n" + + "// In keeping with our flipped Cosom:\n" + "Scale1 = RawCosom >= 0.f ? Scale1 : -Scale1;\n" + + "float4 Result;\n" + + "Result.x = Scale0 * Quat1.x + Scale1 * Quat2.x;\n" + "Result.y = Scale0 * Quat1.y + Scale1 * Quat2.y;\n" + "Result.z = Scale0 * Quat1.z + Scale1 * Quat2.z;\n" + "Result.w = Scale0 * Quat1.w + Scale1 * Quat2.w;\n" + + "return normalize(Result);\n" + "}\n" + ); +} +#endif + +#else //ENGINE_MINOR_VERSION < 1 +#if WITH_EDITORONLY_DATA +void UNiagaraDataInterfaceHoudini::GetCommonHLSL(FString& OutHLSL) +{ + OutHLSL += TEXT("float4 q_slerp(in float4 Quat1, in float4 Quat2, float Slerp)\n" + "{\n" + "// Get cosine of angle between quats.\n" + "float RawCosom = \n" + "Quat1.x * Quat2.x +\n" + "Quat1.y * Quat2.y +\n" + "Quat1.z * Quat2.z +\n" + "Quat1.w * Quat2.w;\n" + "// Unaligned quats - compensate, results in taking shorter route.\n" + "float Cosom = RawCosom >= 0.f ? RawCosom : -RawCosom;\n" + + "float Scale0, Scale1;\n" + + "if( Cosom < 0.9999f )\n" + "{ \n" + "const float Omega = acos(Cosom);\n" + "const float InvSin = 1.f/sin(Omega);\n" + "Scale0 = sin( (1.f - Slerp) * Omega ) * InvSin;\n" + "Scale1 = sin( Slerp * Omega ) * InvSin;\n" + "}\n" + "else\n" + "{\n" + "// Use linear interpolation.\n" + "Scale0 = 1.0f - Slerp;\n" + "Scale1 = Slerp; \n" + "}\n" + + "// In keeping with our flipped Cosom:\n" + "Scale1 = RawCosom >= 0.f ? Scale1 : -Scale1;\n" + + "float4 Result;\n" + + "Result.x = Scale0 * Quat1.x + Scale1 * Quat2.x;\n" + "Result.y = Scale0 * Quat1.y + Scale1 * Quat2.y;\n" + "Result.z = Scale0 * Quat1.z + Scale1 * Quat2.z;\n" + "Result.w = Scale0 * Quat1.w + Scale1 * Quat2.w;\n" + + "return normalize(Result);\n" + "}\n" + ); +} +#endif + +void UNiagaraDataInterfaceHoudini::BuildShaderParameters(FNiagaraShaderParametersBuilder& ShaderParametersBuilder) const +{ + ShaderParametersBuilder.AddNestedStruct(); +} + +void UNiagaraDataInterfaceHoudini::SetShaderParameters(const FNiagaraDataInterfaceSetShaderParametersContext& Context) const +{ + FNiagaraDataInterfaceProxyHoudini& DIProxy = Context.GetProxy(); + FShaderParameters* ShaderParameters = Context.GetParameterNestedStruct(); + + if (FHoudiniPointCacheResource* Resource = DIProxy.Resource) + { + ShaderParameters->NumberOfSamples = Resource->NumSamples; + ShaderParameters->NumberOfAttributes = Resource->NumAttributes; + ShaderParameters->NumberOfPoints = Resource->NumPoints; + ShaderParameters->MaxNumberOfIndexesPerPoint = Resource->MaxNumberOfIndexesPerPoint; + ShaderParameters->LastSpawnedPointId = -1; + ShaderParameters->LastSpawnTime = -FLT_MAX; + ShaderParameters->LastSpawnTimeRequest = -FLT_MAX; + ShaderParameters->FloatValuesBuffer = Resource->FloatValuesGPUBuffer.SRV; + ShaderParameters->SpecialAttributeIndexesBuffer = Resource->SpecialAttributeIndexesGPUBuffer.SRV; + ShaderParameters->SpawnTimesBuffer = Resource->SpawnTimesGPUBuffer.SRV; + ShaderParameters->LifeValuesBuffer = Resource->LifeValuesGPUBuffer.SRV; + ShaderParameters->PointTypesBuffer = Resource->PointTypesGPUBuffer.SRV; + ShaderParameters->PointValueIndexesBuffer = Resource->PointValueIndexesGPUBuffer.SRV; + + // Build the the function index to attribute index lookup table if it has not yet been built for this DI proxy + const FNiagaraDataInterfaceParametersCS_Houdini& ShaderStorage = Context.GetShaderStorage(); + DIProxy.UpdateFunctionIndexToAttributeIndexBuffer(ShaderStorage.FunctionIndexToAttribute); + if (DIProxy.FunctionIndexToAttributeIndexGPUBuffer.NumBytes > 0) + { + ShaderParameters->FunctionIndexToAttributeIndexBuffer = DIProxy.FunctionIndexToAttributeIndexGPUBuffer.SRV; + } + else + { + ShaderParameters->FunctionIndexToAttributeIndexBuffer = FNiagaraRenderer::GetDummyIntBuffer(); + } + } + else + { + ShaderParameters->NumberOfSamples = 0; + ShaderParameters->NumberOfAttributes = 0; + ShaderParameters->NumberOfPoints = 0; + ShaderParameters->MaxNumberOfIndexesPerPoint = 0; + ShaderParameters->LastSpawnedPointId = -1; + ShaderParameters->LastSpawnTime = -FLT_MAX; + ShaderParameters->LastSpawnTimeRequest = -FLT_MAX; + ShaderParameters->FloatValuesBuffer = FNiagaraRenderer::GetDummyFloatBuffer(); + ShaderParameters->SpecialAttributeIndexesBuffer = FNiagaraRenderer::GetDummyIntBuffer(); + ShaderParameters->SpawnTimesBuffer = FNiagaraRenderer::GetDummyFloatBuffer(); + ShaderParameters->LifeValuesBuffer = FNiagaraRenderer::GetDummyFloatBuffer(); + ShaderParameters->PointTypesBuffer = FNiagaraRenderer::GetDummyIntBuffer(); + ShaderParameters->PointValueIndexesBuffer = FNiagaraRenderer::GetDummyIntBuffer(); + ShaderParameters->FunctionIndexToAttributeIndexBuffer = FNiagaraRenderer::GetDummyIntBuffer(); + } +} + +FNiagaraDataInterfaceParametersCS* UNiagaraDataInterfaceHoudini::CreateShaderStorage(const FNiagaraDataInterfaceGPUParamInfo& ParameterInfo, const FShaderParameterMap& ParameterMap) const +{ + FNiagaraDataInterfaceParametersCS_Houdini* ShaderStorage = new FNiagaraDataInterfaceParametersCS_Houdini(); + + // Build an array of function index -> attribute name (for those functions with the Attribute specifier). If a function does not have the + // Attribute specifier, set to NAME_None + const uint32 NumGeneratedFunctions = ParameterInfo.GeneratedFunctions.Num(); + ShaderStorage->FunctionIndexToAttribute.Empty(NumGeneratedFunctions); + const FName NAME_Attribute("Attribute"); + for (const FNiagaraDataInterfaceGeneratedFunction& GeneratedFunction : ParameterInfo.GeneratedFunctions) + { + const FName* Attribute = GeneratedFunction.FindSpecifierValue(NAME_Attribute); + if (Attribute != nullptr) + { + ShaderStorage->FunctionIndexToAttribute.Add(*Attribute); + } + } + + ShaderStorage->FunctionIndexToAttribute.Shrink(); + + return ShaderStorage; +} + +const FTypeLayoutDesc* UNiagaraDataInterfaceHoudini::GetShaderStorageType() const +{ + return &StaticGetTypeLayoutDesc(); +} + +#endif //else ENGINE_MINOR_VERSION < 1 + + +#if WITH_EDITORONLY_DATA + bool UNiagaraDataInterfaceHoudini::GetFunctionHLSL(const FNiagaraDataInterfaceGPUParamInfo & ParamInfo, const FNiagaraDataInterfaceGeneratedFunction & FunctionInfo, int FunctionInstanceIndex, FString & OutHLSL) + { +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 + // Build the buffer/variable names declared for this DI + FString NumberOfSamplesVar = NumberOfSamplesBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString NumberOfAttributesVar = NumberOfAttributesBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString NumberOfPointsVar = NumberOfPointsBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString FloatBufferVar = FloatValuesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString AttributeIndexesBuffer = SpecialAttributeIndexesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString SpawnTimeBuffer = SpawnTimesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString LifeValuesBuffer = LifeValuesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString PointTypesBuffer = PointTypesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString MaxNumberOfIndexesPerPointVar = MaxNumberOfIndexesPerPointBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString PointValueIndexesBuffer = PointValueIndexesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + FString FunctionIndexToAttributeIndexBuffer = FunctionIndexToAttributeIndexBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; +#else + FString NumberOfSamplesVar = ParamInfo.DataInterfaceHLSLSymbol + NumberOfSamplesBaseName; + FString NumberOfAttributesVar = ParamInfo.DataInterfaceHLSLSymbol + NumberOfAttributesBaseName; + FString NumberOfPointsVar = ParamInfo.DataInterfaceHLSLSymbol + NumberOfPointsBaseName; + FString FloatBufferVar = ParamInfo.DataInterfaceHLSLSymbol + FloatValuesBufferBaseName; + FString AttributeIndexesBuffer = ParamInfo.DataInterfaceHLSLSymbol + SpecialAttributeIndexesBufferBaseName; + FString SpawnTimeBuffer = ParamInfo.DataInterfaceHLSLSymbol + SpawnTimesBufferBaseName; + FString LifeValuesBuffer = ParamInfo.DataInterfaceHLSLSymbol + LifeValuesBufferBaseName; + FString PointTypesBuffer = ParamInfo.DataInterfaceHLSLSymbol + PointTypesBufferBaseName; + FString MaxNumberOfIndexesPerPointVar = ParamInfo.DataInterfaceHLSLSymbol + MaxNumberOfIndexesPerPointBaseName; + FString PointValueIndexesBuffer = ParamInfo.DataInterfaceHLSLSymbol + PointValueIndexesBufferBaseName; + FString FunctionIndexToAttributeIndexBuffer = ParamInfo.DataInterfaceHLSLSymbol + FunctionIndexToAttributeIndexBufferBaseName; +#endif + + +// Build the shader function HLSL Code. + + // Lambda returning the HLSL code used for reading a Float value in the FloatBuffer + auto ReadFloatInBuffer = [&](const FString& OutFloatValue, const FString& FloatSampleIndex, const FString& FloatAttrIndex) + { + // \t OutValue = FloatBufferName[ (SampleIndex) + ( (AttrIndex) * (NumberOfSamplesName) ) ];\n + return TEXT("\t ") + OutFloatValue + TEXT(" = ") + FloatBufferVar + TEXT("[ (") + FloatSampleIndex + TEXT(") + ( (") + FloatAttrIndex + TEXT(") * (") + NumberOfSamplesVar + TEXT(") ) ];\n"); + }; + + // Lambda returning the HLSL code for reading a Vector value in the FloatBuffer + // It expects the In_DoSwap and In_DoScale bools to be defined before being called! + auto ReadVectorInBuffer = [&](const FString& OutVectorValue, const FString& VectorSampleIndex, const FString& VectorAttributeIndex) + { + FString OutHLSLCode; + OutHLSLCode += TEXT("\t// ReadVectorInBuffer\n"); + OutHLSLCode += TEXT("\t{\n"); + OutHLSLCode += TEXT("\t\tfloat3 temp_Value = float3(0.0, 0.0, 0.0);\n"); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.x"), VectorSampleIndex, VectorAttributeIndex); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.y"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 1")); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.z"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 2")); + OutHLSLCode += TEXT("\t\t") + OutVectorValue + TEXT(" = temp_Value;\n"); + OutHLSLCode += TEXT("\t\tif ( In_DoSwap )\n"); + OutHLSLCode += TEXT("\t\t{\n"); + OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".y= temp_Value.z;\n"); + OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".z= temp_Value.y;\n"); + OutHLSLCode += TEXT("\t\t}\n"); + OutHLSLCode += TEXT("\t\tif ( In_DoScale )\n"); + OutHLSLCode += TEXT("\t\t{\n"); + OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(" *= 100.0f;\n"); + OutHLSLCode += TEXT("\t\t}\n"); + OutHLSLCode += TEXT("\t}\n"); + return OutHLSLCode; + }; + + // Lambda returning the HLSL code for reading a Vector value in the FloatBuffer + // It expects the In_DoHoudiniToUnrealConversion bool to be defined before being called! + auto ReadVector4InBuffer = [&](const FString& OutVectorValue, const FString& VectorSampleIndex, const FString& VectorAttributeIndex) + { + FString OutHLSLCode; + OutHLSLCode += TEXT("\t// ReadVector4InBuffer\n"); + OutHLSLCode += TEXT("\t{\n"); + OutHLSLCode += TEXT("\t\tfloat4 temp_Value = float4(0.0, 0.0, 0.0, 0.0);\n"); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.x"), VectorSampleIndex, VectorAttributeIndex); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.y"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 1")); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.z"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 2")); + OutHLSLCode += ReadFloatInBuffer(TEXT("temp_Value.w"), VectorSampleIndex, VectorAttributeIndex + TEXT(" + 3")); + OutHLSLCode += TEXT("\t\t") + OutVectorValue + TEXT(" = temp_Value;\n"); + OutHLSLCode += TEXT("\t\tif ( In_DoHoudiniToUnrealConversion )\n"); + OutHLSLCode += TEXT("\t\t{\n"); + OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".x= -temp_Value.x;\n"); + OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".y= -temp_Value.z;\n"); + OutHLSLCode += TEXT("\t\t\t") + OutVectorValue + TEXT(".z= -temp_Value.y;\n"); + OutHLSLCode += TEXT("\t\t}\n"); + OutHLSLCode += TEXT("\t}\n"); + return OutHLSLCode; + }; + + // Lambda returning the HLSL code for reading a special attribute's index in the buffer + auto GetSpecAttributeIndex = [&](const EHoudiniAttributes& Attr) + { + FString OutHLSLCode; + OutHLSLCode += AttributeIndexesBuffer + TEXT("[") + FString::FromInt(Attr) + TEXT("]"); + return OutHLSLCode; + }; + + // Lambda returning an HLSL expression for testing if two floats are nearly equal + auto IsNearlyEqualExpression = [&](const FString& In_A, const FString& In_B, const FString& In_ErrorTolerance = "1.e-8f") + { + return FString::Printf(TEXT("( abs( %s - %s ) <= %s )"), *In_A, *In_B, *In_ErrorTolerance); + }; + + // Lambda returning the HLSL code for getting the previous and next sample indexes for a given particle at a given time + auto GetSampleIndexesForPointAtTime = [&](const FString& In_PointID, const FString& In_Time, const FString& Out_PreviousSampleIndex, const FString& Out_NextSampleIndex, const FString& Out_Weight) + { + FString OutHLSLCode; + OutHLSLCode += TEXT("\t// GetSampleIndexesForPointAtTime\n"); + OutHLSLCode += TEXT("\t{\n"); + + OutHLSLCode += TEXT("\t\tbool prev_time_valid = false;\n"); + OutHLSLCode += TEXT("\t\tfloat prev_time = -1.0f;\n"); + OutHLSLCode += TEXT("\t\tbool next_time_valid = false;\n"); + OutHLSLCode += TEXT("\t\tfloat next_time = -1.0f;\n"); + + // Look at all the values for this Point + OutHLSLCode += TEXT("\t\tfor( int n = 0; n < ") + MaxNumberOfIndexesPerPointVar + TEXT("; n++ )\n\t{\n"); + OutHLSLCode += TEXT("\t\t\tint current_sample_index = ") + PointValueIndexesBuffer + TEXT("[ (") + In_PointID + TEXT(") * ") + MaxNumberOfIndexesPerPointVar + TEXT(" + n ];\n"); + OutHLSLCode += TEXT("\t\t\tif ( current_sample_index < 0 ){ break; }\n"); + + OutHLSLCode += TEXT("\t\t\tfloat current_time = -1.0f;\n"); + OutHLSLCode += TEXT("\t\t\tint time_attr_index = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); + OutHLSLCode += TEXT("\t\t\tif ( time_attr_index < 0 || time_attr_index >= ") + NumberOfAttributesVar + TEXT(" )\n"); + OutHLSLCode += TEXT("\t\t\t\t{ current_time = 0.0f; }\n"); + OutHLSLCode += TEXT("\t\t\telse\n"); + OutHLSLCode += TEXT("\t\t\t{") + ReadFloatInBuffer(TEXT("current_time"), TEXT("current_sample_index"), TEXT("time_attr_index")) + TEXT(" }\n"); + + OutHLSLCode += TEXT("\t\t\tif ( ") + IsNearlyEqualExpression("current_time", In_Time) + TEXT(" )\n"); + OutHLSLCode += TEXT("\t\t\t\t{ ") + Out_PreviousSampleIndex + TEXT(" = current_sample_index; ") + Out_NextSampleIndex + TEXT(" = current_sample_index; ") + Out_Weight + TEXT(" = 1.0; break;}\n"); + OutHLSLCode += TEXT("\t\t\telse if ( current_time < (") + In_Time + TEXT(") ){\n"); + OutHLSLCode += TEXT("\t\t\t\tif ( !prev_time_valid || prev_time < current_time )\n"); + OutHLSLCode += TEXT("\t\t\t\t\t { ") + Out_PreviousSampleIndex + TEXT(" = current_sample_index; prev_time = current_time; prev_time_valid = true; }\n"); + OutHLSLCode += TEXT("\t\t\t}\n"); + OutHLSLCode += TEXT("\t\t\telse if ( !next_time_valid || next_time > current_time )\n"); + OutHLSLCode += TEXT("\t\t\t\t { ") + Out_NextSampleIndex + TEXT(" = current_sample_index; next_time = current_time; next_time_valid = true; break; }\n"); + OutHLSLCode += TEXT("\t\t}\n"); + + OutHLSLCode += TEXT("\t\tif ( ") + Out_PreviousSampleIndex + TEXT(" < 0 )\n"); + OutHLSLCode += TEXT("\t\t\t{ ") + Out_Weight + TEXT(" = 0.0f; ") + Out_PreviousSampleIndex + TEXT(" = ") + Out_NextSampleIndex + TEXT(";}\n"); + OutHLSLCode += TEXT("\t\tif ( ") + Out_NextSampleIndex + TEXT(" < 0 )\n"); + OutHLSLCode += TEXT("\t\t\t{ ") + Out_Weight + TEXT(" = 1.0f; ") + Out_NextSampleIndex + TEXT(" = ") + Out_PreviousSampleIndex + TEXT(";}\n"); + + // Calculate the weight + OutHLSLCode += TEXT("\t\t") + Out_Weight + TEXT(" = ( ( (") + In_Time + TEXT(") - prev_time ) / ( next_time - prev_time ) );\n"); + + OutHLSLCode += TEXT("\t}\n"); + return OutHLSLCode; + }; + + // Build each function's HLSL code + if (FunctionInfo.DefinitionName == GetFloatValueName) + { + // GetFloatValue(int In_SampleIndex, int In_AttributeIndex, out float Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, out float Out_Value) \n{\n"); + + OutHLSL += ReadFloatInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetVectorValueName) + { + // GetVectorValue(int In_SampleIndex, int In_AttributeIndex, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, out float3 Out_Value) \n{\n"); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = true;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetVectorValueExName) + { + // GetVectorValueEx(int In_SampleIndex, int In_AttributeIndex, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) \n{\n"); + + OutHLSL += ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetVector4ValueName) + { + // GetVector4Value(int In_SampleIndex, int In_AttributeIndex, out float4 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, out float4 Out_Value) \n{\n"); + + OutHLSL += TEXT("\tbool In_DoHoudiniToUnrealConversion = false;\n"); + OutHLSL += ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetQuatValueName) + { + // GetQuatValue(int In_SampleIndex, int In_AttributeIndex, bool In_DoHoudiniToUnrealConversion, out float4 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, int In_AttributeIndex, bool In_DoHoudiniToUnrealConversion, out float4 Out_Value) \n{\n"); + + OutHLSL += ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPositionName) + { + // GetPosition(int In_SampleIndex, out float3 Out_Position) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Position) \n{\n"); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = true;\n"); + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex( EHoudiniAttributes::POSITION ) + TEXT(";\n"); + OutHLSL += ReadVectorInBuffer(TEXT("Out_Position"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPositionAndTimeName) + { + // GetPositionAndTime(int In_SampleIndex, out float3 Out_Position, out float Out_Time) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Position, out float Out_Time) \n{\n"); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = true;\n"); + OutHLSL += TEXT("\tint In_PosAttrIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::POSITION) + TEXT(";\n"); + OutHLSL += ReadVectorInBuffer(TEXT("Out_Position"), TEXT("In_SampleIndex"), TEXT("In_PosAttrIndex")); + + OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); + OutHLSL += ReadFloatInBuffer(TEXT("Out_Time"), TEXT("In_SampleIndex"), TEXT("In_TimeAttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetNormalName) + { + // GetNormal(int In_SampleIndex, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Normal) \n{\n"); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = false;\n"); + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::NORMAL) + TEXT(";\n"); + OutHLSL += ReadVectorInBuffer(TEXT("Out_Normal"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetTimeName) + { + // GetTime(int In_SampleIndex, out float Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float Out_Time) \n{\n"); + + OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); + OutHLSL += ReadFloatInBuffer(TEXT("Out_Time"), TEXT("In_SampleIndex"), TEXT("In_TimeAttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetVelocityName) + { + // GetVelocity(int In_SampleIndex, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float3 Out_Velocity) \n{\n"); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = false;\n"); + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::VELOCITY) + TEXT(";\n"); + OutHLSL += ReadVectorInBuffer(TEXT("Out_Velocity"), TEXT("In_SampleIndex"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetImpulseName) + { + // GetImpulse(int In_SampleIndex, out float Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float Out_Impulse) \n{\n"); + + OutHLSL += TEXT("\tint In_ImpulseAttrIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::IMPULSE) + TEXT(";\n"); + OutHLSL += ReadFloatInBuffer(TEXT("Out_Impulse"), TEXT("In_SampleIndex"), TEXT("In_ImpulseAttrIndex")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetColorName) + { + // GetColor(int In_SampleIndex, out float4 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_SampleIndex, out float4 Out_Color) \n{\n"); + + OutHLSL += TEXT("\tfloat3 temp_color = float3(1.0, 1.0, 1.0);\n"); + OutHLSL += TEXT("\tint In_ColorAttrIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::COLOR) + TEXT(";\n"); + OutHLSL += TEXT("\tbool In_DoSwap = false;\n"); + OutHLSL += TEXT("\tbool In_DoScale = false;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("temp_color"), TEXT("In_SampleIndex"), TEXT("In_ColorAttrIndex")); + + OutHLSL += TEXT("\tfloat temp_alpha = 1.0;\n"); + OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); + OutHLSL += ReadFloatInBuffer(TEXT("temp_alpha"), TEXT("In_SampleIndex"), TEXT("In_TimeAttributeIndex")); + + OutHLSL += TEXT("Out_Color.x = temp_color.x;\n"); + OutHLSL += TEXT("Out_Color.y = temp_color.y;\n"); + OutHLSL += TEXT("Out_Color.z = temp_color.z;\n"); + OutHLSL += TEXT("Out_Color.w = temp_alpha;\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetNumberOfPointsName) + { + // GetNumberOfPoints(out int Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(out int Out_NumPoints) \n{\n"); + OutHLSL += TEXT("\tOut_NumPoints = ") + NumberOfPointsVar + TEXT(";\n"); + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetNumberOfSamplesName) + { + // GetNumberOfSamples(out int Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(out int Out_NumSamples) \n{\n"); + OutHLSL += TEXT("\tOut_NumSamples = ") + NumberOfSamplesVar + TEXT(";\n"); + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetNumberOfAttributesName) + { + // GetNumberOfSamples(out int Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(out int Out_NumAttributes) \n{\n"); + OutHLSL += TEXT("\tOut_NumAttributes = ") + NumberOfAttributesVar + TEXT(";\n"); + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetLastSampleIndexAtTimeName) + { + // GetLastSampleIndexAtTime(float In_Time, out int Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(float In_Time, out int Out_Value) \n{\n"); + + OutHLSL += TEXT("\tint In_TimeAttributeIndex = ") + GetSpecAttributeIndex( EHoudiniAttributes::TIME ) + TEXT(";\n"); + OutHLSL += TEXT("\tfloat temp_time = 1.0;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("temp_time"), NumberOfSamplesVar + TEXT("- 1"), TEXT("In_TimeAttributeIndex")); + OutHLSL += TEXT("\tif ( temp_time < In_Time ) { Out_Value = ") + NumberOfSamplesVar + TEXT(" - 1; return; }\n"); + OutHLSL += TEXT("\tint lastSampleIndex = -1;\n"); + OutHLSL += TEXT("\tfor( int n = 0; n < ") + NumberOfSamplesVar + TEXT("; n++ )\n\t{\n"); + OutHLSL += TEXT("\t") + ReadFloatInBuffer(TEXT("temp_time"), TEXT("n"), TEXT("In_TimeAttributeIndex")); + OutHLSL += TEXT("\t\tif ( temp_time == In_Time ){ lastSampleIndex = n ;}"); + OutHLSL += TEXT("\t\telse if ( temp_time > In_Time ){ lastSampleIndex = n -1; return;}"); + OutHLSL += TEXT("\t\tif ( lastSampleIndex == -1 ){ lastSampleIndex = ") + NumberOfSamplesVar + TEXT(" - 1; }"); + OutHLSL += TEXT("\t}\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointIDsToSpawnAtTimeName) + { + // GetPointIDsToSpawnAtTime(float In_Time, float In_LastSpawnTime, float In_LastSpawnTimeRequest, int In_LastSpawnPointID, out int Out_MinID, out int Out_MaxID, out int Out_Count, out float Out_LastSpawnTime, out float Out_LastSpawnTimeRequest, out int Out_LastSpawnPointID) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(float In_Time, float In_LastSpawnTime, float In_LastSpawnTimeRequest, int In_LastSpawnedPointID, out int Out_MinID, out int Out_MaxID, out int Out_Count, out float Out_LastSpawnTime, out float Out_LastSpawnTimeRequest, out int Out_LastSpawnPointID) \n{\n"); + + OutHLSL += TEXT("\tint time_attr_index = ") + GetSpecAttributeIndex(EHoudiniAttributes::TIME) + TEXT(";\n"); + OutHLSL += TEXT("\tif( time_attr_index < 0 )\n"); + OutHLSL += TEXT("\t\t{ Out_Count = ") + NumberOfPointsVar +TEXT("; Out_MinID = 0; Out_MaxID = Out_Count - 1; In_LastSpawnTimeRequest = In_Time; return; }\n"); + + // GetLastPointIDToSpawnAtTime + OutHLSL += TEXT("\tint last_id = -1;\n"); + OutHLSL += TEXT("\tif ( ") + SpawnTimeBuffer + TEXT("[ ") + NumberOfPointsVar + TEXT(" - 1 ] < In_Time && In_Time > In_LastSpawnTimeRequest )\n"); + OutHLSL += TEXT("\t{\n"); + OutHLSL += TEXT("\t\tlast_id = ") + NumberOfPointsVar + TEXT(" - 1;\n"); + OutHLSL += TEXT("\t}\n"); + OutHLSL += TEXT("\telse\n"); + OutHLSL += TEXT("\t{\n"); + OutHLSL += TEXT("\t\tfloat temp_time = 0;\n"); + OutHLSL += TEXT("\t\tfor( int n = 0; n < ") + NumberOfPointsVar + TEXT("; n++ )\n\t\t{\n"); + OutHLSL += TEXT("\t\t\ttemp_time = ") + SpawnTimeBuffer + TEXT("[ n ];\n"); + OutHLSL += TEXT("\t\t\tif ( temp_time > In_Time )\n"); + OutHLSL += TEXT("\t\t\t\t{ break; }\n"); + OutHLSL += TEXT("\t\t\tlast_id = n;\n"); + OutHLSL += TEXT("\t\t}\n"); + OutHLSL += TEXT("\t}\n"); + + // First, detect if we need to reset LastSpawnedPointID (after a loop of the emitter) + OutHLSL += TEXT("\tif ( last_id < In_LastSpawnedPointID || In_Time <= In_LastSpawnTime || In_Time <= In_LastSpawnTimeRequest )\n"); + OutHLSL += TEXT("\t\t{ In_LastSpawnedPointID = -1; }\n"); + + OutHLSL += TEXT("\tif ( last_id < 0 )\n"); + OutHLSL += TEXT("\t{\n"); + // Nothing to spawn, t is lower than the point's time + OutHLSL += TEXT("\t\t In_LastSpawnedPointID = -1;\n"); + OutHLSL += TEXT("\t\tOut_MinID = last_id;\n"); + OutHLSL += TEXT("\t\tOut_MaxID = last_id;\n"); + OutHLSL += TEXT("\t\tOut_Count = 0;\n"); + OutHLSL += TEXT("\t}\n"); + OutHLSL += TEXT("\telse\n"); + OutHLSL += TEXT("\t{\n"); + + // The last time value in the CSV is lower than t, spawn everything if we didnt already! + OutHLSL += TEXT("\t\tif ( last_id >= In_LastSpawnedPointID )\n"); + OutHLSL += TEXT("\t\t{\n"); + OutHLSL += TEXT("\t\t\tlast_id = last_id - 1;\n"); + OutHLSL += TEXT("\t\t}\n"); + + OutHLSL += TEXT("\t\tif ( last_id == In_LastSpawnedPointID )\n"); + OutHLSL += TEXT("\t\t{\n"); + // We dont have any new point to spawn + OutHLSL += TEXT("\t\t\tOut_MinID = last_id;\n"); + OutHLSL += TEXT("\t\t\tOut_MaxID = last_id;\n"); + OutHLSL += TEXT("\t\t\tOut_Count = 0;\n"); + OutHLSL += TEXT("\t\t}\n"); + OutHLSL += TEXT("\t\telse\n"); + OutHLSL += TEXT("\t\t{\n"); + // We have points to spawn at time t + OutHLSL += TEXT("\t\t\tOut_MinID = In_LastSpawnedPointID + 1;\n"); + OutHLSL += TEXT("\t\t\tOut_MaxID = last_id;\n"); + OutHLSL += TEXT("\t\t\tOut_Count = Out_MaxID - Out_MinID + 1;\n"); + + OutHLSL += TEXT("\t\t\tIn_LastSpawnedPointID = Out_MaxID;\n"); + OutHLSL += TEXT("\t\t\tIn_LastSpawnTime = In_Time;\n"); + OutHLSL += TEXT("\t\t}\n"); + + OutHLSL += TEXT("\t}\n"); + + OutHLSL += TEXT("\tIn_LastSpawnTimeRequest = In_Time;\n"); + + // Output the sim state variables + OutHLSL += TEXT("\tOut_LastSpawnTimeRequest = In_LastSpawnTimeRequest;\n"); + OutHLSL += TEXT("\tOut_LastSpawnTime = In_LastSpawnTime;\n"); + OutHLSL += TEXT("\tIn_LastSpawnedPointID = In_LastSpawnedPointID;\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetSampleIndexesForPointAtTimeName) + { + // GetSampleIndexesForPointAtTime(int In_PointID, float In_Time, out int Out_PreviousSampleIndex, out int Out_NextSampleIndex, out float Out_Weight) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out int Out_PreviousSampleIndex, out int Out_NextSampleIndex, out float Out_Weight) \n{\n"); + + OutHLSL += TEXT("\tOut_PreviousSampleIndex = 0;\n\tOut_NextSampleIndex = 0;\n\tOut_Weight = 0;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("Out_PreviousSampleIndex"), TEXT("Out_NextSampleIndex"), TEXT("Out_Weight")); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointPositionAtTimeName) + { + // GetPointPositionAtTime(int In_PointID, float In_Time, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Value) \n{\n"); + OutHLSL += TEXT("Out_Value = float3( 0.0, 0.0, 0.0 );\n"); + OutHLSL += TEXT("\tint pos_attr_index = ") + GetSpecAttributeIndex(EHoudiniAttributes::POSITION) + TEXT(";\n"); + OutHLSL += TEXT("\tint prev_index = 0;int next_index = 0;float weight = 0.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = true;\n"); + + OutHLSL += TEXT("\tfloat3 prev_vector = float3( 0.0, 0.0, 0.0 );\n"); + OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("pos_attr_index")); + OutHLSL += TEXT("\tfloat3 next_vector = float3( 0.0, 0.0, 0.0 );\n"); + OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("pos_attr_index")); + + OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointValueAtTimeName) + { + // GetPointValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, out float Out_Value) \n{\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tfloat prev_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat next_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Value = lerp(prev_value, next_value, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeName) + { + // GetPointVectorValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) \n{\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = true;\n"); + + OutHLSL += TEXT("\tfloat3 prev_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeExName) + { + // GetPointVectorValueAtTimeEx(int In_PointID, int In_AttributeIndex, float In_Time, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, bool In_DoSwap, bool In_DoScale, out float3 Out_Value) \n{\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tfloat3 prev_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + + return true; + } + else if (FunctionInfo.DefinitionName == GetPointVector4ValueAtTimeName) + { + // GetPointVector4ValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, out float4 Out_Value) \n{\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tbool In_DoHoudiniToUnrealConversion = false;\n"); + + OutHLSL += TEXT("\tfloat4 prev_vector;\n"); + OutHLSL += ReadVector4InBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat4 next_vector;\n"); + OutHLSL += ReadVector4InBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Value = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointQuatValueAtTimeName) + { + // GetPointQuatValueAtTime(int In_PointID, int In_AttributeIndex, float In_Time, out float3 Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, int In_AttributeIndex, float In_Time, bool In_DoHoudiniToUnrealConversion, out float4 Out_Value) \n{\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tfloat4 prev_quat;\n"); + OutHLSL += ReadVector4InBuffer(TEXT("prev_quat"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat4 next_quat;\n"); + OutHLSL += ReadVector4InBuffer(TEXT("next_quat"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Value = q_slerp(prev_quat, next_quat, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointLifeName) + { + // GetPointLife(int In_PointID, out float Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, out float Out_Value) \n{\n"); + + OutHLSL += TEXT("\tif ( ( In_PointID < 0 ) || ( In_PointID >= ") + NumberOfPointsVar + TEXT(") )\n"); + OutHLSL += TEXT("\t\t{Out_Value = -1.0f; return;}\n"); + OutHLSL += TEXT("\tOut_Value = ") + LifeValuesBuffer + TEXT("[ In_PointID ];\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointLifeAtTimeName) + { + // GetPointLifeAtTime(int In_PointID, float In_Time, out float Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float Out_Value) \n{\n"); + + OutHLSL += TEXT("\tif ( ( In_PointID < 0 ) || ( In_PointID >= ") + NumberOfPointsVar+ TEXT(") )\n"); + OutHLSL += TEXT("\t\t{Out_Value = -1; return;}\n"); + OutHLSL += TEXT("\telse if ( In_Time < ") + SpawnTimeBuffer + TEXT("[ In_PointID ] )\n"); + OutHLSL += TEXT("\t{\n"); + OutHLSL += TEXT("\t\tOut_Value = ") + LifeValuesBuffer + TEXT("[ In_PointID ];\n"); + OutHLSL += TEXT("\t}\n"); + OutHLSL += TEXT("\telse\n"); + OutHLSL += TEXT("\t{\n"); + OutHLSL += TEXT("\t\tOut_Value = ") + LifeValuesBuffer + TEXT("[ In_PointID ] - ( In_Time - ") + SpawnTimeBuffer + TEXT("[ In_PointID ] );\n"); + OutHLSL += TEXT("\t}\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointTypeName) + { + // GetPointType(int In_PointID, out int Out_Value) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, out int Out_Value) \n{\n"); + + OutHLSL += TEXT("\tif ( ( In_PointID < 0 ) || ( In_PointID >= ") + NumberOfPointsVar+ TEXT(") )\n"); + OutHLSL += TEXT("\t\t{Out_Value = -1; return;}\n"); + OutHLSL += TEXT("\tOut_Value = ") + PointTypesBuffer + TEXT("[ In_PointID ];\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + // BEGIN: helper GetPointAtTime functions, can potentially be removed once get attr by string functions are functional + else if (FunctionInfo.DefinitionName == GetPointNormalAtTimeName) + { + // GetPointNormalAtTime(int In_PointID, float In_Time, out float3 Out_Normal) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Normal) \n{\n"); + + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::NORMAL) + TEXT(";\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = false;\n"); + + OutHLSL += TEXT("\tfloat3 prev_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Normal = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointColorAtTimeName) + { + // GetPointColorAtTime(int In_PointID, float In_Time, out float3 Out_Color) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Color) \n{\n"); + + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::COLOR) + TEXT(";\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = false;\n"); + + OutHLSL += TEXT("\tfloat3 prev_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Color = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointAlphaAtTimeName) + { + // GetPointAlphaAtTime(int In_PointID, float In_Time, out float Out_Alpha) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float Out_Alpha) \n{\n"); + + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::ALPHA) + TEXT(";\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tfloat3 prev_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Alpha = lerp(prev_value, next_value, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointVelocityAtTimeName) + { + // GetPointVelocityAtTime(int In_PointID, float In_Time, out float3 Out_Velocity) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float3 Out_Velocity) \n{\n"); + + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::VELOCITY) + TEXT(";\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tbool In_DoSwap = true;\n"); + OutHLSL += TEXT("\tbool In_DoScale = true;\n"); + + OutHLSL += TEXT("\tfloat3 prev_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("prev_vector"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_vector;\n"); + OutHLSL += ReadVectorInBuffer(TEXT("next_vector"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Velocity = lerp(prev_vector, next_vector, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointImpulseAtTimeName) + { + // GetPointImpulseAtTime(int In_PointID, float In_Time, out float Out_Impulse) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out float Out_Impulse) \n{\n"); + + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::ALPHA) + TEXT(";\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tfloat3 prev_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + OutHLSL += TEXT("\tfloat3 next_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Impulse = lerp(prev_value, next_value, weight);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointTypeAtTimeName) + { + // GetPointTypeAtTime(int In_PointID, float In_Time, out int Out_Type) + OutHLSL += TEXT("void ") + FunctionInfo.InstanceName + TEXT("(int In_PointID, float In_Time, out int Out_Type) \n{\n"); + + OutHLSL += TEXT("\tint In_AttributeIndex = ") + GetSpecAttributeIndex(EHoudiniAttributes::TYPE) + TEXT(";\n"); + + OutHLSL += TEXT("\tint prev_index = -1;int next_index = -1;float weight = 1.0f;\n"); + OutHLSL += GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + + OutHLSL += TEXT("\tfloat3 prev_value;\n"); + OutHLSL += ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("In_AttributeIndex")); + + OutHLSL += TEXT("\tOut_Type = floor(prev_value);\n"); + + OutHLSL += TEXT("\n}\n"); + return true; + // END: helper GetPointAtTime functions, can potentially be removed once get attr by string functions are functional + } + else if (FunctionInfo.DefinitionName == GetFloatValueByStringName || + FunctionInfo.DefinitionName == GetVectorValueByStringName || + FunctionInfo.DefinitionName == GetVectorValueExByStringName || + FunctionInfo.DefinitionName == GetVector4ValueByStringName || + FunctionInfo.DefinitionName == GetQuatValueByStringName) + { + static const TCHAR *FunctionBodyTemplate = TEXT( + "void {FunctionName}(int In_SampleIndex, {AdditionalFunctionArguments}out {AttributeType} Out_Value)\n" + "{\n" + " int AttributeIndex = {FunctionIndexToAttributeIndexVarName}[{AttributeFunctionIndex}];\n" + " {VectorExFunctionDefaults}\n" + " {ReadFromBufferSnippet}\n" + "}\n\n" + ); + + int AttributeFunctionIndex = -1; + const bool bFoundAttributeFunctionIndex = GetAttributeFunctionIndex(ParamInfo.GeneratedFunctions, FunctionInstanceIndex, AttributeFunctionIndex); + if (!bFoundAttributeFunctionIndex) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not determine index for function (counted by Attribute specifier) for '%s'."), *FunctionInfo.InstanceName); + return false; + } + + FString AttributeTypeName; + FString ReadFromBufferSnippet; + FString AdditionalFunctionArguments; + FString VectorExFunctionDefaults; + if (FunctionInfo.DefinitionName == GetFloatValueByStringName) + { + AttributeTypeName = "float"; + AdditionalFunctionArguments = ""; + VectorExFunctionDefaults = ""; + ReadFromBufferSnippet = ReadFloatInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); + } + else if (FunctionInfo.DefinitionName == GetVectorValueByStringName) + { + AttributeTypeName = "float3"; + AdditionalFunctionArguments = ""; + VectorExFunctionDefaults = TEXT( + " bool In_DoSwap = true;\n" + " bool In_DoScale = true;\n" + ); + ReadFromBufferSnippet = ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); + } + else if (FunctionInfo.DefinitionName == GetVectorValueExByStringName) + { + AttributeTypeName = "float3"; + AdditionalFunctionArguments = TEXT("bool In_DoSwap, bool In_DoScale, "); + VectorExFunctionDefaults = ""; + ReadFromBufferSnippet = ReadVectorInBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); + } + else if (FunctionInfo.DefinitionName == GetVector4ValueByStringName) + { + AttributeTypeName = "float4"; + AdditionalFunctionArguments = ""; + VectorExFunctionDefaults = TEXT( + " bool In_DoHoudiniToUnrealConversion = false;\n" + ); + ReadFromBufferSnippet = ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); + } + else if (FunctionInfo.DefinitionName == GetQuatValueByStringName) + { + AttributeTypeName = "float4"; + AdditionalFunctionArguments = TEXT("bool In_DoHoudiniToUnrealConversion, "); + VectorExFunctionDefaults = ""; + ReadFromBufferSnippet = ReadVector4InBuffer(TEXT("Out_Value"), TEXT("In_SampleIndex"), TEXT("AttributeIndex")); + } + else + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Unexpected function definition name: '%s'"), *FunctionInfo.DefinitionName.ToString()); + return false; + } + + TMap FunctionTemplateArgs = { + {TEXT("FunctionName"), FunctionInfo.InstanceName}, + {TEXT("AttributeType"), AttributeTypeName}, + {TEXT("FunctionIndexToAttributeIndexVarName"), FunctionIndexToAttributeIndexBuffer}, + {TEXT("AttributeFunctionIndex"), AttributeFunctionIndex}, + {TEXT("AdditionalFunctionArguments"), AdditionalFunctionArguments}, + {TEXT("VectorExFunctionDefaults"), VectorExFunctionDefaults}, + {TEXT("ReadFromBufferSnippet"), ReadFromBufferSnippet}, + }; + + OutHLSL += FString::Format(FunctionBodyTemplate, FunctionTemplateArgs); + return true; + } + else if (FunctionInfo.DefinitionName == GetPointValueAtTimeByStringName || + FunctionInfo.DefinitionName == GetPointVectorValueAtTimeByStringName || + FunctionInfo.DefinitionName == GetPointVectorValueAtTimeExByStringName || + FunctionInfo.DefinitionName == GetPointVector4ValueAtTimeByStringName || + FunctionInfo.DefinitionName == GetPointQuatValueAtTimeByStringName) + { + static const TCHAR *FunctionBodyTemplate = TEXT( + "void {FunctionName}(int In_PointID, float In_Time, {AdditionalFunctionArguments}out {AttributeType} Out_Value)\n" + "{\n" + " int AttributeIndex = {FunctionIndexToAttributeIndexVarName}[{AttributeFunctionIndex}];\n" + " int prev_index = -1;\n" + " int next_index = -1;\n" + " float weight = 1.0f;\n" + " {GetSampleIndexesForPointAtTimeSnippet}\n" + "\n" + " {VectorExFunctionDefaults}\n" + " {AttributeType} prev_value;\n" + " {AttributeType} next_value;\n" + " {ReadPrevFromBufferSnippet}\n" + " {ReadNextFromBufferSnippet}\n" + + " Out_Value = {LerpFunctionName}(prev_value, next_value, weight);\n" + "}\n\n" + ); + + int AttributeFunctionIndex = -1; + const bool bFoundAttributeFunctionIndex = GetAttributeFunctionIndex(ParamInfo.GeneratedFunctions, FunctionInstanceIndex, AttributeFunctionIndex); + if (!bFoundAttributeFunctionIndex) + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Could not determine index for function (counted by Attribute specifier) for '%s'."), *FunctionInfo.InstanceName); + return false; + } + + FString AttributeTypeName; + FString AdditionalFunctionArguments; + FString GetSampleIndexesForPointAtTimeSnippet; + FString VectorExFunctionDefaults; + FString ReadPrevFromBufferSnippet; + FString ReadNextFromBufferSnippet; + FString LerpFunctionName; + if (FunctionInfo.DefinitionName == GetPointValueAtTimeByStringName) + { + AttributeTypeName = "float"; + GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + AdditionalFunctionArguments = ""; + VectorExFunctionDefaults = ""; + ReadPrevFromBufferSnippet = ReadFloatInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); + ReadNextFromBufferSnippet = ReadFloatInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); + LerpFunctionName = "lerp"; + } + else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeByStringName) + { + AttributeTypeName = "float3"; + GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + AdditionalFunctionArguments = ""; + VectorExFunctionDefaults = TEXT( + " bool In_DoSwap = true;\n" + " bool In_DoScale = true;\n" + ); + ReadPrevFromBufferSnippet = ReadVectorInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); + ReadNextFromBufferSnippet = ReadVectorInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); + LerpFunctionName = "lerp"; + } + else if (FunctionInfo.DefinitionName == GetPointVectorValueAtTimeExByStringName) + { + AttributeTypeName = "float3"; + GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + AdditionalFunctionArguments = TEXT("bool In_DoSwap, bool In_DoScale, "); + VectorExFunctionDefaults = ""; + ReadPrevFromBufferSnippet = ReadVectorInBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); + ReadNextFromBufferSnippet = ReadVectorInBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); + LerpFunctionName = "lerp"; + } + else if (FunctionInfo.DefinitionName == GetPointVector4ValueAtTimeByStringName) + { + AttributeTypeName = "float4"; + GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + AdditionalFunctionArguments = ""; + VectorExFunctionDefaults = TEXT( + " bool In_DoHoudiniToUnrealConversion = false;\n" + ); + ReadPrevFromBufferSnippet = ReadVector4InBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); + ReadNextFromBufferSnippet = ReadVector4InBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); + LerpFunctionName = "lerp"; + } + else if (FunctionInfo.DefinitionName == GetPointQuatValueAtTimeByStringName) + { + AttributeTypeName = "float4"; + GetSampleIndexesForPointAtTimeSnippet = GetSampleIndexesForPointAtTime(TEXT("In_PointID"), TEXT("In_Time"), TEXT("prev_index"), TEXT("next_index"), TEXT("weight")); + AdditionalFunctionArguments = TEXT("bool In_DoHoudiniToUnrealConversion, "); + VectorExFunctionDefaults = ""; + ReadPrevFromBufferSnippet = ReadVector4InBuffer(TEXT("prev_value"), TEXT("prev_index"), TEXT("AttributeIndex")); + ReadNextFromBufferSnippet = ReadVector4InBuffer(TEXT("next_value"), TEXT("next_index"), TEXT("AttributeIndex")); + LerpFunctionName = "q_slerp"; + } + else + { + UE_LOG(LogHoudiniNiagara, Error, TEXT("Unexpected function definition name: '%s'"), *FunctionInfo.DefinitionName.ToString()); + return false; + } + + TMap FunctionTemplateArgs = { + {TEXT("FunctionName"), FunctionInfo.InstanceName}, + {TEXT("AttributeType"), AttributeTypeName}, + {TEXT("FunctionIndexToAttributeIndexVarName"), FunctionIndexToAttributeIndexBuffer}, + {TEXT("AttributeFunctionIndex"), AttributeFunctionIndex}, + {TEXT("GetSampleIndexesForPointAtTimeSnippet"), GetSampleIndexesForPointAtTimeSnippet}, + {TEXT("AdditionalFunctionArguments"), AdditionalFunctionArguments}, + {TEXT("VectorExFunctionDefaults"), VectorExFunctionDefaults}, + {TEXT("ReadPrevFromBufferSnippet"), ReadPrevFromBufferSnippet}, + {TEXT("ReadNextFromBufferSnippet"), ReadNextFromBufferSnippet}, + {TEXT("LerpFunctionName"), LerpFunctionName}, + }; + + OutHLSL += FString::Format(FunctionBodyTemplate, FunctionTemplateArgs); + return true; + } + + // return !OutHLSL.IsEmpty(); + return false; +} + +#endif + + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +#if WITH_EDITORONLY_DATA +void UNiagaraDataInterfaceHoudini::GetParameterDefinitionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, FString& OutHLSL) +{ + // int NumberOfSamples_XX; + FString BufferName = UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // int NumberOfAttributes_XX; + BufferName = UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // int NumberOfPoints_XX; + BufferName = UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // Buffer FloatValuesBuffer_XX; + BufferName = UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer SpecialAttributeIndexesBuffer_XX; + BufferName = UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer SpawnTimesBuffer_XX; + BufferName = UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer LifeValuesBuffer_XX; + BufferName = UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer PointTypesBuffer_XX; + BufferName = UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // int MaxNumberOfIndexesPerPoint_XX; + BufferName = UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // Buffer PointValueIndexesBuffer_XX; + BufferName = UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // int LastSpawnedPointId_XX; + BufferName = UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // float LastSpawnTime_XX; + BufferName = UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("float ") + BufferName + TEXT(";\n"); + + // float LastSpawnTimeRequest_XX; + BufferName = UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("float ") + BufferName + TEXT(";\n"); + + // int FunctionIndexToAttributeIndexBuffer_XX[#]; + BufferName = UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName + ParamInfo.DataInterfaceHLSLSymbol; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n\n"); +} +#endif + +#else + +#if WITH_EDITORONLY_DATA +bool UNiagaraDataInterfaceHoudini::AppendCompileHash(FNiagaraCompileHashVisitor* InVisitor) const +{ + bool bSuccess = Super::AppendCompileHash(InVisitor); + bSuccess &= InVisitor->UpdateShaderParameters(); + return bSuccess; +} + + +// Build buffers and member variables HLSL definition +// Always use the BaseName + the DataInterfaceHLSL indentifier! + +void UNiagaraDataInterfaceHoudini::GetParameterDefinitionHLSL(const FNiagaraDataInterfaceGPUParamInfo& ParamInfo, FString& OutHLSL) +{ + // int NumberOfSamples_XX; + FString BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // int NumberOfAttributes_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // int NumberOfPoints_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // Buffer FloatValuesBuffer_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer SpecialAttributeIndexesBuffer_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer SpawnTimesBuffer_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer LifeValuesBuffer_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // Buffer PointTypesBuffer_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // int MaxNumberOfIndexesPerPoint_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // Buffer PointValueIndexesBuffer_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n"); + + // int LastSpawnedPointId_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName; + OutHLSL += TEXT("int ") + BufferName + TEXT(";\n"); + + // float LastSpawnTime_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName; + OutHLSL += TEXT("float ") + BufferName + TEXT(";\n"); + + // float LastSpawnTimeRequest_XX; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName; + OutHLSL += TEXT("float ") + BufferName + TEXT(";\n"); + + // int FunctionIndexToAttributeIndexBuffer_XX[#]; + BufferName = ParamInfo.DataInterfaceHLSLSymbol + UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName; + OutHLSL += TEXT("Buffer ") + BufferName + TEXT(";\n\n"); +} +#endif +#endif + +//FRWBuffer& UNiagaraDataInterfaceHoudini::GetFloatValuesGPUBuffer() +//{ +// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. +// if ( FloatValuesGPUBufferDirty ) +// { +// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->FloatSampleData.Num() : 0; +// if (NumElements <= 0) +// return FloatValuesGPUBuffer; +// +// FloatValuesGPUBuffer.Release(); +// FloatValuesGPUBuffer.Initialize( sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +// +// uint32 BufferSize = NumElements * sizeof( float ); +// float* BufferData = static_cast( RHILockVertexBuffer( FloatValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); +// +// if ( HoudiniPointCacheAsset ) +// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->FloatSampleData.GetData(), BufferSize ); +// +// RHIUnlockVertexBuffer( FloatValuesGPUBuffer.Buffer ); +// FloatValuesGPUBufferDirty = false; +// } +// +// return FloatValuesGPUBuffer; +//} + +//FRWBuffer& UNiagaraDataInterfaceHoudini::GetSpecialAttributeIndexesGPUBuffer() +//{ +// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. +// if ( SpecialAttributeIndexesGPUBufferDirty ) +// { +// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->SpecialAttributeIndexes.Num() : 0; +// if (NumElements <= 0) +// return SpecialAttributeIndexesGPUBuffer; +// +// SpecialAttributeIndexesGPUBuffer.Release(); +// SpecialAttributeIndexesGPUBuffer.Initialize(sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +// +// uint32 BufferSize = NumElements * sizeof(int32); +// float* BufferData = static_cast(RHILockVertexBuffer(SpecialAttributeIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); +// +// if (HoudiniPointCacheAsset) +// FPlatformMemory::Memcpy(BufferData, HoudiniPointCacheAsset->SpecialAttributeIndexes.GetData(), BufferSize); +// +// RHIUnlockVertexBuffer(SpecialAttributeIndexesGPUBuffer.Buffer); +// SpecialAttributeIndexesGPUBufferDirty = false; +// } +// +// return SpecialAttributeIndexesGPUBuffer; +//} + +//FRWBuffer& UNiagaraDataInterfaceHoudini::GetSpawnTimesGPUBuffer() +//{ +// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. +// if ( SpawnTimesGPUBufferDirty ) +// { +// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->SpawnTimes.Num() : 0; +// if (NumElements <= 0) +// return SpawnTimesGPUBuffer; +// +// SpawnTimesGPUBuffer.Release(); +// SpawnTimesGPUBuffer.Initialize( sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +// +// uint32 BufferSize = NumElements * sizeof( float ); +// float* BufferData = static_cast( RHILockVertexBuffer(SpawnTimesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); +// +// if ( HoudiniPointCacheAsset ) +// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->SpawnTimes.GetData(), BufferSize ); +// +// RHIUnlockVertexBuffer( SpawnTimesGPUBuffer.Buffer ); +// SpawnTimesGPUBufferDirty = false; +// } +// +// return SpawnTimesGPUBuffer; +//} + +//FRWBuffer& UNiagaraDataInterfaceHoudini::GetLifeValuesGPUBuffer() +//{ +// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. +// if ( LifeValuesGPUBufferDirty ) +// { +// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->LifeValues.Num() : 0; +// if (NumElements <= 0) +// return LifeValuesGPUBuffer; +// +// LifeValuesGPUBuffer.Release(); +// LifeValuesGPUBuffer.Initialize( sizeof(float), NumElements, EPixelFormat::PF_R32_FLOAT, BUF_Static); +// +// uint32 BufferSize = NumElements * sizeof( float ); +// float* BufferData = static_cast( RHILockVertexBuffer( LifeValuesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); +// +// if ( HoudiniPointCacheAsset ) +// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->LifeValues.GetData(), BufferSize ); +// +// RHIUnlockVertexBuffer(LifeValuesGPUBuffer.Buffer ); +// LifeValuesGPUBufferDirty = false; +// } +// +// return LifeValuesGPUBuffer; +//} + +//FRWBuffer& UNiagaraDataInterfaceHoudini::GetPointTypesGPUBuffer() +//{ +// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. +// if ( PointTypesGPUBufferDirty ) +// { +// uint32 NumElements = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->PointTypes.Num() : 0; +// if (NumElements <= 0) +// return PointTypesGPUBuffer; +// +// PointTypesGPUBuffer.Release(); +// PointTypesGPUBuffer.Initialize( sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +// +// uint32 BufferSize = NumElements * sizeof(int32); +// int32* BufferData = static_cast( RHILockVertexBuffer(PointTypesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); +// +// if ( HoudiniPointCacheAsset ) +// FPlatformMemory::Memcpy( BufferData, HoudiniPointCacheAsset->PointTypes.GetData(), BufferSize ); +// +// RHIUnlockVertexBuffer(PointTypesGPUBuffer.Buffer ); +// PointTypesGPUBufferDirty = false; +// } +// +// return PointTypesGPUBuffer; +//} + +//FRWBuffer& UNiagaraDataInterfaceHoudini::GetPointValueIndexesGPUBuffer() +//{ +// //TODO: This isn't really very thread safe. Need to move to a proxy like system where DIs can push data to the RT safely. +// if ( PointValueIndexesGPUBufferDirty ) +// { +// uint32 NumPoints = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->PointValueIndexes.Num() : 0; +// // Add an extra to the max number so all indexes end by a -1 +// uint32 MaxNumIndexesPerPoint = HoudiniPointCacheAsset ? HoudiniPointCacheAsset->GetMaxNumberOfPointValueIndexes() + 1: 0; +// uint32 NumElements = NumPoints * MaxNumIndexesPerPoint; +// +// if (NumElements <= 0) +// return PointValueIndexesGPUBuffer; +// +// TArray PointValueIndexes; +// PointValueIndexes.Init(-1, NumElements); +// if ( HoudiniPointCacheAsset ) +// { +// // We need to flatten the nested array for HLSL conversion +// for ( int32 PointID = 0; PointID < HoudiniPointCacheAsset->PointValueIndexes.Num(); PointID++ ) +// { +// TArray SampleIndexes = HoudiniPointCacheAsset->PointValueIndexes[PointID].SampleIndexes; +// for( int32 Idx = 0; Idx < SampleIndexes.Num(); Idx++ ) +// { +// PointValueIndexes[ PointID * MaxNumIndexesPerPoint + Idx ] = SampleIndexes[ Idx ]; +// } +// } +// } +// +// PointValueIndexesGPUBuffer.Release(); +// PointValueIndexesGPUBuffer.Initialize(sizeof(int32), NumElements, EPixelFormat::PF_R32_SINT, BUF_Static); +// +// uint32 BufferSize = NumElements * sizeof(int32); +// int32* BufferData = static_cast( RHILockVertexBuffer( PointValueIndexesGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly ) ); +// FPlatformMemory::Memcpy( BufferData, PointValueIndexes.GetData(), BufferSize ); +// RHIUnlockVertexBuffer( PointValueIndexesGPUBuffer.Buffer ); +// +// PointValueIndexesGPUBufferDirty = false; +// } +// +// return PointValueIndexesGPUBuffer; +//} + +void UNiagaraDataInterfaceHoudini::PushToRenderThreadImpl() +{ + // Need to throw a ref count into the RHI buffer so that the resource is guaranteed to stay alive while in the queue. + FHoudiniPointCacheResource* ThisResource = nullptr; + check(Proxy); + if (HoudiniPointCacheAsset) + { + HoudiniPointCacheAsset->RequestPushToGPU(); + ThisResource = HoudiniPointCacheAsset->Resource.Get(); + } + + FNiagaraDataInterfaceProxyHoudini* ThisProxy = GetProxyAs(); + ENQUEUE_RENDER_COMMAND(FNiagaraDIHoudiniPointCache_ToRT) ( + [ThisProxy, ThisResource](FRHICommandListImmediate& CmdList) mutable + { + ThisProxy->bFunctionIndexToAttributeIndexHasBeenBuilt = false; + ThisProxy->Resource = ThisResource; + } + ); +} + +FNiagaraDataInterfaceProxyHoudini::FNiagaraDataInterfaceProxyHoudini() + : FNiagaraDataInterfaceProxy(), Resource(nullptr) +{ + bFunctionIndexToAttributeIndexHasBeenBuilt = false; +} + + +FNiagaraDataInterfaceProxyHoudini::~FNiagaraDataInterfaceProxyHoudini() +{ +} + +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +void FNiagaraDataInterfaceProxyHoudini::UpdateFunctionIndexToAttributeIndexBuffer(const TMemoryImageArray &FunctionIndexToAttribute, bool bForceUpdate) +#else +void FNiagaraDataInterfaceProxyHoudini::UpdateFunctionIndexToAttributeIndexBuffer(const TMemoryImageArray &FunctionIndexToAttribute, bool bForceUpdate) +#endif +{ + // Don't rebuild the lookup table if it has already been built and bForceUpdate is false + if (bFunctionIndexToAttributeIndexHasBeenBuilt && !bForceUpdate) + return; + + if (!Resource) + return; + + const uint32 NumFunctions = FunctionIndexToAttribute.Num(); + FunctionIndexToAttributeIndex.SetNum(NumFunctions); + // For each generated function that uses the Attribute specifier we want to set the attribute index it uses, + // or -1 if the Attribute is invalid or missing + for (uint32 FunctionIndex = 0; FunctionIndex < NumFunctions; ++FunctionIndex) + { + const FName &Attribute = FunctionIndexToAttribute[FunctionIndex]; + if (Attribute != NAME_None) + { + int32 AttributeIndex = INDEX_NONE; + if (UHoudiniPointCache::GetAttributeIndexInArrayFromString(Attribute.ToString(), Resource->Attributes, AttributeIndex)) + { + FunctionIndexToAttributeIndex[FunctionIndex] = AttributeIndex; + } + if (AttributeIndex == INDEX_NONE) + { + UE_LOG(LogHoudiniNiagara, Warning, TEXT("Trying to access an attribute that does not exist: %s"), *Attribute.ToString()); + } + } + else + { + FunctionIndexToAttributeIndex[FunctionIndex] = INDEX_NONE; + } + } + + const uint32 BufferSize = NumFunctions * sizeof(int32); + if (FunctionIndexToAttributeIndexGPUBuffer.NumBytes != BufferSize) + { + FunctionIndexToAttributeIndexGPUBuffer.Release(); + } + + if (BufferSize > 0) + { + FunctionIndexToAttributeIndexGPUBuffer.Initialize(TEXT("HoudiniGPUBufferIndexToAttributeIndex"), sizeof(int32), NumFunctions, EPixelFormat::PF_R32_SINT, BUF_Static); + int32* BufferData = static_cast(RHILockBuffer(FunctionIndexToAttributeIndexGPUBuffer.Buffer, 0, BufferSize, EResourceLockMode::RLM_WriteOnly)); + FPlatformMemory::Memcpy(BufferData, FunctionIndexToAttributeIndex.GetData(), BufferSize); + RHIUnlockBuffer(FunctionIndexToAttributeIndexGPUBuffer.Buffer); + } + + bFunctionIndexToAttributeIndexHasBeenBuilt = true; +} +#if ENGINE_MAJOR_VERSION==5 && ENGINE_MINOR_VERSION < 1 +// Parameters used for GPU sim compatibility +struct FNiagaraDataInterfaceParametersCS_Houdini : public FNiagaraDataInterfaceParametersCS +{ + DECLARE_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini, NonVirtual); +public: + void Bind(const FNiagaraDataInterfaceGPUParamInfo& ParameterInfo, const class FShaderParameterMap& ParameterMap) + { + NumberOfSamples.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::NumberOfSamplesBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + NumberOfAttributes.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::NumberOfAttributesBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + NumberOfPoints.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::NumberOfPointsBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + FloatValuesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::FloatValuesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + SpecialAttributeIndexesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::SpecialAttributeIndexesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + SpawnTimesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::SpawnTimesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + LifeValuesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LifeValuesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + PointTypesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::PointTypesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + MaxNumberOfIndexesPerPoint.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::MaxNumberOfIndexesPerPointBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + PointValueIndexesBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::PointValueIndexesBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + LastSpawnedPointId.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LastSpawnedPointIdBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + LastSpawnTime.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LastSpawnTimeBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + LastSpawnTimeRequest.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::LastSpawnTimeRequestBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + FunctionIndexToAttributeIndexBuffer.Bind(ParameterMap, *(UNiagaraDataInterfaceHoudini::FunctionIndexToAttributeIndexBufferBaseName + ParameterInfo.DataInterfaceHLSLSymbol)); + + // Build an array of function index -> attribute name (for those functions with the Attribute specifier). If a function does not have the + // Attribute specifier, set to NAME_None + const uint32 NumGeneratedFunctions = ParameterInfo.GeneratedFunctions.Num(); + FunctionIndexToAttribute.Empty(NumGeneratedFunctions); + const FName NAME_Attribute("Attribute"); + for (const FNiagaraDataInterfaceGeneratedFunction& GeneratedFunction : ParameterInfo.GeneratedFunctions) + { + const FName *Attribute = GeneratedFunction.FindSpecifierValue(NAME_Attribute); + if (Attribute != nullptr) + { + FunctionIndexToAttribute.Add(*Attribute); + } + } + } + + void Set(FRHICommandList& RHICmdList, const FNiagaraDataInterfaceSetArgs& Context) const + { + check( IsInRenderingThread() ); + + FRHIComputeShader* ComputeShaderRHI = Context.Shader.GetComputeShader(); + FNiagaraDataInterfaceProxyHoudini* HoudiniDI = static_cast(Context.DataInterface); + if ( !HoudiniDI) + { + return; + } + + FHoudiniPointCacheResource* Resource = HoudiniDI->Resource; + if (!Resource) + { + return; + } + + SetShaderValue(RHICmdList, ComputeShaderRHI, NumberOfSamples, Resource->NumSamples); + SetShaderValue(RHICmdList, ComputeShaderRHI, NumberOfAttributes, Resource->NumAttributes); + SetShaderValue(RHICmdList, ComputeShaderRHI, NumberOfPoints, Resource->NumPoints); + + SetSRVParameter(RHICmdList, ComputeShaderRHI, FloatValuesBuffer, Resource->FloatValuesGPUBuffer.SRV); + + SetSRVParameter(RHICmdList, ComputeShaderRHI, SpecialAttributeIndexesBuffer, Resource->SpecialAttributeIndexesGPUBuffer.SRV); + + SetSRVParameter(RHICmdList, ComputeShaderRHI, SpawnTimesBuffer, Resource->SpawnTimesGPUBuffer.SRV); + SetSRVParameter(RHICmdList, ComputeShaderRHI, LifeValuesBuffer, Resource->LifeValuesGPUBuffer.SRV); + SetSRVParameter(RHICmdList, ComputeShaderRHI, PointTypesBuffer, Resource->PointTypesGPUBuffer.SRV); + + SetShaderValue(RHICmdList, ComputeShaderRHI, MaxNumberOfIndexesPerPoint, Resource->MaxNumberOfIndexesPerPoint); + + SetSRVParameter(RHICmdList, ComputeShaderRHI, PointValueIndexesBuffer, Resource->PointValueIndexesGPUBuffer.SRV); + + SetShaderValue(RHICmdList, ComputeShaderRHI, LastSpawnedPointId, -1); + SetShaderValue(RHICmdList, ComputeShaderRHI, LastSpawnTime, -FLT_MAX); + SetShaderValue(RHICmdList, ComputeShaderRHI, LastSpawnTimeRequest, -FLT_MAX); + + // Build the the function index to attribute index lookup table if it has not yet been built for this DI proxy + HoudiniDI->UpdateFunctionIndexToAttributeIndexBuffer(FunctionIndexToAttribute); + + if (HoudiniDI->FunctionIndexToAttributeIndexGPUBuffer.NumBytes > 0) + { + SetSRVParameter(RHICmdList, ComputeShaderRHI, FunctionIndexToAttributeIndexBuffer, HoudiniDI->FunctionIndexToAttributeIndexGPUBuffer.SRV); + } + else + { + SetSRVParameter(RHICmdList, ComputeShaderRHI, FunctionIndexToAttributeIndexBuffer, FNiagaraRenderer::GetDummyIntBuffer()); + } + } + +private: + LAYOUT_FIELD(FShaderParameter, NumberOfSamples); + LAYOUT_FIELD(FShaderParameter, NumberOfAttributes); + LAYOUT_FIELD(FShaderParameter, NumberOfPoints); + + LAYOUT_FIELD(FShaderResourceParameter, FloatValuesBuffer); + LAYOUT_FIELD(FShaderResourceParameter, SpecialAttributeIndexesBuffer); + + LAYOUT_FIELD(FShaderResourceParameter, SpawnTimesBuffer); + LAYOUT_FIELD(FShaderResourceParameter, LifeValuesBuffer); + LAYOUT_FIELD(FShaderResourceParameter, PointTypesBuffer); + + LAYOUT_FIELD(FShaderParameter, MaxNumberOfIndexesPerPoint); + LAYOUT_FIELD(FShaderResourceParameter, PointValueIndexesBuffer); + + LAYOUT_FIELD(FShaderParameter, LastSpawnedPointId); + LAYOUT_FIELD(FShaderParameter, LastSpawnTime); + LAYOUT_FIELD(FShaderParameter, LastSpawnTimeRequest); + + LAYOUT_FIELD(FShaderResourceParameter, FunctionIndexToAttributeIndexBuffer); + + LAYOUT_FIELD(TMemoryImageArray, FunctionIndexToAttribute); + + LAYOUT_FIELD_INITIALIZED(uint32, Version, 1); +}; + +IMPLEMENT_TYPE_LAYOUT(FNiagaraDataInterfaceParametersCS_Houdini); + +IMPLEMENT_NIAGARA_DI_PARAMETER(UNiagaraDataInterfaceHoudini, FNiagaraDataInterfaceParametersCS_Houdini); +#endif + +#undef LOCTEXT_NAMESPACE diff --git a/Source/HoudiniNiagara/Public/HoudiniPointCache.h b/Source/HoudiniNiagara/Public/HoudiniPointCache.h index eb9f490..c75824d 100644 --- a/Source/HoudiniNiagara/Public/HoudiniPointCache.h +++ b/Source/HoudiniNiagara/Public/HoudiniPointCache.h @@ -1,487 +1,498 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ -#pragma once - -#include "UObject/ObjectMacros.h" -#include "UObject/UObjectGlobals.h" -#include "UObject/Object.h" -#include "RenderResource.h" -#include "RHIUtilities.h" - -#include "HoudiniPointCache.generated.h" - -DECLARE_LOG_CATEGORY_EXTERN( LogHoudiniNiagara, All, All ); - -UENUM() -enum EHoudiniAttributes -{ - HOUDINI_ATTR_BEGIN, - - POSITION = HOUDINI_ATTR_BEGIN, - NORMAL, - TIME, - POINTID, - LIFE, - COLOR, - ALPHA, - VELOCITY, - TYPE, - IMPULSE, - AGE, - - HOUDINI_ATTR_SIZE, - HOUDINI_ATTR_END = HOUDINI_ATTR_SIZE - 1 - -}; - -USTRUCT() -struct FPointIndexes -{ - GENERATED_BODY() - - // Simple structure for storing all the sample indexes used for a given point - UPROPERTY() - TArray SampleIndexes; -}; - -UENUM() -enum class EHoudiniPointCacheFileType : uint8 -{ - Invalid, - CSV, - JSON, - BJSON, -}; - -struct FNiagaraDIHoudini_StaticDataPassToRT -{ - ~FNiagaraDIHoudini_StaticDataPassToRT() - { - //UE_LOG(LogHoudiniNiagara, Warning, TEXT("Deleted!")); - } - - TArray FloatData; - TArray SpawnTimes; - TArray LifeValues; - TArray PointTypes; - TArray SpecialAttributeIndexes; - TArray PointValueIndexes; - TArray Attributes; - - int32 NumSamples; - int32 NumAttributes; - int32 NumPoints; - int32 MaxNumIndexesPerPoint; -}; - -/** - * point cache resource. - */ -class FHoudiniPointCacheResource : public FRenderResource -{ -public: - - // GPU Buffers - FRWBuffer FloatValuesGPUBuffer; - FRWBuffer SpecialAttributeIndexesGPUBuffer; - FRWBuffer SpawnTimesGPUBuffer; - FRWBuffer LifeValuesGPUBuffer; - FRWBuffer PointTypesGPUBuffer; - FRWBuffer PointValueIndexesGPUBuffer; - - int32 MaxNumberOfIndexesPerPoint; - int32 NumSamples; - int32 NumAttributes; - int32 NumPoints; - - TArray Attributes; - - TUniquePtr CachedData; - - /** Default constructor. */ - FHoudiniPointCacheResource() : CachedData(nullptr){} - - virtual void InitRHI() override; - virtual void ReleaseRHI() override; - - virtual FString GetFriendlyName() const override { return TEXT("FHoudiniPointCacheResource"); } - - void AcceptStaticDataUpdate(TUniquePtr& Update); - - virtual ~FHoudiniPointCacheResource() {} -}; - - -UCLASS(BlueprintType) -class HOUDININIAGARA_API UHoudiniPointCache : public UObject -{ - friend class UNiagaraDataInterfaceHoudini; - - GENERATED_UCLASS_BODY() - - public: - - //----------------------------------------------------------------------------------------- - // MEMBER FUNCTIONS - //----------------------------------------------------------------------------------------- - -#if WITH_EDITOR - bool UpdateFromFile( const FString& TheFileName ); -#endif - - void SetFileName( const FString& TheFilename ); - - // Returns the number of points found in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - int32 GetNumberOfPoints() const; - - // Returns the number of samples found in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - int32 GetNumberOfSamples() const; - - // Returns the number of attributes found in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - int32 GetNumberOfAttributes() const; - - // Return the attribute index for a specific attribute - //UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - int32 GetAttributeAttributeIndex(const EHoudiniAttributes& Attr) const; - - // Returns if the specific attribute has a valid attribute index - bool IsValidAttributeAttributeIndex(const EHoudiniAttributes& Attr) const; - - // Returns the attribute index for a given string. - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetAttributeIndexFromString(const FString& Attribute, int32& AttributeIndex) const; - - // Returns the attribute index for a given string. This is a static version of the function that - // takes the attribute name array as an argument as well. - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - static bool GetAttributeIndexInArrayFromString(const FString& InAttribute, const TArray& InAttributeArray, int32& OutAttributeIndex); - - // Returns the float value at a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetFloatValue( const int32& sampleIndex, const int32& attrIndex, float& value ) const; - // Returns the float value at a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetFloatValueForString( const int32& sampleIndex, const FString& Attribute, float& value ) const; - /* - // Returns the string value at a given point in the point cache - bool GetCSVStringValue( const int32& sampleIndex, const int32& attrIndex, FString& value ); - // Returns the string value at a given point in the point cache - bool GetCSVStringValue( const int32& sampleIndex, const FString& Attribute, FString& value ); - */ - // Returns a Vector3 for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetVectorValue( const int32& sampleIndex, const int32& attrIndex, FVector& value, const bool& DoSwap = true, const bool& DoScale = true ) const; - // Returns a Vector3 for a given point in the point cache by column name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetVectorValueForString(const int32& sampleIndex, const FString& Attribute, FVector& value, const bool& DoSwap = true, const bool& DoScale = true) const; - // Returns a Vector4 for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetVector4Value( const int32& sampleIndex, const int32& attrIndex, FVector4& value ) const; - // Returns a Vector4 for a given point in the point cache by column name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetVector4ValueForString(const int32& sampleIndex, const FString& Attribute, FVector4& value ) const; - // Returns a Quat for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetQuatValue( const int32& sampleIndex, const int32& attrIndex, FQuat& value, const bool& DoHoudiniToUnrealConversion = true ) const; - // Returns a Quat for a given point in the point cache by column name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetQuatValueForString(const int32& sampleIndex, const FString& Attribute, FQuat& value, const bool& DoHoudiniToUnrealConversion = true ) const; - - // Returns a time value for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetTimeValue( const int32& sampleIndex, float& value ) const; - // Returns a Position Vector3 for a given point in the point cache (converted to unreal's coordinate system) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPositionValue( const int32& sampleIndex, FVector& value ) const; - // Returns a Normal Vector3 for a given point in the point cache (converted to unreal's coordinate system) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetNormalValue( const int32& sampleIndex, FVector& value ) const; - // Returns a Color for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetColorValue( const int32& sampleIndex, FLinearColor& value ) const; - // Returns a Velocity Vector3 for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetVelocityValue(const int32& sampleIndex, FVector& value ) const; - // Returns an Impulse float value for a given point in the point cache - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetImpulseValue(const int32& sampleIndex, float& value) const; - - // Get the last sample index for a given time value (the sample with a time smaller or equal to desiredTime) - // If the point cache doesn't have time informations, returns false and set LastsampleIndex to the last sample in the file - // If desiredTime is smaller than the time value in the first sample, LastsampleIndex will be set to -1 - // If desiredTime is higher than the last time value in the last sample of the point cache, LastIndex will be set to the last sample's index - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetLastSampleIndexAtTime( const float& desiredTime, int32& lastSampleIndex ) const; - - // Get the last pointID of the points to be spawned at time t - // Invalid Index are used to indicate edge cases: - // -1 will be returned if there is no points to spawn ( t is smaller than the first point time ) - // NumberOfSamples will be returned if all points in the CSV have been spawned ( t is higher than the last point time ) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetLastPointIDToSpawnAtTime( const float& time, int32& lastID ) const; - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointIDsToSpawnAtTime( - const float& desiredTime, - int32& MinID, int32& MaxID, int32& Count, - int32& LastSpawnedPointID, float& LastSpawnTime, float& LastSpawnTimeRequest) const; - - bool GetPointIDsToSpawnAtTime_DEPR( - const float& desiredTime, - int32& MinID, int32& MaxID, int32& Count, - int32& LastSpawnedPointID, float& LastSpawnTime ) const; - - // Returns the previous and next sample indexes for reading the values of a specified point at a given time - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetSampleIndexesForPointAtTime(const int32& PointID, const float& desiredTime, int32& PrevSampleIndex, int32& NextSampleIndex, float& PrevWeight) const; - // Returns the value for a point at a given time value (linearly interpolated) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointValueAtTime(const int32& PointID, const int32& AttributeIndex, const float& desiredTime, float& Value) const; - // Returns the value for a point at a given time value (linearly interpolated), via the attribute name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointValueAtTimeForString(const int32& PointID, const FString& Attribute, const float& desiredTime, float& Value) const; - - // Returns the Vector Value for a given point at a given time value (linearly interpolated) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointVectorValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, FVector& Vector, bool DoSwap, bool DoScale) const; - - // Returns the Vector Value for a given point at a given time value (linearly interpolated), via the attribute name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointVectorValueAtTimeForString(int32 PointID, const FString& Attribute, float desiredTime, FVector& Vector, bool DoSwap, bool DoScale) const; - - // Returns the Vector4 Value for a given point at a given time value (linearly interpolated) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointVector4ValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, FVector4& Vector) const; - - // Returns the Vector4 Value for a given point at a given time value (linearly interpolated), via the attribute name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointVector4ValueAtTimeForString(int32 PointID, const FString& Attribute, float desiredTime, FVector4& Vector) const; - - // Returns the Quat Value for a given point at a given time value (linearly interpolated) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointQuatValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, FQuat& Quat, bool DoHoudiniToUnrealConversion = true ) const; - - // Returns the Quat Value for a given point at a given time value (linearly interpolated), via the attribute name - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointQuatValueAtTimeForString(int32 PointID, const FString& Attribute, float desiredTime, FQuat& Quat, bool DoHoudiniToUnrealConversion = true ) const; - - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointFloatValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, float& Value) const; - - // Return the integer value of the point at the keyframe before the desired time. No value interpolation will take place. - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointInt32ValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, int32& Value) const; - - // Returns the Position Value for a given point at a given time value (linearly interpolated) - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointPositionAtTime(const int32& PointID, const float& desiredTime, FVector& Vector) const; - // Return a given point's life value at spawn - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointLife(const int32& PointID, float& Value) const; - // Return a point's life for a given time value - // Note this function currently behaves exactly the same as GetPointLife - // since the Lifetime value is currently treated as a constant. This could - // change in the future. - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointLifeAtTime(const int32& PointID, const float& DesiredTime, float& Value) const; - // Return a point's type at spawn - UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") - bool GetPointType(const int32& PointID, int32& Value) const; - - - // Returns the maximum number of indexes per point, used for flattening the buffer for HLSL conversion - int32 GetMaxNumberOfPointValueIndexes() const; - - //----------------------------------------------------------------------------------------- - // MEMBER VARIABLES - //----------------------------------------------------------------------------------------- - - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - FString FileName; - - // The number of values stored in the point cache - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - int32 NumberOfSamples; - - // The number of attributes stored in the point cache - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - int32 NumberOfAttributes; - - // The number of unique points found in the point cache - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") - int32 NumberOfPoints; - - // The number of frames imported into the point cache - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") - int32 NumberOfFrames; - - // The first frame of the exported frame range - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") - float FirstFrame; - - // The last frame of the exported frame range - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") - float LastFrame; - - // The minimum sample time value, in seconds, in the point cache - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") - float MinSampleTime; - - // The maximum sample time value, in seconds, in the point cache - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") - float MaxSampleTime; - - // The source title row for CSV files, describing the content of each column and used to locate specific values in the point cache. - // Editing this will trigger a re-import of the point cache. - UPROPERTY(EditAnywhere, Category = "Houdini Point Cache Properties") - FString SourceCSVTitleRow; - - // The final attribute names used by the asset after parsing. - // Packed vector values are expanded, so additional attributes (.0, .1, ... or .x, .y, .z) might have been inserted. - // Use the indexes in this array to access your data. - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - TArray AttributeArray; - -#if WITH_EDITORONLY_DATA - /** Importing data and options used for this asset */ - UPROPERTY( EditAnywhere, Instanced, Category = ImportSettings ) - class UAssetImportData* AssetImportData; - - // Raw data of the source file so that we can export it again. - UPROPERTY() - TArray RawDataCompressed; - - // Compression scheme used to compress raw - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - FName RawDataFormatID; - - // Size of data when uncompressed - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - uint32 RawDataUncompressedSize; - - // Compression scheme used to compress raw - UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) - FName RawDataCompressionMethod; -#endif - -#if WITH_EDITOR - bool HasRawData() const { return RawDataCompressed.Num() > 0; }; - - virtual void PostInitProperties() override; - virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override; -#endif - - virtual void GetAssetRegistryTags(TArray< FAssetRegistryTag > & OutTags) const override; - - void BeginDestroy() override; - - // Data Accessors, const and non-const versions - TArray& GetFloatSampleData() { return FloatSampleData; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") - const TArray& GetFloatSampleData() const { return FloatSampleData; } - - TArray& GetSpawnTimes() { return SpawnTimes; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") - const TArray& GetSpawnTimes() const { return SpawnTimes; } - - TArray& GetLifeValues() { return LifeValues; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") - const TArray& GetLifeValues() const { return LifeValues; } - - TArray& GetPointTypes() { return PointTypes; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") - const TArray& GetPointTypes() const { return PointTypes; } - - TArray& GetSpecialAttributeIndexes() { return SpecialAttributeIndexes; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") - const TArray& GetSpecialAttributeIndexes() const { return SpecialAttributeIndexes; } - - TArray& GetPointValueIndexes() { return PointValueIndexes; } - - UFUNCTION() - const TArray& GetPointValueIndexes() const { return PointValueIndexes; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Settings") - bool GetUseCustomCSVTitleRow() const { return UseCustomCSVTitleRow; } - - UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Settings") - void SetUseCustomCSVTitleRow(bool bInUseCustomCSVTitleRow) { UseCustomCSVTitleRow = bInUseCustomCSVTitleRow; } - - /** The GPU resource for this point cache. */ - TUniquePtr Resource; - - void RequestPushToGPU(); - - private: - - /* - // Array containing the Raw String data - UPROPERTY() - TArray StringCSVData; - */ - - // Array containing all the sample data converted to floats - UPROPERTY() - TArray FloatSampleData; - - // Array containing the spawn times for each point in the point cache - UPROPERTY() - TArray SpawnTimes; - - // Array containing all the life values for each point in the point cache - UPROPERTY() - TArray LifeValues; - - // Array containing all the type values for each point in the point cache - UPROPERTY() - TArray PointTypes; - - // Array containing the column indexes of the special attributes - UPROPERTY() - TArray SpecialAttributeIndexes; - - /* - // Row indexes for new time values - UPROPERTY() - TMap TimeValuesIndexes; - */ - - // Sample indexes for each point - UPROPERTY() - TArray< FPointIndexes > PointValueIndexes; - - /** For CSV source files, whether to use a custom title row. */ - UPROPERTY() - bool UseCustomCSVTitleRow; - - // The type of source file, such as CSV or JSON. - UPROPERTY() - EHoudiniPointCacheFileType FileType; +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ +#pragma once + +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "Misc/FileHelper.h" +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/UObjectGlobals.h" +#include "UObject/Object.h" +#include "RenderResource.h" +#include "RHIUtilities.h" + +#include "HoudiniPointCache.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN( LogHoudiniNiagara, All, All ); + +UENUM() +enum EHoudiniAttributes +{ + HOUDINI_ATTR_BEGIN, + + POSITION = HOUDINI_ATTR_BEGIN, + NORMAL, + TIME, + POINTID, + LIFE, + COLOR, + ALPHA, + VELOCITY, + TYPE, + IMPULSE, + AGE, + + HOUDINI_ATTR_SIZE, + HOUDINI_ATTR_END = HOUDINI_ATTR_SIZE - 1 + +}; + +USTRUCT() +struct FPointIndexes +{ + GENERATED_BODY() + + // Simple structure for storing all the sample indexes used for a given point + UPROPERTY() + TArray SampleIndexes; +}; + +UENUM() +enum class EHoudiniPointCacheFileType : uint8 +{ + Invalid, + CSV, + JSON, + BJSON, +}; + +struct FNiagaraDIHoudini_StaticDataPassToRT +{ + ~FNiagaraDIHoudini_StaticDataPassToRT() + { + //UE_LOG(LogHoudiniNiagara, Warning, TEXT("Deleted!")); + } + + TArray FloatData; + TArray SpawnTimes; + TArray LifeValues; + TArray PointTypes; + TArray SpecialAttributeIndexes; + TArray PointValueIndexes; + TArray Attributes; + + int32 NumSamples; + int32 NumAttributes; + int32 NumPoints; + int32 MaxNumIndexesPerPoint; +}; + +/** + * point cache resource. + */ +class FHoudiniPointCacheResource : public FRenderResource +{ +public: + + // GPU Buffers + FRWBuffer FloatValuesGPUBuffer; + FRWBuffer SpecialAttributeIndexesGPUBuffer; + FRWBuffer SpawnTimesGPUBuffer; + FRWBuffer LifeValuesGPUBuffer; + FRWBuffer PointTypesGPUBuffer; + FRWBuffer PointValueIndexesGPUBuffer; + + int32 MaxNumberOfIndexesPerPoint; + int32 NumSamples; + int32 NumAttributes; + int32 NumPoints; + + TArray Attributes; + + TUniquePtr CachedData; + + /** Default constructor. */ + FHoudiniPointCacheResource() : CachedData(nullptr){} + +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + virtual void InitRHI(FRHICommandListBase& RHICmdList) override; +#else + virtual void InitRHI() override; +#endif + virtual void ReleaseRHI() override; + + virtual FString GetFriendlyName() const override { return TEXT("FHoudiniPointCacheResource"); } + + void AcceptStaticDataUpdate(TUniquePtr& Update); + + virtual ~FHoudiniPointCacheResource() {} +}; + + +UCLASS(BlueprintType) +class HOUDININIAGARA_API UHoudiniPointCache : public UObject +{ + friend class UNiagaraDataInterfaceHoudini; + + GENERATED_UCLASS_BODY() + + public: + + //----------------------------------------------------------------------------------------- + // MEMBER FUNCTIONS + //----------------------------------------------------------------------------------------- + +#if WITH_EDITOR + bool UpdateFromFile( const FString& TheFileName ); +#endif + + void SetFileName( const FString& TheFilename ); + + // Returns the number of points found in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + int32 GetNumberOfPoints() const; + + // Returns the number of samples found in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + int32 GetNumberOfSamples() const; + + // Returns the number of attributes found in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + int32 GetNumberOfAttributes() const; + + // Return the attribute index for a specific attribute + //UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + int32 GetAttributeAttributeIndex(const EHoudiniAttributes& Attr) const; + + // Returns if the specific attribute has a valid attribute index + bool IsValidAttributeAttributeIndex(const EHoudiniAttributes& Attr) const; + + // Returns the attribute index for a given string. + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetAttributeIndexFromString(const FString& Attribute, int32& AttributeIndex) const; + + // Returns the attribute index for a given string. This is a static version of the function that + // takes the attribute name array as an argument as well. + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + static bool GetAttributeIndexInArrayFromString(const FString& InAttribute, const TArray& InAttributeArray, int32& OutAttributeIndex); + + // Returns the float value at a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetFloatValue( const int32& sampleIndex, const int32& attrIndex, float& value ) const; + // Returns the float value at a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetFloatValueForString( const int32& sampleIndex, const FString& Attribute, float& value ) const; + /* + // Returns the string value at a given point in the point cache + bool GetCSVStringValue( const int32& sampleIndex, const int32& attrIndex, FString& value ); + // Returns the string value at a given point in the point cache + bool GetCSVStringValue( const int32& sampleIndex, const FString& Attribute, FString& value ); + */ + // Returns a Vector3 for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetVectorValue( const int32& sampleIndex, const int32& attrIndex, FVector& value, const bool& DoSwap = true, const bool& DoScale = true ) const; + // Returns a Vector3 for a given point in the point cache by column name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetVectorValueForString(const int32& sampleIndex, const FString& Attribute, FVector& value, const bool& DoSwap = true, const bool& DoScale = true) const; + // Returns a Vector4 for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetVector4Value( const int32& sampleIndex, const int32& attrIndex, FVector4& value ) const; + // Returns a Vector4 for a given point in the point cache by column name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetVector4ValueForString(const int32& sampleIndex, const FString& Attribute, FVector4& value ) const; + // Returns a Quat for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetQuatValue( const int32& sampleIndex, const int32& attrIndex, FQuat& value, const bool& DoHoudiniToUnrealConversion = true ) const; + // Returns a Quat for a given point in the point cache by column name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetQuatValueForString(const int32& sampleIndex, const FString& Attribute, FQuat& value, const bool& DoHoudiniToUnrealConversion = true ) const; + + // Returns a time value for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetTimeValue( const int32& sampleIndex, float& value ) const; + // Returns a Position Vector3 for a given point in the point cache (converted to unreal's coordinate system) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPositionValue( const int32& sampleIndex, FVector& value ) const; + // Returns a Normal Vector3 for a given point in the point cache (converted to unreal's coordinate system) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetNormalValue( const int32& sampleIndex, FVector& value ) const; + // Returns a Color for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetColorValue( const int32& sampleIndex, FLinearColor& value ) const; + // Returns a Velocity Vector3 for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetVelocityValue(const int32& sampleIndex, FVector& value ) const; + // Returns an Impulse float value for a given point in the point cache + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetImpulseValue(const int32& sampleIndex, float& value) const; + + // Get the last sample index for a given time value (the sample with a time smaller or equal to desiredTime) + // If the point cache doesn't have time informations, returns false and set LastsampleIndex to the last sample in the file + // If desiredTime is smaller than the time value in the first sample, LastsampleIndex will be set to -1 + // If desiredTime is higher than the last time value in the last sample of the point cache, LastIndex will be set to the last sample's index + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetLastSampleIndexAtTime( const float& desiredTime, int32& lastSampleIndex ) const; + + // Get the last pointID of the points to be spawned at time t + // Invalid Index are used to indicate edge cases: + // -1 will be returned if there is no points to spawn ( t is smaller than the first point time ) + // NumberOfSamples will be returned if all points in the CSV have been spawned ( t is higher than the last point time ) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetLastPointIDToSpawnAtTime( const float& time, int32& lastID ) const; + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointIDsToSpawnAtTime( + const float& desiredTime, + int32& MinID, int32& MaxID, int32& Count, + int32& LastSpawnedPointID, float& LastSpawnTime, float& LastSpawnTimeRequest) const; + + bool GetPointIDsToSpawnAtTime_DEPR( + const float& desiredTime, + int32& MinID, int32& MaxID, int32& Count, + int32& LastSpawnedPointID, float& LastSpawnTime ) const; + + // Returns the previous and next sample indexes for reading the values of a specified point at a given time + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetSampleIndexesForPointAtTime(const int32& PointID, const float& desiredTime, int32& PrevSampleIndex, int32& NextSampleIndex, float& PrevWeight) const; + // Returns the value for a point at a given time value (linearly interpolated) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointValueAtTime(const int32& PointID, const int32& AttributeIndex, const float& desiredTime, float& Value) const; + // Returns the value for a point at a given time value (linearly interpolated), via the attribute name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointValueAtTimeForString(const int32& PointID, const FString& Attribute, const float& desiredTime, float& Value) const; + + // Returns the Vector Value for a given point at a given time value (linearly interpolated) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointVectorValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, FVector& Vector, bool DoSwap, bool DoScale) const; + + // Returns the Vector Value for a given point at a given time value (linearly interpolated), via the attribute name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointVectorValueAtTimeForString(int32 PointID, const FString& Attribute, float desiredTime, FVector& Vector, bool DoSwap, bool DoScale) const; + + // Returns the Vector4 Value for a given point at a given time value (linearly interpolated) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointVector4ValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, FVector4& Vector) const; + + // Returns the Vector4 Value for a given point at a given time value (linearly interpolated), via the attribute name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointVector4ValueAtTimeForString(int32 PointID, const FString& Attribute, float desiredTime, FVector4& Vector) const; + + // Returns the Quat Value for a given point at a given time value (linearly interpolated) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointQuatValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, FQuat& Quat, bool DoHoudiniToUnrealConversion = true ) const; + + // Returns the Quat Value for a given point at a given time value (linearly interpolated), via the attribute name + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointQuatValueAtTimeForString(int32 PointID, const FString& Attribute, float desiredTime, FQuat& Quat, bool DoHoudiniToUnrealConversion = true ) const; + + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointFloatValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, float& Value) const; + + // Return the integer value of the point at the keyframe before the desired time. No value interpolation will take place. + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointInt32ValueAtTime(int32 PointID, int32 AttributeIndex, float desiredTime, int32& Value) const; + + // Returns the Position Value for a given point at a given time value (linearly interpolated) + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointPositionAtTime(const int32& PointID, const float& desiredTime, FVector& Vector) const; + // Return a given point's life value at spawn + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointLife(const int32& PointID, float& Value) const; + // Return a point's life for a given time value + // Note this function currently behaves exactly the same as GetPointLife + // since the Lifetime value is currently treated as a constant. This could + // change in the future. + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointLifeAtTime(const int32& PointID, const float& DesiredTime, float& Value) const; + // Return a point's type at spawn + UFUNCTION(BlueprintCallable, Category = "Houdini Attributes Data") + bool GetPointType(const int32& PointID, int32& Value) const; + + + // Returns the maximum number of indexes per point, used for flattening the buffer for HLSL conversion + int32 GetMaxNumberOfPointValueIndexes() const; + + //----------------------------------------------------------------------------------------- + // MEMBER VARIABLES + //----------------------------------------------------------------------------------------- + + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + FString FileName; + + // The number of values stored in the point cache + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + int32 NumberOfSamples; + + // The number of attributes stored in the point cache + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + int32 NumberOfAttributes; + + // The number of unique points found in the point cache + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") + int32 NumberOfPoints; + + // The number of frames imported into the point cache + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") + int32 NumberOfFrames; + + // The first frame of the exported frame range + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") + float FirstFrame; + + // The last frame of the exported frame range + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") + float LastFrame; + + // The minimum sample time value, in seconds, in the point cache + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") + float MinSampleTime; + + // The maximum sample time value, in seconds, in the point cache + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties") + float MaxSampleTime; + + // The source title row for CSV files, describing the content of each column and used to locate specific values in the point cache. + // Editing this will trigger a re-import of the point cache. + UPROPERTY(EditAnywhere, Category = "Houdini Point Cache Properties") + FString SourceCSVTitleRow; + + // The final attribute names used by the asset after parsing. + // Packed vector values are expanded, so additional attributes (.0, .1, ... or .x, .y, .z) might have been inserted. + // Use the indexes in this array to access your data. + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + TArray AttributeArray; + +#if WITH_EDITORONLY_DATA + /** Importing data and options used for this asset */ + UPROPERTY( EditAnywhere, Instanced, Category = ImportSettings ) + class UAssetImportData* AssetImportData; + + // Raw data of the source file so that we can export it again. + UPROPERTY() + TArray RawDataCompressed; + + // Compression scheme used to compress raw + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + FName RawDataFormatID; + + // Size of data when uncompressed + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + uint32 RawDataUncompressedSize; + + // Compression scheme used to compress raw + UPROPERTY( VisibleAnywhere, Category = "Houdini Point Cache Properties" ) + FName RawDataCompressionMethod; +#endif + +#if WITH_EDITOR + bool HasRawData() const { return RawDataCompressed.Num() > 0; }; + + virtual void PostInitProperties() override; + virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override; +#endif + + virtual void GetAssetRegistryTags(TArray< FAssetRegistryTag > & OutTags) const override; + + void BeginDestroy() override; + + // Data Accessors, const and non-const versions + TArray& GetFloatSampleData() { return FloatSampleData; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") + const TArray& GetFloatSampleData() const { return FloatSampleData; } + + TArray& GetSpawnTimes() { return SpawnTimes; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") + const TArray& GetSpawnTimes() const { return SpawnTimes; } + + TArray& GetLifeValues() { return LifeValues; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") + const TArray& GetLifeValues() const { return LifeValues; } + + TArray& GetPointTypes() { return PointTypes; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") + const TArray& GetPointTypes() const { return PointTypes; } + + TArray& GetSpecialAttributeIndexes() { return SpecialAttributeIndexes; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Data") + const TArray& GetSpecialAttributeIndexes() const { return SpecialAttributeIndexes; } + + TArray& GetPointValueIndexes() { return PointValueIndexes; } + + UFUNCTION() + const TArray& GetPointValueIndexes() const { return PointValueIndexes; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Settings") + bool GetUseCustomCSVTitleRow() const { return UseCustomCSVTitleRow; } + + UFUNCTION(BlueprintCallable, Category = "Houdini Point Cache Settings") + void SetUseCustomCSVTitleRow(bool bInUseCustomCSVTitleRow) { UseCustomCSVTitleRow = bInUseCustomCSVTitleRow; } + + /** The GPU resource for this point cache. */ + TUniquePtr Resource; + + void RequestPushToGPU(); + + private: + + /* + // Array containing the Raw String data + UPROPERTY() + TArray StringCSVData; + */ + + // Array containing all the sample data converted to floats + UPROPERTY() + TArray FloatSampleData; + + // Array containing the spawn times for each point in the point cache + UPROPERTY() + TArray SpawnTimes; + + // Array containing all the life values for each point in the point cache + UPROPERTY() + TArray LifeValues; + + // Array containing all the type values for each point in the point cache + UPROPERTY() + TArray PointTypes; + + // Array containing the column indexes of the special attributes + UPROPERTY() + TArray SpecialAttributeIndexes; + + /* + // Row indexes for new time values + UPROPERTY() + TMap TimeValuesIndexes; + */ + + // Sample indexes for each point + UPROPERTY() + TArray< FPointIndexes > PointValueIndexes; + + /** For CSV source files, whether to use a custom title row. */ + UPROPERTY() + bool UseCustomCSVTitleRow; + + // The type of source file, such as CSV or JSON. + UPROPERTY() + EHoudiniPointCacheFileType FileType; }; \ No newline at end of file diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheAssetActions.cpp b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheAssetActions.cpp index 64c89e0..49e0fb0 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheAssetActions.cpp +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheAssetActions.cpp @@ -1,253 +1,253 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ -#include "HoudiniPointCacheAssetActions.h" - -#include "ToolMenus.h" -#include "HoudiniPointCache.h" -#include "EditorStyleSet.h" -#include "Toolkits/AssetEditorToolkit.h" -#include "EditorReimportHandler.h" -#include "HAL/FileManager.h" - -//#include "HoudiniPointCacheAssetEditorToolkit.h" - -#define LOCTEXT_NAMESPACE "AssetTypeActions" - - -FHoudiniPointCacheAssetActions::FHoudiniPointCacheAssetActions() -{ } - -bool FHoudiniPointCacheAssetActions::CanFilter() -{ - return true; -} - - -void FHoudiniPointCacheAssetActions::GetActions(const TArray& InObjects, FToolMenuSection& Section) -{ - FAssetTypeActions_Base::GetActions(InObjects, Section); - - auto HoudiniPointCacheAssets = GetTypedWeakObjectPtrs(InObjects); - - Section.AddMenuEntry( - "ReimportHoudiniPointCacheLabel", - LOCTEXT("ReimportHoudiniPointCacheLabel", "Reimport"), - LOCTEXT("ReimportHoudiniPointCacheTooltip", "Reimport the selected Houdini Point Cache file(s)."), - FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.ReimportAsset"), - FUIAction( - FExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::ExecuteReimport, HoudiniPointCacheAssets), - FCanExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::CanExecuteReimport, HoudiniPointCacheAssets) - ) - ); - - Section.AddMenuEntry( - "OpenHoudiniPointCacheLabel", - LOCTEXT("OpenHoudiniPointCacheLabel", "Open in Text Editor"), - LOCTEXT("OpenHoudiniPointCacheTooltip", "Open the selected Houdini Point Cache file(s) in a Text Editor."), - FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.OpenInExternalEditor"), - FUIAction( - FExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::ExecuteOpenInEditor, HoudiniPointCacheAssets), - FCanExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::CanExecuteOpenInEditor, HoudiniPointCacheAssets) - ) - ); - - Section.AddMenuEntry( - "FindHoudiniPointCacheInExplorer", - LOCTEXT("FindHoudiniPointCacheInExplorer", "Find Source File"), - LOCTEXT("FindHoudiniPointCacheInExplorerTooltip", "Opens explorer at the location of this asset's source file."), - FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.OpenInExternalEditor"), - FUIAction( - FExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::ExecuteFindInExplorer, HoudiniPointCacheAssets), - FCanExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::CanExecuteFindInExplorer, HoudiniPointCacheAssets) - ) - ); -} - - -uint32 FHoudiniPointCacheAssetActions::GetCategories() -{ - return EAssetTypeCategories::Misc; -} - - -FText FHoudiniPointCacheAssetActions::GetName() const -{ - return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_HoudiniPointCache", "Houdini Point Cache Asset"); -} - - -UClass* FHoudiniPointCacheAssetActions::GetSupportedClass() const -{ - return UHoudiniPointCache::StaticClass(); -} - -FText FHoudiniPointCacheAssetActions::GetAssetDescription(const FAssetData& AssetData) const -{ - /* - UHoudiniPointCache* PointCacheAsset = Cast(AssetData.GetAsset()); - if ( !PointCacheAsset ) - return FText::GetEmpty(); - - FString StrDescription; - StrDescription += TEXT("Number of Rows: ") + FString::FromInt(PointCacheAsset->NumberOfRows) + TEXT("\n"); - StrDescription += TEXT("Number of Columns: ") + FString::FromInt(PointCacheAsset->NumberOfColumns) + TEXT("\n"); - StrDescription += TEXT("Number of Points: ") + FString::FromInt(PointCacheAsset->NumberOfPoints) + TEXT("\n"); - - return FText::FromString(StrDescription); - */ - return FText::GetEmpty(); -} - - -FColor FHoudiniPointCacheAssetActions::GetTypeColor() const -{ - //return FColor::Orange; - return FColor(255, 165, 0); -} - - -bool FHoudiniPointCacheAssetActions::HasActions(const TArray& InObjects) const -{ - return true; -} - - -class UThumbnailInfo* FHoudiniPointCacheAssetActions::GetThumbnailInfo(UObject* Asset) const -{ - /* - UHoudiniPointCache* HoudiniPointCache = CastChecked(Asset); - UThumbnailInfo* ThumbnailInfo = HoudiniPointCache->ThumbnailInfo; - if (ThumbnailInfo == NULL) - { - ThumbnailInfo = NewObject(HoudiniPointCache, NAME_None, RF_Transactional); - HoudiniPointCache->ThumbnailInfo = ThumbnailInfo; - } - - return ThumbnailInfo; - */ - - return nullptr; -} - - -bool FHoudiniPointCacheAssetActions::CanExecuteReimport(const TArray> Objects) const -{ - for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) - { - auto Object = (*ObjIt).Get(); - if (!Object) - continue; - - // If one object is valid, we can execute the action - return true; - } - - return false; -} - -void FHoudiniPointCacheAssetActions::ExecuteReimport(const TArray> Objects) const -{ - for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) - { - auto Object = (*ObjIt).Get(); - if (!Object) - continue; - - FReimportManager::Instance()->Reimport(Object, true); - } -} - - -bool -FHoudiniPointCacheAssetActions::CanExecuteOpenInEditor(const TArray> Objects) const -{ - for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) - { - auto Object = ( *ObjIt ).Get(); - if (!Object) - continue; - - const FString SourceFilePath = Object->FileName; - if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE) - continue; - - // If one object is valid, we can execute the action - return true; - } - - return false; -} - -void -FHoudiniPointCacheAssetActions::ExecuteOpenInEditor(const TArray> Objects) const -{ - for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) - { - auto Object = ( *ObjIt ).Get(); - if (!Object) - continue; - - const FString SourceFilePath = Object->FileName; - if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE) - continue; - - FPlatformProcess::LaunchFileInDefaultExternalApplication(*SourceFilePath, NULL, ELaunchVerb::Open); - } -} - -bool -FHoudiniPointCacheAssetActions::CanExecuteFindInExplorer(const TArray> Objects) const -{ - for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) - { - auto Object = (*ObjIt).Get(); - if (!Object) - continue; - - const FString SourceFilePath = Object->FileName; - if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE) - continue; - - // If one object is valid, we can execute the action - return true; - } - - return false; -} - -void -FHoudiniPointCacheAssetActions::ExecuteFindInExplorer(const TArray> Objects) const -{ - for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) - { - auto Object = (*ObjIt).Get(); - if (!Object) - continue; - - const FString SourceFilePath = Object->FileName; - if ( SourceFilePath.Len() && IFileManager::Get().FileSize(*SourceFilePath) != INDEX_NONE ) - return FPlatformProcess::ExploreFolder(*SourceFilePath); - } -} - -#undef LOCTEXT_NAMESPACE +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ +#include "HoudiniPointCacheAssetActions.h" + +#include "ToolMenus.h" +#include "HoudiniPointCache.h" +#include "EditorStyleSet.h" +#include "Toolkits/AssetEditorToolkit.h" +#include "EditorReimportHandler.h" +#include "HAL/FileManager.h" + +//#include "HoudiniPointCacheAssetEditorToolkit.h" + +#define LOCTEXT_NAMESPACE "AssetTypeActions" + + +FHoudiniPointCacheAssetActions::FHoudiniPointCacheAssetActions() +{ } + +bool FHoudiniPointCacheAssetActions::CanFilter() +{ + return true; +} + + +void FHoudiniPointCacheAssetActions::GetActions(const TArray& InObjects, FToolMenuSection& Section) +{ + FAssetTypeActions_Base::GetActions(InObjects, Section); + + auto HoudiniPointCacheAssets = GetTypedWeakObjectPtrs(InObjects); + + Section.AddMenuEntry( + "ReimportHoudiniPointCacheLabel", + LOCTEXT("ReimportHoudiniPointCacheLabel", "Reimport"), + LOCTEXT("ReimportHoudiniPointCacheTooltip", "Reimport the selected Houdini Point Cache file(s)."), + FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.ReimportAsset"), + FUIAction( + FExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::ExecuteReimport, HoudiniPointCacheAssets), + FCanExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::CanExecuteReimport, HoudiniPointCacheAssets) + ) + ); + + Section.AddMenuEntry( + "OpenHoudiniPointCacheLabel", + LOCTEXT("OpenHoudiniPointCacheLabel", "Open in Text Editor"), + LOCTEXT("OpenHoudiniPointCacheTooltip", "Open the selected Houdini Point Cache file(s) in a Text Editor."), + FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.OpenInExternalEditor"), + FUIAction( + FExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::ExecuteOpenInEditor, HoudiniPointCacheAssets), + FCanExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::CanExecuteOpenInEditor, HoudiniPointCacheAssets) + ) + ); + + Section.AddMenuEntry( + "FindHoudiniPointCacheInExplorer", + LOCTEXT("FindHoudiniPointCacheInExplorer", "Find Source File"), + LOCTEXT("FindHoudiniPointCacheInExplorerTooltip", "Opens explorer at the location of this asset's source file."), + FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.OpenInExternalEditor"), + FUIAction( + FExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::ExecuteFindInExplorer, HoudiniPointCacheAssets), + FCanExecuteAction::CreateSP(this, &FHoudiniPointCacheAssetActions::CanExecuteFindInExplorer, HoudiniPointCacheAssets) + ) + ); +} + + +uint32 FHoudiniPointCacheAssetActions::GetCategories() +{ + return EAssetTypeCategories::Misc; +} + + +FText FHoudiniPointCacheAssetActions::GetName() const +{ + return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_HoudiniPointCache", "Houdini Point Cache Asset"); +} + + +UClass* FHoudiniPointCacheAssetActions::GetSupportedClass() const +{ + return UHoudiniPointCache::StaticClass(); +} + +FText FHoudiniPointCacheAssetActions::GetAssetDescription(const FAssetData& AssetData) const +{ + /* + UHoudiniPointCache* PointCacheAsset = Cast(AssetData.GetAsset()); + if ( !PointCacheAsset ) + return FText::GetEmpty(); + + FString StrDescription; + StrDescription += TEXT("Number of Rows: ") + FString::FromInt(PointCacheAsset->NumberOfRows) + TEXT("\n"); + StrDescription += TEXT("Number of Columns: ") + FString::FromInt(PointCacheAsset->NumberOfColumns) + TEXT("\n"); + StrDescription += TEXT("Number of Points: ") + FString::FromInt(PointCacheAsset->NumberOfPoints) + TEXT("\n"); + + return FText::FromString(StrDescription); + */ + return FText::GetEmpty(); +} + + +FColor FHoudiniPointCacheAssetActions::GetTypeColor() const +{ + //return FColor::Orange; + return FColor(255, 165, 0); +} + + +bool FHoudiniPointCacheAssetActions::HasActions(const TArray& InObjects) const +{ + return true; +} + + +class UThumbnailInfo* FHoudiniPointCacheAssetActions::GetThumbnailInfo(UObject* Asset) const +{ + /* + UHoudiniPointCache* HoudiniPointCache = CastChecked(Asset); + UThumbnailInfo* ThumbnailInfo = HoudiniPointCache->ThumbnailInfo; + if (ThumbnailInfo == NULL) + { + ThumbnailInfo = NewObject(HoudiniPointCache, NAME_None, RF_Transactional); + HoudiniPointCache->ThumbnailInfo = ThumbnailInfo; + } + + return ThumbnailInfo; + */ + + return nullptr; +} + + +bool FHoudiniPointCacheAssetActions::CanExecuteReimport(const TArray> Objects) const +{ + for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) + { + auto Object = (*ObjIt).Get(); + if (!Object) + continue; + + // If one object is valid, we can execute the action + return true; + } + + return false; +} + +void FHoudiniPointCacheAssetActions::ExecuteReimport(const TArray> Objects) const +{ + for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) + { + auto Object = (*ObjIt).Get(); + if (!Object) + continue; + + FReimportManager::Instance()->Reimport(Object, true); + } +} + + +bool +FHoudiniPointCacheAssetActions::CanExecuteOpenInEditor(const TArray> Objects) const +{ + for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) + { + auto Object = ( *ObjIt ).Get(); + if (!Object) + continue; + + const FString SourceFilePath = Object->FileName; + if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE) + continue; + + // If one object is valid, we can execute the action + return true; + } + + return false; +} + +void +FHoudiniPointCacheAssetActions::ExecuteOpenInEditor(const TArray> Objects) const +{ + for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) + { + auto Object = ( *ObjIt ).Get(); + if (!Object) + continue; + + const FString SourceFilePath = Object->FileName; + if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE) + continue; + + FPlatformProcess::LaunchFileInDefaultExternalApplication(*SourceFilePath, NULL, ELaunchVerb::Open); + } +} + +bool +FHoudiniPointCacheAssetActions::CanExecuteFindInExplorer(const TArray> Objects) const +{ + for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) + { + auto Object = (*ObjIt).Get(); + if (!Object) + continue; + + const FString SourceFilePath = Object->FileName; + if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE) + continue; + + // If one object is valid, we can execute the action + return true; + } + + return false; +} + +void +FHoudiniPointCacheAssetActions::ExecuteFindInExplorer(const TArray> Objects) const +{ + for ( auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt ) + { + auto Object = (*ObjIt).Get(); + if (!Object) + continue; + + const FString SourceFilePath = Object->FileName; + if ( SourceFilePath.Len() && IFileManager::Get().FileSize(*SourceFilePath) != INDEX_NONE ) + return FPlatformProcess::ExploreFolder(*SourceFilePath); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.cpp b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.cpp index 7c06c44..fab62b9 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.cpp +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.cpp @@ -1,89 +1,90 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#include "HoudiniPointCacheExporterBase.h" - -#include "HoudiniPointCache.h" -#include "Misc/FileHelper.h" - -UHoudiniPointCacheExporterBase::UHoudiniPointCacheExporterBase() -{ - -} - -bool UHoudiniPointCacheExporterBase::SupportsObject(UObject* Object) const -{ - if (!UExporter::SupportsObject(Object)) - return false; // If the object doesn't match the SupportedClass, return false. - - // Further, ensure that the asset contains the source data needed for exporting. - UHoudiniPointCache* PointCache = Cast(Object); - if (!PointCache) - return false; - - if (!IsRawFormatSupported(PointCache)) - { - return false; - } - - return PointCache->HasRawData(); -} - -bool UHoudiniPointCacheExporterBase::ExportBinary(UObject* Object, const TCHAR* Type, FArchive& Ar, - FFeedbackContext* Warn, int32 FileIndex, uint32 PortFlags) -{ - UHoudiniPointCache* PointCache = Cast(Object); - if (!PointCache) - { - return false; - } - - if (!PointCache->HasRawData()) - { - return false; - } - - if (PointCache->RawDataCompressionMethod.IsEqual(NAME_None)) - { - return false; - } - - // Uncompress data before serialization - const uint32 UncompressedSize = PointCache->RawDataUncompressedSize; - - int32 CompressedSize = PointCache->RawDataCompressed.Num(); - TArray UncompressedData; - UncompressedData.SetNumUninitialized(UncompressedSize); - - if (FCompression::UncompressMemory( - PointCache->RawDataCompressionMethod, - UncompressedData.GetData(), - UncompressedSize, - PointCache->RawDataCompressed.GetData(), - PointCache->RawDataCompressed.Num())) - { - Ar.Serialize(UncompressedData.GetData(), UncompressedSize); - } - - return true; -} +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include "HoudiniPointCacheExporterBase.h" +#include "CoreMinimal.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "HoudiniPointCache.h" + +UHoudiniPointCacheExporterBase::UHoudiniPointCacheExporterBase() +{ + +} + +bool UHoudiniPointCacheExporterBase::SupportsObject(UObject* Object) const +{ + if (!UExporter::SupportsObject(Object)) + return false; // If the object doesn't match the SupportedClass, return false. + + // Further, ensure that the asset contains the source data needed for exporting. + UHoudiniPointCache* PointCache = Cast(Object); + if (!PointCache) + return false; + + if (!IsRawFormatSupported(PointCache)) + { + return false; + } + + return PointCache->HasRawData(); +} + +bool UHoudiniPointCacheExporterBase::ExportBinary(UObject* Object, const TCHAR* Type, FArchive& Ar, + FFeedbackContext* Warn, int32 FileIndex, uint32 PortFlags) +{ + UHoudiniPointCache* PointCache = Cast(Object); + if (!PointCache) + { + return false; + } + + if (!PointCache->HasRawData()) + { + return false; + } + + if (PointCache->RawDataCompressionMethod.IsEqual(NAME_None)) + { + return false; + } + + // Uncompress data before serialization + const uint32 UncompressedSize = PointCache->RawDataUncompressedSize; + + int32 CompressedSize = PointCache->RawDataCompressed.Num(); + TArray UncompressedData; + UncompressedData.SetNumUninitialized(UncompressedSize); + + if (FCompression::UncompressMemory( + PointCache->RawDataCompressionMethod, + UncompressedData.GetData(), + UncompressedSize, + PointCache->RawDataCompressed.GetData(), + PointCache->RawDataCompressed.Num())) + { + Ar.Serialize(UncompressedData.GetData(), UncompressedSize); + } + + return true; +} diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.h b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.h index 8484d26..ec07753 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.h +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterBase.h @@ -1,46 +1,45 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#pragma once - -#include "CoreMinimal.h" -#include "Exporters/Exporter.h" - -#include "HoudiniPointCacheExporterBase.generated.h" - -UCLASS() -class UHoudiniPointCacheExporterBase : public UExporter -{ - GENERATED_BODY() -public: - UHoudiniPointCacheExporterBase(); - - // Returns whether this exporter supports the specific object - virtual bool SupportsObject(UObject* Object) const override; - virtual bool IsRawFormatSupported(class UHoudiniPointCache* PointCache) const { return true; } - - //~ Begin UExporter Interface - // Default behaviour is to simply export the raw data, as is. - virtual bool ExportBinary( UObject* Object, const TCHAR* Type, FArchive& Ar, FFeedbackContext* Warn, int32 FileIndex = 0, uint32 PortFlags=0 ) override; - //~ End UExporter Interface -}; +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#pragma once + +#include "CoreMinimal.h" +#include "Exporters/Exporter.h" +#include "HoudiniPointCacheExporterBase.generated.h" + +UCLASS() +class UHoudiniPointCacheExporterBase : public UExporter +{ + GENERATED_BODY() +public: + UHoudiniPointCacheExporterBase(); + + // Returns whether this exporter supports the specific object + virtual bool SupportsObject(UObject* Object) const override; + virtual bool IsRawFormatSupported(class UHoudiniPointCache* PointCache) const { return true; } + + //~ Begin UExporter Interface + // Default behaviour is to simply export the raw data, as is. + virtual bool ExportBinary( UObject* Object, const TCHAR* Type, FArchive& Ar, FFeedbackContext* Warn, int32 FileIndex = 0, uint32 PortFlags=0 ) override; + //~ End UExporter Interface +}; diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHBJSON.cpp b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHBJSON.cpp index a6a40e8..05446fd 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHBJSON.cpp +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHBJSON.cpp @@ -1,44 +1,45 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#include "HoudiniPointCacheExporterHBJSON.h" - -#include "HoudiniPointCache.h" - -UHoudiniPointCacheExporterHBJSON::UHoudiniPointCacheExporterHBJSON() -{ - SupportedClass = UHoudiniPointCache::StaticClass(); - bText = false; - PreferredFormatIndex = 0; - FormatExtension.Add(TEXT("hbjson")); - FormatDescription.Add(TEXT("HoudiniPointCache HBJSON File")); -} - -bool UHoudiniPointCacheExporterHBJSON::IsRawFormatSupported(UHoudiniPointCache* PointCache) const -{ - if (!Super::IsRawFormatSupported(PointCache)) - return false; - const bool bIsSupported = PointCache->RawDataFormatID.IsEqual("HBJSON"); - return bIsSupported; -} - +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include "HoudiniPointCacheExporterHBJSON.h" +#include "CoreMinimal.h" +#include "Misc/Paths.h" +#include "HoudiniPointCache.h" + +UHoudiniPointCacheExporterHBJSON::UHoudiniPointCacheExporterHBJSON() +{ + SupportedClass = UHoudiniPointCache::StaticClass(); + bText = false; + PreferredFormatIndex = 0; + FormatExtension.Add(TEXT("hbjson")); + FormatDescription.Add(TEXT("HoudiniPointCache HBJSON File")); +} + +bool UHoudiniPointCacheExporterHBJSON::IsRawFormatSupported(UHoudiniPointCache* PointCache) const +{ + if (!Super::IsRawFormatSupported(PointCache)) + return false; + const bool bIsSupported = PointCache->RawDataFormatID.IsEqual("HBJSON"); + return bIsSupported; +} + diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHCSV.cpp b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHCSV.cpp index a33b79a..7fa1c14 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHCSV.cpp +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHCSV.cpp @@ -1,44 +1,45 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#include "HoudiniPointCacheExporterHCSV.h" - -#include "HoudiniPointCache.h" - -UHoudiniPointCacheExporterHCSV::UHoudiniPointCacheExporterHCSV() -{ - SupportedClass = UHoudiniPointCache::StaticClass(); - bText = false; - PreferredFormatIndex = 0; - FormatExtension.Add(TEXT("hcsv")); - FormatDescription.Add(TEXT("HoudiniPointCache HCSV File")); -} - -bool UHoudiniPointCacheExporterHCSV::IsRawFormatSupported(UHoudiniPointCache* PointCache) const -{ - if (!Super::IsRawFormatSupported(PointCache)) - return false; - const bool bIsSupported = PointCache->RawDataFormatID.IsEqual("HCSV"); - return bIsSupported; -} - +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include "HoudiniPointCacheExporterHCSV.h" +#include "CoreMinimal.h" +#include "Misc/Paths.h" +#include "HoudiniPointCache.h" + +UHoudiniPointCacheExporterHCSV::UHoudiniPointCacheExporterHCSV() +{ + SupportedClass = UHoudiniPointCache::StaticClass(); + bText = false; + PreferredFormatIndex = 0; + FormatExtension.Add(TEXT("hcsv")); + FormatDescription.Add(TEXT("HoudiniPointCache HCSV File")); +} + +bool UHoudiniPointCacheExporterHCSV::IsRawFormatSupported(UHoudiniPointCache* PointCache) const +{ + if (!Super::IsRawFormatSupported(PointCache)) + return false; + const bool bIsSupported = PointCache->RawDataFormatID.IsEqual("HCSV"); + return bIsSupported; +} + diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.cpp b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.cpp index 8f6651c..7445672 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.cpp +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.cpp @@ -1,44 +1,48 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#include "HoudiniPointCacheExporterHJSON.h" - -#include "HoudiniPointCache.h" - -UHoudiniPointCacheExporterHJSON::UHoudiniPointCacheExporterHJSON() -{ - SupportedClass = UHoudiniPointCache::StaticClass(); - bText = false; - PreferredFormatIndex = 0; - FormatExtension.Add(TEXT("hjson")); - FormatDescription.Add(TEXT("HoudiniPointCache HJSON File")); -} - -bool UHoudiniPointCacheExporterHJSON::IsRawFormatSupported(UHoudiniPointCache* PointCache) const -{ - if (!Super::IsRawFormatSupported(PointCache)) - return false; - const bool bIsSupported = PointCache->RawDataFormatID.IsEqual("HJSON"); - return bIsSupported; -} - +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include "HoudiniPointCacheExporterHJSON.h" +#include "CoreMinimal.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "HoudiniPointCache.h" +#include "CoreMinimal.h" + + +UHoudiniPointCacheExporterHJSON::UHoudiniPointCacheExporterHJSON() +{ + SupportedClass = UHoudiniPointCache::StaticClass(); + bText = false; + PreferredFormatIndex = 0; + FormatExtension.Add(TEXT("hjson")); + FormatDescription.Add(TEXT("HoudiniPointCache HJSON File")); +} + +bool UHoudiniPointCacheExporterHJSON::IsRawFormatSupported(UHoudiniPointCache* PointCache) const +{ + if (!Super::IsRawFormatSupported(PointCache)) + return false; + const bool bIsSupported = PointCache->RawDataFormatID.IsEqual("HJSON"); + return bIsSupported; +} + diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.h b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.h index e0680d7..fab6abd 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.h +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheExporterHJSON.h @@ -1,40 +1,39 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#pragma once - -#include "CoreMinimal.h" -#include "HoudiniPointCacheExporterBase.h" - -#include "HoudiniPointCacheExporterHJSON.generated.h" - -UCLASS() -class UHoudiniPointCacheExporterHJSON : public UHoudiniPointCacheExporterBase -{ - GENERATED_BODY() -public: - UHoudiniPointCacheExporterHJSON(); - - // Returns whether this exporter supports the specific object - virtual bool IsRawFormatSupported(UHoudiniPointCache* PointCache) const override; -}; +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#pragma once + +#include "CoreMinimal.h" +#include "HoudiniPointCacheExporterBase.h" +#include "HoudiniPointCacheExporterHJSON.generated.h" + +UCLASS() +class UHoudiniPointCacheExporterHJSON : public UHoudiniPointCacheExporterBase +{ + GENERATED_BODY() +public: + UHoudiniPointCacheExporterHJSON(); + + // Returns whether this exporter supports the specific object + virtual bool IsRawFormatSupported(UHoudiniPointCache* PointCache) const override; +}; diff --git a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheFactory.cpp b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheFactory.cpp index bd4b121..75f574f 100644 --- a/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheFactory.cpp +++ b/Source/HoudiniNiagaraEditor/Private/HoudiniPointCacheFactory.cpp @@ -1,200 +1,203 @@ -/* -* Copyright (c) <2018> Side Effects Software Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -*/ - -#include "HoudiniPointCacheFactory.h" -#include "HoudiniPointCache.h" -#include "EditorFramework/AssetImportData.h" -#include "HAL/FileManager.h" -#include "Misc/FileHelper.h" -#include "Misc/Paths.h" -#include "Editor.h" - -DEFINE_LOG_CATEGORY(LogHoudiniNiagaraEditor); - -#define LOCTEXT_NAMESPACE "HoudiniPointCacheFactory" - -///////////////////////////////////////////////////// -// UHoudiniPointCacheFactory -UHoudiniPointCacheFactory::UHoudiniPointCacheFactory(const FObjectInitializer& ObjectInitializer) : Super( ObjectInitializer ) -{ - // This factory is responsible for manufacturing HoudiniEngine assets. - SupportedClass = UHoudiniPointCache::StaticClass(); - - // This factory does not manufacture new objects from scratch. - bCreateNew = false; - - // This factory will open the editor for each new object. - bEditAfterNew = false; - - // This factory will import objects from files. - bEditorImport = true; - - // Factory does not import objects from text. - bText = true; - - // Add supported formats. - Formats.Add(FString(TEXT("hcsv;")) + NSLOCTEXT("HoudiniPointCacheFactory", "FormatHCSV", "HCSV File").ToString()); - Formats.Add(FString(TEXT("hjson;")) + NSLOCTEXT("HoudiniPointCacheFactory", "FormatHJSON", "HJSON File").ToString()); - Formats.Add(FString(TEXT("hbjson;")) + NSLOCTEXT("HoudiniPointCacheFactory", "FormatHBJSON", "HBJSON File").ToString()); -} - - -UObject* -UHoudiniPointCacheFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) -{ - UHoudiniPointCache* NewHoudiniPointCacheObject = NewObject(InParent, Class, Name, Flags | RF_Transactional); - return NewHoudiniPointCacheObject; -} - -UObject* -UHoudiniPointCacheFactory::FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Parms, FFeedbackContext* Warn, bool& bOutOperationCanceled) -{ - bOutOperationCanceled = false; - - UHoudiniPointCache* NewHoudiniPointCacheObject = NewObject(InParent, InClass, InName, Flags); - if ( !NewHoudiniPointCacheObject ) - return nullptr; - - if ( !NewHoudiniPointCacheObject->UpdateFromFile( Filename ) ) - return nullptr; - - // Create reimport information. - UAssetImportData * AssetImportData = NewHoudiniPointCacheObject->AssetImportData; - if (!AssetImportData) - { - AssetImportData = NewObject< UAssetImportData >(NewHoudiniPointCacheObject, UAssetImportData::StaticClass()); - NewHoudiniPointCacheObject->AssetImportData = AssetImportData; - } - - //NewHoudiniPointCacheObject->AssetImportData->Update(Filename); - AssetImportData->Update(UFactory::GetCurrentFilename()); - - // Broadcast notification that the new asset has been imported. - GEditor->GetEditorSubsystem()->BroadcastAssetPostImport(this, NewHoudiniPointCacheObject); - - return NewHoudiniPointCacheObject; -} - -FText -UHoudiniPointCacheFactory::GetDisplayName() const -{ - return LOCTEXT("HoudiniPointCacheFactoryDescription", "Houdini Point Cache File"); -} - -bool -UHoudiniPointCacheFactory::DoesSupportClass(UClass * Class) -{ - return Class == SupportedClass; -} -bool -UHoudiniPointCacheFactory::FactoryCanImport(const FString& Filename) -{ - const FString Extension = FPaths::GetExtension(Filename).ToLower(); - - if (Extension == TEXT("hcsv") || Extension == TEXT("hbjson") || Extension == TEXT("hjson")) - { - return true; - } - return false; -} - -bool -UHoudiniPointCacheFactory::CanReimport(UObject* Obj, TArray& OutFilenames) -{ - UHoudiniPointCache* HoudiniPointCache = Cast(Obj); - if (HoudiniPointCache) - { - if (HoudiniPointCache->AssetImportData) - { - HoudiniPointCache->AssetImportData->ExtractFilenames(OutFilenames); - } - else - { - OutFilenames.Add(TEXT("")); - } - return true; - } - return false; -} - -void -UHoudiniPointCacheFactory::SetReimportPaths(UObject* Obj, const TArray& NewReimportPaths) -{ - UHoudiniPointCache* HoudiniPointCache = Cast( Obj ); - if ( HoudiniPointCache - && HoudiniPointCache->AssetImportData - && ensure( NewReimportPaths.Num() == 1 ) ) - { - HoudiniPointCache->AssetImportData->UpdateFilenameOnly(NewReimportPaths[0]); - } -} - -EReimportResult::Type -UHoudiniPointCacheFactory::Reimport(UObject* Obj) -{ - UHoudiniPointCache* HoudiniPointCache = Cast(Obj); - if (!HoudiniPointCache || !HoudiniPointCache->AssetImportData ) - return EReimportResult::Failed; - - const FString FilePath = HoudiniPointCache->AssetImportData->GetFirstFilename(); - if (!FilePath.Len()) - return EReimportResult::Failed; - - UE_LOG(LogHoudiniNiagaraEditor, Log, TEXT("Performing atomic reimport of [%s]"), *FilePath); - - // Ensure that the file provided by the path exists - if (IFileManager::Get().FileSize(*FilePath) == INDEX_NONE) - { - UE_LOG(LogHoudiniNiagaraEditor, Warning, TEXT("Cannot reimport: source file cannot be found.")); - return EReimportResult::Failed; - } - - bool OutCanceled = false; - if (ImportObject(HoudiniPointCache->GetClass(), HoudiniPointCache->GetOuter(), *HoudiniPointCache->GetName(), RF_Public | RF_Standalone, FilePath, nullptr, OutCanceled) != nullptr) - { - UE_LOG(LogHoudiniNiagaraEditor, Log, TEXT("Imported successfully")); - // Try to find the outer package so we can dirty it up - if (HoudiniPointCache->GetOuter()) - HoudiniPointCache->GetOuter()->MarkPackageDirty(); - else - HoudiniPointCache->MarkPackageDirty(); - } - else if (OutCanceled) - { - UE_LOG(LogHoudiniNiagaraEditor, Warning, TEXT("-- import canceled")); - } - else - { - UE_LOG(LogHoudiniNiagaraEditor, Warning, TEXT("-- import failed")); - } - - return EReimportResult::Succeeded; -} - -int32 -UHoudiniPointCacheFactory::GetPriority() const -{ - return ImportPriority; -} - +/* +* Copyright (c) <2018> Side Effects Software Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include "HoudiniPointCacheFactory.h" +#include "CoreMinimal.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "ShaderCompiler.h" +#include "Misc/CoreMiscDefines.h" +#include "HoudiniPointCache.h" +#include "EditorFramework/AssetImportData.h" +#include "HAL/FileManager.h" +#include "Editor.h" + +DEFINE_LOG_CATEGORY(LogHoudiniNiagaraEditor); + +#define LOCTEXT_NAMESPACE "HoudiniPointCacheFactory" + +///////////////////////////////////////////////////// +// UHoudiniPointCacheFactory +UHoudiniPointCacheFactory::UHoudiniPointCacheFactory(const FObjectInitializer& ObjectInitializer) : Super( ObjectInitializer ) +{ + // This factory is responsible for manufacturing HoudiniEngine assets. + SupportedClass = UHoudiniPointCache::StaticClass(); + + // This factory does not manufacture new objects from scratch. + bCreateNew = false; + + // This factory will open the editor for each new object. + bEditAfterNew = false; + + // This factory will import objects from files. + bEditorImport = true; + + // Factory does not import objects from text. + bText = true; + + // Add supported formats. + Formats.Add(FString(TEXT("hcsv;")) + NSLOCTEXT("HoudiniPointCacheFactory", "FormatHCSV", "HCSV File").ToString()); + Formats.Add(FString(TEXT("hjson;")) + NSLOCTEXT("HoudiniPointCacheFactory", "FormatHJSON", "HJSON File").ToString()); + Formats.Add(FString(TEXT("hbjson;")) + NSLOCTEXT("HoudiniPointCacheFactory", "FormatHBJSON", "HBJSON File").ToString()); +} + + +UObject* +UHoudiniPointCacheFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + UHoudiniPointCache* NewHoudiniPointCacheObject = NewObject(InParent, Class, Name, Flags | RF_Transactional); + return NewHoudiniPointCacheObject; +} + +UObject* +UHoudiniPointCacheFactory::FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Parms, FFeedbackContext* Warn, bool& bOutOperationCanceled) +{ + bOutOperationCanceled = false; + + UHoudiniPointCache* NewHoudiniPointCacheObject = NewObject(InParent, InClass, InName, Flags); + if ( !NewHoudiniPointCacheObject ) + return nullptr; + + if ( !NewHoudiniPointCacheObject->UpdateFromFile( Filename ) ) + return nullptr; + + // Create reimport information. + UAssetImportData * AssetImportData = NewHoudiniPointCacheObject->AssetImportData; + if (!AssetImportData) + { + AssetImportData = NewObject< UAssetImportData >(NewHoudiniPointCacheObject, UAssetImportData::StaticClass()); + NewHoudiniPointCacheObject->AssetImportData = AssetImportData; + } + + //NewHoudiniPointCacheObject->AssetImportData->Update(Filename); + AssetImportData->Update(UFactory::GetCurrentFilename()); + + // Broadcast notification that the new asset has been imported. + GEditor->GetEditorSubsystem()->BroadcastAssetPostImport(this, NewHoudiniPointCacheObject); + + return NewHoudiniPointCacheObject; +} + +FText +UHoudiniPointCacheFactory::GetDisplayName() const +{ + return LOCTEXT("HoudiniPointCacheFactoryDescription", "Houdini Point Cache File"); +} + +bool +UHoudiniPointCacheFactory::DoesSupportClass(UClass * Class) +{ + return Class == SupportedClass; +} +bool +UHoudiniPointCacheFactory::FactoryCanImport(const FString& Filename) +{ + const FString Extension = FPaths::GetExtension(Filename).ToLower(); + + if (Extension == TEXT("hcsv") || Extension == TEXT("hbjson") || Extension == TEXT("hjson")) + { + return true; + } + return false; +} + +bool +UHoudiniPointCacheFactory::CanReimport(UObject* Obj, TArray& OutFilenames) +{ + UHoudiniPointCache* HoudiniPointCache = Cast(Obj); + if (HoudiniPointCache) + { + if (HoudiniPointCache->AssetImportData) + { + HoudiniPointCache->AssetImportData->ExtractFilenames(OutFilenames); + } + else + { + OutFilenames.Add(TEXT("")); + } + return true; + } + return false; +} + +void +UHoudiniPointCacheFactory::SetReimportPaths(UObject* Obj, const TArray& NewReimportPaths) +{ + UHoudiniPointCache* HoudiniPointCache = Cast( Obj ); + if ( HoudiniPointCache + && HoudiniPointCache->AssetImportData + && ensure( NewReimportPaths.Num() == 1 ) ) + { + HoudiniPointCache->AssetImportData->UpdateFilenameOnly(NewReimportPaths[0]); + } +} + +EReimportResult::Type +UHoudiniPointCacheFactory::Reimport(UObject* Obj) +{ + UHoudiniPointCache* HoudiniPointCache = Cast(Obj); + if (!HoudiniPointCache || !HoudiniPointCache->AssetImportData ) + return EReimportResult::Failed; + + const FString FilePath = HoudiniPointCache->AssetImportData->GetFirstFilename(); + if (!FilePath.Len()) + return EReimportResult::Failed; + + UE_LOG(LogHoudiniNiagaraEditor, Log, TEXT("Performing atomic reimport of [%s]"), *FilePath); + + // Ensure that the file provided by the path exists + if (IFileManager::Get().FileSize(*FilePath) == INDEX_NONE) + { + UE_LOG(LogHoudiniNiagaraEditor, Warning, TEXT("Cannot reimport: source file cannot be found.")); + return EReimportResult::Failed; + } + + bool OutCanceled = false; + if (ImportObject(HoudiniPointCache->GetClass(), HoudiniPointCache->GetOuter(), *HoudiniPointCache->GetName(), RF_Public | RF_Standalone, FilePath, nullptr, OutCanceled) != nullptr) + { + UE_LOG(LogHoudiniNiagaraEditor, Log, TEXT("Imported successfully")); + // Try to find the outer package so we can dirty it up + if (HoudiniPointCache->GetOuter()) + HoudiniPointCache->GetOuter()->MarkPackageDirty(); + else + HoudiniPointCache->MarkPackageDirty(); + } + else if (OutCanceled) + { + UE_LOG(LogHoudiniNiagaraEditor, Warning, TEXT("-- import canceled")); + } + else + { + UE_LOG(LogHoudiniNiagaraEditor, Warning, TEXT("-- import failed")); + } + + return EReimportResult::Succeeded; +} + +int32 +UHoudiniPointCacheFactory::GetPriority() const +{ + return ImportPriority; +} + #undef LOCTEXT_NAMESPACE \ No newline at end of file