2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
/*=============================================================================
HTML5TargetPlatform . cpp : Implements the FHTML5TargetPlatform class .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "HTML5TargetPlatformPrivatePCH.h"
# if WITH_EDITOR
2014-07-04 08:02:14 -04:00
# include "TextureLODSettings.h"
2014-03-14 14:13:41 -04:00
# endif
/* FHTML5TargetPlatform structors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
FHTML5TargetPlatform : : FHTML5TargetPlatform ( )
{
2015-01-26 10:22:57 -05:00
RefreshAvailableDevices ( ) ;
2014-09-02 14:36:52 -04:00
2014-03-14 14:13:41 -04:00
# if WITH_ENGINE
// load up texture settings from the config file
HTML5LODSettings . Initialize ( HTML5EngineSettings , TEXT ( " SystemSettings " ) ) ;
StaticMeshLODSettings . Initialize ( HTML5EngineSettings ) ;
# endif
}
/* ITargetPlatform interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void FHTML5TargetPlatform : : GetAllDevices ( TArray < ITargetDevicePtr > & OutDevices ) const
{
OutDevices . Reset ( ) ;
2014-09-02 14:36:52 -04:00
OutDevices . Append ( LocalDevice ) ;
2014-03-14 14:13:41 -04:00
}
ECompressionFlags FHTML5TargetPlatform : : GetBaseCompressionMethod ( ) const
{
return COMPRESS_ZLIB ;
}
ITargetDevicePtr FHTML5TargetPlatform : : GetDefaultDevice ( ) const
{
2014-09-02 14:36:52 -04:00
if ( LocalDevice . Num ( ) )
return LocalDevice [ 0 ] ;
else
return NULL ;
2014-03-14 14:13:41 -04:00
}
ITargetDevicePtr FHTML5TargetPlatform : : GetDevice ( const FTargetDeviceId & DeviceId )
{
2014-09-02 14:36:52 -04:00
for ( auto Device : LocalDevice )
2014-03-14 14:13:41 -04:00
{
2014-09-02 14:36:52 -04:00
if ( Device . IsValid ( ) & & DeviceId = = Device - > GetId ( ) )
return Device ;
2014-03-14 14:13:41 -04:00
}
return NULL ;
}
2014-06-20 11:47:12 -04:00
bool FHTML5TargetPlatform : : IsSdkInstalled ( bool bProjectHasCode , FString & OutDocumentationPath ) const
{
2015-01-26 12:02:40 -05:00
FConfigSection SDKPaths ;
2015-01-26 10:22:57 -05:00
//New style detection of devices
2015-01-26 12:02:40 -05:00
if ( HTML5EngineSettings . Find ( " /Script/HTML5PlatformEditor.HTML5SDKSettings " ) )
2015-01-26 10:22:57 -05:00
{
2015-02-20 04:41:01 -05:00
2015-01-26 12:02:40 -05:00
SDKPaths = HTML5EngineSettings [ " /Script/HTML5PlatformEditor.HTML5SDKSettings " ] ;
for ( auto It : SDKPaths )
{
const FString & Platform = It . Key . ToString ( ) ;
FString Path = It . Value ;
2015-02-20 04:41:01 -05:00
if ( Platform = = " EmscriptenRoot " )
2015-01-26 10:22:57 -05:00
{
2015-02-20 04:41:01 -05:00
FString SDKPathString ;
FString VersionString ;
auto Index = Path . Find ( TEXT ( " SDKPath= " ) ) ;
if ( Index ! = INDEX_NONE )
2015-01-26 12:02:40 -05:00
{
2015-02-20 04:41:01 -05:00
Index + = 9 ;
auto Index2 = Path . Find ( TEXT ( " \" " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart , Index ) ;
if ( Index2 ! = INDEX_NONE )
{
SDKPathString = Path . Mid ( Index , Index2 - Index ) ;
}
}
Index = Path . Find ( TEXT ( " EmscriptenVersion= " ) ) ;
if ( Index ! = INDEX_NONE )
{
Index + = 19 ;
auto Index2 = Path . Find ( TEXT ( " \" " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart , Index ) ;
if ( Index2 ! = INDEX_NONE )
{
VersionString = Path . Mid ( Index , Index2 - Index ) ;
}
}
if ( ! VersionString . IsEmpty ( ) & & ! SDKPathString . IsEmpty ( ) )
{
bool bFoundSDK = false ;
FHTML5SDKVersionNumber RequiredVersion ;
RequiredVersion . VersionNumberFromString ( * VersionString ) ;
TArray < FHTML5SDKVersionNumber > SDKVersions ;
GetInstalledSDKVersions ( * SDKPathString , SDKVersions ) ;
if ( SDKVersions . Num ( ) > 0 & &
RequiredVersion . VersionNumber . Major = = - 1 & &
RequiredVersion . VersionNumber . Minor = = - 1 & &
RequiredVersion . VersionNumber . Revision = = - 1 )
{
bFoundSDK = true ;
SDKPathString = SDKVersions . Last ( ) . VersionPath ;
}
else
{
for ( const auto & i : SDKVersions )
{
if ( i = = RequiredVersion )
{
SDKPathString = i . VersionPath ;
bFoundSDK = true ;
break ;
}
}
}
return bFoundSDK & & IFileManager : : Get ( ) . DirectoryExists ( * SDKPathString ) ;
2015-01-26 12:02:40 -05:00
}
2015-01-26 10:22:57 -05:00
}
}
}
// Old fallbacks
2015-01-26 12:02:40 -05:00
if ( HTML5EngineSettings . Find ( " HTML5SDKPaths " ) )
2014-10-31 04:31:19 -04:00
{
2015-01-26 12:02:40 -05:00
FString SectionName = " HTML5SDKPaths " ;
SDKPaths = HTML5EngineSettings [ SectionName ] ;
for ( auto It : SDKPaths )
2014-10-31 04:31:19 -04:00
{
2015-01-26 12:02:40 -05:00
const FString & Platform = It . Key . ToString ( ) ;
const FString & Path = It . Value ;
2014-12-10 09:07:36 -05:00
{
2015-01-26 12:02:40 -05:00
if ( Platform = = " Emscripten " & & IFileManager : : Get ( ) . DirectoryExists ( * Path ) )
{
return true ;
}
2014-10-31 04:31:19 -04:00
# if PLATFORM_WINDOWS
2015-01-26 12:02:40 -05:00
if ( Platform = = " Windows " & & IFileManager : : Get ( ) . DirectoryExists ( * Path ) )
{
return true ;
}
2014-10-31 04:31:19 -04:00
# endif
# if PLATFORM_MAC
2015-01-26 12:02:40 -05:00
if ( Platform = = " Mac " & & IFileManager : : Get ( ) . DirectoryExists ( * Path ) )
{
return true ;
}
2014-10-31 04:31:19 -04:00
# endif
2015-01-26 12:02:40 -05:00
}
2014-10-31 04:31:19 -04:00
}
}
TCHAR BaseSDKPath [ 512 ] ;
2014-06-20 11:47:12 -04:00
FPlatformMisc : : GetEnvironmentVariable ( TEXT ( " EMSCRIPTEN " ) , BaseSDKPath , ARRAY_COUNT ( BaseSDKPath ) ) ;
2014-10-31 04:31:19 -04:00
if ( FString ( BaseSDKPath ) . Len ( ) > 0 & & IFileManager : : Get ( ) . DirectoryExists ( BaseSDKPath ) )
{
return true ;
}
return false ;
2014-06-20 11:47:12 -04:00
}
2014-03-14 14:13:41 -04:00
bool FHTML5TargetPlatform : : IsRunningPlatform ( ) const
{
return false ; // but this will never be called because this platform doesn't run the target platform framework
}
# if WITH_ENGINE
static FName NAME_OPENGL_ES2_WEBGL ( TEXT ( " GLSL_ES2_WEBGL " ) ) ;
2014-05-09 08:51:44 -04:00
void FHTML5TargetPlatform : : GetAllPossibleShaderFormats ( TArray < FName > & OutFormats ) const
2014-03-14 14:13:41 -04:00
{
OutFormats . AddUnique ( NAME_OPENGL_ES2_WEBGL ) ;
}
2014-05-09 08:51:44 -04:00
void FHTML5TargetPlatform : : GetAllTargetedShaderFormats ( TArray < FName > & OutFormats ) const
{
GetAllPossibleShaderFormats ( OutFormats ) ;
}
2014-03-14 14:13:41 -04:00
const class FStaticMeshLODSettings & FHTML5TargetPlatform : : GetStaticMeshLODSettings ( ) const
{
return StaticMeshLODSettings ;
}
void FHTML5TargetPlatform : : GetTextureFormats ( const UTexture * Texture , TArray < FName > & OutFormats ) const
{
FName TextureFormatName = NAME_None ;
# if WITH_EDITOR
// Supported texture format names.
static FName NameDXT1 ( TEXT ( " DXT1 " ) ) ;
static FName NameDXT3 ( TEXT ( " DXT3 " ) ) ;
static FName NameDXT5 ( TEXT ( " DXT5 " ) ) ;
static FName NameDXT5n ( TEXT ( " DXT5n " ) ) ;
static FName NameAutoDXT ( TEXT ( " AutoDXT " ) ) ;
static FName NameBGRA8 ( TEXT ( " BGRA8 " ) ) ;
static FName NameG8 ( TEXT ( " G8 " ) ) ;
static FName NameRGBA16F ( TEXT ( " RGBA16F " ) ) ;
2014-05-22 09:13:12 -04:00
static FName NameRGBA8 ( TEXT ( " RGBA8 " ) ) ;
2014-03-14 14:13:41 -04:00
bool bNoCompression = Texture - > CompressionNone // Code wants the texture uncompressed.
| | ( HasEditorOnlyData ( ) & & Texture - > DeferCompression ) // The user wishes to defer compression, this is ok for the Editor only.
| | ( Texture - > CompressionSettings = = TC_EditorIcon )
| | ( Texture - > LODGroup = = TEXTUREGROUP_ColorLookupTable ) // Textures in certain LOD groups should remain uncompressed.
| | ( Texture - > LODGroup = = TEXTUREGROUP_Bokeh )
| | ( Texture - > LODGroup = = TEXTUREGROUP_IESLightProfile )
| | ( Texture - > Source . GetSizeX ( ) < 4 ) // Don't compress textures smaller than the DXT block size.
| | ( Texture - > Source . GetSizeY ( ) < 4 )
| | ( Texture - > Source . GetSizeX ( ) % 4 ! = 0 )
| | ( Texture - > Source . GetSizeY ( ) % 4 ! = 0 ) ;
ETextureSourceFormat SourceFormat = Texture - > Source . GetFormat ( ) ;
// Determine the pixel format of the (un/)compressed texture
if ( bNoCompression )
{
2014-04-23 17:30:27 -04:00
if ( Texture - > HasHDRSource ( ) )
{
TextureFormatName = NameBGRA8 ;
}
else if ( SourceFormat = = TSF_G8 | | Texture - > CompressionSettings = = TC_Grayscale )
{
TextureFormatName = NameG8 ;
}
else if ( Texture - > LODGroup = = TEXTUREGROUP_Shadowmap )
{
TextureFormatName = NameG8 ;
}
2014-09-12 16:47:24 -04:00
else if ( Texture - > CompressionSettings = = TC_EditorIcon )
{
TextureFormatName = NameRGBA8 ;
}
else
2014-04-23 17:30:27 -04:00
{
TextureFormatName = NameBGRA8 ;
}
2014-03-14 14:13:41 -04:00
}
2015-02-03 18:35:25 -05:00
else if ( Texture - > CompressionSettings = = TC_HDR
| | Texture - > CompressionSettings = = TC_HDR_Compressed )
2014-03-14 14:13:41 -04:00
{
TextureFormatName = NameRGBA16F ;
}
else if ( Texture - > CompressionSettings = = TC_Normalmap )
{
TextureFormatName = NameDXT5 ;
}
else if ( Texture - > CompressionSettings = = TC_Displacementmap )
{
TextureFormatName = NameG8 ;
}
else if ( Texture - > CompressionSettings = = TC_VectorDisplacementmap )
{
2014-05-22 09:13:12 -04:00
TextureFormatName = NameRGBA8 ;
2014-03-14 14:13:41 -04:00
}
else if ( Texture - > CompressionSettings = = TC_Grayscale )
{
TextureFormatName = NameG8 ;
}
else if ( Texture - > CompressionSettings = = TC_Alpha )
{
TextureFormatName = NameDXT5 ;
}
2014-07-30 15:36:36 -04:00
else if ( Texture - > CompressionSettings = = TC_DistanceFieldFont )
{
TextureFormatName = NameG8 ;
}
2014-03-14 14:13:41 -04:00
else if ( Texture - > CompressionNoAlpha )
{
TextureFormatName = NameDXT1 ;
}
else if ( Texture - > bDitherMipMapAlpha )
{
TextureFormatName = NameDXT5 ;
}
else
{
TextureFormatName = NameAutoDXT ;
}
// Some PC GPUs don't support sRGB read from G8 textures (e.g. AMD DX10 cards on ShaderModel3.0)
// This solution requires 4x more memory but a lot of PC HW emulate the format anyway
if ( ( TextureFormatName = = NameG8 ) & & Texture - > SRGB & & ! SupportsFeature ( ETargetPlatformFeatures : : GrayscaleSRGB ) )
{
TextureFormatName = NameBGRA8 ;
}
# endif
OutFormats . Add ( TextureFormatName ) ;
}
const struct FTextureLODSettings & FHTML5TargetPlatform : : GetTextureLODSettings ( ) const
{
return HTML5LODSettings ;
}
2014-10-03 14:56:20 -04:00
FName FHTML5TargetPlatform : : GetWaveFormat ( const USoundWave * Wave ) const
2014-03-14 14:13:41 -04:00
{
static FName NAME_OGG ( TEXT ( " OGG " ) ) ;
return NAME_OGG ;
}
2015-01-26 14:52:47 -05:00
# endif // WITH_ENGINE
2015-01-26 10:22:57 -05:00
void FHTML5TargetPlatform : : RefreshAvailableDevices ( )
{
2015-02-20 04:41:01 -05:00
// load the final HTML5 engine settings for this game
FConfigCacheIni : : LoadLocalIniFile ( HTML5EngineSettings , TEXT ( " Engine " ) , true , * PlatformName ( ) ) ;
2015-01-26 10:22:57 -05:00
//New style detection of devices
for ( const auto & Device : LocalDevice )
{
DeviceLostEvent . Broadcast ( Device . ToSharedRef ( ) ) ;
}
LocalDevice . Reset ( ) ;
auto * Config = GConfig - > FindConfigFile ( GEngineIni ) ;
if ( ! Config )
{
Config = & HTML5EngineSettings ;
}
TArray < FString > ValueArray ;
2015-01-26 12:02:40 -05:00
if ( Config - > Find ( " /Script/HTML5PlatformEditor.HTML5SDKSettings " ) )
2015-01-26 10:22:57 -05:00
{
2015-01-26 12:02:40 -05:00
FConfigSection AvaliableDevicesNewSection = ( * Config ) [ " /Script/HTML5PlatformEditor.HTML5SDKSettings " ] ;
for ( auto It : AvaliableDevicesNewSection )
2015-01-26 10:22:57 -05:00
{
2015-01-26 12:02:40 -05:00
ValueArray . Reset ( ) ;
if ( It . Key = = TEXT ( " DeviceMap " ) )
2015-01-26 10:22:57 -05:00
{
2015-01-26 12:02:40 -05:00
FString DeviceName ;
FString DevicePath ;
It . Value . RemoveFromStart ( TEXT ( " ( " ) ) ;
It . Value . RemoveFromEnd ( TEXT ( " ) " ) ) ;
2015-03-02 15:51:37 -05:00
It . Value . ParseIntoArray ( ValueArray , TEXT ( " , " ) , 1 ) ;
2015-01-26 12:02:40 -05:00
for ( auto & Value : ValueArray )
2015-01-26 10:22:57 -05:00
{
2015-01-26 12:02:40 -05:00
if ( Value . StartsWith ( TEXT ( " DeviceName= " ) ) )
{
DeviceName = Value . RightChop ( 11 ) . TrimQuotes ( ) ;
}
else if ( Value . StartsWith ( TEXT ( " DevicePath=(FilePath= " ) ) )
{
DevicePath = Value . RightChop ( 21 ) ;
DevicePath . RemoveFromEnd ( TEXT ( " ) " ) ) ;
DevicePath = DevicePath . TrimQuotes ( ) ;
}
2015-01-26 10:22:57 -05:00
}
2015-01-26 12:02:40 -05:00
if ( ! DeviceName . IsEmpty ( ) & & ! DevicePath . IsEmpty ( ) & &
2015-02-20 04:41:01 -05:00
( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * DevicePath ) | |
FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . DirectoryExists ( * DevicePath ) ) )
2015-01-26 12:02:40 -05:00
{
ITargetDevicePtr Device = MakeShareable ( new FHTML5TargetDevice ( * this , FString : : Printf ( TEXT ( " %s on %s " ) , * DeviceName , FPlatformProcess : : ComputerName ( ) ) ) ) ;
LocalDevice . Add ( Device ) ;
DeviceDiscoveredEvent . Broadcast ( Device . ToSharedRef ( ) ) ;
}
2015-01-26 10:22:57 -05:00
}
}
}
// Old Fallback
if ( LocalDevice . Num ( ) = = 0 )
{
FString DeviceSectionName ;
# if PLATFORM_WINDOWS
DeviceSectionName = " HTML5DevicesWindows " ;
# elif PLATFORM_MAC
DeviceSectionName = " HTML5DevicesMac " ;
# else
DeviceSectionName = " HTML5DevicesLinux " ;
# endif
2015-01-26 12:02:40 -05:00
if ( HTML5EngineSettings . Find ( DeviceSectionName ) )
2015-01-26 10:22:57 -05:00
{
2015-01-26 12:02:40 -05:00
FConfigSection AvaliableDevicesSection = HTML5EngineSettings [ DeviceSectionName ] ;
for ( auto It : AvaliableDevicesSection )
2015-01-26 10:22:57 -05:00
{
2015-01-26 12:02:40 -05:00
const FString & BrowserName = It . Key . ToString ( ) ;
const FString & BrowserPath = It . Value ;
if ( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * It . Value ) )
{
ITargetDevicePtr Device = MakeShareable ( new FHTML5TargetDevice ( * this , FString : : Printf ( TEXT ( " %s on %s " ) , * It . Key . ToString ( ) , FPlatformProcess : : ComputerName ( ) ) ) ) ;
LocalDevice . Add ( Device ) ;
DeviceDiscoveredEvent . Broadcast ( Device . ToSharedRef ( ) ) ;
}
2015-01-26 10:22:57 -05:00
}
}
}
}
2015-02-20 04:41:01 -05:00
void FHTML5TargetPlatform : : GetInstalledSDKVersions ( const TCHAR * SDKDirectory , TArray < FHTML5SDKVersionNumber > & OutSDKs )
{
if ( ! SDKDirectory )
{
return ;
}
struct FVersionSearch : public IPlatformFile : : FDirectoryVisitor
{
IPlatformFile * PlatformFile ;
TArray < FHTML5SDKVersionNumber > & SDKs ;
FString VersionFilePath ;
FVersionSearch ( IPlatformFile * InPlatformFile , TArray < FHTML5SDKVersionNumber > & InSDKs )
: PlatformFile ( InPlatformFile )
, SDKs ( InSDKs )
{ }
virtual bool Visit ( const TCHAR * FilenameOrDirectory , bool bIsDirectory )
{
if ( bIsDirectory = = true )
{
VersionFilePath = FPaths : : Combine ( FilenameOrDirectory , TEXT ( " emscripten-version.txt " ) ) ;
if ( PlatformFile - > FileExists ( * VersionFilePath ) )
{
FString VersionText ;
FFileHelper : : LoadFileToString ( VersionText , * VersionFilePath ) ;
VersionText . Trim ( ) ;
VersionText . TrimTrailing ( ) ;
FHTML5SDKVersionNumber Ver ;
Ver . VersionPath = FilenameOrDirectory ;
Ver . VersionNumberFromString ( * VersionText ) ;
SDKs . Add ( Ver ) ;
}
}
return true ;
}
} ;
auto & PlatformFile = FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) ;
FVersionSearch VersionSearch ( & PlatformFile , OutSDKs ) ;
FString EmscriptenSDkDir = FPaths : : Combine ( SDKDirectory , TEXT ( " emscripten " ) ) ;
PlatformFile . IterateDirectory ( * EmscriptenSDkDir , VersionSearch ) ;
OutSDKs . Sort ( ) ;
}