/* * Copyright (c) <2021> Side Effects Software Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. The name of Side Effects Software may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "CoreTypes.h" #include "UObject/Object.h" #include "UObject/ObjectMacros.h" #include "Misc/Optional.h" #include "HoudiniInputTypes.h" #include "HoudiniInputObject.h" #include "GameFramework/Actor.h" #include "LandscapeProxy.h" #include "HoudiniInput.generated.h" class FReply; enum class EHoudiniCurveType : int8; enum class ECheckBoxState : unsigned char; UCLASS() class HOUDINIENGINERUNTIME_API UHoudiniInput : public UObject { GENERATED_BODY() public: UHoudiniInput(); // Equality operator, // We consider two inputs equals if they have the same name, objparam state, and input index/parmId // TODO: ParmId might be an incorrect condition bool operator==(const UHoudiniInput& other) const { return (bIsObjectPathParameter == other.bIsObjectPathParameter && InputIndex == other.InputIndex && ParmId == other.ParmId && Name.Equals(other.Name) && Label.Equals(other.Label)); } bool Matches(const UHoudiniInput& other) const { return (*this == other); }; // Helper function returning a string from an InputType static FString InputTypeToString(const EHoudiniInputType& InInputType); // Helper function returning an InputType from a string static EHoudiniInputType StringToInputType(const FString& InInputTypeString); // Helper function returning a Houdini curve type from a string static EHoudiniCurveType StringToHoudiniCurveType(const FString& CurveTypeString); // Helper function returning a Houdini curve method from a string static EHoudiniCurveMethod StringToHoudiniCurveMethod(const FString& CurveMethodString); // Helper function indicating what classes are supported by an input type static TArray GetAllowedClasses(const EHoudiniInputType& InInputType); // Helper function indicating if an object is supported by an input type static bool IsObjectAcceptable(const EHoudiniInputType& InInputType, const UObject* InObject); //------------------------------------------------------------------------------------------------ // Accessors //------------------------------------------------------------------------------------------------ // Returns the NodeId of the asset / object merge we are associated with int32 GetAssetNodeId() const { return AssetNodeId; }; // For objpath parameter, return the associated ParamId, -1 if we're a Geo input int32 GetParameterId() const { return bIsObjectPathParameter ? ParmId : -1; }; // Returns the NodeId of the node plugged into this input int32 GetInputNodeId() const { return InputNodeId; }; // For Geo inputs, returns the InputIndex, -1 if we're an object path parameter int32 GetInputIndex() const { return bIsObjectPathParameter ? -1 : InputIndex; }; // Return the array containing all the nodes created for this input's data TArray& GetCreatedDataNodeIds() { return CreatedDataNodeIds; }; // Returns the current input type EHoudiniInputType GetInputType() const { return Type; }; // Returns the previous input type EHoudiniInputType GetPreviousInputType() const { return PreviousType; }; // Returns the current input type as a string FString GetInputTypeAsString() const { return InputTypeToString(Type); }; EHoudiniXformType GetDefaultXTransformType(); // Returns true when this input's Transform Type is set to NONE, // false if set to INTO_THIS_OBJECT, 2 will use the input's type default value bool GetKeepWorldTransform() const; // Indicates if this input has changed and should be updated bool HasChanged(); // Indicates if this input needs to trigger an update bool NeedsToTriggerUpdate(); // Indicates this input should upload its data bool IsDataUploadNeeded(); // Indicates this input's transform need to be uploaded bool IsTransformUploadNeeded(); // Indicates if this input type has been changed bool HasInputTypeChanged() const { return PreviousType != EHoudiniInputType::Invalid ? PreviousType != Type : false; } // bool GetUpdateInputLandscape() const; void SetUpdateInputLandscape(const bool bInUpdateInputLandcape); FString GetName() const { return Name; }; FString GetLabel() const { return Label; }; FString GetHelp() const { return Help; }; bool GetPackBeforeMerge() const { return bPackBeforeMerge; }; bool GetImportAsReference() const { return bImportAsReference; }; bool GetExportLODs() const { return bExportLODs; }; bool GetExportSockets() const { return bExportSockets; }; bool GetExportColliders() const { return bExportColliders; }; bool IsObjectPathParameter() const { return bIsObjectPathParameter; }; float GetUnrealSplineResolution() const { return UnrealSplineResolution; }; virtual bool GetCookOnCurveChange() const { return bCookOnCurveChanged; }; TArray* GetHoudiniInputObjectArray(const EHoudiniInputType& InType); const TArray* GetHoudiniInputObjectArray(const EHoudiniInputType& InType) const; TArray* GetBoundSelectorObjectArray(); const TArray* GetBoundSelectorObjectArray() const; UHoudiniInputObject* GetHoudiniInputObjectAt(const int32& AtIndex); const UHoudiniInputObject* GetHoudiniInputObjectAt(const int32& AtIndex) const; AActor* GetBoundSelectorObjectAt(const int32& AtIndex); UHoudiniInputObject* GetHoudiniInputObjectAt(const EHoudiniInputType& InType, const int32& AtIndex); UObject* GetInputObjectAt(const int32& AtIndex); UObject* GetInputObjectAt(const EHoudiniInputType& InType, const int32& AtIndex); int32 GetNumberOfInputObjects(); int32 GetNumberOfInputObjects(const EHoudiniInputType& InType); int32 GetNumberOfInputMeshes(); int32 GetNumberOfInputMeshes(const EHoudiniInputType& InType); int32 GetNumberOfBoundSelectorObjects() const; bool IsWorldInputBoundSelector() const { return bIsWorldInputBoundSelector; }; bool GetWorldInputBoundSelectorAutoUpdates() const { return bWorldInputBoundSelectorAutoUpdate; }; FString GetNodeBaseName() const; bool IsTransformUIExpanded(const int32& AtIndex); // Return the transform offset for a given input object FTransform* GetTransformOffset(const int32& AtIndex); const FTransform GetTransformOffset(const int32& AtIndex) const; // Returns the position offset for a given input object TOptional GetPositionOffsetX(int32 AtIndex) const; TOptional GetPositionOffsetY(int32 AtIndex) const; TOptional GetPositionOffsetZ(int32 AtIndex) const; // Returns the rotation offset for a given input object TOptional GetRotationOffsetRoll(int32 AtIndex) const; TOptional GetRotationOffsetPitch(int32 AtIndex) const; TOptional GetRotationOffsetYaw(int32 AtIndex) const; // Returns the scale offset for a given input object TOptional GetScaleOffsetX(int32 AtIndex) const; TOptional GetScaleOffsetY(int32 AtIndex) const; TOptional GetScaleOffsetZ(int32 AtIndex) const; // Returns true if the object is one of our input object for the given type bool ContainsInputObject(const UObject* InObject, const EHoudiniInputType& InType) const; // Get all input object arrays TArray*> GetAllObjectArrays() const; TArray*> GetAllObjectArrays(); // Iterate over all input object arrays void ForAllHoudiniInputObjectArrays(TFunctionRef&)> Fn) const; void ForAllHoudiniInputObjectArrays(TFunctionRef&)> Fn); void ForAllHoudiniInputObjects(TFunctionRef Fn) const; // Collect top-level HoudiniInputObjects from this UHoudiniInput. Does not traverse nested input objects. void GetAllHoudiniInputObjects(TArray& OutObjects) const; // Collect top-level UHoudiniInputSceneComponent from this UHoudiniInput. Does not traverse nested input objects. void ForAllHoudiniInputSceneComponents(TFunctionRef Fn) const; void GetAllHoudiniInputSceneComponents(TArray& OutObjects) const; void GetAllHoudiniInputSplineComponents(TArray& OutObjects) const; // Remove all instances of this input object from all object arrays. void RemoveHoudiniInputObject(UHoudiniInputObject* InInputObject); bool IsAddRotAndScaleAttributesEnabled() const { return bAddRotAndScaleAttributesOnCurves; }; //------------------------------------------------------------------------------------------------ // Mutators //------------------------------------------------------------------------------------------------ void MarkChanged(const bool& bInChanged) { bHasChanged = bInChanged; SetNeedsToTriggerUpdate(bInChanged); }; void SetNeedsToTriggerUpdate(const bool& bInTriggersUpdate) { bNeedsToTriggerUpdate = bInTriggersUpdate; }; void MarkDataUploadNeeded(const bool& bInDataUploadNeeded) { bDataUploadNeeded = bInDataUploadNeeded; }; void MarkAllInputObjectsChanged(const bool& bInChanged); void SetSOPInput(const int32& InInputIndex); void SetObjectPathParameter(const int32& InParmId); void SetKeepWorldTransform(const bool& bInKeepWorldTransform); void SetName(const FString& InName) { Name = InName; }; void SetLabel(const FString& InLabel) { Label = InLabel; }; void SetHelp(const FString& InHelp) { Help = InHelp; }; void SetAssetNodeId(const int32& InNodeId) { AssetNodeId = InNodeId; }; void SetInputType(const EHoudiniInputType &InInputType, bool& bOutBlueprintStructureModified); void SetPreviousInputType(const EHoudiniInputType& InType) { PreviousType = InType; }; void SetPackBeforeMerge(const bool& bInPackBeforeMerge) { bPackBeforeMerge = bInPackBeforeMerge; }; void SetImportAsReference(const bool& bInImportAsReference) { bImportAsReference = bInImportAsReference; }; void SetExportLODs(const bool& bInExportLODs) { bExportLODs = bInExportLODs; }; void SetExportSockets(const bool& bInExportSockets) { bExportSockets = bInExportSockets; }; void SetExportColliders(const bool& bInExportColliders) { bExportColliders = bInExportColliders; }; void SetInputNodeId(const int32& InCreatedNodeId) { InputNodeId = InCreatedNodeId; }; void SetUnrealSplineResolution(const float& InResolution) { UnrealSplineResolution = InResolution; }; virtual void SetCookOnCurveChange(const bool & bInCookOnCurveChanged) { bCookOnCurveChanged = bInCookOnCurveChanged; }; void ResetDefaultCurveOffset() { DefaultCurveOffset = 0.f; } UHoudiniInputObject* CreateNewCurveInputObject(bool& bBlueprintStructureModified); void SetGeometryInputObjectsNumber(const int32& NewCount); void SetInputObjectsNumber(const EHoudiniInputType& InType, const int32& InNewCount); void InsertInputObjectAt(const int32& AtIndex); void InsertInputObjectAt(const EHoudiniInputType& InType, const int32& AtIndex); void DeleteInputObjectAt(const int32& AtIndex); void DeleteInputObjectAt(const EHoudiniInputType& InType, const int32& AtIndex); void DuplicateInputObjectAt(const int32& AtIndex); void DuplicateInputObjectAt(const EHoudiniInputType& InType, const int32& AtIndex); void SetInputObjectAt(const int32& AtIndex, UObject* InObject); void SetInputObjectAt(const EHoudiniInputType& InType, const int32& AtIndex, UObject* InObject); void SetBoundSelectorObjectsNumber(const int32& InNewCount); void SetBoundSelectorObjectAt(const int32& AtIndex, AActor* InActor); void SetWorldInputBoundSelector(const bool& InIsBoundSelector) { bIsWorldInputBoundSelector = InIsBoundSelector; }; void SetWorldInputBoundSelectorAutoUpdates(const bool& InAutoUpdate) { bWorldInputBoundSelectorAutoUpdate = InAutoUpdate; }; // Updates the world selection using bound selectors // returns false if the selection hasn't changed bool UpdateWorldSelectionFromBoundSelectors(); // Updates the world selection // returns false if the selection hasn't changed bool UpdateWorldSelection(const TArray& InNewSelection); void OnTransformUIExpand(const int32& AtIndex); // Sets the input's transform offset bool SetTransformOffsetAt(const float& Value, const int32& AtIndex, const int32& PosRotScaleIndex, const int32& XYZIndex); // Sets the input's transform scale values void SetPositionOffsetX(float InValue, int32 AtIndex); void SetPositionOffsetY(float InValue, int32 AtIndex); void SetPositionOffsetZ(float InValue, int32 AtIndex); // Sets the input's transform rotation value void SetRotationOffsetRoll(float InValue, int32 AtIndex); void SetRotationOffsetPitch(float InValue, int32 AtIndex); void SetRotationOffsetYaw(float InValue, int32 AtIndex); // Sets the input's transform scale values void SetScaleOffsetX(float InValue, int32 AtIndex); void SetScaleOffsetY(float InValue, int32 AtIndex); void SetScaleOffsetZ(float InValue, int32 AtIndex); void SetAddRotAndScaleAttributes(const bool& InValue); // Duplicate this object and copy its state to the resulting object. // This is typically used to transfer state between between template and instance components. UHoudiniInput* DuplicateAndCopyState(UObject* DestOuter, bool bInCanDeleteHoudiniNodes); virtual void CopyStateFrom(UHoudiniInput* InInput, bool bCopyAllProperties, bool bInCanDeleteHoudiniNodes); void SetCanDeleteHoudiniNodes(bool bInCanDeleteNodes); bool CanDeleteHoudiniNodes() { return bCanDeleteHoudiniNodes; } virtual void InvalidateData(); protected: void CopyInputs(TArray& ToInputs, TArray& FromInputs, bool bInCanDeleteHoudiniNodes); public: // Create a Houdini Spline input component, with an existing Houdini Spline input Object. // Pass in nullptr to create a default Houdini Spline UHoudiniInputHoudiniSplineComponent* CreateHoudiniSplineInput( UHoudiniInputHoudiniSplineComponent* FromHoudiniSplineInputObject, const bool & bAttachToParent, const bool & bAppendToInputArray, bool& bOutBlueprintStructureModified); // Given an existing spline input object, remove the associated // Houdini Spline component from the owning actor / blueprint. void RemoveSplineFromInputObject( UHoudiniInputHoudiniSplineComponent* InHoudiniSplineInputObject, bool& bOutBlueprintStructureModified) const; bool HasLandscapeExportTypeChanged () const; void SetHasLandscapeExportTypeChanged(const bool InChanged); #if WITH_EDITOR FText GetCurrentSelectionText() const; #endif EHoudiniLandscapeExportType GetLandscapeExportType() const { return LandscapeExportType; }; void SetLandscapeExportType(const EHoudiniLandscapeExportType InType) { LandscapeExportType = InType; }; virtual void BeginDestroy() override; #if WITH_EDITOR virtual void PostEditUndo() override; #endif FBox GetBounds() const; protected: // Name of the input / Object path parameter UPROPERTY() FString Name; // Label of the SOP input or of the object path parameter UPROPERTY() FString Label; // Input type UPROPERTY() EHoudiniInputType Type; // Previous type, used to detect input type changes UPROPERTY(Transient, DuplicateTransient) EHoudiniInputType PreviousType; // NodeId of the asset / object merge we are associated with UPROPERTY(Transient, DuplicateTransient) int32 AssetNodeId; // NodeId of the created input node // when there is multiple inputs objects, this will be the merge node. UPROPERTY(Transient, DuplicateTransient, NonTransactional) int32 InputNodeId; // SOP input index (-1 if we're an object path input) UPROPERTY() int32 InputIndex; // Parameter Id of the associated object path parameter (-1 if we're a SOP input) UPROPERTY(Transient, DuplicateTransient, NonTransactional) int32 ParmId; // Indicates if we're an object path parameter input UPROPERTY() bool bIsObjectPathParameter; // Array containing all the node Ids created by this input UPROPERTY(Transient, DuplicateTransient, NonTransactional) TArray CreatedDataNodeIds; // Indicates data connected to this input should be uploaded UPROPERTY(Transient, DuplicateTransient) bool bHasChanged; // Indicates this input should trigger an HDA update/cook UPROPERTY(Transient, DuplicateTransient) bool bNeedsToTriggerUpdate; // Indicates data for this input needs to be uploaded // If this is false but the input has changed, we may have just updated in input parameter, // and don't need to resend all the input data bool bDataUploadNeeded; // Help for this parameter/input UPROPERTY() FString Help; //------------------------------------------------------------------------------------------------------------------------- // General Input options // Is set to true when this input's Transform Type is set to NONE, 2 will use the input's default value UPROPERTY() EHoudiniXformType KeepWorldTransform; // Indicates that the geometry must be packed before merging it into the input UPROPERTY() bool bPackBeforeMerge; // Indicates that all the input objects are imported to Houdini as references instead of actual geo // (for Geo/World/Asset input types only) UPROPERTY() bool bImportAsReference = false; // Indicates that all LODs in the input should be marshalled to Houdini UPROPERTY() bool bExportLODs; // Indicates that all sockets in the input should be marshalled to Houdini UPROPERTY() bool bExportSockets; // Indicates that all colliders in the input should be marshalled to Houdini UPROPERTY() bool bExportColliders; // Indicates that if trigger cook automatically on curve Input spline modified UPROPERTY() bool bCookOnCurveChanged; //------------------------------------------------------------------------------------------------------------------------- // Geometry objects UPROPERTY() TArray GeometryInputObjects; // Is set to true when static mesh used for geometry input has changed. UPROPERTY() bool bStaticMeshChanged; #if WITH_EDITORONLY_DATA // Are the transform UI expanded ? // Values default to false and are actually added to the array in OnTransformUIExpand() UPROPERTY() TArray TransformUIExpanded; #endif //------------------------------------------------------------------------------------------------------------------------- // Asset inputs UPROPERTY() TArray AssetInputObjects; // Is set to true if the asset input is actually connected inside Houdini. UPROPERTY() bool bInputAssetConnectedInHoudini; //------------------------------------------------------------------------------------------------------------------------- // Curve/Spline inputs UPROPERTY() TArray CurveInputObjects; // Offset used when using muiltiple curves UPROPERTY() float DefaultCurveOffset; // Set this to true to add rot and scale attributes on curve inputs. UPROPERTY() bool bAddRotAndScaleAttributesOnCurves; //------------------------------------------------------------------------------------------------------------------------- // Landscape inputs UPROPERTY() TArray LandscapeInputObjects; UPROPERTY() bool bLandscapeHasExportTypeChanged = false; //------------------------------------------------------------------------------------------------------------------------- // World inputs UPROPERTY() TArray WorldInputObjects; // Objects used for automatic bound selection UPROPERTY() TArray WorldInputBoundSelectorObjects; // Indicates that this world input is in "BoundSelector" mode UPROPERTY() bool bIsWorldInputBoundSelector; // Indicates that selected actors by the bound selectors should update automatically UPROPERTY() bool bWorldInputBoundSelectorAutoUpdate; // Resolution used when converting unreal splines to houdini curves UPROPERTY() float UnrealSplineResolution; //------------------------------------------------------------------------------------------------------------------------- // Skeletal Inputs UPROPERTY() TArray SkeletalInputObjects; public: // This array is to record the last insert action, for undo input insertion actions. UPROPERTY(Transient, DuplicateTransient) TArray LastInsertedInputs; // This array is to cache the action of last undo delete action, and redo that action. UPROPERTY(Transient, DuplicateTransient, NonTransactional) TArray LastUndoDeletedInputs; // Indicates that the landscape input's source landscape should be updated instead of creating a new component UPROPERTY() bool bUpdateInputLandscape; // Indicates if the landscape should be exported as heightfield, mesh or points UPROPERTY() EHoudiniLandscapeExportType LandscapeExportType = EHoudiniLandscapeExportType::Heightfield; // Is set to true when landscape input is set to selection only. UPROPERTY() bool bLandscapeExportSelectionOnly = false; // Is set to true when the automatic selection of landscape component is active UPROPERTY() bool bLandscapeAutoSelectComponent = false; // Is set to true when materials are to be exported. UPROPERTY() bool bLandscapeExportMaterials = false; // Is set to true when lightmap information export is desired. UPROPERTY() bool bLandscapeExportLighting = false; // Is set to true when uvs should be exported in [0,1] space. UPROPERTY() bool bLandscapeExportNormalizedUVs = false; // Is set to true when uvs should be exported for each tile separately. UPROPERTY() bool bLandscapeExportTileUVs = false; UPROPERTY() bool bCanDeleteHoudiniNodes = true; };