696 lines
23 KiB
C++
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
|