Files

504 lines
18 KiB
C++

/*
* Copyright (c) <2017> 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 "HoudiniRuntimeSettings.h"
#include "HoudiniApi.h"
#include "HoudiniEngineRuntimePrivatePCH.h"
#include "HoudiniEngineUtils.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
UHoudiniRuntimeSettings::UHoudiniRuntimeSettings( const FObjectInitializer & ObjectInitializer )
: Super( ObjectInitializer )
{
/** Session options. **/
SessionType = HRSST_NamedPipe;
ServerHost = HAPI_UNREAL_SESSION_SERVER_HOST;
ServerPort = HAPI_UNREAL_SESSION_SERVER_PORT;
ServerPipeName = HAPI_UNREAL_SESSION_SERVER_PIPENAME;
bStartAutomaticServer = HAPI_UNREAL_SESSION_SERVER_AUTOSTART;
AutomaticServerTimeout = HAPI_UNREAL_SESSION_SERVER_TIMEOUT;
#if PLATFORM_LINUX
// Since 4.17, Linux has library conflict, so we need to create an out-of-process session by default
// We default to a named pipe, but TCP Sockets should work fine too.
SessionType = HRSST_Socket;
bStartAutomaticServer = true;
#endif
/** Instantiation options. **/
bShowMultiAssetDialog = true;
/** Cooking options. **/
bPauseCookingOnStart = false;
bEnableCooking = true;
bUploadTransformsToHoudiniEngine = true;
bTransformChangeTriggersCooks = false;
bDisplaySlateCookingNotifications = true;
bCookCurvesOnMouseRelease = false;
TemporaryCookFolder = LOCTEXT("Temp", "/Game/HoudiniEngine/Temp");
/** Parameter options. **/
bTreatRampParametersAsMultiparms = false;
/** Collision generation. **/
CollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_COLLISION );
RenderedCollisionGroupNamePrefix = TEXT(HAPI_UNREAL_GROUP_GEOMETRY_RENDERED_COLLISION );
UCXCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_COLLISION_UCX );
UCXRenderedCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_RENDERED_COLLISION_UCX );
SimpleCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_SIMPLE_COLLISION );
SimpleRenderedCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_SIMPLE_RENDERED_COLLISION );
/** Geometry marshalling. **/
MarshallingAttributeMaterial = TEXT( HAPI_UNREAL_ATTRIB_MATERIAL );
MarshallingAttributeMaterialHole = TEXT( HAPI_UNREAL_ATTRIB_MATERIAL_HOLE );
MarshallingAttributeInstanceOverride = TEXT( HAPI_UNREAL_ATTRIB_INSTANCE_OVERRIDE );
MarshallingAttributeFaceSmoothingMask = TEXT( HAPI_UNREAL_ATTRIB_FACE_SMOOTHING_MASK );
MarshallingAttributeLightmapResolution = TEXT( HAPI_UNREAL_ATTRIB_LIGHTMAP_RESOLUTION );
MarshallingAttributeGeneratedMeshName = TEXT( HAPI_UNREAL_ATTRIB_GENERATED_MESH_NAME );
MarshallingAttributeInputMeshName = TEXT( HAPI_UNREAL_ATTRIB_INPUT_MESH_NAME );
MarshallingAttributeInputSourceFile = TEXT( HAPI_UNREAL_ATTRIB_INPUT_SOURCE_FILE );
MarshallingSplineResolution = HAPI_UNREAL_PARAM_SPLINE_RESOLUTION_DEFAULT;
MarshallingLandscapesUseDefaultUnrealScaling = false;
MarshallingLandscapesUseFullResolution = true;
MarshallingLandscapesForceMinMaxValues = false;
MarshallingLandscapesForcedMinValue = -2000.0f;
MarshallingLandscapesForcedMaxValue = 4553.0f;
/** Geometry scaling. **/
GeneratedGeometryScaleFactor = HAPI_UNREAL_SCALE_FACTOR_POSITION;
TransformScaleFactor = HAPI_UNREAL_SCALE_FACTOR_TRANSLATION;
ImportAxis = HRSAI_Unreal;
/** Generated StaticMesh settings. **/
bDoubleSidedGeometry = false;
PhysMaterial = nullptr;
DefaultBodyInstance.SetCollisionProfileName("BlockAll");
CollisionTraceFlag = CTF_UseDefault;
LightMapResolution = 32;
LpvBiasMultiplier = 1.0f;
LightMapCoordinateIndex = 1;
bUseMaximumStreamingTexelRatio = false;
StreamingDistanceMultiplier = 1.0f;
GeneratedDistanceFieldResolutionScale = 0.0f;
/** Static Mesh build settings. **/
bUseFullPrecisionUVs = false;
SrcLightmapIndex = 0;
DstLightmapIndex = 1;
MinLightmapResolution = 64;
bRemoveDegenerates = true;
GenerateLightmapUVsFlag = HRSRF_OnlyIfMissing;
RecomputeNormalsFlag = HRSRF_OnlyIfMissing;
RecomputeTangentsFlag = HRSRF_OnlyIfMissing;
bUseMikkTSpace = true;
bBuildAdjacencyBuffer = false;
/** Custom Houdini location. **/
bUseCustomHoudiniLocation = false;
CustomHoudiniLocation.Path = TEXT( "" );
// Placement Mode Tools
bHidePlacementModeHoudiniTools = false;
/** Arguments for HAPI_Initialize */
CookingThreadStackSize = -1;
}
UHoudiniRuntimeSettings::~UHoudiniRuntimeSettings()
{}
FProperty *
UHoudiniRuntimeSettings::LocateProperty( const FString & PropertyName ) const
{
for ( TFieldIterator< FProperty > PropIt( GetClass() ); PropIt; ++PropIt )
{
FProperty * Property = *PropIt;
if ( Property->GetNameCPP() == PropertyName )
return Property;
}
return nullptr;
}
void
UHoudiniRuntimeSettings::SetPropertyReadOnly( const FString & PropertyName, bool bReadOnly )
{
FProperty * Property = LocateProperty( PropertyName );
if ( Property )
{
if ( bReadOnly )
Property->SetPropertyFlags( CPF_EditConst );
else
Property->ClearPropertyFlags( CPF_EditConst );
}
}
void
UHoudiniRuntimeSettings::PostInitProperties()
{
Super::PostInitProperties();
// Set Collision generation options as read only
{
if ( FProperty* Property = LocateProperty( TEXT( "CollisionGroupNamePrefix" ) ) )
Property->SetPropertyFlags( CPF_EditConst );
if ( FProperty* Property = LocateProperty( TEXT( "RenderedCollisionGroupNamePrefix" ) ) )
Property->SetPropertyFlags( CPF_EditConst );
if ( FProperty* Property = LocateProperty(TEXT("UCXCollisionGroupNamePrefix" ) ) )
Property->SetPropertyFlags(CPF_EditConst);
if ( FProperty* Property = LocateProperty(TEXT("UCXRenderedCollisionGroupNamePrefix" ) ) )
Property->SetPropertyFlags(CPF_EditConst);
if ( FProperty* Property = LocateProperty(TEXT("SimpleCollisionGroupNamePrefix" ) ) )
Property->SetPropertyFlags(CPF_EditConst);
if ( FProperty* Property = LocateProperty(TEXT("SimpleRenderedCollisionGroupNamePrefix" ) ) )
Property->SetPropertyFlags(CPF_EditConst);
}
// Set marshalling attributes options as read only
{
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeMaterial")))
Property->SetPropertyFlags(CPF_EditConst);
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeMaterialHole")))
Property->SetPropertyFlags(CPF_EditConst);
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeInstanceOverride")))
Property->SetPropertyFlags(CPF_EditConst);
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeFaceSmoothingMask")))
Property->SetPropertyFlags(CPF_EditConst);
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeLightmapResolution")))
Property->SetPropertyFlags(CPF_EditConst);
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeGeneratedMeshName")))
Property->SetPropertyFlags(CPF_EditConst);
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeInputMeshName")))
Property->SetPropertyFlags(CPF_EditConst);
}
/*
// Set Cook Folder as read-only
{
if ( FProperty* Property = LocateProperty( TEXT( "TemporaryCookFolder" ) ) )
Property->SetPropertyFlags( CPF_EditConst );
}
*/
// Set Landscape forced min/max as read only when not overriden
if ( !MarshallingLandscapesForceMinMaxValues )
{
if ( FProperty* Property = LocateProperty( TEXT( "MarshallingLandscapesForcedMinValue" ) ) )
Property->SetPropertyFlags( CPF_EditConst );
if ( FProperty* Property = LocateProperty( TEXT( "MarshallingLandscapesForcedMaxValue" ) ) )
Property->SetPropertyFlags( CPF_EditConst );
}
// Disable UI elements depending on current session type.
#if WITH_EDITOR
UpdateSessionUi();
#endif // WITH_EDITOR
SetPropertyReadOnly( TEXT( "CustomHoudiniLocation" ), !bUseCustomHoudiniLocation );
}
#if WITH_EDITOR
void
UHoudiniRuntimeSettings::PostEditChangeProperty( struct FPropertyChangedEvent & PropertyChangedEvent )
{
Super::PostEditChangeProperty( PropertyChangedEvent );
FProperty * Property = PropertyChangedEvent.MemberProperty;
FProperty * LookupProperty = nullptr;
if ( !Property )
return;
if ( Property->GetName() == TEXT( "GeneratedGeometryScaleFactor" ) )
GeneratedGeometryScaleFactor = FMath::Clamp( GeneratedGeometryScaleFactor, KINDA_SMALL_NUMBER, 10000.0f );
else if ( Property->GetName() == TEXT( "TransformScaleFactor" ) )
GeneratedGeometryScaleFactor = FMath::Clamp( GeneratedGeometryScaleFactor, KINDA_SMALL_NUMBER, 10000.0f );
else if ( Property->GetName() == TEXT( "SessionType" ) )
UpdateSessionUi();
else if ( Property->GetName() == TEXT( "bUseCustomHoudiniLocation" ) )
SetPropertyReadOnly( TEXT( "CustomHoudiniLocation" ), !bUseCustomHoudiniLocation );
else if ( Property->GetName() == TEXT( "CustomHoudiniLocation" ) )
{
FString LibHAPIName = FHoudiniEngineUtils::HoudiniGetLibHAPIName();
FString & CustomHoudiniLocationPath = CustomHoudiniLocation.Path;
FString LibHAPICustomPath = FString::Printf( TEXT( "%s/%s" ), *CustomHoudiniLocationPath, *LibHAPIName );
// If path does not point to libHAPI location, we need to let user know.
if ( !FPaths::FileExists( LibHAPICustomPath ) )
{
FString MessageString = FString::Printf(
TEXT( "%s was not found in %s" ), *LibHAPIName, *CustomHoudiniLocationPath );
FPlatformMisc::MessageBoxExt(
EAppMsgType::Ok, *MessageString,
TEXT( "Invalid Custom Location Specified, resetting." ) );
CustomHoudiniLocationPath = TEXT( "" );
}
}
else if (Property->GetName() == TEXT("MarshallingSplineResolution"))
MarshallingSplineResolution = FMath::Clamp(MarshallingSplineResolution, 0.0f, 10000.0f);
if ( Property->GetName() == TEXT( "MarshallingLandscapesForceMinMaxValues" ) )
{
// Set Landscape forced min/max as read only when not overriden
if ( !MarshallingLandscapesForceMinMaxValues )
{
if ( FProperty* MinProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMinValue") ) )
MinProperty->SetPropertyFlags( CPF_EditConst );
if ( FProperty* MaxProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMaxValue" ) ) )
MaxProperty->SetPropertyFlags( CPF_EditConst );
}
else
{
if ( FProperty* MinProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMinValue") ) )
MinProperty->ClearPropertyFlags( CPF_EditConst );
if ( FProperty* MaxProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMaxValue" ) ) )
MaxProperty->ClearPropertyFlags( CPF_EditConst );
}
}
/*
if ( Property->GetName() == TEXT( "bEnableCooking" ) )
{
// Cooking is disabled, we need to disable transform change triggers cooks option is as well.
if ( bEnableCooking )
{
LookupProperty = LocateProperty( TEXT( "bUploadTransformsToHoudiniEngine" ) );
if ( LookupProperty )
LookupProperty->ClearPropertyFlags( CPF_EditConst );
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
if ( LookupProperty )
LookupProperty->ClearPropertyFlags( CPF_EditConst );
}
else
{
LookupProperty = LocateProperty( TEXT( "bUploadTransformsToHoudiniEngine" ) );
if ( LookupProperty )
LookupProperty->SetPropertyFlags( CPF_EditConst );
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
if ( LookupProperty )
LookupProperty->SetPropertyFlags( CPF_EditConst );
}
}
else if ( Property->GetName() == TEXT( "bUploadTransformsToHoudiniEngine" ) )
{
// If upload of transformations is disabled, then there's no sense in cooking asset on transformation change.
if ( bUploadTransformsToHoudiniEngine )
{
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
if ( LookupProperty )
LookupProperty->ClearPropertyFlags( CPF_EditConst );
}
else
{
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
if ( LookupProperty )
LookupProperty->SetPropertyFlags( CPF_EditConst );
}
}
*/
}
void
UHoudiniRuntimeSettings::SetMeshBuildSettings( FMeshBuildSettings & MeshBuildSettings, FRawMesh & RawMesh ) const
{
MeshBuildSettings.bRemoveDegenerates = bRemoveDegenerates;
MeshBuildSettings.bUseMikkTSpace = bUseMikkTSpace;
MeshBuildSettings.bBuildAdjacencyBuffer = bBuildAdjacencyBuffer;
MeshBuildSettings.MinLightmapResolution = MinLightmapResolution;
MeshBuildSettings.bUseFullPrecisionUVs = bUseFullPrecisionUVs;
MeshBuildSettings.SrcLightmapIndex = SrcLightmapIndex;
MeshBuildSettings.DstLightmapIndex = DstLightmapIndex;
// Recomputing normals.
switch ( RecomputeNormalsFlag )
{
case HRSRF_Always:
{
MeshBuildSettings.bRecomputeNormals = true;
break;
}
case HRSRF_OnlyIfMissing:
{
MeshBuildSettings.bRecomputeNormals = ( 0 == RawMesh.WedgeTangentZ.Num() );
break;
}
case HRSRF_Nothing:
default:
{
MeshBuildSettings.bRecomputeNormals = false;
break;
}
}
// Recomputing tangents.
switch ( RecomputeTangentsFlag )
{
case HRSRF_Always:
{
MeshBuildSettings.bRecomputeTangents = true;
break;
}
case HRSRF_OnlyIfMissing:
{
MeshBuildSettings.bRecomputeTangents = ( 0 == RawMesh.WedgeTangentX.Num() || 0 == RawMesh.WedgeTangentY.Num() );
break;
}
case HRSRF_Nothing:
default:
{
MeshBuildSettings.bRecomputeTangents = false;
break;
}
}
// Lightmap UV generation.
bool bHasLightmapUVSet = FHoudiniEngineUtils::CountUVSets( RawMesh ) > 1;
switch ( GenerateLightmapUVsFlag )
{
case HRSRF_Always:
{
MeshBuildSettings.bGenerateLightmapUVs = true;
break;
}
case HRSRF_OnlyIfMissing:
{
MeshBuildSettings.bGenerateLightmapUVs = !bHasLightmapUVSet;
break;
}
case HRSRF_Nothing:
default:
{
MeshBuildSettings.bGenerateLightmapUVs = false;
break;
}
}
}
void
UHoudiniRuntimeSettings::UpdateSessionUi()
{
SetPropertyReadOnly( TEXT( "ServerHost" ), true );
SetPropertyReadOnly( TEXT( "ServerPort" ), true );
SetPropertyReadOnly( TEXT( "ServerPipeName" ), true );
SetPropertyReadOnly( TEXT( "bStartAutomaticServer" ), true );
SetPropertyReadOnly( TEXT( "AutomaticServerTimeout" ), true );
bool bServerType = false;
switch ( SessionType )
{
case HRSST_Socket:
{
SetPropertyReadOnly( TEXT( "ServerHost" ), false);
SetPropertyReadOnly( TEXT( "ServerPort" ), false);
bServerType = true;
break;
}
case HRSST_NamedPipe:
{
SetPropertyReadOnly( TEXT( "ServerPipeName" ), false);
bServerType = true;
break;
}
default:
break;
}
if ( bServerType )
{
SetPropertyReadOnly( TEXT( "bStartAutomaticServer" ), false );
SetPropertyReadOnly( TEXT( "AutomaticServerTimeout" ), false );
}
}
#endif // WITH_EDITOR
bool
UHoudiniRuntimeSettings::GetSettingsValue( const FString & PropertyName, std::string & PropertyValue )
{
FString PropertyString = TEXT( "" );
if ( UHoudiniRuntimeSettings::GetSettingsValue( PropertyName, PropertyString ) )
{
FHoudiniEngineUtils::ConvertUnrealString( PropertyString, PropertyValue );
return true;
}
return false;
}
bool
UHoudiniRuntimeSettings::GetSettingsValue( const FString & PropertyName, FString & PropertyValue )
{
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault< UHoudiniRuntimeSettings >();
if ( HoudiniRuntimeSettings )
{
FStrProperty * Property = CastField< FStrProperty >( HoudiniRuntimeSettings->LocateProperty( PropertyName ) );
if ( Property )
{
const void * ValueRaw = Property->ContainerPtrToValuePtr< void >( HoudiniRuntimeSettings );
FString RetrievedPropertyValue = Property->GetPropertyValue( ValueRaw );
if ( !RetrievedPropertyValue.IsEmpty() )
{
PropertyValue = RetrievedPropertyValue;
return true;
}
}
}
return false;
}
#undef LOCTEXT_NAMESPACE