573 lines
22 KiB
C++
573 lines
22 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 "HoudiniEngineCommandlet.h"
|
|
|
|
#include "HoudiniApi.h"
|
|
#include "HoudiniEngine.h"
|
|
#include "HoudiniEngineUtils.h"
|
|
#include "HoudiniEngineBakeUtils.h"
|
|
#include "HoudiniAssetComponent.h"
|
|
#include "HoudiniEngineRuntimePrivatePCH.h"
|
|
#include "CoreMinimal.h"
|
|
#include "Engine/StaticMesh.h"
|
|
#include "HAL/PlatformFilemanager.h"
|
|
#include "HAL/FileManagerGeneric.h"
|
|
|
|
|
|
const FString LocalAutoBakeFolder = TEXT("/HoudiniEngine/AutoBake/");
|
|
|
|
UHoudiniEngineConvertBgeoCommandlet::UHoudiniEngineConvertBgeoCommandlet()
|
|
{
|
|
IsClient = false;
|
|
IsEditor = true;
|
|
IsServer = false;
|
|
LogToConsole = true;
|
|
}
|
|
|
|
int32 UHoudiniEngineConvertBgeoCommandlet::Main( const FString& Params )
|
|
{
|
|
// Run me via UE4editor.exe my.uproject -run=HoudiniEngineConvertBgeo BGEO_IN (UASSET_OUT)
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Houdini Engine Convert BGEO Commandlet" ) );
|
|
|
|
// Parse the params to a string arrays
|
|
TArray<FString> ArgumentsArray;
|
|
Params.ParseIntoArray(ArgumentsArray, TEXT(" "), true);
|
|
|
|
// We're expecting at least one param (the bgeo in) and a maximum of 2 params (bgeo in, uasset out)
|
|
// The first param is the Commandlet name, so ignore that
|
|
if ( ( ArgumentsArray.Num() < 2 ) || ( ArgumentsArray.Num() > 3 ) )
|
|
{
|
|
// Invalid number of arguments, Print usage and error out
|
|
HOUDINI_LOG_MESSAGE( TEXT( "HoudiniEngineConvertBgeoCommandlet" ) );
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Converts a .bgeo file to Static Meshes .uasset files." ) );
|
|
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Usage: -run=HoudiniEngineConvertBgeo BGEO_IN UASSET_OUT" ) );
|
|
|
|
HOUDINI_LOG_MESSAGE( TEXT( "BGEO_IN" ) );
|
|
HOUDINI_LOG_MESSAGE( TEXT( "\tPath to the the source .bgeo file to convert." ) );
|
|
|
|
HOUDINI_LOG_MESSAGE( TEXT( "UASSET_OUT (optional)" ) );
|
|
HOUDINI_LOG_MESSAGE( TEXT( "\tPath for the converted uasset file. If not present, the directory/name of the bgeo file will be used" ) );
|
|
|
|
return 1;
|
|
}
|
|
|
|
FString BGEOFilePath = ArgumentsArray[ 1 ];
|
|
FString UASSETFilePath = ArgumentsArray.Num() > 2 ? ArgumentsArray[ 2 ] : FString();
|
|
|
|
if ( !FHoudiniCommandletUtils::ConvertBGEOFileToUAsset( BGEOFilePath, UASSETFilePath ) )
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
UHoudiniEngineConvertBgeoDirCommandlet::UHoudiniEngineConvertBgeoDirCommandlet()
|
|
{
|
|
IsClient = false;
|
|
IsEditor = true;
|
|
IsServer = false;
|
|
LogToConsole = true;
|
|
}
|
|
|
|
int32 UHoudiniEngineConvertBgeoDirCommandlet::Main(const FString& Params)
|
|
{
|
|
// Run me via UE4editor.exe my.uproject -run=HoudiniEngineConvertBgeoDir BGEO_DIR_IN (UASSET_DIR_OUT)
|
|
HOUDINI_LOG_MESSAGE(TEXT("Houdini Engine Convert BGEO directory"));
|
|
|
|
// Parse the params to a string arrays
|
|
TArray<FString> ArgumentsArray;
|
|
Params.ParseIntoArray(ArgumentsArray, TEXT(" "), true);
|
|
|
|
// We're expecting at least one param (the bgeo dir in) and a maximum of 3 params (bgeo dir in, uasset dir out, timeout)
|
|
// The first param is the Commandlet name, so ignore that
|
|
if ( (ArgumentsArray.Num() < 1 ) || ( ArgumentsArray.Num() > 3 ) )
|
|
{
|
|
// Invalid number of arguments, Print usage and error out
|
|
HOUDINI_LOG_MESSAGE(TEXT("HoudiniEngineTestCommandlet:"));
|
|
HOUDINI_LOG_MESSAGE(TEXT("Converts .bgeo files in directory to Static Meshes .uasset files in a Out directory."));
|
|
|
|
HOUDINI_LOG_MESSAGE(TEXT("Usage: -run=HoudiniEngineConvertBgeoDir BGEO_DIR_IN UASSET_DIR_OUT TIMEOUT"));
|
|
|
|
HOUDINI_LOG_MESSAGE(TEXT("BGEO_DIR_IN"));
|
|
HOUDINI_LOG_MESSAGE(TEXT("\tPath to a directory containing the .bgeo files to convert."));
|
|
|
|
HOUDINI_LOG_MESSAGE(TEXT("UASSET_DIR_OUT (optional)"));
|
|
HOUDINI_LOG_MESSAGE(TEXT("\tPath for the converted uasset files."));
|
|
|
|
HOUDINI_LOG_MESSAGE(TEXT("TIMEOUT (optional)"));
|
|
HOUDINI_LOG_MESSAGE(TEXT("\tAfter this amount of time of inactivity, the commandlet will exit."));
|
|
|
|
return 1;
|
|
}
|
|
|
|
FString BGEODirPath = ArgumentsArray[ 0 ];
|
|
FString UASSETDirPath = ArgumentsArray.Num() > 1 ? ArgumentsArray[ 1 ] : BGEODirPath;
|
|
FString InactivityTimeOutStr = ArgumentsArray.Num() > 3 ? ArgumentsArray[ 2 ] : FString();
|
|
float InactivityTimeOut = 1000.0f;
|
|
if ( InactivityTimeOutStr.IsNumeric() )
|
|
InactivityTimeOut = FCString::Atof( *InactivityTimeOutStr );
|
|
|
|
// First check the source directory is valid
|
|
if ( !FPaths::DirectoryExists( BGEODirPath ) )
|
|
{
|
|
// Cant find input BGEO dir
|
|
HOUDINI_LOG_ERROR( TEXT( "The source BGEO directory does not exist: %s" ), *BGEODirPath );
|
|
return false;
|
|
}
|
|
|
|
// Then the output directory
|
|
if ( !FPaths::DirectoryExists( UASSETDirPath ) )
|
|
{
|
|
// Cant find Output dir
|
|
HOUDINI_LOG_ERROR( TEXT( "The output UASSET directory does not exist: %s" ), *UASSETDirPath );
|
|
return false;
|
|
}
|
|
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Looking for .bgeo files in %s ." ), *BGEODirPath );
|
|
|
|
// Sleep time in seconds before listing the files again
|
|
const float SleepTime = 1.0f;
|
|
// Maximum number of conversion for a file
|
|
const int32 NumConvertAttempts = 2;
|
|
// If true, will literally try to erase all files before overwriting them
|
|
// Will also empty the "local" directory
|
|
const bool CrushFiles = true;
|
|
|
|
// If true, source bgeo files will be deleted upon conversion
|
|
const bool DeleteFileAfterConversion = false;
|
|
|
|
if ( CrushFiles )
|
|
{
|
|
// Nuke everything in our temporary bake folder
|
|
FFileManagerGeneric::Get().DeleteDirectory( *LocalAutoBakeFolder, false, true );
|
|
}
|
|
|
|
// Map tracking the number of failures for a given file
|
|
TMap< FString, int32 > FailingFileMap;
|
|
|
|
// M<ap listing the files that couldn't/weren't removed
|
|
TArray< FString > UndeletedFileMap;
|
|
|
|
bool KeepLookingForFile = true;
|
|
float currentInactivity = 0.0f;
|
|
while ( KeepLookingForFile )
|
|
{
|
|
// List all the .bgeo files in the directory
|
|
TArray< FString > CurrentFileList;
|
|
FFileManagerGeneric::Get().FindFiles( CurrentFileList, *BGEODirPath, TEXT( ".bgeo" ) );
|
|
|
|
// Convert the files we found
|
|
int32 ConversionCount = 0;
|
|
for ( int32 n = CurrentFileList.Num() - 1; n >= 0; n-- )
|
|
{
|
|
FString CurrentFile = CurrentFileList[ n ];
|
|
|
|
// Skip undeleted files
|
|
if ( UndeletedFileMap.Contains( CurrentFile ) )
|
|
continue;
|
|
|
|
// Skip failing files
|
|
if ( FailingFileMap.Contains(CurrentFile) && FailingFileMap[ CurrentFile ] >= NumConvertAttempts )
|
|
continue;
|
|
|
|
// Build the in / out file names
|
|
FString BGEOFile = BGEODirPath + TEXT("/") + CurrentFileList[ n ];
|
|
FString UASSETFile = UASSETDirPath + TEXT("/") + CurrentFileList[ n ].LeftChop(5) + TEXT(".uasset");
|
|
|
|
if ( CrushFiles )
|
|
{
|
|
if ( FFileManagerGeneric::Get().FileExists( *UASSETFile ) )
|
|
{
|
|
// Erase the file if it already exists!
|
|
FFileManagerGeneric::Get().Delete( *UASSETFile, false, true, true );
|
|
}
|
|
}
|
|
|
|
// Attempting to convert the file
|
|
ConversionCount++;
|
|
if ( !FHoudiniCommandletUtils::ConvertBGEOFileToUAsset( BGEOFile, UASSETFile ) )
|
|
{
|
|
if ( FailingFileMap.Contains( CurrentFile ) )
|
|
FailingFileMap[ CurrentFile ]++;
|
|
else
|
|
FailingFileMap.Add( CurrentFile, 1 );
|
|
|
|
continue;
|
|
}
|
|
|
|
HOUDINI_LOG_MESSAGE(TEXT("Successfully converted BGEO file: %s to %s"), *BGEOFile, *UASSETFile );
|
|
|
|
// Delete the source BGEO
|
|
if ( !DeleteFileAfterConversion || !FFileManagerGeneric::Get().Delete( *BGEOFile, false, true, true ) )
|
|
UndeletedFileMap.Add( CurrentFile );
|
|
}
|
|
|
|
// Update the inactivity counter
|
|
if ( ConversionCount == 0 )
|
|
{
|
|
currentInactivity += SleepTime;
|
|
if ( (InactivityTimeOut > 0.0f ) && ( currentInactivity > InactivityTimeOut ) )
|
|
KeepLookingForFile = false;
|
|
}
|
|
else
|
|
{
|
|
// reset the inactivity counter
|
|
currentInactivity = 0.0f;
|
|
}
|
|
|
|
if ( CrushFiles )
|
|
{
|
|
// Nuke everything in our temporary bake folder
|
|
FFileManagerGeneric::Get().DeleteDirectory(*LocalAutoBakeFolder, false, true);
|
|
}
|
|
|
|
// Go to bed for a while...
|
|
FPlatformProcess::Sleep( SleepTime );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool FHoudiniCommandletUtils::ConvertBGEOFileToUAsset( const FString& InBGEOFilePath, const FString& OutUAssetFilePath )
|
|
{
|
|
#if WITH_EDITOR
|
|
//---------------------------------------------------------------------------------------------
|
|
// 1. Handle the BGEO param
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
FString BGEOFilePath = InBGEOFilePath;
|
|
if ( !FPaths::FileExists( BGEOFilePath ) )
|
|
{
|
|
// Cant find BGEO file
|
|
HOUDINI_LOG_ERROR( TEXT( "BGEO file %s could not be found!" ), *BGEOFilePath );
|
|
return false;
|
|
}
|
|
|
|
// Make sure we're using absolute path!
|
|
BGEOFilePath = FPaths::ConvertRelativePathToFull( BGEOFilePath );
|
|
|
|
// Split the file path
|
|
FString BGEOPath, BGEOFileName, BGEOExtension;
|
|
FPaths::Split( BGEOFilePath, BGEOPath, BGEOFileName, BGEOExtension );
|
|
if ( BGEOExtension.IsEmpty() )
|
|
BGEOExtension = TEXT("bgeo");
|
|
|
|
if ( BGEOExtension.Compare( TEXT("bgeo"), ESearchCase::IgnoreCase ) != 0 )
|
|
{
|
|
// Not a bgeo file!
|
|
HOUDINI_LOG_ERROR( TEXT( "First argument %s is not a .bgeo FILE!"), *BGEOFilePath );
|
|
return false;
|
|
}
|
|
|
|
BGEOFilePath = BGEOPath + TEXT("/") + BGEOFileName + TEXT(".") + BGEOExtension;
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 2. Handle the UASSET param
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
FString UASSETFilePath = OutUAssetFilePath;
|
|
if ( UASSETFilePath.IsEmpty() )
|
|
{
|
|
// No OUT parameter, build it from the bgeo
|
|
UASSETFilePath = BGEOPath + TEXT("/") + BGEOFileName + TEXT(".uasset");
|
|
HOUDINI_LOG_MESSAGE( TEXT( "UASSET_OUT argument missing! Will use %s.") , *UASSETFilePath);
|
|
}
|
|
|
|
// Make sure we're using absolute path!
|
|
UASSETFilePath = FPaths::ConvertRelativePathToFull( UASSETFilePath );
|
|
if ( FPaths::FileExists( UASSETFilePath ) )
|
|
{
|
|
// UAsset already exists, overwrite?
|
|
HOUDINI_LOG_MESSAGE( TEXT( "UASSET file : %s already exists, overwriting!"), *UASSETFilePath );
|
|
}
|
|
|
|
// Split the file path
|
|
FString UASSETPath, UASSETFileName, UASSETExtension;
|
|
FPaths::Split( UASSETFilePath, UASSETPath, UASSETFileName, UASSETExtension );
|
|
|
|
UASSETFilePath = UASSETPath + TEXT("/") + UASSETFileName + TEXT(".") + UASSETExtension;
|
|
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Converting BGEO file: %s to UASSET file : %s" ), *BGEOFilePath, *UASSETFilePath );
|
|
|
|
// ERROR Lambda
|
|
// Saves a debug HIP file through HEngine and returns an error (in case of HAPI/HEngine issue).
|
|
auto SaveDebugHipFileAndReturnError = [&]()
|
|
{
|
|
FString HipFileName = BGEOPath + BGEOFileName + TEXT(".hip");
|
|
std::string HipFileNameStr = TCHAR_TO_ANSI(*HipFileName);
|
|
FHoudiniApi::SaveHIPFile(FHoudiniEngine::Get().GetSession(), HipFileNameStr.c_str(), false);
|
|
|
|
return false;
|
|
};
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 3. Load the bgeo file in HAPI
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
HAPI_NodeId NodeId = -1;
|
|
if ( !FHoudiniCommandletUtils::LoadBGEOFileInHAPI( BGEOFilePath, NodeId) )
|
|
return SaveDebugHipFileAndReturnError();
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 4. Create a package for the result
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
FString PackagePath = LocalAutoBakeFolder + UASSETFileName;
|
|
FString PackageFilePath = UPackageTools::SanitizePackageName( PackagePath );
|
|
UPackage * Package = FindPackage( nullptr, *PackageFilePath );
|
|
if ( !Package )
|
|
{
|
|
// Create actual package.
|
|
Package = CreatePackage( nullptr, *PackageFilePath );
|
|
if ( !Package )
|
|
{
|
|
// Couldn't create the package
|
|
HOUDINI_LOG_ERROR( TEXT( "Could not create local Package for the UASSET !!!" ) );
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Package already exists, overwrite?
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Package %s already exists, overwriting!" ), *PackageFilePath );
|
|
}
|
|
|
|
// ERROR Lambda
|
|
// Tries to delete the local package and creates an error ( in case of UE4/Package error)
|
|
auto DeleteLocalPackageAndReturnError = [&]()
|
|
{
|
|
FFileManagerGeneric::Get().Delete( *PackageFilePath, false, true, true );
|
|
return SaveDebugHipFileAndReturnError();
|
|
};
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 5. Create the Static Meshes from the result of the bgeo cooking
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
TMap< FHoudiniGeoPartObject, UStaticMesh * > StaticMeshesOut;
|
|
if ( !FHoudiniCommandletUtils::CreateStaticMeshes(
|
|
BGEOFileName, NodeId, Package, StaticMeshesOut ) )
|
|
{
|
|
// There was some cook errors
|
|
HOUDINI_LOG_ERROR(TEXT("Could not create Static Meshes from the bgeo!!!"));
|
|
return SaveDebugHipFileAndReturnError();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 6. Bake the resulting Static Meshes to the package
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
if ( !FHoudiniCommandletUtils::BakeStaticMeshesToPackage( BGEOFileName, StaticMeshesOut, Package ) )
|
|
return SaveDebugHipFileAndReturnError();
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 7. Delete the node in Houdini
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
if ( HAPI_RESULT_SUCCESS != FHoudiniApi::DeleteNode( FHoudiniEngine::Get().GetSession(), NodeId ) )
|
|
{
|
|
// Could not delete the bgeo's file sop !
|
|
HOUDINI_LOG_WARNING( TEXT( "Could not delete the bgeo file sop for %s"), * BGEOFileName );
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 8. Save the package
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
Package->SetDirtyFlag( true );
|
|
Package->FullyLoad();
|
|
|
|
FString LocalPackageFileName = FPackageName::LongPackageNameToFilename( PackageFilePath, FPackageName::GetAssetPackageExtension() );
|
|
if (!UPackage::SavePackage(Package, NULL, RF_Standalone, *LocalPackageFileName, GError, nullptr, false, true, SAVE_NoError))
|
|
{
|
|
// There was some cook errors
|
|
HOUDINI_LOG_ERROR( TEXT( "Could not save the local package %s"), *PackageFilePath );
|
|
return DeleteLocalPackageAndReturnError();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// 9. Move the local package to its final destination
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
LocalPackageFileName = FPaths::ConvertRelativePathToFull( LocalPackageFileName );
|
|
if (!FFileManagerGeneric::Get().Move(*UASSETFilePath, *LocalPackageFileName, true, true, false, false ) )
|
|
{
|
|
HOUDINI_LOG_ERROR( TEXT("Could not move local package %s to %s"), *LocalPackageFileName, *UASSETFilePath);
|
|
return DeleteLocalPackageAndReturnError();
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FHoudiniCommandletUtils::LoadBGEOFileInHAPI( const FString& InputFilePath, HAPI_NodeId& NodeId )
|
|
{
|
|
NodeId = -1;
|
|
|
|
// Check HoudiniEngine / HAPI init?
|
|
if ( !FHoudiniEngine::IsInitialized() )
|
|
{
|
|
HOUDINI_LOG_ERROR( TEXT( "Couldn't initialize HoudiniEngine!") );
|
|
return false;
|
|
}
|
|
|
|
// Create a file SOP
|
|
HOUDINI_CHECK_ERROR_RETURN( FHoudiniApi::CreateNode(
|
|
FHoudiniEngine::Get().GetSession(), -1,
|
|
"SOP/file", "bgeo", true, &NodeId ), false );
|
|
|
|
// Set the file path parameter
|
|
HAPI_ParmId ParmId = -1;
|
|
HOUDINI_CHECK_ERROR_RETURN( FHoudiniApi::GetParmIdFromName(
|
|
FHoudiniEngine::Get().GetSession(),
|
|
NodeId, "file", &ParmId), false );
|
|
|
|
std::string ConvertedString = TCHAR_TO_UTF8( *InputFilePath );
|
|
HOUDINI_CHECK_ERROR_RETURN( FHoudiniApi::SetParmStringValue(
|
|
FHoudiniEngine::Get().GetSession(), NodeId, ConvertedString.c_str(), ParmId, 0 ), false );
|
|
|
|
// Cook the node
|
|
HAPI_CookOptions CookOptions;
|
|
FHoudiniApi::CookOptions_Init(&CookOptions);
|
|
//FMemory::Memzero< HAPI_CookOptions >( CookOptions );
|
|
CookOptions.curveRefineLOD = 8.0f;
|
|
CookOptions.clearErrorsAndWarnings = false;
|
|
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;
|
|
HOUDINI_CHECK_ERROR_RETURN( FHoudiniApi::CookNode(
|
|
FHoudiniEngine::Get().GetSession(), NodeId, &CookOptions ), false );
|
|
|
|
// Wait for the cook to finish
|
|
int status = HAPI_STATE_MAX_READY_STATE + 1;
|
|
while ( status > HAPI_STATE_MAX_READY_STATE )
|
|
{
|
|
// Retrieve the status
|
|
HOUDINI_CHECK_ERROR_RETURN( FHoudiniApi::GetStatus(
|
|
FHoudiniEngine::Get().GetSession(),
|
|
HAPI_STATUS_COOK_STATE, &status ), false );
|
|
|
|
FString StatusString = FHoudiniEngineUtils::GetStatusString( HAPI_STATUS_COOK_STATE, HAPI_STATUSVERBOSITY_ERRORS );
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Still Cooking, current status: %s." ), *StatusString );
|
|
|
|
// Go to bed..
|
|
if ( status > HAPI_STATE_MAX_READY_STATE )
|
|
FPlatformProcess::Sleep( 0.5f );
|
|
}
|
|
|
|
if ( status != HAPI_STATE_READY )
|
|
{
|
|
// There was some cook errors
|
|
HOUDINI_LOG_ERROR( TEXT("Finished Cooking with errors!") );
|
|
return false;
|
|
}
|
|
|
|
HOUDINI_LOG_MESSAGE( TEXT( "Finished Cooking!" ) );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FHoudiniCommandletUtils::CreateStaticMeshes(
|
|
const FString& InputName, HAPI_NodeId& NodeId, UPackage* OuterPackage,
|
|
TMap<FHoudiniGeoPartObject, UStaticMesh *>& StaticMeshesOut )
|
|
{
|
|
if (!OuterPackage || OuterPackage->IsPendingKill())
|
|
return false;
|
|
|
|
// Create a "fake" HoudiniAssetComponent
|
|
FName HACName( *InputName );
|
|
UHoudiniAssetComponent* HoudiniAssetComponent = NewObject< UHoudiniAssetComponent >( OuterPackage, HACName );
|
|
|
|
// Create the CookParams
|
|
FHoudiniCookParams HoudiniCookParams( HoudiniAssetComponent );
|
|
HoudiniCookParams.StaticMeshBakeMode = EBakeMode::CookToTemp; // EBakeMode::CreateNewAssets?
|
|
HoudiniCookParams.MaterialAndTextureBakeMode = EBakeMode::CookToTemp; // FHoudiniCookParams::GetDefaultMaterialAndTextureCookMode()?
|
|
|
|
FTransform ComponentTransform;
|
|
TMap< FHoudiniGeoPartObject, UStaticMesh * > StaticMeshesIn;
|
|
//TMap< FHoudiniGeoPartObject, UStaticMesh * > StaticMeshesOut;
|
|
|
|
// Create the Static Meshes from the cook result
|
|
bool ProcessResult = FHoudiniEngineUtils::CreateStaticMeshesFromHoudiniAsset(
|
|
NodeId, HoudiniCookParams, true, true,
|
|
StaticMeshesIn, StaticMeshesOut, ComponentTransform );
|
|
|
|
if ( !ProcessResult || StaticMeshesOut.Num() <= 0 )
|
|
{
|
|
// There was some cook errors
|
|
HOUDINI_LOG_ERROR( TEXT( "Could not create Static Meshes from the bgeo!!!" ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FHoudiniCommandletUtils::BakeStaticMeshesToPackage(
|
|
const FString& InputName, TMap<FHoudiniGeoPartObject, UStaticMesh *>& StaticMeshes, UPackage* OutPackage )
|
|
{
|
|
bool BakedSomething = false;
|
|
for ( TMap< FHoudiniGeoPartObject, UStaticMesh * >::TIterator Iter( StaticMeshes ); Iter; ++Iter )
|
|
{
|
|
// Get the Static Mesh
|
|
const FHoudiniGeoPartObject HoudiniGeoPartObject = Iter.Key();
|
|
UStaticMesh* CurrentSM = Iter.Value();
|
|
if ( !CurrentSM )
|
|
continue;
|
|
|
|
// Build a name for this Static Mesh
|
|
FName StaticMeshName = FName( *( InputName + CurrentSM->GetName() ) );
|
|
|
|
// Duplicate the Static MEsh to copy it to the package.
|
|
UStaticMesh* DuplicatedStaticMesh = DuplicateObject< UStaticMesh >( CurrentSM, OutPackage, StaticMeshName );
|
|
if ( !DuplicatedStaticMesh )
|
|
continue;
|
|
|
|
// Set the proper flags on the duplicated mesh
|
|
DuplicatedStaticMesh->SetFlags( RF_Public | RF_Standalone );
|
|
|
|
// Notify the registry that we have created a new duplicate mesh.
|
|
FAssetRegistryModule::AssetCreated( DuplicatedStaticMesh );
|
|
|
|
// Dirty the static mesh package.
|
|
DuplicatedStaticMesh->MarkPackageDirty();
|
|
BakedSomething = true;
|
|
}
|
|
|
|
if ( !BakedSomething )
|
|
{
|
|
// There was some cook errors
|
|
HOUDINI_LOG_ERROR( TEXT( "Could not create Static Meshes from the bgeo!!!" ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|