Files

696 lines
23 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 "HoudiniEngine.h"
#include "HoudiniApi.h"
#include "HoudiniEngineRuntimePrivatePCH.h"
#include "HoudiniEngineScheduler.h"
#include "HoudiniEngineTask.h"
#include "HoudiniEngineTaskInfo.h"
#include "HoudiniEngineUtils.h"
#include "HoudiniLandscapeUtils.h"
#include "HoudiniEngineInstancerUtils.h"
#include "HoudiniAsset.h"
#include "HoudiniRuntimeSettings.h"
#include "HAL/PlatformMisc.h"
#include "HAL/PlatformFilemanager.h"
#include "Misc/ScopeLock.h"
#include "Framework/Application/SlateApplication.h"
#include "Materials/Material.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
const FName FHoudiniEngine::HoudiniEngineAppIdentifier = FName( TEXT( "HoudiniEngineApp" ) );
IMPLEMENT_MODULE( FHoudiniEngine, HoudiniEngineRuntime );
DEFINE_LOG_CATEGORY( LogHoudiniEngine );
FHoudiniEngine *
FHoudiniEngine::HoudiniEngineInstance = nullptr;
FHoudiniEngine::FHoudiniEngine()
: HoudiniLogoStaticMesh( nullptr )
, HoudiniDefaultMaterial( nullptr )
, HoudiniBgeoAsset( nullptr )
, HoudiniEngineSchedulerThread( nullptr )
, HoudiniEngineScheduler( nullptr )
, EnableCookingGlobal( true )
, FirstSessionCreated( false )
{
Session.type = HAPI_SESSION_MAX;
Session.id = -1;
}
#if WITH_EDITOR
TSharedPtr< FSlateDynamicImageBrush >
FHoudiniEngine::GetHoudiniLogoBrush() const
{
return HoudiniLogoBrush;
}
#endif
TWeakObjectPtr<UStaticMesh>
FHoudiniEngine::GetHoudiniLogoStaticMesh() const
{
return HoudiniLogoStaticMesh;
}
TWeakObjectPtr<UMaterial>
FHoudiniEngine::GetHoudiniDefaultMaterial() const
{
return HoudiniDefaultMaterial;
}
TWeakObjectPtr<UHoudiniAsset>
FHoudiniEngine::GetHoudiniBgeoAsset() const
{
return HoudiniBgeoAsset;
}
bool
FHoudiniEngine::CheckHapiVersionMismatch() const
{
return bHAPIVersionMismatch;
}
const FString &
FHoudiniEngine::GetLibHAPILocation() const
{
return LibHAPILocation;
}
HAPI_Result
FHoudiniEngine::GetHapiState() const
{
return HAPIState;
}
void
FHoudiniEngine::SetHapiState( HAPI_Result Result )
{
HAPIState = Result;
}
const HAPI_Session *
FHoudiniEngine::GetSession() const
{
return Session.type == HAPI_SESSION_MAX ? nullptr : &Session;
}
FHoudiniEngine &
FHoudiniEngine::Get()
{
check( FHoudiniEngine::HoudiniEngineInstance );
return *FHoudiniEngine::HoudiniEngineInstance;
}
bool
FHoudiniEngine::IsInitialized()
{
return FHoudiniEngine::HoudiniEngineInstance != nullptr && FHoudiniEngineUtils::IsInitialized();
}
void
FHoudiniEngine::StartupModule()
{
bHAPIVersionMismatch = false;
HAPIState = HAPI_RESULT_NOT_INITIALIZED;
HOUDINI_LOG_MESSAGE( TEXT( "Starting the Houdini Engine module." ) );
#if WITH_EDITOR
// Register settings.
if( ISettingsModule * SettingsModule = FModuleManager::GetModulePtr< ISettingsModule >( "Settings" ) )
{
SettingsModule->RegisterSettings(
"Project", "Plugins", "HoudiniEngine",
LOCTEXT( "RuntimeSettingsName", "Houdini Engine" ),
LOCTEXT( "RuntimeSettingsDescription", "Configure the HoudiniEngine plugin" ),
GetMutableDefault< UHoudiniRuntimeSettings >() );
}
// Before starting the module, we need to locate and load HAPI library.
{
void * HAPILibraryHandle = FHoudiniEngineUtils::LoadLibHAPI( LibHAPILocation );
if ( HAPILibraryHandle )
{
FHoudiniApi::InitializeHAPI( HAPILibraryHandle );
}
else
{
// Get platform specific name of libHAPI.
FString LibHAPIName = FHoudiniEngineUtils::HoudiniGetLibHAPIName();
HOUDINI_LOG_MESSAGE( TEXT( "Failed locating or loading %s" ), *LibHAPIName );
}
}
#endif
// Create static mesh Houdini logo.
HoudiniLogoStaticMesh = LoadObject< UStaticMesh >(
nullptr, HAPI_UNREAL_RESOURCE_HOUDINI_LOGO, nullptr, LOAD_None, nullptr );
if ( HoudiniLogoStaticMesh.IsValid() )
HoudiniLogoStaticMesh->AddToRoot();
// Create default material.
HoudiniDefaultMaterial = LoadObject< UMaterial >(
nullptr, HAPI_UNREAL_RESOURCE_HOUDINI_MATERIAL, nullptr, LOAD_None, nullptr );
if ( HoudiniDefaultMaterial.IsValid() )
HoudiniDefaultMaterial->AddToRoot();
// Create Houdini digital asset which is used for loading the bgeo files.
HoudiniBgeoAsset = LoadObject< UHoudiniAsset >(
nullptr, HAPI_UNREAL_RESOURCE_BGEO_IMPORT, nullptr, LOAD_None, nullptr );
if ( HoudiniBgeoAsset.IsValid() )
HoudiniBgeoAsset->AddToRoot();
#if WITH_EDITOR
if ( !IsRunningCommandlet() && !IsRunningDedicatedServer() )
{
// Create Houdini logo brush.
const TArray< TSharedRef< IPlugin > > Plugins = IPluginManager::Get().GetDiscoveredPlugins();
for ( auto PluginIt( Plugins.CreateConstIterator() ); PluginIt; ++PluginIt )
{
const TSharedRef< IPlugin > & Plugin = *PluginIt;
if (Plugin->GetName() != TEXT("HoudiniEngine"))
continue;
FString Icon128FilePath = Plugin->GetBaseDir() / TEXT("Resources/Icon128.png");
if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*Icon128FilePath))
{
const FName BrushName(*Icon128FilePath);
const FIntPoint Size = FSlateApplication::Get().GetRenderer()->GenerateDynamicImageResource(BrushName);
if (Size.X > 0 && Size.Y > 0)
{
static const int32 ProgressIconSize = 32;
HoudiniLogoBrush = MakeShareable(new FSlateDynamicImageBrush(
BrushName, FVector2D(ProgressIconSize, ProgressIconSize)));
}
}
break;
}
}
// Build and running versions match, we can perform HAPI initialization.
if ( FHoudiniApi::IsHAPIInitialized() )
{
// We do not automatically try to start a session when starting up the module now.
FirstSessionCreated = false;
// Create HAPI scheduler and processing thread.
HoudiniEngineScheduler = new FHoudiniEngineScheduler();
HoudiniEngineSchedulerThread = FRunnableThread::Create(
HoudiniEngineScheduler, TEXT( "HoudiniTaskCookAsset" ), 0, TPri_Normal );
// Set the default value for pausing houdini engine cooking
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault< UHoudiniRuntimeSettings >();
EnableCookingGlobal = !HoudiniRuntimeSettings->bPauseCookingOnStart;
}
#endif
// Store the instance.
FHoudiniEngine::HoudiniEngineInstance = this;
}
void
FHoudiniEngine::ShutdownModule()
{
HOUDINI_LOG_MESSAGE( TEXT( "Shutting down the Houdini Engine module." ) );
// We no longer need Houdini logo static mesh.
if ( HoudiniLogoStaticMesh.IsValid() )
{
HoudiniLogoStaticMesh->RemoveFromRoot();
HoudiniLogoStaticMesh = nullptr;
}
// We no longer need Houdini default material.
if ( HoudiniDefaultMaterial.IsValid() )
{
HoudiniDefaultMaterial->RemoveFromRoot();
HoudiniDefaultMaterial = nullptr;
}
// We no longer need Houdini digital asset used for loading bgeo files.
if ( HoudiniBgeoAsset.IsValid() )
{
HoudiniBgeoAsset->RemoveFromRoot();
HoudiniBgeoAsset = nullptr;
}
#if WITH_EDITOR
// Unregister settings.
ISettingsModule * SettingsModule = FModuleManager::GetModulePtr< ISettingsModule >( "Settings" );
if ( SettingsModule )
SettingsModule->UnregisterSettings( "Project", "Plugins", "HoudiniEngine" );
#endif
// Do scheduler and thread clean up.
if ( HoudiniEngineScheduler )
HoudiniEngineScheduler->Stop();
if ( HoudiniEngineSchedulerThread )
{
//HoudiniEngineSchedulerThread->Kill( true );
HoudiniEngineSchedulerThread->WaitForCompletion();
delete HoudiniEngineSchedulerThread;
HoudiniEngineSchedulerThread = nullptr;
}
if ( HoudiniEngineScheduler )
{
delete HoudiniEngineScheduler;
HoudiniEngineScheduler = nullptr;
}
// Perform HAPI finalization.
if ( FHoudiniApi::IsHAPIInitialized() )
{
FHoudiniApi::Cleanup( GetSession() );
FHoudiniApi::CloseSession( GetSession() );
}
FHoudiniApi::FinalizeHAPI();
}
void
FHoudiniEngine::AddTask( const FHoudiniEngineTask & Task )
{
if ( HoudiniEngineScheduler )
HoudiniEngineScheduler->AddTask( Task );
FScopeLock ScopeLock( &CriticalSection );
FHoudiniEngineTaskInfo TaskInfo;
TaskInfos.Add( Task.HapiGUID, TaskInfo );
}
void
FHoudiniEngine::AddTaskInfo( const FGuid HapIGUID, const FHoudiniEngineTaskInfo & TaskInfo )
{
FScopeLock ScopeLock( &CriticalSection );
TaskInfos.Add( HapIGUID, TaskInfo );
}
void
FHoudiniEngine::RemoveTaskInfo( const FGuid HapIGUID )
{
FScopeLock ScopeLock( &CriticalSection );
TaskInfos.Remove( HapIGUID );
}
bool
FHoudiniEngine::RetrieveTaskInfo( const FGuid HapIGUID, FHoudiniEngineTaskInfo & TaskInfo )
{
FScopeLock ScopeLock( &CriticalSection );
if ( TaskInfos.Contains( HapIGUID ) )
{
TaskInfo = TaskInfos[ HapIGUID ];
return true;
}
return false;
}
bool
FHoudiniEngine::CookNode(
HAPI_NodeId AssetId, FHoudiniCookParams& HoudiniCookParams,
bool ForceRebuildStaticMesh, bool ForceRecookAll,
const TMap< FHoudiniGeoPartObject, UStaticMesh * > & StaticMeshesIn,
TMap< FHoudiniGeoPartObject, UStaticMesh * > & StaticMeshesOut,
TMap< FHoudiniGeoPartObject, TWeakObjectPtr<ALandscapeProxy> >& LandscapesIn,
TMap< FHoudiniGeoPartObject, TWeakObjectPtr<ALandscapeProxy> >& LandscapesOut,
TMap< FHoudiniGeoPartObject, USceneComponent * >& InstancersIn,
TMap< FHoudiniGeoPartObject, USceneComponent * >& InstancersOut,
USceneComponent* ParentComponent, FTransform & ComponentTransform )
{
//
TMap< FHoudiniGeoPartObject, UStaticMesh * > CookResultArray;
bool bReturn = FHoudiniEngineUtils::CreateStaticMeshesFromHoudiniAsset(
AssetId, HoudiniCookParams, ForceRebuildStaticMesh,
ForceRecookAll, StaticMeshesIn, CookResultArray, ComponentTransform );
if ( !bReturn )
return false;
// Extract the static mesh and the volumes/heightfields from the CookResultArray
TArray< FHoudiniGeoPartObject > FoundVolumes;
TArray< FHoudiniGeoPartObject > FoundInstancers;
for ( TMap< FHoudiniGeoPartObject, UStaticMesh * >::TIterator Iter( CookResultArray ); Iter; ++Iter )
{
const FHoudiniGeoPartObject HoudiniGeoPartObject = Iter.Key();
UStaticMesh * StaticMesh = Iter.Value();
if ( HoudiniGeoPartObject.IsInstancer() )
FoundInstancers.Add( HoudiniGeoPartObject );
else if (HoudiniGeoPartObject.IsPackedPrimitiveInstancer())
FoundInstancers.Add( HoudiniGeoPartObject );
else if (HoudiniGeoPartObject.IsCurve())
continue;
else if (HoudiniGeoPartObject.IsVolume())
FoundVolumes.Add( HoudiniGeoPartObject );
else
StaticMeshesOut.Add(HoudiniGeoPartObject, StaticMesh);
}
#if WITH_EDITOR
// The meshes are already created but we need to create the landscape too
if ( FoundVolumes.Num() > 0 )
{
TArray< ALandscapeProxy* > NullLandscapes;
if ( !FHoudiniLandscapeUtils::CreateAllLandscapes( HoudiniCookParams, FoundVolumes, LandscapesIn, LandscapesOut, NullLandscapes , -200.0f, 200.0f ) )
HOUDINI_LOG_WARNING( TEXT("FHoudiniEngine::CookNode : Failed to create landscapes!") );
}
#endif
// And the instancers
if ( FoundInstancers.Num() > 0 )
{
if ( !FHoudiniEngineInstancerUtils::CreateAllInstancers(
HoudiniCookParams, AssetId, FoundInstancers,
StaticMeshesOut, ParentComponent,
InstancersIn, InstancersOut ) )
{
HOUDINI_LOG_WARNING( TEXT( "FHoudiniEngine::CookNode : Failed to create instancers!" ) );
}
}
if ( StaticMeshesOut.Num() <= 0 && LandscapesOut.Num() <= 0 && InstancersOut.Num() <= 0 )
return false;
return true;
}
void
FHoudiniEngine::SetEnableCookingGlobal(const bool& enableCooking)
{
EnableCookingGlobal = enableCooking;
}
bool
FHoudiniEngine::GetEnableCookingGlobal()
{
return EnableCookingGlobal;
}
bool
FHoudiniEngine::StartSession( HAPI_Session*& SessionPtr,
const bool& StartAutomaticServer,
const float& AutomaticServerTimeout,
const EHoudiniRuntimeSettingsSessionType& SessionType,
const FString& ServerPipeName,
const int32& ServerPort,
const FString& ServerHost )
{
// Indicates that we've tried to start the session once
// whether it failed or succeed
FirstSessionCreated = true;
// HAPI needs to be initialized
if ( !FHoudiniApi::IsHAPIInitialized() )
return false;
// Only start a new Session if we dont have a valid one
if ( HAPI_RESULT_SUCCESS == FHoudiniApi::IsSessionValid( SessionPtr ) )
return true;
HAPI_Result SessionResult = HAPI_RESULT_FAILURE;
HAPI_ThriftServerOptions ServerOptions;
FMemory::Memzero< HAPI_ThriftServerOptions >( ServerOptions );
ServerOptions.autoClose = true;
ServerOptions.timeoutMs = AutomaticServerTimeout;
auto UpdatePathForServer = [&]
{
// Modify our PATH so that HARC will find HARS.exe
const TCHAR* PathDelimiter = FPlatformMisc::GetPathVarDelimiter();
FString OrigPathVar = FPlatformMisc::GetEnvironmentVariable(TEXT("PATH"));
FString ModifiedPath =
#if PLATFORM_MAC
// On Mac our binaries are split between two folders
LibHAPILocation + TEXT( "/../Resources/bin" ) + PathDelimiter +
#endif
LibHAPILocation + PathDelimiter + OrigPathVar;
FPlatformMisc::SetEnvironmentVar( TEXT( "PATH" ), *ModifiedPath );
};
switch ( SessionType )
{
case EHoudiniRuntimeSettingsSessionType::HRSST_InProcess:
{
// As of Unreal 4.19, InProcess sessions are not supported anymore
// We create an auto started pipe session instead using default values
/*
SessionResult = FHoudiniApi::CreateInProcessSession(&this->Session);
#if PLATFORM_WINDOWS
// Workaround for Houdini libtools setting stdout to binary
FWindowsPlatformMisc::SetUTF8Output();
#endif
*/
UpdatePathForServer();
FHoudiniApi::StartThriftNamedPipeServer(
&ServerOptions, TCHAR_TO_UTF8( *ServerPipeName ), nullptr );
SessionResult = FHoudiniApi::CreateThriftNamedPipeSession(
SessionPtr, TCHAR_TO_UTF8( *ServerPipeName ) );
}
break;
case EHoudiniRuntimeSettingsSessionType::HRSST_Socket:
{
// Try to connect to an existing socket session first
SessionResult = FHoudiniApi::CreateThriftSocketSession(
SessionPtr, TCHAR_TO_UTF8(*ServerHost), ServerPort);
// Start a session and try to connect to it if we failed
if (StartAutomaticServer && SessionResult != HAPI_RESULT_SUCCESS)
{
UpdatePathForServer();
FHoudiniApi::StartThriftSocketServer(
&ServerOptions, ServerPort, nullptr );
SessionResult = FHoudiniApi::CreateThriftSocketSession(
SessionPtr, TCHAR_TO_UTF8(*ServerHost), ServerPort );
}
}
break;
case EHoudiniRuntimeSettingsSessionType::HRSST_NamedPipe:
{
// Try to connect to an existing pipe session first
SessionResult = FHoudiniApi::CreateThriftNamedPipeSession(
SessionPtr, TCHAR_TO_UTF8(*ServerPipeName));
// Start a session and try to connect to it if we failed
if (StartAutomaticServer && SessionResult != HAPI_RESULT_SUCCESS)
{
UpdatePathForServer();
FHoudiniApi::StartThriftNamedPipeServer(
&ServerOptions, TCHAR_TO_UTF8( *ServerPipeName ), nullptr );
SessionResult = FHoudiniApi::CreateThriftNamedPipeSession(
SessionPtr, TCHAR_TO_UTF8(*ServerPipeName) );
}
}
break;
default:
HOUDINI_LOG_ERROR( TEXT( "Unsupported Houdini Engine session type" ) );
break;
}
if (SessionResult != HAPI_RESULT_SUCCESS || !SessionPtr)
return false;
return true;
}
bool
FHoudiniEngine::InitializeHAPISession()
{
// The HAPI stubs needs to be initialized
if (!FHoudiniApi::IsHAPIInitialized())
{
HOUDINI_LOG_ERROR(TEXT("Failed to initialize HAPI: The Houdini API stubs have not been properly initialized."));
return false;
}
// We need a Valid Session
if (HAPI_RESULT_SUCCESS != FHoudiniApi::IsSessionValid(&Session))
{
HOUDINI_LOG_ERROR(TEXT("Failed to initialize HAPI: The session is invalid."));
return false;
}
// Now, initialize HAPI with the new session
// We need to make sure HAPI version is correct.
int32 RunningEngineMajor = 0;
int32 RunningEngineMinor = 0;
int32 RunningEngineApi = 0;
// Retrieve version numbers for running Houdini Engine.
FHoudiniApi::GetEnvInt( HAPI_ENVINT_VERSION_HOUDINI_ENGINE_MAJOR, &RunningEngineMajor );
FHoudiniApi::GetEnvInt( HAPI_ENVINT_VERSION_HOUDINI_ENGINE_MINOR, &RunningEngineMinor );
FHoudiniApi::GetEnvInt( HAPI_ENVINT_VERSION_HOUDINI_ENGINE_API, &RunningEngineApi );
// Compare defined and running versions.
if (RunningEngineMajor != HAPI_VERSION_HOUDINI_ENGINE_MAJOR
|| RunningEngineMinor != HAPI_VERSION_HOUDINI_ENGINE_MINOR)
{
// Major or minor HAPI version differs, stop here
HOUDINI_LOG_ERROR(
TEXT("Starting up the Houdini Engine module failed: built and running versions do not match."));
HOUDINI_LOG_ERROR(
TEXT("Defined version: %d.%d.api:%d vs Running version: %d.%d.api:%d"),
HAPI_VERSION_HOUDINI_ENGINE_MAJOR, HAPI_VERSION_HOUDINI_ENGINE_MINOR, HAPI_VERSION_HOUDINI_ENGINE_API,
RunningEngineMajor, RunningEngineMinor, RunningEngineApi);
return false;
}
else if (RunningEngineApi != HAPI_VERSION_HOUDINI_ENGINE_API)
{
// Major/minor HAPIversions match, but only the API version differs,
// Allow the user to continue but warn him of possible instabilities
HOUDINI_LOG_WARNING(
TEXT("Starting up the Houdini Engine module: built and running API versions do not match."));
HOUDINI_LOG_WARNING(
TEXT("Defined version: %d.%d.api:%d vs Running version: %d.%d.api:%d"),
HAPI_VERSION_HOUDINI_ENGINE_MAJOR, HAPI_VERSION_HOUDINI_ENGINE_MINOR, HAPI_VERSION_HOUDINI_ENGINE_API,
RunningEngineMajor, RunningEngineMinor, RunningEngineApi);
HOUDINI_LOG_WARNING(
TEXT("This could cause instabilities and crashes when using the Houdini Engine plugin"));
}
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault< UHoudiniRuntimeSettings >();
// Default CookOptions
HAPI_CookOptions CookOptions;
FHoudiniApi::CookOptions_Init(&CookOptions);
//FMemory::Memzero< HAPI_CookOptions >( CookOptions );
CookOptions.curveRefineLOD = 8.0f;
CookOptions.clearErrorsAndWarnings = true;
CookOptions.maxVerticesPerPrimitive = 3;
CookOptions.splitGeosByGroup = false;
CookOptions.splitGeosByAttribute = false;
CookOptions.splitAttrSH = 0;
CookOptions.refineCurveToLinear = true;
CookOptions.handleBoxPartTypes = false;
CookOptions.handleSpherePartTypes = false;
CookOptions.splitPointsByVertexAttributes = false;
CookOptions.packedPrimInstancingMode = HAPI_PACKEDPRIM_INSTANCING_MODE_FLAT;
HAPI_Result Result = FHoudiniApi::Initialize( &Session, &CookOptions, true,
HoudiniRuntimeSettings->CookingThreadStackSize,
TCHAR_TO_UTF8( *HoudiniRuntimeSettings->HoudiniEnvironmentFiles),
TCHAR_TO_UTF8( *HoudiniRuntimeSettings->OtlSearchPath),
TCHAR_TO_UTF8( *HoudiniRuntimeSettings->DsoSearchPath),
TCHAR_TO_UTF8( *HoudiniRuntimeSettings->ImageDsoSearchPath),
TCHAR_TO_UTF8( *HoudiniRuntimeSettings->AudioDsoSearchPath) );
if ( Result != HAPI_RESULT_SUCCESS )
{
HOUDINI_LOG_MESSAGE(
TEXT("Starting up the Houdini Engine API module failed: %s"),
*FHoudiniEngineUtils::GetErrorDescription( Result ) );
return false;
}
HOUDINI_LOG_MESSAGE( TEXT( "Successfully intialized the Houdini Engine API module." ) );
FHoudiniApi::SetServerEnvString(&Session, HAPI_ENV_CLIENT_NAME, HAPI_UNREAL_CLIENT_NAME );
return true;
}
bool
FHoudiniEngine::StopSession( HAPI_Session*& SessionPtr )
{
// HAPI needs to be initialized
if ( !FHoudiniApi::IsHAPIInitialized() )
return false;
if ( HAPI_RESULT_SUCCESS == FHoudiniApi::IsSessionValid( SessionPtr ) )
{
// SessionPtr is valid, clean up and close the session
FHoudiniApi::Cleanup( SessionPtr );
FHoudiniApi::CloseSession( SessionPtr );
}
return true;
}
bool
FHoudiniEngine::RestartSession()
{
HAPI_Session* SessionPtr = &Session;
// Stop the current session if it is still valid
if ( !StopSession( SessionPtr ) )
return false;
// Try to reconnect/start a new session
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault< UHoudiniRuntimeSettings >();
if (!StartSession(
SessionPtr, true,
HoudiniRuntimeSettings->AutomaticServerTimeout,
HoudiniRuntimeSettings->SessionType,
HoudiniRuntimeSettings->ServerPipeName,
HoudiniRuntimeSettings->ServerPort,
HoudiniRuntimeSettings->ServerHost))
{
HOUDINI_LOG_ERROR(TEXT("Failed to restart the Houdini Engine session"));
return false;
}
// Now initialize HAPI for this session
if (!InitializeHAPISession())
return false;
return true;
}
bool
FHoudiniEngine::GetFirstSessionCreated() const
{
return FirstSessionCreated;
}
#undef LOCTEXT_NAMESPACE