2019-12-26 15:32:37 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-04 13:11:45 -04:00
# include "DatasmithMeshExporter.h"
2022-03-23 16:31:37 -04:00
# include "DatasmithCore.h"
2024-04-26 06:13:46 -04:00
# include "DatasmithCloth.h" // UE_DEPRECATED(5.5, "The experimental Cloth importer is no longer supported.")
2020-09-24 00:43:27 -04:00
# include "DatasmithExporterManager.h"
2019-10-04 13:11:45 -04:00
# include "DatasmithMesh.h"
# include "DatasmithMeshUObject.h"
2022-03-25 14:12:48 -04:00
# include "DatasmithMeshSerialization.h"
2019-10-04 13:11:45 -04:00
# include "DatasmithSceneFactory.h"
# include "DatasmithUtils.h"
2020-02-17 13:28:31 -05:00
# include "Containers/LockFreeList.h"
2019-10-04 13:11:45 -04:00
# include "HAL/FileManager.h"
2020-03-18 11:01:39 -04:00
# include "Misc/Guid.h"
2019-10-04 13:11:45 -04:00
# include "Misc/Paths.h"
# include "Serialization/MemoryWriter.h"
2021-03-05 19:27:14 -04:00
2022-03-23 16:31:37 -04:00
struct FDatasmithMeshExporterOptions
{
2022-08-16 08:22:50 -04:00
FDatasmithMeshExporterOptions ( const FString & InFullPath , FDatasmithMesh & InMesh , EDSExportLightmapUV InLightmapUV , FDatasmithMesh * InCollisionMesh = nullptr )
: MeshFullPath ( InFullPath )
, Mesh ( InMesh )
, LightmapUV ( InLightmapUV )
, CollisionMesh ( InCollisionMesh )
2022-03-23 16:31:37 -04:00
{ }
FString MeshFullPath ;
FDatasmithMesh & Mesh ;
EDSExportLightmapUV LightmapUV ;
FDatasmithMesh * CollisionMesh ;
} ;
2022-03-25 14:12:48 -04:00
class FDatasmithMeshExporterImpl
2020-02-17 13:28:31 -05:00
{
2022-03-23 16:31:37 -04:00
public :
2022-08-16 08:22:50 -04:00
bool DoExport ( TSharedPtr < IDatasmithMeshElement > & MeshElement , const FDatasmithMeshExporterOptions & ExportOptions ) ;
2022-03-23 16:31:37 -04:00
FString LastError ;
private :
bool WriteMeshFile ( const FDatasmithMeshExporterOptions & ExporterOptions , FMD5Hash & OutHash ) ;
} ;
2022-08-16 08:22:50 -04:00
bool FDatasmithMeshExporterImpl : : DoExport ( TSharedPtr < IDatasmithMeshElement > & MeshElement , const FDatasmithMeshExporterOptions & ExportOptions )
2022-03-23 16:31:37 -04:00
{
FDatasmithMesh & Mesh = ExportOptions . Mesh ;
// If the mesh doesn't have a name, use the filename as its name
2022-08-16 08:22:50 -04:00
if ( FCString : : Strlen ( Mesh . GetName ( ) ) = = 0 )
2022-03-23 16:31:37 -04:00
{
2022-08-16 08:22:50 -04:00
Mesh . SetName ( * FPaths : : GetBaseFilename ( ExportOptions . MeshFullPath ) ) ;
2022-03-23 16:31:37 -04:00
}
FMD5Hash Hash ;
2022-08-16 08:22:50 -04:00
if ( WriteMeshFile ( ExportOptions , Hash ) )
2022-03-23 16:31:37 -04:00
{
// If no existing MeshElement provided, create one.
2022-08-16 08:22:50 -04:00
if ( ! MeshElement )
2022-03-23 16:31:37 -04:00
{
2022-08-16 08:22:50 -04:00
MeshElement = FDatasmithSceneFactory : : CreateMesh ( Mesh . GetName ( ) ) ;
2022-03-23 16:31:37 -04:00
}
2022-08-16 08:22:50 -04:00
MeshElement - > SetFile ( * ExportOptions . MeshFullPath ) ;
MeshElement - > SetFileHash ( Hash ) ;
2022-03-23 16:31:37 -04:00
2022-03-28 16:55:59 -04:00
FBox3f Extents = Mesh . GetExtents ( ) ;
2022-03-23 16:31:37 -04:00
float Width = Extents . Max [ 0 ] - Extents . Min [ 0 ] ;
float Height = Extents . Max [ 2 ] - Extents . Min [ 2 ] ;
float Depth = Extents . Max [ 1 ] - Extents . Min [ 1 ] ;
2022-08-16 08:22:50 -04:00
MeshElement - > SetDimensions ( Mesh . ComputeArea ( ) , Width , Height , Depth ) ;
MeshElement - > SetLightmapSourceUV ( Mesh . GetLightmapSourceUVChannel ( ) ) ;
2022-03-23 16:31:37 -04:00
return true ;
}
else
{
2022-08-24 09:23:49 -04:00
UE_LOG ( LogDatasmith , Warning , TEXT ( " Cannot export mesh %s: %s " ) , Mesh . GetName ( ) , * LastError ) ;
2022-03-23 16:31:37 -04:00
}
return false ;
2020-02-17 13:28:31 -05:00
}
2019-10-04 13:11:45 -04:00
2022-08-16 08:22:50 -04:00
FDatasmithMeshExporter : : FDatasmithMeshExporter ( )
: Impl ( MakeUnique < FDatasmithMeshExporterImpl > ( ) )
2022-03-23 16:31:37 -04:00
{ }
2022-08-16 08:22:50 -04:00
2022-03-23 16:31:37 -04:00
FDatasmithMeshExporter : : ~ FDatasmithMeshExporter ( ) = default ;
2022-08-16 08:22:50 -04:00
FString GetMeshFilePath ( const TCHAR * Filepath , const TCHAR * Filename )
2022-03-23 16:31:37 -04:00
{
FString NormalizedFilepath = Filepath ;
2022-08-16 08:22:50 -04:00
FPaths : : NormalizeDirectoryName ( NormalizedFilepath ) ;
2022-03-23 16:31:37 -04:00
FString NormalizedFilename = Filename ;
2022-08-16 08:22:50 -04:00
FPaths : : NormalizeFilename ( NormalizedFilename ) ;
2022-03-23 16:31:37 -04:00
2022-08-16 08:22:50 -04:00
return FPaths : : Combine ( * NormalizedFilepath , FPaths : : SetExtension ( NormalizedFilename , UDatasmithMesh : : GetFileExtension ( ) ) ) ;
2022-03-23 16:31:37 -04:00
}
2022-08-16 08:22:50 -04:00
bool FDatasmithMeshExporterImpl : : WriteMeshFile ( const FDatasmithMeshExporterOptions & ExporterOptions , FMD5Hash & OutHash )
2022-03-23 16:31:37 -04:00
{
FDatasmithPackedMeshes Pack ;
auto PackMeshModels = [ & ] ( FDatasmithMesh & Mesh , bool bIsCollisionMesh ) - > FDatasmithMeshModels
{
FDatasmithMeshModels Models ;
Models . bIsCollisionMesh = bIsCollisionMesh ;
Models . MeshName = Mesh . GetName ( ) ;
Models . SourceModels . Reserve ( Mesh . GetLODsCount ( ) + 1 ) ;
FMeshDescription & BaseMeshDescription = Models . SourceModels . AddDefaulted_GetRef ( ) ;
2022-08-16 12:53:38 -04:00
FDatasmithMeshUtils : : ToMeshDescription ( Mesh , BaseMeshDescription , FDatasmithMeshUtils : : GenerateBox ) ;
2022-03-23 16:31:37 -04:00
for ( int32 LodIndex = 0 ; LodIndex < Mesh . GetLODsCount ( ) ; + + LodIndex )
{
2022-08-16 12:53:38 -04:00
if ( FDatasmithMesh * LodMesh = Mesh . GetLOD ( LodIndex ) )
2022-03-23 16:31:37 -04:00
{
FMeshDescription & LodMeshDescription = Models . SourceModels . AddDefaulted_GetRef ( ) ;
2022-08-16 12:53:38 -04:00
FDatasmithMeshUtils : : ToMeshDescription ( * LodMesh , LodMeshDescription , FDatasmithMeshUtils : : GenerateBox ) ;
2022-03-23 16:31:37 -04:00
}
}
return Models ;
} ;
2022-05-23 08:40:15 -04:00
Pack . Meshes . Add ( PackMeshModels ( ExporterOptions . Mesh , false ) ) ;
2022-03-23 16:31:37 -04:00
if ( ExporterOptions . CollisionMesh )
{
2022-05-23 08:40:15 -04:00
Pack . Meshes . Add ( PackMeshModels ( * ExporterOptions . CollisionMesh , true ) ) ;
2022-03-23 16:31:37 -04:00
}
2022-08-16 08:22:50 -04:00
TUniquePtr < FArchive > Archive ( IFileManager : : Get ( ) . CreateFileWriter ( * ExporterOptions . MeshFullPath ) ) ;
2022-03-23 16:31:37 -04:00
if ( ! Archive . IsValid ( ) )
{
2022-08-16 08:22:50 -04:00
LastError = FString : : Printf ( TEXT ( " Failed writing to file %s " ) , * ExporterOptions . MeshFullPath ) ;
2022-03-23 16:31:37 -04:00
return false ;
}
int32 LegacyMeshCount = 0 ;
* Archive < < LegacyMeshCount ; // the legacy importer expect a mesh count on the first bytes. Just in case a new file would end up parsed by the legacy code...
2022-04-01 11:50:17 -04:00
OutHash = Pack . Serialize ( * Archive ) ;
2022-03-23 16:31:37 -04:00
return ! Archive - > IsError ( ) ;
}
2022-08-16 08:22:50 -04:00
TSharedPtr < IDatasmithMeshElement > FDatasmithMeshExporter : : ExportToUObject ( const TCHAR * Filepath , const TCHAR * Filename , FDatasmithMesh & Mesh , FDatasmithMesh * CollisionMesh , EDSExportLightmapUV LightmapUV )
2020-09-24 00:43:27 -04:00
{
2022-08-16 08:22:50 -04:00
FString FullPath ( GetMeshFilePath ( Filepath , Filename ) ) ;
2019-10-04 13:11:45 -04:00
2020-09-24 00:43:27 -04:00
TSharedPtr < IDatasmithMeshElement > ExportedMeshElement ;
2022-08-26 13:20:02 -04:00
FDatasmithMeshExporterOptions ExportOptions ( FullPath , Mesh , LightmapUV , CollisionMesh ) ;
2022-08-16 08:22:50 -04:00
Impl - > DoExport ( ExportedMeshElement , ExportOptions ) ;
2020-11-24 18:42:39 -04:00
2020-09-24 00:43:27 -04:00
return ExportedMeshElement ;
}
2022-04-01 11:50:17 -04:00
2022-08-16 08:22:50 -04:00
bool FDatasmithMeshExporter : : ExportToUObject ( TSharedPtr < IDatasmithMeshElement > & MeshElement , const TCHAR * Filepath , FDatasmithMesh & Mesh , FDatasmithMesh * CollisionMesh , EDSExportLightmapUV LightmapUV )
2020-09-24 00:43:27 -04:00
{
2022-08-16 08:22:50 -04:00
FString FullPath ( GetMeshFilePath ( Filepath , MeshElement - > GetName ( ) ) ) ;
FDatasmithMeshExporterOptions ExportOptions ( FullPath , Mesh , LightmapUV , CollisionMesh ) ;
2020-11-24 18:42:39 -04:00
2022-08-16 08:22:50 -04:00
return Impl - > DoExport ( MeshElement , ExportOptions ) ;
2019-10-04 13:11:45 -04:00
}
2022-03-23 16:31:37 -04:00
2024-04-26 06:13:46 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
bool FDatasmithMeshExporter : : ExportCloth ( FDatasmithCloth & Cloth , TSharedPtr < IDatasmithClothElement > & ClothElement , const TCHAR * FilePath , const TCHAR * AssetsOutputPath ) const // UE_DEPRECATED(5.5, "The experimental Cloth importer is no longer supported.")
2022-08-26 13:20:02 -04:00
{
FString Path = FPaths : : SetExtension ( FilePath , TEXT ( " .udscloth " ) ) ;
FPaths : : NormalizeFilename ( Path ) ;
FString RelativeFilePath = Path ;
if ( AssetsOutputPath )
{
FString Tmp ( AssetsOutputPath ) ;
Tmp + = TEXT ( ' / ' ) ;
FPaths : : MakePathRelativeTo ( RelativeFilePath , * Tmp ) ;
}
ClothElement - > SetFile ( * RelativeFilePath ) ;
TUniquePtr < FArchive > Archive ( IFileManager : : Get ( ) . CreateFileWriter ( * Path ) ) ;
if ( ! Archive . IsValid ( ) )
{
Impl - > LastError = FString : : Printf ( TEXT ( " Failed writing to file %s " ) , * Path ) ;
return false ;
}
FDatasmithPackedCloths Pack ;
FDatasmithClothInfo & Info = Pack . ClothInfos . AddDefaulted_GetRef ( ) ;
Info . Cloth = Cloth ;
FMD5Hash OutHash = Pack . Serialize ( * Archive ) ;
return true ;
}
2024-04-26 06:13:46 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2022-08-26 13:20:02 -04:00
2020-02-17 13:28:31 -05:00
FString FDatasmithMeshExporter : : GetLastError ( ) const
{
2022-08-16 08:22:50 -04:00
return Impl - > LastError ;
2020-02-17 13:28:31 -05:00
}