diff --git a/Download_SDK_Desktop.bat b/Download_SDK_Desktop.bat index ab37a65..adf00d5 100644 --- a/Download_SDK_Desktop.bat +++ b/Download_SDK_Desktop.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_desktop -bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.18.6_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" +bitsadmin /addfile third_party_download_desktop https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.19.0_Win64_Linux64_Mac64.7z "%~dp0\_PopcornFX_Runtime_SDK_Desktop.7z" bitsadmin /setpriority third_party_download_desktop "FOREGROUND" bitsadmin /resume third_party_download_desktop diff --git a/Download_SDK_Mobile.bat b/Download_SDK_Mobile.bat index 7b9d51d..c3ec39a 100644 --- a/Download_SDK_Mobile.bat +++ b/Download_SDK_Mobile.bat @@ -6,7 +6,7 @@ setlocal bitsadmin /reset bitsadmin /create third_party_download_mobile -bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.18.6_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" +bitsadmin /addfile third_party_download_mobile https://downloads.popcornfx.com/Plugins/UE4/UnrealEngine_PopcornFXPlugin_2.19.0_iOS_Android.7z "%~dp0\_PopcornFX_Runtime_SDK_Mobile.7z" bitsadmin /setpriority third_party_download_mobile "FOREGROUND" bitsadmin /resume third_party_download_mobile diff --git a/PopcornFX.uplugin b/PopcornFX.uplugin index 46a6f6f..22edee4 100644 --- a/PopcornFX.uplugin +++ b/PopcornFX.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 21806, - "VersionName": "2.18.6", + "Version": 21900, + "VersionName": "2.19.0", "FriendlyName": "PopcornFX", "Description": "PopcornFX Realtime Particle Solution integration into Unreal Engine", "Category": "PopcornFX", diff --git a/README.md b/README.md index 7df2cb1..c94898c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Unreal Engine PopcornFX Plugin -Integrates the **PopcornFX Runtime SDK** into **Unreal Engine 4** and **Unreal Engine 5** as a Plugin. -* **Version:** `v2.18.6` -* **Unreal Engine:** `4.27`, `5.1`, `5.2` and `5.3` +Integrates the **PopcornFX Runtime SDK** into **Unreal Engine 5** as a Plugin. +* **Version:** `v2.19.0` +* **Unreal Engine:** `5.1`, `5.2` and `5.3` * **Supported platforms:** `Windows`, `MacOS`, `Linux`, `iOS`, `Android`, `PS4`, `PS5`, `XboxOne`, `Xbox Series`, `Switch` [Contact-us](http://www.popcornfx.com/contact-us/) to request access to the plugin for consoles. diff --git a/Shaders/Private/PopcornFXGPUBillboard.ush b/Shaders/Private/PopcornFXGPUBillboard.ush index 6cd7c6c..34da918 100644 --- a/Shaders/Private/PopcornFXGPUBillboard.ush +++ b/Shaders/Private/PopcornFXGPUBillboard.ush @@ -33,6 +33,7 @@ struct FVertexFactoryIntermediates { float3 ParticleWorldPosition; // UE units float3 VertexWorldPosition; // UE units + float3 VertexPrevWorldPosition; // UE units float4 VertexTexCoords; //float ParticleLifeRatio; TODO @@ -167,6 +168,9 @@ void PopcornFXGPUBillboard(uint instanceID, float2 texCoords, out FVertexFactory else radius = PKSimData_Load2f(particleID, PopcornFXGPUBillboardVSUniforms.InSize2sOffset); + if (PopcornFXGPUBillboardVSUniforms.InEnabledOffset != -1) + radius *= PKSimData_Loadi(particleID, PopcornFXGPUBillboardVSUniforms.InEnabledOffset) != 0 ? 1.0f : 0.0f; + float rotation = 0.0f; float3 xAxis = float3(0.0f, 0.0f, 0.0f); @@ -293,6 +297,17 @@ void PopcornFXGPUBillboard(uint instanceID, float2 texCoords, out FVertexFactory intermediates.VertexWorldPosition += ResolvedView.PreViewTranslation; #endif // (ENGINE_MAJOR_VERSION == 5) + BRANCH + if (PopcornFXGPUBillboardVSUniforms.InPreviousPositionOffset != -1) + intermediates.VertexPrevWorldPosition = (PKSimData_Load3f(particleID, PopcornFXGPUBillboardVSUniforms.InPreviousPositionOffset) + bbCorner) * GLOBAL_SCALE; + else + intermediates.VertexPrevWorldPosition = (worldPos + bbCorner) * GLOBAL_SCALE; // no velocity +#if (ENGINE_MAJOR_VERSION == 5) + intermediates.VertexPrevWorldPosition += LWCToFloat(ResolvedView.PrevPreViewTranslation); +#else + intermediates.VertexPrevWorldPosition += ResolvedView.PrevPreViewTranslation; +#endif // (ENGINE_MAJOR_VERSION == 5) + #if USE_PARTICLE_POSITION const float particleRadius = min(radius.x, radius.y) * GLOBAL_SCALE; # if (ENGINE_MAJOR_VERSION == 5) diff --git a/Shaders/Private/PopcornFXGPUVertexFactory.ush b/Shaders/Private/PopcornFXGPUVertexFactory.ush index 63a68df..9420647 100644 --- a/Shaders/Private/PopcornFXGPUVertexFactory.ush +++ b/Shaders/Private/PopcornFXGPUVertexFactory.ush @@ -184,9 +184,9 @@ FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, VertexParameters.PreSkinnedPosition = Intermediates.ParticleWorldPosition.xyz; VertexParameters.PreSkinnedNormal = TangentToLocal[2].xyz; #if (ENGINE_MAJOR_VERSION == 5) - VertexParameters.PrevFrameLocalToWorld = GetPrimitiveDataFromUniformBuffer().LocalToWorld; // No velocity + VertexParameters.PrevFrameLocalToWorld = GetPrimitiveDataFromUniformBuffer().PreviousLocalToWorld; #else - VertexParameters.PrevFrameLocalToWorld = Primitive.LocalToWorld; // No velocity + VertexParameters.PrevFrameLocalToWorld = Primitive.PreviousLocalToWorld; #endif // (ENGINE_MAJOR_VERSION == 5) #if (DYNAMIC_PARAMETERS_MASK != 0) @@ -431,7 +431,7 @@ float3x3 VertexFactoryGetTangentToLocal(FVertexFactoryInput Input, FVertexFactor float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates) { - return VertexFactoryGetWorldPosition(Input, Intermediates); // TODO + return float4(Intermediates.VertexPrevWorldPosition, 1.f); } float4 VertexFactoryGetTranslatedPrimitiveVolumeBounds(FVertexFactoryInterpolantsVSToPS Interpolants) diff --git a/Shaders/Private/PopcornFXMeshVertexFactory.ush b/Shaders/Private/PopcornFXMeshVertexFactory.ush index 8ba9a14..d999f77 100644 --- a/Shaders/Private/PopcornFXMeshVertexFactory.ush +++ b/Shaders/Private/PopcornFXMeshVertexFactory.ush @@ -149,6 +149,8 @@ struct FVertexFactoryIntermediates float4x4 ParticleToWorld; float4x4 WorldToParticle; + float4 PreviousPosition; + #if (ENGINE_MAJOR_VERSION == 5) /** Cached primitive and instance data */ FSceneDataIntermediates SceneData; @@ -233,7 +235,7 @@ FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVS # if USE_PARTICLE_WORLD_TO_LOCAL Result.Particle.WorldToParticle = LWCPromoteInverse(transpose(float4x4(Interpolants.WorldToParticle[0], Interpolants.WorldToParticle[1], Interpolants.WorldToParticle[2], float4(0.0f, 0.0f, 0.0f, 1.0f)))); # if NEEDS_INSTANCE_WORLD_TO_LOCAL_PS - Result.InstanceWorldtoLocal = Result.Particle.WorldToParticle; + Result.InstanceWorldToLocal = Result.Particle.WorldToParticle; # endif // NEEDS_INSTANCE_WORLD_TO_LOCAL_PS # endif // USE_PARTICLE_WORLD_TO_LOCAL #else @@ -395,6 +397,19 @@ float4 CalcWorldPosition(FVertexFactoryInput Input) return float4(WorldPosition, Input.Position.w); } +float4 CalcPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates) +{ + // FIXME only offsets the particle position, properly store the previous rotation transforms as well. + float4x4 Transform = float4x4(Input.Transform1, Input.Transform2, Input.Transform3, Intermediates.PreviousPosition); + +#if (ENGINE_MAJOR_VERSION == 5) + float3 WorldPosition = mul(Input.Position, Transform).xyz + LWCHackToFloat(ResolvedView.PrevPreViewTranslation); +#else + float3 WorldPosition = mul(Input.Position, Transform).xyz + ResolvedView.PrevPreViewTranslation; +#endif // (ENGINE_MAJOR_VERSION == 5) + return float4(WorldPosition, Input.Position.w); +} + FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input) { FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0; @@ -429,6 +444,12 @@ FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput In if (PopcornFXMeshVSUniforms.InEmissiveColorsOffset != -1) Intermediates.EmissiveColor = PKSimData_Load4f(particleID, PopcornFXMeshVSUniforms.InEmissiveColorsOffset); + BRANCH + if (PopcornFXMeshVSUniforms.InPreviousPositionOffset != -1) + Intermediates.PreviousPosition = float4(PKSimData_Load3f(particleID, PopcornFXMeshVSUniforms.InPreviousPositionOffset), Input.Transform4.w); + else + Intermediates.PreviousPosition = Input.Transform4; + // Cursor sent through RelativeTime (either one) BRANCH if (PopcornFXMeshVSUniforms.InVATCursorsOffset != -1) @@ -632,8 +653,7 @@ FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFacto // @return previous translated world position float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates) { - // The previous local to world instance transform isn't available. - return CalcWorldPosition(Input); + return CalcPreviousWorldPosition(Input, Intermediates); } #if USING_TESSELLATION diff --git a/Shaders/Private/PopcornFXSkeletalMeshVertexFactory.ush b/Shaders/Private/PopcornFXSkeletalMeshVertexFactory.ush index 29cb666..d692876 100644 --- a/Shaders/Private/PopcornFXSkeletalMeshVertexFactory.ush +++ b/Shaders/Private/PopcornFXSkeletalMeshVertexFactory.ush @@ -250,7 +250,7 @@ FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVS # if USE_PARTICLE_WORLD_TO_LOCAL Result.Particle.WorldToParticle = LWCPromoteInverse(transpose(float4x4(Interpolants.WorldToParticle[0], Interpolants.WorldToParticle[1], Interpolants.WorldToParticle[2], float4(0.0f, 0.0f, 0.0f, 1.0f)))); # if NEEDS_INSTANCE_WORLD_TO_LOCAL_PS - Result.InstanceWorldtoLocal = Result.Particle.WorldToParticle; + Result.InstanceWorldToLocal = Result.Particle.WorldToParticle; # endif // NEEDS_INSTANCE_WORLD_TO_LOCAL_PS # endif // USE_PARTICLE_WORLD_TO_LOCAL #else diff --git a/Shaders/Private/PopcornFXVertexFactory.ush b/Shaders/Private/PopcornFXVertexFactory.ush index eeb1c1e..d05c9c6 100644 --- a/Shaders/Private/PopcornFXVertexFactory.ush +++ b/Shaders/Private/PopcornFXVertexFactory.ush @@ -54,6 +54,7 @@ struct FVertexFactoryInput struct FVertexFactoryIntermediates { float3 Position; + float3 PrevPosition; float4 ParticleColor; float3 ParticleEmissiveColor; @@ -229,6 +230,12 @@ FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, VertexParameters.PreSkinnedPosition = Input.Position.xyz; VertexParameters.PreSkinnedNormal = TangentToLocal[2].xyz; +#if (ENGINE_MAJOR_VERSION == 5) + VertexParameters.PrevFrameLocalToWorld = GetPrimitiveDataFromUniformBuffer().PreviousLocalToWorld; +#else + VertexParameters.PrevFrameLocalToWorld = Primitive.PreviousLocalToWorld; +#endif // (ENGINE_MAJOR_VERSION == 5) + #if NEEDS_PARTICLE_COLOR VertexParameters.Particle.Color = Intermediates.ParticleColor; #endif @@ -316,6 +323,22 @@ FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput In Intermediates.Position = worldVertexPosition; + float3 prevVertexPosition = vertexPosition; + + BRANCH + if (PopcornFXBillboardVSUniforms.InPreviousPositionOffset != -1) + prevVertexPosition = PKSimData_Load3f(particleID, PopcornFXBillboardVSUniforms.InPreviousPositionOffset); + +#if (ENGINE_MAJOR_VERSION == 5) + float3 prevWorldVertexPosition = mul(float4(prevVertexPosition,1), LWCToFloat(GetPrimitiveDataFromUniformBuffer().PreviousLocalToWorld)).xyz; + prevWorldVertexPosition += LWCToFloat(ResolvedView.PrevPreViewTranslation); +#else + float3 prevWorldVertexPosition = mul(float4(prevVertexPosition,1), Primitive.PreviousLocalToWorld).xyz; + prevWorldVertexPosition += ResolvedView.PrevPreViewTranslation; +#endif // (ENGINE_MAJOR_VERSION == 5) + + Intermediates.PrevPosition = prevWorldVertexPosition; + BRANCH if (PopcornFXBillboardVSUniforms.InColorsOffset != -1) Intermediates.ParticleColor = PKSimData_Load4f(particleID, PopcornFXBillboardVSUniforms.InColorsOffset); @@ -427,7 +450,7 @@ float3x3 VertexFactoryGetTangentToLocal(FVertexFactoryInput Input, FVertexFactor float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates) { - return VertexFactoryGetWorldPosition(Input, Intermediates); + return float4(Intermediates.PrevPosition, 1); } float4 VertexFactoryGetTranslatedPrimitiveVolumeBounds(FVertexFactoryInterpolantsVSToPS Interpolants) diff --git a/Source/PopcornFX/PopcornFX.Build.cs b/Source/PopcornFX/PopcornFX.Build.cs index 059309b..11ed87a 100644 --- a/Source/PopcornFX/PopcornFX.Build.cs +++ b/Source/PopcornFX/PopcornFX.Build.cs @@ -229,7 +229,7 @@ private bool SetupPopcornFX(TargetInfo Target) #if !UE_5_0_OR_LATER // Support dropped with UE5 if (Target.Platform == UnrealTargetPlatform.Win32) { - libPrefix = clientLibDir + "vs2017_Win32/"; + libPrefix = clientLibDir + "vs2019_Win32/"; libExt = ".lib"; } else @@ -237,7 +237,7 @@ private bool SetupPopcornFX(TargetInfo Target) if (Target.Platform == UnrealTargetPlatform.Win64 || isWinUNKNOWN) // Win32 UNKNOWN (WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP), just link with the same libs as Win64 { - libPrefix = clientLibDir + "vs2017_x64/"; + libPrefix = clientLibDir + "vs2019_x64/"; libExt = ".lib"; } else if (Target.Platform == UnrealTargetPlatform.Mac) @@ -248,31 +248,31 @@ private bool SetupPopcornFX(TargetInfo Target) #if !UE_5_0_OR_LATER // Support dropped with UE5 else if (Target.Platform == UnrealTargetPlatform.XboxOne) { - libPrefix = clientLibDir + "vs2017_Durango/"; + libPrefix = clientLibDir + "vs2019_Durango/"; libExt = ".lib"; } #endif // !UE_5_0_OR_LATER else if (isXboxOneUNKNOWN) { - libPrefix = clientLibDir + "vs2017_UNKNOWN.x64/"; + libPrefix = clientLibDir + "vs2019_UNKNOWN.x64/"; libExt = ".lib"; } else if (isUNKNOWN) { - libPrefix = clientLibDir + "vs2017_UNKNOWN.x64/"; + libPrefix = clientLibDir + "vs2019_UNKNOWN.x64/"; libExt = ".lib"; } #if !UE_5_0_OR_LATER // Support dropped with UE5 else if (Target.Platform == UnrealTargetPlatform.PS4) { - libPrefix = clientLibDir + "vs2017_ORBIS/"; + libPrefix = clientLibDir + "vs2019_ORBIS/"; // "vs" + WindowsPlatform.GetVisualStudioCompilerVersionName(); // error (exception) on >= 4.16 libExt = ".a"; } #endif // !UE_5_0_OR_LATER else if (isUNKNOWN2) { - libPrefix = clientLibDir + "vs2017_UNKNOWN2/"; + libPrefix = clientLibDir + "vs2019_UNKNOWN2/"; libExt = ".a"; } else if (Target.Platform == UnrealTargetPlatform.IOS) @@ -294,7 +294,7 @@ private bool SetupPopcornFX(TargetInfo Target) #if !UE_5_0_OR_LATER // Support dropped with UE5 else if (Target.Platform == UnrealTargetPlatform.Switch) { - libPrefix = clientLibDir + "vs2017_NX64/"; + libPrefix = clientLibDir + "vs2019_NX64/"; libExt = ".a"; } #endif // !UE_5_0_OR_LATER diff --git a/Source/PopcornFX/PopcornFX.natvis b/Source/PopcornFX/PopcornFX.natvis new file mode 100644 index 0000000..ecb5cee --- /dev/null +++ b/Source/PopcornFX/PopcornFX.natvis @@ -0,0 +1,410 @@ + + + + + + + + + + + + null + {*((char**)((unsigned long long)m_Container.m_Ptr + (((sizeof(PopcornFX::CStringContainer) + 4) + (sizeof(void*) - 1)) & ~((unsigned long long)(sizeof(void*) - 1))))),s} [Len={m_Container.m_Ptr->m_Length & 0x7FFFFFFF}] + {(char*)((unsigned long long)m_Container.m_Ptr + sizeof(PopcornFX::CStringContainer) + (0xF - ((sizeof(PopcornFX::CStringContainer) + 0xF) & ((unsigned long long)0xF)))),s} [Len={m_Container.m_Ptr->m_Length & 0x7FFFFFFF}] + null + *((char**)((unsigned long long)m_Container.m_Ptr + (((sizeof(PopcornFX::CStringContainer) + 4) + (sizeof(void*) - 1)) & ~((unsigned long long)(sizeof(void*) - 1))))),s + (char*)((unsigned long long)m_Container.m_Ptr + sizeof(PopcornFX::CStringContainer) + (0xF - ((sizeof(PopcornFX::CStringContainer) + 0xF) & ((unsigned long long)0xF)))),s + + + + null + {*((wchar_t**)((unsigned long long)m_Container.m_Ptr + sizeof(PopcornFX::CStringUnicodeContainer) + 4)),su} [Len={m_Container.m_Ptr->m_Length & 0x7FFFFFFF}] + {(wchar_t*)(((unsigned long long)m_Container.m_Ptr + sizeof(PopcornFX::CStringUnicodeContainer) + 0xF) & ~((unsigned long long)0xF)),su} [Len={m_Container.m_Ptr->m_Length & 0x7FFFFFFF}] + null + *((wchar_t**)((unsigned long long)m_Container.m_Ptr + sizeof(PopcornFX::CStringUnicodeContainer) + 4)),su + (wchar_t*)(((unsigned long long)m_Container.m_Ptr + sizeof(PopcornFX::CStringUnicodeContainer) + 0xF) & ~((unsigned long long)0xF)),su + + + + Id=0 null + Id={m_Id} {PopcornFX::CStringInternals::m_StringIdDictionnary->m_StringIdPool.m_Chunks[m_Id / PopcornFX::CStringIdDictionary::kPoolChunkSize][m_Id % PopcornFX::CStringIdDictionary::kPoolChunkSize]} + + PopcornFX::CStringInternals::m_StringIdDictionnary->m_StringIdPool.m_Chunks[m_Id / PopcornFX::CStringIdDictionary::kPoolChunkSize][m_Id % PopcornFX::CStringIdDictionary::kPoolChunkSize] + + + + + null + {m_Data,[m_Length]s} [Len={m_Length}] + + + + null + {m_DataFeed.m_Ptr} + + m_DataFeed.m_Ptr + + + + + {{RefPtr={(void*)m_Ptr}}} + + m_Ptr + + + + {{WeakPtr={(void*)m_Ptr}}} + + m_Ptr + + + + {{ScopedPtr={(void*)m_Ptr}}} + + m_Ptr + + + + + {{A Count={m_Count}}} + + + m_Count + ($T1*)m_Data + + + + + + {{A Count={m_Count}}} + + + m_Count + ($T1*)m_Data + + + + + + {{SDA Count={m_Count & 0x7FFFFFFF} Data={(void*)m_Allocated.m_Data}} + {{SDA Count={m_Count & 0x7FFFFFFF} Data={(void*)(((unsigned long long)m_StaticData + kAlignment - 1) & - kAlignment)}} + + + m_Count & 0x7FFFFFFF + ($T1*)m_Allocated.m_Data + + + m_Count + ($T1*)(((unsigned long long)m_StaticData + kAlignment - 1) & - kAlignment) + + + + + + {{SFA Count={m_Count}, Data={(void*)m_Data}, Cap={m_Capacity}}} + + + m_Count + ($T1*)m_Data + + + + + + {{SA _Count={$T2}, Data={(void*)(((unsigned long long)_m_Data + kAlignment - 1) & - kAlignment)} + + + $T2 + ($T1*)(((unsigned long long)_m_Data + kAlignment - 1) & - kAlignment) + + + + + + {{SCA Count={m_Count}, Data={(void*)(((unsigned long long)_m_Data + kAlignment - 1) & - kAlignment)}}} + + + m_Count + ($T1*)(((unsigned long long)_m_Data + kAlignment - 1) & - kAlignment) + + + + + + {{CA Count={$T2 * m_ChunksCount}({$T2}*{m_ChunksCount}), ChuncksCap={m_ChunksCapacity}}} + + + $T2 * m_ChunksCount + m_Chunks[$i / $T2][$i % $T2] + + + + + + {{SlotA UsedCount={m_UsedSlots} _Count={$T2}}} + + + $T2 + ($T1*)m_Data + + + + + + {{SlotA UsedCount={m_UsedSlots} Count={m_DataSizeInBytes / sizeof($T1)}}} + + + m_DataSizeInBytes / sizeof($T1) + ($T1*)m_Data + + + + + + {{MV Count={m_Count}, Data={(void*)m_Data}, sizeof={sizeof($T1)}}} + + + m_Count + ($T1*)m_Data + + + + + + {{SMV Count={m_Storage.m_Count}, Data={(void*)m_Storage.m_RawDataPtr}, Stride={m_Storage.m_Stride}, sizeof={sizeof($T1)}}} + + + m_Storage.m_Count + *(($T1*)(m_Storage.m_RawDataPtr + $i * m_Storage.m_Stride)) + + + + + + {{SMVF Count={m_Storage.m_Count}, Data={(void*)m_Storage.m_RawDataPtr}, Stride={m_Storage.m_Stride}, Footp={m_ElementFootprintInBytes}, sizeof={sizeof($T1)}} + + + m_Storage.m_Count + *(($T1*)(m_Storage.m_RawDataPtr + $i * m_Storage.m_Stride)) + + + + + + {{First={m_First}, Second={m_Second}}} + + m_First + m_Second + + + + + {{FHM Count={m_Count}, Data={(void*)m_Slots}, Size={m_Size}}} + + + m_Size + m_Slots + + + + + + + + empty + + void (error) + + + const class cr{m_RawBits & 0xFFFF,d} + variable class vr{m_RawBits & 0xFFFF,d} + instance class ir{m_RawBits & 0xFFFF,d} + stream class sr{m_RawBits & 0xFFFF,d} + + + const bool1 cr{m_RawBits & 0xFFFF,d} + variable bool1 vr{m_RawBits & 0xFFFF,d} + instance bool1 ir{m_RawBits & 0xFFFF,d} + stream bool1 sr{m_RawBits & 0xFFFF,d} + + const bool2 cr{m_RawBits & 0xFFFF,d} + variable bool2 vr{m_RawBits & 0xFFFF,d} + instance bool2 ir{m_RawBits & 0xFFFF,d} + stream bool2 sr{m_RawBits & 0xFFFF,d} + + const bool3 cr{m_RawBits & 0xFFFF,d} + variable bool3 vr{m_RawBits & 0xFFFF,d} + instance bool3 ir{m_RawBits & 0xFFFF,d} + stream bool3 sr{m_RawBits & 0xFFFF,d} + + const bool4 cr{m_RawBits & 0xFFFF,d} + variable bool4 vr{m_RawBits & 0xFFFF,d} + instance bool4 ir{m_RawBits & 0xFFFF,d} + stream bool4 sr{m_RawBits & 0xFFFF,d} + + + const int1 cr{m_RawBits & 0xFFFF,d} + variable int1 vr{m_RawBits & 0xFFFF,d} + instance int1 ir{m_RawBits & 0xFFFF,d} + stream int1 sr{m_RawBits & 0xFFFF,d} + + const int2 cr{m_RawBits & 0xFFFF,d} + variable int2 vr{m_RawBits & 0xFFFF,d} + instance int2 ir{m_RawBits & 0xFFFF,d} + stream int2 sr{m_RawBits & 0xFFFF,d} + + const int3 cr{m_RawBits & 0xFFFF,d} + variable int3 vr{m_RawBits & 0xFFFF,d} + instance int3 ir{m_RawBits & 0xFFFF,d} + stream int3 sr{m_RawBits & 0xFFFF,d} + + const int4 cr{m_RawBits & 0xFFFF,d} + variable int4 vr{m_RawBits & 0xFFFF,d} + instance int4 ir{m_RawBits & 0xFFFF,d} + stream int4 sr{m_RawBits & 0xFFFF,d} + + + const float1 cr{m_RawBits & 0xFFFF,d} + variable float1 vr{m_RawBits & 0xFFFF,d} + instance float1 ir{m_RawBits & 0xFFFF,d} + stream float1 sr{m_RawBits & 0xFFFF,d} + + const float2 cr{m_RawBits & 0xFFFF,d} + variable float2 vr{m_RawBits & 0xFFFF,d} + instance float2 ir{m_RawBits & 0xFFFF,d} + stream float2 sr{m_RawBits & 0xFFFF,d} + + const float3 cr{m_RawBits & 0xFFFF,d} + variable float3 vr{m_RawBits & 0xFFFF,d} + instance float3 ir{m_RawBits & 0xFFFF,d} + stream float3 sr{m_RawBits & 0xFFFF,d} + + const float4 cr{m_RawBits & 0xFFFF,d} + variable float4 vr{m_RawBits & 0xFFFF,d} + instance float4 ir{m_RawBits & 0xFFFF,d} + stream float4 sr{m_RawBits & 0xFFFF,d} + + + const orientation cr{m_RawBits & 0xFFFF,d} + variable orientation vr{m_RawBits & 0xFFFF,d} + instance orientation ir{m_RawBits & 0xFFFF,d} + stream orientation sr{m_RawBits & 0xFFFF,d} + + + + + + Range = ]{m_BoundMin.m_Value.m_Data32u,X}, {m_BoundMax.m_Value.m_Data32u,X}[ - ]{m_BoundMin.m_Value.m_Data32f}, {m_BoundMax.m_Value.m_Data32f}[ - ]{m_BoundMin.m_Value.m_Data32s}, {m_BoundMax.m_Value.m_Data32s}[ + Range = ]{m_BoundMin.m_Value.m_Data32u,X}, {m_BoundMax.m_Value.m_Data32u,X}] - ]{m_BoundMin.m_Value.m_Data32f}, {m_BoundMax.m_Value.m_Data32f}] - ]{m_BoundMin.m_Value.m_Data32s}, {m_BoundMax.m_Value.m_Data32s}] + Range = [{m_BoundMin.m_Value.m_Data32u,X}, {m_BoundMax.m_Value.m_Data32u,X}[ - [{m_BoundMin.m_Value.m_Data32f}, {m_BoundMax.m_Value.m_Data32f}[ - [{m_BoundMin.m_Value.m_Data32s}, {m_BoundMax.m_Value.m_Data32s}[ + Range = [{m_BoundMin.m_Value.m_Data32u,X}, {m_BoundMax.m_Value.m_Data32u,X}] - [{m_BoundMin.m_Value.m_Data32f}, {m_BoundMax.m_Value.m_Data32f}] - [{m_BoundMin.m_Value.m_Data32s}, {m_BoundMax.m_Value.m_Data32s}] + + + + X + O + + + + {*(PopcornFX::Range::Internal::_SConstantRange_Natvis*)(m_BoundMin.m_Value.m_Data32u + 0)} + + + 4 + (PopcornFX::Range::Internal::_SConstantRange_Natvis*)(m_BoundMin.m_Value.m_Data32u + $i) + + + + + + {*(PopcornFX::Range::Internal::_SConstantEdge_Natvis*)(m_Edge.m_Data+0)}{*(PopcornFX::Range::Internal::_SConstantEdge_Natvis*)(m_Edge.m_Data+1)}{*(PopcornFX::Range::Internal::_SConstantEdge_Natvis*)(m_Edge.m_Data+2)}{*(PopcornFX::Range::Internal::_SConstantEdge_Natvis*)(m_Edge.m_Data+3)}: |{m_Value.m_Data32u[0],X}, {m_Value.m_Data32u[1],X}, {m_Value.m_Data32u[2],X}, {m_Value.m_Data32u[3],X}| - |{m_Value.m_Data32f[0]}, {m_Value.m_Data32f[1]}, {m_Value.m_Data32f[2]}, {m_Value.m_Data32f[3]}| - |{m_Value.m_Data32s[0]}, {m_Value.m_Data32s[1]}, {m_Value.m_Data32s[2]}, {m_Value.m_Data32s[3]}| + + + + INVALID + void + auto + byte + float + float2 + float3 + float4 + int + int2 + int3 + int4 + bool + bool2 + bool3 + bool4 + orientation + + m_Index + + + + + {(PopcornFX::CVStreamSemanticDictionnary::EDefaultOrdinals)(m_Code >> 8)} + (m_Code >> 8) + + (PopcornFX::CVStreamSemanticDictionnary::EDefaultOrdinals)(m_Code >> 8) + (m_Code >> 8) + (PopcornFX::SVStreamCode::EElementType)(m_Code & 0x1F) + (m_Code & 0x80) != 0 + (m_Code & 0x40) != 0 + m_Code + + + + + v{(m_Key >> 29) & 0x7,d}.{(m_Key >> 24) & 0x1F,d}.{(m_Key >> 18) & 0x3F,d}.{m_Key & 0x3FFFF,d} + + m_Key + + + + + {m_Data} + + + $T2 + m_Data + + + + + + {m_Axes} + + + $T2 + m_Axes + + + + + + {{{m_Imag[0]}, {m_Imag[1]}, {m_Imag[2]}, {m_Real}}} + + + 4 + m_Imag + + + + + diff --git a/Source/PopcornFX/Private/Assets/PopcornFXAssetDep.cpp b/Source/PopcornFX/Private/Assets/PopcornFXAssetDep.cpp index 2ea2d04..462d751 100644 --- a/Source/PopcornFX/Private/Assets/PopcornFXAssetDep.cpp +++ b/Source/PopcornFX/Private/Assets/PopcornFXAssetDep.cpp @@ -195,7 +195,7 @@ bool UPopcornFXAssetDep::SetAsset(UPopcornFXFile *file, UObject *asset) FString UPopcornFXAssetDep::GetDefaultAssetPath() const { - return FPopcornFXPlugin::Get().BuildPathFromPkPath(TCHAR_TO_ANSI(*ImportPath), true); + return FPopcornFXPlugin::Get().BuildPathFromPkPath(ToPk(ImportPath), true); } //---------------------------------------------------------------------------- @@ -237,16 +237,16 @@ bool UPopcornFXAssetDep::ReimportAndResetDefaultAsset(UPopcornFXFile *file, bool FString importSourcePath; if (bImportFromCache) { - importSourcePath = FPopcornFXPlugin::Get().SettingsEditor()->SourcePackCacheDir / GetSourcePath(); + importSourcePath = FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackCacheDir / GetSourcePath(); if (!FPaths::FileExists(importSourcePath)) { - UE_LOG(LogPopcornFXAssetDep, Error, TEXT("Source File '%s' not found. Please make sure to right click and 'Build Assets' on the source file."), *(FPopcornFXPlugin::Get().SettingsEditor()->SourcePackRootDir / GetSourcePath())); + UE_LOG(LogPopcornFXAssetDep, Error, TEXT("Source File '%s' not found. Please make sure to right click and 'Build Assets' on the source file."), *(FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackRootDir / GetSourcePath())); return false; } } else { - importSourcePath = FPopcornFXPlugin::Get().SettingsEditor()->SourcePackRootDir / GetSourcePath(); + importSourcePath = FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackRootDir / GetSourcePath(); if (!FPaths::FileExists(importSourcePath)) { UE_LOG(LogPopcornFXAssetDep, Error, TEXT("Source File '%s' not found to Import"), *importSourcePath); @@ -299,17 +299,17 @@ void UPopcornFXAssetDep::GetAssetPath(FString &outputPath) const } PopcornFX::PFilePack pack; - const PopcornFX::CString assetPath = TCHAR_TO_ANSI(*Asset->GetPathName()); + const PopcornFX::CString assetPath = ToPk(Asset->GetPathName()); PK_ASSERT(PopcornFX::File::DefaultFileSystem() != null); const PopcornFX::CString virtPath = PopcornFX::File::DefaultFileSystem()->PhysicalToVirtual(assetPath, &pack); if (!virtPath.Empty()) { PK_VERIFY(pack == FPopcornFXPlugin::Get().FilePack()); - outputPath = ANSI_TO_TCHAR(virtPath.Data()); + outputPath = ToUE(virtPath); return; // OK } - UE_LOG(LogPopcornFXAssetDep, Warning, TEXT("Asset '%s' is outside the mounted PopcornFX Pack"), ANSI_TO_TCHAR(assetPath.Data())); + UE_LOG(LogPopcornFXAssetDep, Warning, TEXT("Asset '%s' is outside the mounted PopcornFX Pack"), *ToUE(assetPath)); outputPath = ImportPath; } @@ -339,7 +339,7 @@ bool UPopcornFXAssetDep::Setup(UPopcornFXFile *file, const FString &sourcePathOr ext == "pkan") bImportFromCache = true; - UObject *asset = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(TCHAR_TO_ANSI(*ImportPath), false); + UObject *asset = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(ToPk(ImportPath), false); if (asset != null) { if (PK_VERIFY(IsCompatibleClass(asset->GetClass()))) @@ -397,7 +397,7 @@ void UPopcornFXAssetDep::PatchFields(UPopcornFXFile *file) const FString newAssetPath; GetAssetPath(newAssetPath); - PopcornFX::CString newAssetPathPk = TCHAR_TO_ANSI(*newAssetPath); // Conv to UE, can't have PK types in public header. + PopcornFX::CString newAssetPathPk = ToPk(newAssetPath); // Conv to UE, can't have PK types in public header. if (!PK_VERIFY(!newAssetPathPk.Empty())) return; @@ -427,7 +427,7 @@ void UPopcornFXAssetDep::PatchFields(UPopcornFXFile *file) const if (bo != null) { - const PopcornFX::CString fieldName = TCHAR_TO_ANSI(*(patch.FieldName)); + const PopcornFX::CString fieldName = ToPk(patch.FieldName); PopcornFX::CGuid fieldId = bo->GetFieldIndex(PopcornFX::CStringView(fieldName)); if (PK_VERIFY(fieldId.Valid())) { @@ -468,7 +468,7 @@ UPopcornFXFile *UPopcornFXAssetDep::ParentPopcornFXFile() const bool UPopcornFXAssetDep::Conflicts(const FString &importPath, EPopcornFXAssetDepType::Type type, const TArray &otherAssetDeps) { - const FString gamePath = FPopcornFXPlugin::Get().BuildPathFromPkPath(TCHAR_TO_ANSI(*importPath), true); + const FString gamePath = FPopcornFXPlugin::Get().BuildPathFromPkPath(ToPk(importPath), true); if (!PK_VERIFY(!gamePath.IsEmpty())) return false; diff --git a/Source/PopcornFX/Private/Assets/PopcornFXEffect.cpp b/Source/PopcornFX/Private/Assets/PopcornFXEffect.cpp index d5b3af6..2b4ff50 100644 --- a/Source/PopcornFX/Private/Assets/PopcornFXEffect.cpp +++ b/Source/PopcornFX/Private/Assets/PopcornFXEffect.cpp @@ -188,7 +188,7 @@ void UPopcornFXEffect::BeginCacheForCookedPlatformData(const ITargetPlatform *ta } FString bakedFilePath; - if (_BakeFile(path, bakedFilePath, false, TCHAR_TO_ANSI(*targetPlatform->PlatformName()))) + if (_BakeFile(path, bakedFilePath, false, targetPlatform->PlatformName())) { // For debugging purposes only, helps inspect content of baked effects if (FPopcornFXPlugin::Get().SettingsEditor()->bDebugBakedEffects) @@ -235,7 +235,7 @@ const PopcornFX::CStringView kQualityLevelNames[] = { "low", "medium", "high", " //---------------------------------------------------------------------------- -bool UPopcornFXEffect::LoadEffect() +bool UPopcornFXEffect::LoadEffect(bool forceImport) { ClearEffect(); @@ -272,7 +272,7 @@ bool UPopcornFXEffect::LoadEffect() m_Loaded = true; - DefaultAttributeList->SetupDefault(this); + DefaultAttributeList->SetupDefault(this, forceImport); return m_Loaded; } @@ -577,7 +577,7 @@ namespace if (filePath.Empty()) return; - FString cleanFilePath = filePath.Data(); + FString cleanFilePath = ToUE(filePath); const PopcornFX::HBO::CFieldDefinition &fieldDef = hbo.GetFieldDefinition(fieldIndex); const PopcornFX::HBO::CFieldAttributesBase &fieldAttribs = fieldDef.GetBaseAttributes(); @@ -716,7 +716,6 @@ namespace bool UPopcornFXEffect::_ImportFile(const FString &filePath) { - DefaultAttributeList->Clean(); ClearEffect(); if (!Super::_ImportFile(filePath)) @@ -749,7 +748,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi for (s32 i = 0; i < qualityLevelCount; ++i) PK_VERIFY(targetBuildVersions.PushBack(PopcornFX::CString::Format("%s:%s%s", kQualityLevelNames[i].Data(), backendAndBuildTags.m_BuildTags.Data(), kQualityLevelNames[i].Data())).Valid()); - const TCHAR *targetPlatformNameForLog = forEditor ? ANSI_TO_TCHAR("UnrealEditor") : *targetPlatformName; + const TCHAR *targetPlatformNameForLog = forEditor ? UTF8_TO_TCHAR("UnrealEditor") : *targetPlatformName; UE_LOG(LogPopcornFXEffect, Display, TEXT("Begin effect baking '%s' for '%s'..."), *GetPathName(), targetPlatformNameForLog); @@ -777,7 +776,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi } PopcornFX::CCookery cookery; - const PopcornFX::SBakeTarget defaultTarget("UE_Generic", TCHAR_TO_ANSI(*bakeDirPath)); + const PopcornFX::SBakeTarget defaultTarget("UE_Generic", ToPk(bakeDirPath)); if (FPopcornFXPlugin::Get().Settings() == null) // Will trigger a load of settings if necessary return false; @@ -846,7 +845,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi #if (PK_COMPILE_GPU != 0) if (backendAndBuildTags.m_BackendTargets > 0) { - if (!_SetupBakeBackendCompilers(bakeConfig, backendAndBuildTags, TCHAR_TO_ANSI(*FileSourceVirtualPath))) + if (!_SetupBakeBackendCompilers(bakeConfig, backendAndBuildTags, ToPk(FileSourceVirtualPath))) { UE_LOG(LogPopcornFXEffect, Warning, TEXT("Couldn't bake effect '%s': failed setting up GPU backend compilers"), *GetPathName()); return false; @@ -859,7 +858,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi bakeConfig->SetExtensionsRemap(extensionsRemap); PopcornFX::CMessageStream bakerErrors; - if (!cookery.BakeAsset(TCHAR_TO_ANSI(*resolvedSrcFilePath), configFile, bakerErrors)) + if (!cookery.BakeAsset(ToPk(resolvedSrcFilePath), configFile, bakerErrors)) { UE_LOG(LogPopcornFXEffect, Warning, TEXT("Failed baking effect '%s' for '%s'%s"), *GetPathName(), targetPlatformNameForLog, !bakerErrors.Messages().Empty() ? ":" : "."); for (const auto &message : bakerErrors.Messages()) @@ -867,7 +866,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi if (message.m_Level >= PopcornFX::CMessageStream::Warning) { const PopcornFX::CString messageText = message.ToString(); - UE_LOG(LogPopcornFXEffect, Warning, TEXT(" - %s"), ANSI_TO_TCHAR(messageText.Data())); + UE_LOG(LogPopcornFXEffect, Warning, TEXT(" - %s"), *ToUE(messageText)); } } return false; @@ -879,7 +878,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi if (message.m_Level >= PopcornFX::CMessageStream::Warning) { const PopcornFX::CString messageText = message.ToString(); - UE_LOG(LogPopcornFXEffect, Warning, TEXT(" - %s"), ANSI_TO_TCHAR(messageText.Data())); + UE_LOG(LogPopcornFXEffect, Warning, TEXT(" - %s"), *ToUE(messageText)); } } } @@ -892,7 +891,7 @@ bool UPopcornFXEffect::_BakeFile(const FString &srcFilePath, FString &outBakedFi bool UPopcornFXEffect::FinishImport() { - if (!LoadEffect()) + if (!LoadEffect(true)) return false; TArray oldAssetDeps = AssetDependencies; diff --git a/Source/PopcornFX/Private/Assets/PopcornFXFile.cpp b/Source/PopcornFX/Private/Assets/PopcornFXFile.cpp index b608621..3e5b0a2 100644 --- a/Source/PopcornFX/Private/Assets/PopcornFXFile.cpp +++ b/Source/PopcornFX/Private/Assets/PopcornFXFile.cpp @@ -40,21 +40,21 @@ namespace { PK_ASSERT(!file.IsUnreachable()); - PopcornFX::CString rawFilePath = TCHAR_TO_ANSI(*file.GetPathName()); + PopcornFX::CString rawFilePath = ToPk(file.GetPathName()); PopcornFX::PFilePack pack = FPopcornFXPlugin::Get().FilePack(); if (pack == null) { - UE_LOG(LogPopcornFile, Warning/*Error*/, TEXT("PopcornFX pack not loaded, cannot find '%s'"), ANSI_TO_TCHAR(rawFilePath.Data())); + UE_LOG(LogPopcornFile, Warning/*Error*/, TEXT("PopcornFX pack not loaded, cannot find '%s'"), *ToUE(rawFilePath)); return null; } const PopcornFX::CString &packPath = pack->Path(); - if (!rawFilePath.StartsWith(packPath.Data())) + if (!rawFilePath.StartsWith(packPath)) { #if WITH_EDITOR if (!IsRunningCommandlet()) // We don't want this error to fail the packaging { FText title = LOCTEXT("import_outside_mountpoint_title", "PopcornFX: Invalid file location"); - FText finalText = FText::FromString(FString::Printf(TEXT("The PopcornFX file '%s' is outside the mount point of the PopcornFX pack '%s'"), ANSI_TO_TCHAR(rawFilePath.Data()), ANSI_TO_TCHAR(packPath.Data()))); + FText finalText = FText::FromString(FString::Printf(TEXT("The PopcornFX file '%s' is outside the mount point of the PopcornFX pack '%s'"), *ToUE(rawFilePath), *ToUE(packPath))); OpenMessageBox(EAppMsgType::Ok, finalText, title); } @@ -71,7 +71,7 @@ namespace rawFilePath = PopcornFX::CFilePath::StripExtension(rawFilePath); rawFilePath += "."; - rawFilePath += TCHAR_TO_ANSI(*file.PkExtension()); + rawFilePath += ToPk(file.PkExtension()); return rawFilePath; } } @@ -229,13 +229,13 @@ bool UPopcornFXFile::ImportThumbnail() { UE_LOG(LogPopcornFile, Warning, TEXT("Imported file is outside Source PopcornFX Project, we cannot import its thumbnail !")); } - else if (!PK_VERIFY(settings != null) || settings->SourcePackThumbnailsDir.IsEmpty()) + else if (!PK_VERIFY(settings != null) || settings->AbsSourcePackThumbnailsDir.IsEmpty()) { UE_LOG(LogPopcornFile, Warning, TEXT("Source PopcornFX Project is invalid, we cannot import its thumbnail !")); } else // ok { - const FString srcPath = settings->SourcePackThumbnailsDir / FileSourceVirtualPath + TEXT(".png"); + const FString srcPath = settings->AbsSourcePackThumbnailsDir / FileSourceVirtualPath + TEXT(".png"); bool bImportWasCancelled; if (ThumbnailImage == null || !FReimportManager::Instance()->Reimport(ThumbnailImage, false, false)) @@ -272,7 +272,7 @@ FString UPopcornFXFile::FileSourcePath() const { PK_ASSERT(!FileSourceVirtualPath.IsEmpty()); if (FileSourceVirtualPathIsNotVirtual == 0) - return FPopcornFXPlugin::Get().SettingsEditor()->SourcePackRootDir / FileSourceVirtualPath; + return FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackRootDir / FileSourceVirtualPath; return FileSourceVirtualPath; } @@ -286,7 +286,7 @@ void UPopcornFXFile::SetFileSourcePath(const FString &fileSourcePath) m_IsBaseObject = false; bool absoluteImport = true; - const FString packDir = FPopcornFXPlugin::Get().SettingsEditor()->SourcePackRootDir / ""; + const FString packDir = FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackRootDir / ""; if (packDir.Len() > 0) { @@ -340,8 +340,8 @@ void UPopcornFXFile::AskImportAssetDependenciesIFN() bool foundSome = false; - const FString sourcePack = FPopcornFXPlugin::Get().SettingsEditor()->SourcePackRootDir; - const FString sourcePackCacheDir = FPopcornFXPlugin::Get().SettingsEditor()->SourcePackCacheDir; + const FString sourcePack = FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackRootDir; + const FString sourcePackCacheDir = FPopcornFXPlugin::Get().SettingsEditor()->AbsSourcePackCacheDir; for (int32 asseti = 0; asseti < AssetDependencies.Num(); ++asseti) { const UPopcornFXAssetDep *assetDep = AssetDependencies[asseti]; diff --git a/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp b/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp index 4f0ab09..41fe6f6 100644 --- a/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp +++ b/Source/PopcornFX/Private/Assets/PopcornFXMesh.cpp @@ -228,7 +228,7 @@ PopcornFX::PResourceMesh UPopcornFXMesh::LoadResourceMeshIFN(bool editorBuildIFN m_ResourceMesh = PopcornFX::CResourceMesh::Load(PopcornFX::File::DefaultFileSystem(), PopcornFX::CFilePackPath(FPopcornFXPlugin::Get().FilePack(), PkPath()), outReport); if (m_ResourceMesh == null) { - UE_LOG(LogPopcornMesh, Warning, TEXT("Couldn't load PopcornFX mesh '%s'"), ANSI_TO_TCHAR(PkPath())); + UE_LOG(LogPopcornMesh, Warning, TEXT("Couldn't load PopcornFX mesh '%s'"), *ToUE(PkPath())); m_ResourceMesh = null; } } @@ -394,6 +394,13 @@ namespace const u32 numVertices = section.GetNumVertices(); const u32 sectionInfluenceCount = section.MaxBoneInfluences; +#if (ENGINE_MAJOR_VERSION == 4) + const float boneWeightNormalizer = 1.0f / 255.0f; +#else + // 'GetBoneWeight()' will always return 16-bit bone weights, even if 'Use16BitBoneWeight()' is false, or if 'GetBoneWeightByteSize()' returns 1 + const float boneWeightNormalizer = 1.0f / 65535.0f; +#endif + for (u32 iVertex = 0; iVertex < numVertices; ++iVertex) { const u32 vertexIndex = sectionOffset + iVertex; @@ -419,7 +426,7 @@ namespace for (u32 iInfluence = 0; iInfluence < sectionInfluenceCount; ++iInfluence) { const float localBoneWeight = LODRenderData.SkinWeightVertexBuffer.GetBoneWeight(vertexIndex, iInfluence); - const float boneWeight = localBoneWeight / 255.0f; + const float boneWeight = localBoneWeight * boneWeightNormalizer; PK_ONLY_IF_ASSERTS(weightsSum += boneWeight); _boneWeights[offsetInfluences + iInfluence] = boneWeight; diff --git a/Source/PopcornFX/Private/Assets/PopcornFXRendererMaterial.cpp b/Source/PopcornFX/Private/Assets/PopcornFXRendererMaterial.cpp index 9e801ce..55ad466 100644 --- a/Source/PopcornFX/Private/Assets/PopcornFXRendererMaterial.cpp +++ b/Source/PopcornFX/Private/Assets/PopcornFXRendererMaterial.cpp @@ -1649,16 +1649,16 @@ UTexture2D *LoadTexturePk(const PopcornFX::CString &pkPath) if (pkPath.Empty()) return null; - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath.Data(), false); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath, false); UTexture2D *texture = Cast(obj); if (obj != null && texture == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not a texture: '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not a texture: '%s'"), *ToUE(pkPath)); return null; } if (texture == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load texture '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load texture '%s'"), *ToUE(pkPath)); return null; } return texture; @@ -1671,16 +1671,16 @@ UPopcornFXTextureAtlas *LoadAtlasPk(const PopcornFX::CString &pkPath) if (pkPath.Empty()) return null; - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath.Data(), false); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath, false); UPopcornFXTextureAtlas *atlas = Cast(obj); if (obj != null && atlas == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not an atlas: '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not an atlas: '%s'"), *ToUE(pkPath)); return null; } if (atlas == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load atlas '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load atlas '%s'"), *ToUE(pkPath)); return null; } return atlas; @@ -1693,16 +1693,16 @@ UStaticMesh *LoadMeshPk(const PopcornFX::CString &pkPath) if (pkPath.Empty()) return null; - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath.Data(), false); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath, false); UStaticMesh *mesh = Cast(obj); if (obj != null && mesh == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not a mesh: '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not a mesh: '%s'"), *ToUE(pkPath)); return null; } if (mesh == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load mesh '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load mesh '%s'"), *ToUE(pkPath)); return null; } return mesh; @@ -1715,16 +1715,16 @@ USkeletalMesh *LoadSkelMeshPk(const PopcornFX::CString &pkPath) if (pkPath.Empty()) return null; - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath.Data(), false); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(pkPath, false); USkeletalMesh *mesh = Cast(obj); if (obj != null && mesh == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not a skeletal mesh: '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Asset is not a skeletal mesh: '%s'"), *ToUE(pkPath)); return null; } if (mesh == null) { - UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load skeletal mesh '%s'"), ANSI_TO_TCHAR(pkPath.Data())); + UE_LOG(LogPopcornFXRendererMaterial, Warning, TEXT("Could not load skeletal mesh '%s'"), *ToUE(pkPath)); return null; } return mesh; @@ -1734,7 +1734,7 @@ USkeletalMesh *LoadSkelMeshPk(const PopcornFX::CString &pkPath) void SetMaterialTextureParameter(UMaterialInstanceDynamic *mat, FName textureName, const PopcornFX::CString &pkTexturePath) { - mat->SetTextureParameterValue(textureName, LoadTexturePk(pkTexturePath.Data())); + mat->SetTextureParameterValue(textureName, LoadTexturePk(pkTexturePath)); } //---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeFunctions.cpp b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeFunctions.cpp index 9341ef4..8cd4f4f 100644 --- a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeFunctions.cpp +++ b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeFunctions.cpp @@ -112,11 +112,10 @@ namespace const char *attrType = (dstAttrTraits.ScalarType == PopcornFX::BaseType_Bool ? "Bool" : (dstAttrTraits.IsFp ? "Float" : "Int")); UE_LOG(LogPopcornFXAttributeFunctions, Warning, TEXT("SetAttributeAs: the Attribute [%d] \"%s\" cannot be set as %s %d: the attribute is %s %d (%s)"), - attri, ANSI_TO_TCHAR(decl->ExportedName().Data()), - ANSI_TO_TCHAR(inType), _Dim, - ANSI_TO_TCHAR(attrType), dstAttrTraits.VectorDimension, - *(component->GetPathName()) - ); + attri, *ToUE(decl->ExportedName()), + UTF8_TO_TCHAR(inType), _Dim, + UTF8_TO_TCHAR(attrType), dstAttrTraits.VectorDimension, + *(component->GetPathName())); return false; } } @@ -176,11 +175,10 @@ namespace const char *attrType = (dstAttrTraits.ScalarType == PopcornFX::BaseType_Bool ? "Bool" : (dstAttrTraits.IsFp ? "Float" : "Int")); UE_LOG(LogPopcornFXAttributeFunctions, Warning, TEXT("GetAttributeAs: the Attribute [%d] \"%s\" cannot be get as %s %d: the attribute is %s %d (%s)"), - attri, ANSI_TO_TCHAR(decl->ExportedName().Data()), - ANSI_TO_TCHAR(inType), _Dim, - ANSI_TO_TCHAR(attrType), dstAttrTraits.VectorDimension, - *(component->GetPathName()) - ); + attri, *ToUE(decl->ExportedName()), + UTF8_TO_TCHAR(inType), _Dim, + UTF8_TO_TCHAR(attrType), dstAttrTraits.VectorDimension, + *(component->GetPathName())); return false; } } diff --git a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeList.cpp b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeList.cpp index 0624885..eaca5e6 100644 --- a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeList.cpp +++ b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeList.cpp @@ -86,6 +86,8 @@ EPopcornFXAttributeSamplerType::Type ResolveAttribSamplerType(const PopcornFX::C return EPopcornFXAttributeSamplerType::Shape; case PopcornFX::SParticleDeclaration::SSampler::Sampler_Image: return EPopcornFXAttributeSamplerType::Image; + case PopcornFX::SParticleDeclaration::SSampler::Sampler_Grid: + return EPopcornFXAttributeSamplerType::Grid; case PopcornFX::SParticleDeclaration::SSampler::Sampler_Text: return EPopcornFXAttributeSamplerType::Text; case PopcornFX::SParticleDeclaration::SSampler::Sampler_VectorField: @@ -109,7 +111,7 @@ void ResetAttribute(FPopcornFXAttributeDesc &attrib, const PopcornFX::CParticleA { if (decl != null) { - attrib.m_AttributeFName = *FString(ANSI_TO_TCHAR(decl->ExportedName().Data())); + attrib.m_AttributeFName = *FString(ToUE(decl->ExportedName())); attrib.m_AttributeType = decl->ExportedType(); #if WITH_EDITOR @@ -126,7 +128,7 @@ void ResetAttribute(FPopcornFXAttributeDesc &attrib, const PopcornFX::CParticleA attrib.m_EnumList.SetNum(decl->EnumList().Count()); for (u32 i = 0; i < decl->EnumList().Count(); ++i) - attrib.m_EnumList[i] = ANSI_TO_TCHAR(decl->EnumList()[i].Data()); + attrib.m_EnumList[i] = ToUE(decl->EnumList()[i]); if ((PopcornFX::EBaseTypeID)attrib.m_AttributeType == PopcornFX::BaseType_Quaternion) { @@ -135,7 +137,7 @@ void ResetAttribute(FPopcornFXAttributeDesc &attrib, const PopcornFX::CParticleA attrib.m_AttributeEulerAngles = FVector(rotator.Roll, rotator.Pitch, rotator.Yaw); } #endif // WITH_EDITOR - attrib.m_AttributeCategoryName = *FString((const UTF16CHAR*)decl->CategoryName().MapDefault().Data()); + attrib.m_AttributeCategoryName = *ToUE(decl->CategoryName().MapDefault()); if (!attrib.m_AttributeCategoryName.IsValid() || attrib.m_AttributeCategoryName.IsNone()) attrib.m_AttributeCategoryName = "General"; } @@ -150,10 +152,10 @@ void ResetAttributeSampler(FPopcornFXSamplerDesc &attribSampler, const PopcornFX { if (decl != null) { - attribSampler.m_SamplerFName = *FString(ANSI_TO_TCHAR(decl->ExportedName().Data())); + attribSampler.m_SamplerFName = *FString(ToUE(decl->ExportedName())); attribSampler.m_SamplerType = ResolveAttribSamplerType(decl); - attribSampler.m_AttributeCategoryName = *FString((const UTF16CHAR*)decl->CategoryName().MapDefault().Data()); + attribSampler.m_AttributeCategoryName = *ToUE(decl->CategoryName().MapDefault()); if (!attribSampler.m_AttributeCategoryName.IsValid() || attribSampler.m_AttributeCategoryName.IsNone()) attribSampler.m_AttributeCategoryName = "General"; } @@ -506,6 +508,7 @@ void UPopcornFXAttributeList::SetupDefault(UPopcornFXEffect *effect, bool force) { DBG_HERE(); + if (!force && IsUpToDate(effect)) { #if WITH_EDITOR @@ -519,6 +522,8 @@ void UPopcornFXAttributeList::SetupDefault(UPopcornFXEffect *effect, bool force) return; } + const uint32 oldAttributesCount = m_Attributes.Num(); + #if WITH_EDITOR Modify(); #endif @@ -552,23 +557,27 @@ void UPopcornFXAttributeList::SetupDefault(UPopcornFXEffect *effect, bool force) const int32 attrCount = attrs.Count(); const int32 samplerCount = samplers.Count(); -#if WITH_EDITOR m_Attributes.SetNum(attrCount); for (int32 attri = 0; attri < attrCount; ++attri) { ResetAttribute(m_Attributes[attri], attrs[attri]); +#if WITH_EDITOR if (m_Attributes[attri].m_AttributeCategoryName.IsValid() && !m_Attributes[attri].m_AttributeCategoryName.IsNone()) m_Categories.AddUnique(m_Attributes[attri].m_AttributeCategoryName); +#endif // WITH_EDITOR } m_Samplers.SetNum(samplerCount); for (int32 sampleri = 0; sampleri < samplerCount; ++sampleri) { ResetAttributeSampler(m_Samplers[sampleri], samplers[sampleri]); +#if WITH_EDITOR if (m_Samplers[sampleri].m_AttributeCategoryName.IsValid() && !m_Samplers[sampleri].m_AttributeCategoryName.IsNone()) m_Categories.AddUnique(m_Samplers[sampleri].m_AttributeCategoryName); +#endif // WITH_EDITOR } +#if WITH_EDITOR if (attrCount > 0 || samplerCount > 0) { // Make "General" the first category if not already @@ -588,7 +597,8 @@ void UPopcornFXAttributeList::SetupDefault(UPopcornFXEffect *effect, bool force) const uint32 attribBytes = defContainer->Attributes().CoveredBytes(); m_AttributesRawData.SetNumUninitialized(attribBytes); - if (attribBytes > 0) + + if (attribBytes > 0 && (oldAttributesCount != attrCount)) PopcornFX::Mem::Copy(m_AttributesRawData.GetData(), defContainer->Attributes().Data(), attribBytes); PK_ASSERT(CheckDataIntegrity()); @@ -1298,6 +1308,46 @@ void UPopcornFXAttributeList::SetAttributeDim(uint32 attributeId, uint32 d SetAttribute(attributeId, *reinterpret_cast(&newValue), fromUI); // Ugly cast, so PopcornFXAttributeList.h is a public header to satisfy UE4 nativization bugs. To refactor some day } +//---------------------------------------------------------------------------- + +void UPopcornFXAttributeList::PulseBoolAttributeDim(uint32 attributeId, uint32 dim, bool fromUI/* = false*/) +{ + SetAttributeDim(attributeId, dim, true, fromUI); + m_HasPendingOneShotReset = true; +} + +//---------------------------------------------------------------------------- + +void UPopcornFXAttributeList::ResetPulsedBoolAttributesIFN() +{ + if (!m_HasPendingOneShotReset) // Early-out most of the time + return; + m_HasPendingOneShotReset = false; + + if (!m_Owner.IsValid() /*&& m_Owner->IsEmitterStarted()*/) // don't check if the emitter is started, even if stopped as long as particles are still here we want this logic to run + return; + PopcornFX::CParticleEffectInstance *effectInstance = m_Owner->_GetEffectInstance(); + if (effectInstance == null) + return; + + for (int32 i = 0; i < m_Attributes.Num(); i++) + { + const PopcornFX::CParticleAttributeDeclaration *decl = effectInstance->GetAttributeDecl(i); + if (decl != null && decl->OneShotTrigger()) + { + const PopcornFX::EBaseTypeID typeID = PopcornFX::EBaseTypeID(decl->ExportedType()); + if (PK_VERIFY(PopcornFX::CBaseTypeTraits::Traits(typeID).ScalarType == PopcornFX::BaseType_Bool)) // OneShotTrigger but not a 'bool' type ? + { + // Do not call 'UPopcornFXAttributeList::SetAttribute()', we don't want the 'RestartEmitter' logic at all here ! + FPopcornFXAttributeValue newValue = { 0, 0, 0, 0 }; + const PopcornFX::SAttributesContainer_SAttrib &_value = *reinterpret_cast(&newValue); // FIXME: We don't actually care about FPopcornFXAttributeValue, add a way to ctor a new SAttrib in one line + PK_VERIFY(effectInstance->SetRawAttribute(i, typeID, &_value, true)); + AttributeRawDataAttributes(this)[i] = _value; + } + } + } +} + #endif // WITH_EDITOR //---------------------------------------------------------------------------- @@ -1392,7 +1442,7 @@ void UPopcornFXAttributeList::_RefreshAttributeSamplers(UPopcornFXEmitterCompone if (desc.SamplerType() == EPopcornFXAttributeSamplerType::None) { - effectInstance->SetAttributeSampler(TCHAR_TO_ANSI(*desc.SamplerName()), null); + effectInstance->SetAttributeSampler(TCHAR_TO_UTF8(*desc.SamplerName()), null); continue; } @@ -1401,7 +1451,7 @@ void UPopcornFXAttributeList::_RefreshAttributeSamplers(UPopcornFXEmitterCompone if (attribSampler == null || !PK_VERIFY(desc.SamplerType() == attribSampler->SamplerType())) { - effectInstance->SetAttributeSampler(TCHAR_TO_ANSI(*desc.SamplerName()), null); + effectInstance->SetAttributeSampler(TCHAR_TO_UTF8(*desc.SamplerName()), null); continue; } @@ -1411,7 +1461,7 @@ void UPopcornFXAttributeList::_RefreshAttributeSamplers(UPopcornFXEmitterCompone if (!IsRunningCommandlet() && attribSampler != null) samplerDescriptor = attribSampler->_AttribSampler_SetupSamplerDescriptor(desc, defaultSampler.Get()); - effectInstance->SetAttributeSampler(TCHAR_TO_ANSI(*desc.SamplerName()), samplerDescriptor != null ? samplerDescriptor : null); + effectInstance->SetAttributeSampler(TCHAR_TO_UTF8(*desc.SamplerName()), samplerDescriptor != null ? samplerDescriptor : null); } } diff --git a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplerSkinnedMesh.cpp b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplerSkinnedMesh.cpp index 09728f2..1fb0c8f 100644 --- a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplerSkinnedMesh.cpp +++ b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplerSkinnedMesh.cpp @@ -211,7 +211,7 @@ void UPopcornFXAttributeSamplerSkinnedMesh::Clear() m_Data->m_SkinContext.m_SrcPositions = TStridedMemoryView(); m_Data->m_SkinContext.m_SrcNormals = TStridedMemoryView(); - m_Data->m_SkinContext.m_SrcTangents = TStridedMemoryView(); + m_Data->m_SkinContext.m_SrcTangents = TStridedMemoryView(); m_Data->m_SkinContext.m_DstPositions = TStridedMemoryView(); m_Data->m_SkinContext.m_DstNormals = TStridedMemoryView(); @@ -313,7 +313,8 @@ void UPopcornFXAttributeSamplerSkinnedMesh::Skin_Finish(const PopcornFX::SSkinCo // Rebuild sampling structures if bone visibility array has changed if (!m_Data->m_BoneVisibilityChanged) return; - if (!PK_VERIFY(bSkinPositions)) + + if (!bSkinPositions) { // @TODO : warn the user that distribution will be invalid if he only checked bSkinNormals or bSkinTangents // and he either is sampling a destructible mesh or the target skinned mesh component got one of its bone hidden/unhidden @@ -710,16 +711,16 @@ namespace _IndexType * __restrict boneIndices = reinterpret_cast<_IndexType*>(data->m_BoneIndices.RawDataPointer()); - const bool skin = (buildDesc.m_BuildFlags & (Build_Positions | Build_Tangents | Build_Normals)) != 0; + const bool skin = (buildDesc.m_BuildFlags & (Build_Positions | Build_Normals | Build_Tangents)) != 0; if (skin) { PK_NAMEDSCOPEDPROFILE_C("AttributeSamplerSkinnedMesh::Copy src positions/normals/tangents", POPCORNFX_UE_PROFILER_COLOR); - PK_ASSERT(srcPositionsView.Stride() == data->m_DstPositions.Stride()); if (buildDesc.m_BuildFlags & Build_Positions) { if (!PK_VERIFY(srcPositionsView.Count() == data->m_DstPositions.Count())) return false; + PK_ASSERT(srcPositionsView.Stride() == data->m_DstPositions.Stride()); data->m_SkinContext.m_SrcPositions = srcPositionsView; PopcornFX::Mem::Copy(data->m_DstPositions.RawDataPointer(), srcPositionsView.Data(), sizeof(CFloat4) * srcPositionsView.Count()); } @@ -734,7 +735,7 @@ namespace } if (buildDesc.m_BuildFlags & Build_Tangents) { - const TStridedMemoryView srcTangentsView = TStridedMemoryView::Reinterpret(vstream.Tangents()); + const TStridedMemoryView srcTangentsView = vstream.Tangents(); if (!PK_VERIFY(srcTangentsView.Count() == data->m_DstTangents.Count())) return false; PK_ASSERT(srcTangentsView.Stride() == data->m_DstTangents.Stride()); diff --git a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplers.cpp b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplers.cpp index 1e20f65..8a9fff3 100644 --- a/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplers.cpp +++ b/Source/PopcornFX/Private/Attributes/PopcornFXAttributeSamplers.cpp @@ -13,6 +13,7 @@ #include "PopcornFXAttributeSamplerShape.h" #include "PopcornFXAttributeSamplerSkinnedMesh.h" #include "PopcornFXAttributeSamplerImage.h" +#include "PopcornFXAttributeSamplerGrid.h" #include "PopcornFXAttributeSamplerText.h" #include "PopcornFXAttributeSamplerCurve.h" #include "PopcornFXAttributeSamplerCurveDynamic.h" @@ -22,6 +23,7 @@ #include "Assets/PopcornFXMesh.h" #include "Assets/PopcornFXTextureAtlas.h" #include "Internal/ResourceHandlerImage_UE.h" +#include "Platforms/PopcornFXPlatform.h" #include "Components/SplineComponent.h" #include "Components/BillboardComponent.h" @@ -33,6 +35,10 @@ #include "VectorField/VectorFieldStatic.h" #include "Serialization/BulkData.h" #include "Curves/RichCurve.h" +#include "Engine/VolumeTexture.h" +#include "Materials/MaterialInstanceDynamic.h" +#include "Engine/TextureRenderTarget2D.h" +#include "Engine/TextureRenderTargetVolume.h" #include "Engine/Texture.h" #include "Engine/Texture2D.h" #include "UObject/Package.h" @@ -62,6 +68,7 @@ #if (PK_GPU_D3D12 != 0) # include # include + # include "Windows/HideWindowsPlatformTypes.h" # include "D3D12RHIPrivate.h" # include "D3D12Util.h" @@ -97,7 +104,6 @@ APopcornFXAttributeSamplerActor::APopcornFXAttributeSamplerActor(const FObjectIn {} }; static FConstructorStatics ConstructorStatics; - // SpriteComponent->RelativeScale3D = FVector(0.5f, 0.5f, 0.5f); SpriteComponent->SetRelativeScale3D(FVector(1.5f)); SpriteComponent->bHiddenInGame = true; @@ -153,6 +159,12 @@ APopcornFXAttributeSamplerImageActor::APopcornFXAttributeSamplerImageActor(const _CtorRootSamplerComponent(PCIP, EPopcornFXAttributeSamplerComponentType::Image); } +APopcornFXAttributeSamplerGridActor::APopcornFXAttributeSamplerGridActor(const FObjectInitializer &PCIP) +: Super(PCIP) +{ + _CtorRootSamplerComponent(PCIP, EPopcornFXAttributeSamplerComponentType::Grid); +} + APopcornFXAttributeSamplerCurveActor::APopcornFXAttributeSamplerCurveActor(const FObjectInitializer &PCIP) : Super(PCIP) { @@ -204,6 +216,9 @@ void APopcornFXAttributeSamplerActor::ReloadSprite() case EPopcornFXAttributeSamplerComponentType::Image: spriteName = "AttributeSampler_Image"; break; + case EPopcornFXAttributeSamplerComponentType::Grid: + spriteName = "AttributeSampler_Image"; //"AttributeSampler_Grid"; // TODO: Grid icon + break; case EPopcornFXAttributeSamplerComponentType::AnimTrack: spriteName = "Attributesampler_AnimTrack"; break; @@ -271,7 +286,7 @@ void APopcornFXAttributeSamplerActor::PostRegisterAllComponents() //---------------------------------------------------------------------------- -void APopcornFXAttributeSamplerActor::PostLoad() +void APopcornFXAttributeSamplerActor::PostLoad() { Super::PostLoad(); #if WITH_EDITOR @@ -286,7 +301,7 @@ void APopcornFXAttributeSamplerActor::PostLoad() //---------------------------------------------------------------------------- -void APopcornFXAttributeSamplerActor::PostActorCreated() +void APopcornFXAttributeSamplerActor::PostActorCreated() { Super::PostActorCreated(); #if WITH_EDITOR @@ -301,7 +316,7 @@ void APopcornFXAttributeSamplerActor::PostActorCreated() //---------------------------------------------------------------------------- // static -UClass *UPopcornFXAttributeSampler::SamplerComponentClass(EPopcornFXAttributeSamplerComponentType::Type type) +UClass *UPopcornFXAttributeSampler::SamplerComponentClass(EPopcornFXAttributeSamplerComponentType::Type type) { switch (type) { @@ -311,6 +326,8 @@ UClass *UPopcornFXAttributeSampler::SamplerComponentClass(EPopcornFXAttributeSa return UPopcornFXAttributeSamplerSkinnedMesh::StaticClass(); case EPopcornFXAttributeSamplerComponentType::Image: return UPopcornFXAttributeSamplerImage::StaticClass(); + case EPopcornFXAttributeSamplerComponentType::Grid: + return UPopcornFXAttributeSamplerGrid::StaticClass(); case EPopcornFXAttributeSamplerComponentType::Curve: return UPopcornFXAttributeSamplerCurve::StaticClass(); case EPopcornFXAttributeSamplerComponentType::AnimTrack: @@ -1976,7 +1993,7 @@ PopcornFX::CParticleSamplerDescriptor *UPopcornFXAttributeSamplerText::_AttribSa // @TODO kerning PopcornFX::CFontMetrics *fontMetrics = null; bool useKerning = false; - if (!PK_VERIFY(m_Data->m_Desc->_Setup(TCHAR_TO_ANSI(*Text), fontMetrics, useKerning))) + if (!PK_VERIFY(m_Data->m_Desc->_Setup(ToPk(Text), fontMetrics, useKerning))) return null; m_Data->m_NeedsReload = false; } @@ -2069,13 +2086,10 @@ void UPopcornFXAttributeSamplerImage::OnUnregister() { if (m_Data != null) { -#if (PK_GPU_D3D12 != 0)//(PK_HAS_GPU != 0) // Unregister the component during OnUnregister instead of BeginDestroy. // In editor mode, BeginDestroy is only called when saving a level: // Components ReregisterComponent() do not have a matching BeginDestroy call in editor - if (m_Data->m_Desc != null) - m_Data->m_Desc = null; -#endif // (PK_HAS_GPU != 0) + m_Data->m_Desc = null; } Super::OnUnregister(); } @@ -2113,9 +2127,9 @@ void UPopcornFXAttributeSamplerImage::PostEditChangeProperty(FPropertyChangedEve m_Data->m_ReloadTextureAtlas = true; m_Data->m_RebuildPDF = true; } - else if (propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerImage, SamplingMode) || - propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerImage, DensitySource) || - propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerImage, DensityPower)) + else if ( propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerImage, SamplingMode) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerImage, DensitySource) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerImage, DensityPower)) { m_Data->m_RebuildPDF = true; } @@ -2172,7 +2186,7 @@ bool UPopcornFXAttributeSamplerImage::_RebuildImageSampler() const bool rebuildImage = m_Data->m_ReloadTexture; if (rebuildImage) { - const PopcornFX::CString fullPath = TCHAR_TO_ANSI(*Texture->GetPathName()); + const PopcornFX::CString fullPath = ToPk(Texture->GetPathName()); bool success = false; m_Data->m_TextureResource = PopcornFX::Resource::DefaultManager()->Load(fullPath, true); success |= (m_Data->m_TextureResource != null && !m_Data->m_TextureResource->Empty()); @@ -2196,7 +2210,7 @@ bool UPopcornFXAttributeSamplerImage::_RebuildImageSampler() if (!success) // Couldn't load any of the resources (CPU/GPU) { - UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("AttrSamplerImage: couldn't load texture '%s' for CPU/GPU sim sampling"), fullPath.Data()); + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("AttrSamplerImage: couldn't load texture '%s' for CPU/GPU sim sampling"), *ToUE(fullPath)); return false; } m_Data->m_ReloadTexture = false; @@ -2207,7 +2221,7 @@ bool UPopcornFXAttributeSamplerImage::_RebuildImageSampler() if (TextureAtlas != null) { bool success = false; - const PopcornFX::CString fullPath = TCHAR_TO_ANSI(*TextureAtlas->GetPathName()); + const PopcornFX::CString fullPath = ToPk(TextureAtlas->GetPathName()); m_Data->m_TextureAtlasResource = PopcornFX::Resource::DefaultManager()->Load(fullPath, true); success |= (m_Data->m_TextureAtlasResource != null && !m_Data->m_TextureAtlasResource->Empty()); @@ -2223,7 +2237,7 @@ bool UPopcornFXAttributeSamplerImage::_RebuildImageSampler() if (!success) // Couldn't load any of the resources (CPU/GPU) { - UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("AttrSamplerImage: couldn't load texture atlas '%s' for CPU/GPU sim sampling"), fullPath.Data()); + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("AttrSamplerImage: couldn't load texture atlas '%s' for CPU/GPU sim sampling"), *ToUE(fullPath)); return false; } } @@ -2368,8 +2382,8 @@ bool UPopcornFXAttributeSamplerImage::_BuildRegularImage(PopcornFX::CImageSurfac UE_LOG(LogPopcornFXAttributeSampler, Log, TEXT("AttrSamplerImage: texture '%s' format %s not supported for sampling, converting to %s (because AllowTextureConvertionAtRuntime) in '%s'"), *Texture->GetName(), - ANSI_TO_TCHAR(PopcornFX::CImage::GetFormatName(m_Data->m_TextureResource->m_Format)), - ANSI_TO_TCHAR(PopcornFX::CImage::GetFormatName(dstFormat)), + UTF8_TO_TCHAR(PopcornFX::CImage::GetFormatName(m_Data->m_TextureResource->m_Format)), + UTF8_TO_TCHAR(PopcornFX::CImage::GetFormatName(dstFormat)), *GetPathName()); PopcornFX::CImageSurface newSurface; @@ -2379,8 +2393,8 @@ bool UPopcornFXAttributeSamplerImage::_BuildRegularImage(PopcornFX::CImageSurfac UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("AttrSamplerImage: could not convert texture '%s' from %s to %s in %s"), *Texture->GetName(), - ANSI_TO_TCHAR(PopcornFX::CImage::GetFormatName(m_Data->m_TextureResource->m_Format)), - ANSI_TO_TCHAR(PopcornFX::CImage::GetFormatName(dstFormat)), + UTF8_TO_TCHAR(PopcornFX::CImage::GetFormatName(m_Data->m_TextureResource->m_Format)), + UTF8_TO_TCHAR(PopcornFX::CImage::GetFormatName(dstFormat)), *GetPathName()); return false; } @@ -2394,7 +2408,7 @@ bool UPopcornFXAttributeSamplerImage::_BuildRegularImage(PopcornFX::CImageSurfac UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("AttrSamplerImage: texture '%s' format %s not supported for sampling (and AllowTextureConvertionAtRuntime not enabled) in %s"), *Texture->GetName(), - ANSI_TO_TCHAR(PopcornFX::CImage::GetFormatName(m_Data->m_TextureResource->m_Format)), + UTF8_TO_TCHAR(PopcornFX::CImage::GetFormatName(m_Data->m_TextureResource->m_Format)), *GetPathName()); return false; } @@ -2402,6 +2416,424 @@ bool UPopcornFXAttributeSamplerImage::_BuildRegularImage(PopcornFX::CImageSurfac return true; } +//---------------------------------------------------------------------------- +// +// UPopcornFXAttributeSamplerGrid +// +//---------------------------------------------------------------------------- + +struct FAttributeSamplerGridData +{ + bool m_ReloadGrid = true; + PopcornFX::PParticleSamplerDescriptor_Grid_Default m_Desc; + + void Clear() + { + m_Desc = null; + m_ReloadGrid = true; + } + + FAttributeSamplerGridData() { } + + ~FAttributeSamplerGridData() + { + } +}; + +//---------------------------------------------------------------------------- + +void UPopcornFXAttributeSamplerGrid::SetRenderTarget(class UTextureRenderTarget *InRenderTarget) +{ + RenderTarget = InRenderTarget; +} + +//---------------------------------------------------------------------------- + +void UPopcornFXAttributeSamplerGrid::SetAsMaterialTextureParameter(UMaterialInstanceDynamic *Material, FName ParameterName) +{ + if (Material == null) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("SetAsMaterialTextureParameter: couldn't set grid as material texture parameter: null material")); + return; + } + UTexture *texture = GridTexture(); + if (texture == null) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("SetAsMaterialTextureParameter: couldn't set grid as material texture parameter: empty grid texture")); + return; + } + Material->SetTextureParameterValue(ParameterName, texture); +} + +//---------------------------------------------------------------------------- + +UPopcornFXAttributeSamplerGrid::UPopcornFXAttributeSamplerGrid(const FObjectInitializer &PCIP) +: Super(PCIP) +{ + bAutoActivate = true; + + RenderTarget = null; + bAssetGrid = false; + + bSRGB = false; + + SizeX = 128; + SizeY = 128; + SizeZ = 1; + + DataType = EPopcornFXGridDataType::RGBA; + + // UPopcornFXAttributeSampler override: + m_SamplerType = EPopcornFXAttributeSamplerType::Grid; + + m_Data = new FAttributeSamplerGridData(); + check(m_Data != null); +} + +//---------------------------------------------------------------------------- + +void UPopcornFXAttributeSamplerGrid::OnUnregister() +{ + if (m_Data != null) + { + // Unregister the component during OnUnregister instead of BeginDestroy. + // In editor mode, BeginDestroy is only called when saving a level: + // Components ReregisterComponent() do not have a matching BeginDestroy call in editor + m_Data->m_Desc = null; + m_Data->m_ReloadGrid = true; + } + Super::OnUnregister(); +} + +//---------------------------------------------------------------------------- + +void UPopcornFXAttributeSamplerGrid::BeginDestroy() +{ + if (m_Data != null) + { + delete m_Data; + m_Data = null; + } + Super::BeginDestroy(); +} + +//---------------------------------------------------------------------------- + +UTexture *UPopcornFXAttributeSamplerGrid::GridTexture() +{ + return bAssetGrid != 0 ? RenderTarget : m_GridTexture; +} + +//---------------------------------------------------------------------------- + +#if WITH_EDITOR + +void UPopcornFXAttributeSamplerGrid::PostEditChangeProperty(FPropertyChangedEvent &propertyChangedEvent) +{ + if (propertyChangedEvent.Property != NULL) + { + const FString propertyName = propertyChangedEvent.Property->GetName(); + + if (propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, bAssetGrid) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, bSRGB) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, RenderTarget) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, SizeX) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, SizeY) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, SizeZ) || + propertyName == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXAttributeSamplerGrid, DataType)) + { + // Rebuild + m_Data->m_ReloadGrid = true; + } + } + Super::PostEditChangeProperty(propertyChangedEvent); +} + +#endif // WITH_EDITOR + +//---------------------------------------------------------------------------- + +PopcornFX::CParticleSamplerDescriptor *UPopcornFXAttributeSamplerGrid::_AttribSampler_SetupSamplerDescriptor(FPopcornFXSamplerDesc &desc, const PopcornFX::CResourceDescriptor *defaultSampler) +{ + LLM_SCOPE(ELLMTag::Particles); + const PopcornFX::CResourceDescriptor_Grid *defaultGridSampler = PopcornFX::HBO::Cast(defaultSampler); + if (!PK_VERIFY(defaultGridSampler != null)) + return null; + if (m_Data->m_ReloadGrid) + { + if (!RebuildGridSampler()) + return null; + m_Data->m_ReloadGrid = false; + } + + // Make sure the sampler matches what the effect expects + const u32 gridOrder = Cast(GridTexture()) != null ? 2 : 3; + const PopcornFX::Nodegraph::SDataTypeTraits &srcTypeTraits = PopcornFX::Nodegraph::SDataTypeTraits::Traits((PopcornFX::Nodegraph::EDataType)defaultGridSampler->Type()); + if (defaultGridSampler->Order() != gridOrder || + srcTypeTraits.BaseType() != m_Data->m_Desc->m_DataType) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, + TEXT("AttrSamplerGrid: Failed to setup grid attribute sampler, does not match with sampler defined in source effect '%s':\n" + "\t- SrcOrder=%d, Built=%d.\n" + "\t- SrcType=%s, Built=%s.\n"), + *ToUE(defaultGridSampler->FilePath()), + defaultGridSampler->Order(), gridOrder, + UTF8_TO_TCHAR(srcTypeTraits.Name()), + UTF8_TO_TCHAR(PopcornFX::CBaseTypeTraits::Traits(m_Data->m_Desc->m_DataType).Name)); + m_Data->Clear(); + return null; + } + + return m_Data->m_Desc.Get(); +} + +//---------------------------------------------------------------------------- + +bool UPopcornFXAttributeSamplerGrid::RebuildGridSampler() +{ + if (!_RebuildGridSampler()) + { + const FString imageName = RenderTarget != null ? RenderTarget->GetName() : FString(TEXT("null")); + UE_LOG(LogPopcornFXAttributeSampler, Warning, + TEXT("AttrSamplerGrid: Failed to setup grid attribute sampler (RenderTarget=%s, Dimensions=(%d,%d,%d), DataType=%d"), + *imageName, + SizeX, SizeY, SizeZ, + DataType); + m_Data->Clear(); + return false; + } + return true; +} + +//---------------------------------------------------------------------------- + +bool UPopcornFXAttributeSamplerGrid::_RebuildGridSampler() +{ + PK_NAMEDSCOPEDPROFILE_C("UPopcornFXAttributeSamplerGrid::Build grid sampler", POPCORNFX_UE_PROFILER_COLOR); + + PopcornFX::PParticleSamplerDescriptor_Grid_Default descriptor = PK_NEW(PopcornFX::CParticleSamplerDescriptor_Grid_Default); + if (!PK_VERIFY(descriptor != null)) + return false; + + bool needsGPUHandle = false; +#if (PK_GPU_D3D12 != 0) + needsGPUHandle = g_PopcornFXRHIAPI == SUERenderContext::D3D12; +#endif + + EPixelFormat pixelFormat = PF_Unknown; + bool isVolumeTexture = false; + + m_GridTexture = null; + + UTexture *texture = null; + if (bAssetGrid) + { + if (RenderTarget == null) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: couldn't build grid sampler: null texture")); + return false; + } + texture = RenderTarget; + + UTextureRenderTarget2D *RT2D = Cast(texture); + UTextureRenderTargetVolume *RTVolume = Cast(texture); + if (RT2D != null) + { + const EPixelFormat RTFormat = GetPixelFormatFromRenderTargetFormat(RT2D->RenderTargetFormat); + const bool hasSupportedFormat = RTFormat == PF_R32_FLOAT || + RTFormat == PF_G32R32F || + RTFormat == PF_A32B32G32R32F; + const bool hasCorrectGamma = bSRGB == RT2D->IsSRGB(); + + if (!hasSupportedFormat) + { + // Error, don't try to convert the texture, let the user specify the desired format. + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: can only setup attribute sampler from UTextureRenderTarget2D with format set to RTF_R32f, RTF_RG32f or RTF_RGBA32f")); + return false; + } + if (!hasCorrectGamma) + { + UE_LOG(LogPopcornFXAttributeSampler, Log, TEXT("UPopcornFXAttributeSamplerGrid: converting UTextureRenderTarget2D format to sRGB=%d"), bSRGB); + } + if ((!RT2D->bCanCreateUAV || !hasCorrectGamma) && needsGPUHandle) + { + RT2D->bCanCreateUAV = true; + RT2D->SRGB = bSRGB; + RT2D->UpdateResource(); + } + + PopcornFX::EBaseTypeID dataType; + switch (RTFormat) + { + case PF_R32_FLOAT: + dataType = PopcornFX::BaseType_Float; + break; + case PF_G32R32F: + dataType = PopcornFX::BaseType_Float2; + break; + case PF_A32B32G32R32F: + default: + dataType = PopcornFX::BaseType_Float4; + break; + }; + descriptor->m_DataType = dataType; + descriptor->m_GridDimensions = CUint4(RT2D->SizeX, RT2D->SizeY, 1, 1); + pixelFormat = RTFormat; + } + else if (RTVolume != null) + { + const EPixelFormat RTFormat = RTVolume->OverrideFormat; + const bool hasSupportedFormat = RTFormat == PF_A32B32G32R32F; + const bool hasCorrectGamma = bSRGB == RTVolume->SRGB; + + if (!hasSupportedFormat) + { + UE_LOG(LogPopcornFXAttributeSampler, Log, TEXT("UPopcornFXAttributeSamplerGrid: converting UTextureRenderTargetVolume format to RTF_RGBA32f")); + } + if (!hasCorrectGamma) + { + UE_LOG(LogPopcornFXAttributeSampler, Log, TEXT("UPopcornFXAttributeSamplerGrid: converting UTextureRenderTargetVolume format to sRGB=%d"), bSRGB); + } + if ((!RTVolume->bCanCreateUAV || !hasSupportedFormat || !hasCorrectGamma) || needsGPUHandle) + { + RTVolume->bCanCreateUAV = true; + RTVolume->OverrideFormat = PF_A32B32G32R32F; + RTVolume->SRGB = bSRGB; + RTVolume->UpdateResource(); + } + descriptor->m_DataType = PopcornFX::BaseType_Float4; + descriptor->m_GridDimensions = CUint4(RTVolume->SizeX, RTVolume->SizeY, RTVolume->SizeZ, 1); + isVolumeTexture = true; + pixelFormat = PF_A32B32G32R32F; + } + else + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: can only setup attribute sampler from UTextureRenderTarget2D or UTextureRenderTargetVolume")); + return false; + } + } + else + { + if (SizeX < 0 || SizeY < 0 || SizeZ < 0) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: couldn't build grid sampler: Invalid dimensions (%d,%d,%d)"), SizeX, SizeY, SizeZ); + return false; + } + ETextureRenderTargetFormat RTFormat = ETextureRenderTargetFormat::RTF_RGBA32f; + PopcornFX::EBaseTypeID dataType = PopcornFX::BaseType_Void; + + switch (DataType) + { + case EPopcornFXGridDataType::R: + RTFormat = RTF_R32f; + dataType = PopcornFX::BaseType_Float; + break; + case EPopcornFXGridDataType::RG: + RTFormat = RTF_RG32f; + dataType = PopcornFX::BaseType_Float2; + break; + case EPopcornFXGridDataType::RGBA: + RTFormat = RTF_RGBA32f; + dataType = PopcornFX::BaseType_Float4; + break; + default: + PK_ASSERT_NOT_REACHED(); + return false; + }; + pixelFormat = GetPixelFormatFromRenderTargetFormat(RTFormat); + + if (needsGPUHandle) + { + if (SizeZ > 1) + { + UTextureRenderTargetVolume *newTexture = NewObject(GetTransientPackage(), TEXT("PopcornFX Grid Attribute Sampler Volume"), RF_Transient); + check(newTexture != null); + newTexture->bCanCreateUAV = true; + newTexture->SRGB = bSRGB; + newTexture->Init(SizeX, SizeY, SizeZ, pixelFormat); + newTexture->UpdateResourceImmediate(true); + texture = newTexture; + isVolumeTexture = true; + } + else + { + UTextureRenderTarget2D *newTexture = NewObject(GetTransientPackage(), TEXT("PopcornFX Grid Attribute Sampler 2D"), RF_Transient); + check(newTexture != null); + newTexture->RenderTargetFormat = RTFormat; + newTexture->bAutoGenerateMips = false; + newTexture->bCanCreateUAV = true; + newTexture->SRGB = bSRGB; + newTexture->InitAutoFormat(SizeX, SizeY); + newTexture->UpdateResourceImmediate(true); + texture = newTexture; + } + if (texture == null) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: couldn't build grid sampler: couldn't create transient texture")); + return false; + } + m_GridTexture = texture; + } + descriptor->m_DataType = dataType; + descriptor->m_GridDimensions = CUint4(SizeX, SizeY, SizeZ, 1); + } + + if (needsGPUHandle) + { + check(texture != null); + + // WIP: Flush render commands to make sure the RHI resource is available. + FlushRenderingCommands(); + } + +#if (PK_GPU_D3D12 != 0) + // There is no way currently to know if the current sampler descriptor will be used by the CPU or GPU sim, so we'll have to load both, if possible + // GPU sim image load is trivial: it will just grab the ref to the native resource + if (g_PopcornFXRHIAPI == SUERenderContext::D3D12) + { + // Simplified CResourceHandlerImage_UE_D3D12::NewFromTexture() + FTextureReferenceRHIRef texRef = texture->TextureReference.TextureReferenceRHI; + if (!IsValidRef(texRef)) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: UTexture TextureReference not available \"%s\""), *texture->GetPathName()); + return false; + } + FRHITexture *texRHI = texRef->GetReferencedTexture(); + if (texRHI == null) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: UTexture TextureReference FRHITexture not available \"%s\""), *texture->GetPathName()); + return false; + } + ID3D12Resource *gpuTexture = static_cast(texRHI->GetNativeResource()); + if (gpuTexture == null) + { + UE_LOG(LogPopcornFXAttributeSampler, Warning, TEXT("UPopcornFXAttributeSamplerGrid: UTexture TextureReference FRHITexture D3D12 not available \"%s\""), *texture->GetPathName()); + return false; + } + + descriptor->SetupD3D12Resources(gpuTexture, + (u32)GPixelFormats[pixelFormat].PlatformFormat, + (u32)(isVolumeTexture ? D3D12_UAV_DIMENSION_TEXTURE3D : D3D12_UAV_DIMENSION_TEXTURE2D)); + } +#endif // PK_GPU_D3D12 != 0 + + // Build a CPU sim visible memory buffer (we could expose RW access functions into it) + { + const PopcornFX::CImage::EFormat pkFormat = _UE2PKImageFormat(pixelFormat, false); + PK_ASSERT(pkFormat != PopcornFX::CImage::Format_Invalid); + const u32 expectedSizeInBytes = PopcornFX::CImage::GetFormatPixelBufferSizeInBytes(pkFormat, CUint3(SizeX, SizeY, SizeZ)); + + enum { kAlignment = 0x80 }; + descriptor->m_RawDataRef = PopcornFX::CRefCountedMemoryBuffer::AllocAligned(expectedSizeInBytes + kAlignment, kAlignment); + if (!PK_VERIFY(descriptor->m_RawDataRef != null)) + return false; + descriptor->m_RawDataPtr = descriptor->m_RawDataRef->Data(); + descriptor->m_RawDataByteCount = descriptor->m_RawDataRef->DataSizeInBytes(); + } + + m_Data->m_Desc = descriptor; + return true; +} //---------------------------------------------------------------------------- // diff --git a/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp b/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp index 7c92961..76c2219 100644 --- a/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp +++ b/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModuleLevelEditor.cpp @@ -87,7 +87,7 @@ void FPopcornFXDependencyModuleLevelEditor::OpenSourcePack() PK_ASSERT(m_Settings->bSourcePackFound); // We can now directly rely on opening the pkproj directly - FPlatformProcess::LaunchFileInDefaultExternalApplication(*m_Settings->SourcePackProjectFile); + FPlatformProcess::LaunchFileInDefaultExternalApplication(*m_Settings->AbsSourcePackProjectFile); } //---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModulePropertyEditor.cpp b/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModulePropertyEditor.cpp index 291c321..f7f9e17 100644 --- a/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModulePropertyEditor.cpp +++ b/Source/PopcornFX/Private/DependencyModules/PopcornFXDependencyModulePropertyEditor.cpp @@ -12,6 +12,7 @@ #include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerShape.h" #include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerCurve.h" #include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerImage.h" +#include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.h" #include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerVectorField.h" #include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerActor.h" #include "Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerSkinnedMesh.h" @@ -50,6 +51,7 @@ void FPopcornFXDependencyModulePropertyEditor::Load() propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerShape", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerShape::MakeInstance)); propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerCurve", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerCurve::MakeInstance)); propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerImage", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerImage::MakeInstance)); + propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerGrid", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerGrid::MakeInstance)); propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerVectorField", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerVectorField::MakeInstance)); propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerActor", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerActor::MakeInstance)); propertyModule.RegisterCustomClassLayout("PopcornFXAttributeSamplerSkinnedMesh", FOnGetDetailCustomizationInstance::CreateStatic(&FPopcornFXDetailsAttributeSamplerSkinnedMesh::MakeInstance)); @@ -81,6 +83,7 @@ void FPopcornFXDependencyModulePropertyEditor::Unload() propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerShape"); propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerCurve"); propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerImage"); + propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerGrid"); propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerVectorField"); propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerActor"); propertyModule.UnregisterCustomClassLayout("PopcornFXAttributeSamplerSkinnedMesh"); diff --git a/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeList.cpp b/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeList.cpp index 84fe137..b23413d 100644 --- a/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeList.cpp +++ b/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeList.cpp @@ -89,6 +89,8 @@ namespace return "AttributeSampler_Curve"; case EPopcornFXAttributeSamplerType::Image: return "AttributeSampler_Image"; + case EPopcornFXAttributeSamplerType::Grid: + return "AttributeSampler_Image"; //"AttributeSampler_Grid"; // TODO: Grid icon case EPopcornFXAttributeSamplerType::AnimTrack: return "Attributesampler_AnimTrack"; case EPopcornFXAttributeSamplerType::Text: @@ -535,6 +537,7 @@ namespace m_Traits = &(PopcornFX::CBaseTypeTraits::Traits(attributeBaseTypeID)); m_IsQuaternion = attributeBaseTypeID == PopcornFX::BaseType_Quaternion; + m_IsOneShotTrigger = decl->OneShotTrigger(); // force vector dimension to 3 for quaternion, allow to display 3 float and use euler angles in editor m_VectorDimension = (!m_IsQuaternion) ? m_Traits->VectorDimension : 3; @@ -549,11 +552,9 @@ namespace m_Title = FText::FromString(name); { - FString description; - FString shortDescription; - description = (const UTF16CHAR*)decl->Description().MapDefault().Data(); - description = description.Replace(TEXT("\\n"), TEXT("\n")); - int32 shortOffset; + FString description = ToUE(decl->Description().MapDefault()).Replace(TEXT("\\n"), TEXT("\n")); + FString shortDescription; + int32 shortOffset; if (description.FindChar('\n', shortOffset)) shortDescription = description.Left(shortOffset - 1); else @@ -563,7 +564,7 @@ namespace } // TODO: add an icon for quaternion attributes, right now fallbacks to F3 - const FString typeName = (!m_IsQuaternion) ? GenerateTypeName(attributeBaseTypeID) : TEXT("F3"); + const FString typeName = (!m_IsQuaternion) ? GenerateTypeName(attributeBaseTypeID) : TEXT("F3"); m_AttributeIcon = *(TEXT("PopcornFX.Attribute.") + typeName); m_IsColor = @@ -803,19 +804,36 @@ namespace TSharedRef sharedThis = SharedThis(this); check(dimi < m_Traits->VectorDimension); - TSharedPtr< SCheckBox > axis; - if (m_ReadOnly) + if (!m_IsOneShotTrigger) { - SAssignNew(axis, SCheckBox) - .IsChecked(sharedThis, &TSelf::GetValueBool, dimi); + TSharedPtr axis; + if (m_ReadOnly) + { + SAssignNew(axis, SCheckBox) + .IsChecked(sharedThis, &TSelf::GetValueBool, dimi); + } + else + { + SAssignNew(axis, SCheckBox) + .OnCheckStateChanged(sharedThis, &TSelf::OnValueChangedBool, dimi) + .IsChecked(sharedThis, &TSelf::GetValueBool, dimi); + } + return axis.ToSharedRef(); } else { - SAssignNew(axis, SCheckBox) - .OnCheckStateChanged(sharedThis, &TSelf::OnValueChangedBool, dimi) - .IsChecked(sharedThis, &TSelf::GetValueBool, dimi); + TSharedPtr axis; + SAssignNew(axis, SButton) + .Text(FText::FromString("Pulse")) + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + .ClickMethod(EButtonClickMethod::MouseDown) + .OnClicked(this, &TSelf::OnValuePulsedBool, dimi) + .ContentPadding(0.0f) + .ForegroundColor(FSlateColor::UseForeground()) + .IsFocusable(false); + return axis.ToSharedRef(); } - return axis.ToSharedRef(); } template @@ -965,6 +983,22 @@ namespace attrList->PostEditChange(); } + FReply OnValuePulsedBool(uint32 dimi) + { + if (m_ReadOnly) + return FReply::Handled(); + UPopcornFXAttributeList *attrList; + if (!_GetAttrib(attrList)) + return FReply::Handled(); + + const FScopedTransaction Transaction(LOCTEXT("AttributeCommit", "Attribute Value Pulse")); + attrList->SetFlags(RF_Transactional); + attrList->Modify(); + attrList->PulseBoolAttributeDim(m_Index, dimi, true); + attrList->PostEditChange(); + return FReply::Handled(); + } + FText GetValueEnumText() const { UPopcornFXAttributeList *attrList; @@ -1138,17 +1172,18 @@ namespace bool m_ReadOnly = false; bool m_ExpandOnly = false; - uint32 m_Index; - u32 m_VectorDimension; - const PopcornFX::CBaseTypeTraits *m_Traits; + uint32 m_Index = 0; + u32 m_VectorDimension = 0; + const PopcornFX::CBaseTypeTraits *m_Traits = null; FText m_Title; FText m_Description; FText m_ShortDescription; FName m_AttributeIcon; - bool m_IsColor; - bool m_IsQuaternion; + bool m_IsColor = false; + bool m_IsQuaternion = false; + bool m_IsOneShotTrigger = false; EPopcornFXAttributeDropDownMode::Type m_DropDownMode; TArray m_EnumList; // copy TArray> m_EnumListIndices; diff --git a/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.cpp b/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.cpp new file mode 100644 index 0000000..005f223 --- /dev/null +++ b/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.cpp @@ -0,0 +1,70 @@ +//---------------------------------------------------------------------------- +// Copyright Persistant Studios, SARL. All Rights Reserved. +// https://www.popcornfx.com/terms-and-conditions/ +//---------------------------------------------------------------------------- + +#if WITH_EDITOR +#include "PopcornFXDetailsAttributeSamplerGrid.h" +#include "PopcornFXAttributeSamplerGrid.h" +#include "PopcornFXSDK.h" + +#include "DetailLayoutBuilder.h" +#include "DetailCategoryBuilder.h" +#include "PropertyCustomizationHelpers.h" +#include "PropertyHandle.h" + +//---------------------------------------------------------------------------- + +FPopcornFXDetailsAttributeSamplerGrid::FPopcornFXDetailsAttributeSamplerGrid() +: m_CachedDetailLayoutBuilder(null) +{ + +} + +//---------------------------------------------------------------------------- + +TSharedRef FPopcornFXDetailsAttributeSamplerGrid::MakeInstance() +{ + return MakeShareable(new FPopcornFXDetailsAttributeSamplerGrid); +} + +//---------------------------------------------------------------------------- + +void FPopcornFXDetailsAttributeSamplerGrid::RebuildDetails() +{ + if (!PK_VERIFY(m_CachedDetailLayoutBuilder != null)) + return; + m_CachedDetailLayoutBuilder->ForceRefreshDetails(); +} + +//---------------------------------------------------------------------------- + +void FPopcornFXDetailsAttributeSamplerGrid::CustomizeDetails(IDetailLayoutBuilder &detailLayout) +{ + TSharedRef isAssetGrid = detailLayout.GetProperty("bAssetGrid"); + IDetailCategoryBuilder &detailCategory = detailLayout.EditCategory("PopcornFX AttributeSampler"); + + m_CachedDetailLayoutBuilder = &detailLayout; + if (isAssetGrid->IsValidHandle()) + { + bool _isAssetGrid = false; + + isAssetGrid->GetValue(_isAssetGrid); + if (_isAssetGrid) + { + detailLayout.HideProperty("SizeX"); + detailLayout.HideProperty("SizeY"); + detailLayout.HideProperty("SizeZ"); + detailLayout.HideProperty("DataType"); + } + else + { + detailLayout.HideProperty("RenderTarget"); + } + isAssetGrid->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FPopcornFXDetailsAttributeSamplerGrid::RebuildDetails)); + } + +} + +//---------------------------------------------------------------------------- +#endif // WITH_EDITOR diff --git a/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.h b/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.h new file mode 100644 index 0000000..eba9eef --- /dev/null +++ b/Source/PopcornFX/Private/Editor/CustomizeDetails/PopcornFXDetailsAttributeSamplerGrid.h @@ -0,0 +1,30 @@ +//---------------------------------------------------------------------------- +// Copyright Persistant Studios, SARL. All Rights Reserved. +// https://www.popcornfx.com/terms-and-conditions/ +//---------------------------------------------------------------------------- + +#pragma once + +#if WITH_EDITOR + +#include "PopcornFXMinimal.h" + +#include "PropertyEditorModule.h" +#include "IDetailCustomization.h" + +class FPopcornFXDetailsAttributeSamplerGrid : public IDetailCustomization +{ +public: + FPopcornFXDetailsAttributeSamplerGrid(); + + /** Makes a new instance of this detail layout class for a specific detail view requesting it */ + static TSharedRef MakeInstance(); + + virtual void CustomizeDetails(IDetailLayoutBuilder &detailLayout) override; +private: + void RebuildDetails(); + + IDetailLayoutBuilder *m_CachedDetailLayoutBuilder; +}; + +#endif // WITH_EDITOR diff --git a/Source/PopcornFX/Private/Editor/PopcornFXEffectEditor.cpp b/Source/PopcornFX/Private/Editor/PopcornFXEffectEditor.cpp index 334959f..8bdeb2c 100644 --- a/Source/PopcornFX/Private/Editor/PopcornFXEffectEditor.cpp +++ b/Source/PopcornFX/Private/Editor/PopcornFXEffectEditor.cpp @@ -364,6 +364,7 @@ void FPopcornFXEffectEditor::ReimportEffect() PK_ASSERT(m_Effect != null); FReimportManager::Instance()->Reimport(m_Effect, true); + PreviewViewport->ResetEmitterAttributes(); } //---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/Editor/PopcornFXStyle.cpp b/Source/PopcornFX/Private/Editor/PopcornFXStyle.cpp index c0ab734..c26a5df 100644 --- a/Source/PopcornFX/Private/Editor/PopcornFXStyle.cpp +++ b/Source/PopcornFX/Private/Editor/PopcornFXStyle.cpp @@ -95,6 +95,7 @@ void FPopcornFXStyle::Initialize() ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerShape", "AttributeSampler_Shape", "SlateBrushes/AttributeSampler_Shape"); ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerSkinnedMesh", "AttributeSampler_SkeletalMesh", "SlateBrushes/AttributeSampler_SkeletalMesh"); ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerImage", "AttributeSampler_Image", "SlateBrushes/AttributeSampler_Image"); + ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerGrid", "AttributeSampler_Image", "SlateBrushes/AttributeSampler_Image"); // TODO: Grid icon ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerAnimTrack", "Attributesampler_AnimTrack", "SlateBrushes/Attributesampler_AnimTrack"); ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerCurve", "AttributeSampler_Curve", "SlateBrushes/AttributeSampler_Curve"); ATTRIBSAMPLER_STYLE("PopcornFXAttributeSamplerText", "AttributeSampler_Text", "SlateBrushes/AttributeSampler_Text"); diff --git a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim.cpp b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim.cpp index 4631c4f..c67224f 100644 --- a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim.cpp +++ b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim.cpp @@ -48,12 +48,18 @@ void SetupPopcornFXRHIAPI(uint32 API) bool _IsGpuSupportedOnPlatform(const EShaderPlatform &platform) { - const bool platformSupportsSM5OrEquivalent = IsFeatureLevelSupported(platform, ERHIFeatureLevel::SM5); - const bool isStaticShaderPlatform = FStaticShaderPlatformNames::Get().IsStaticPlatform(platform); +#if WITH_EDITOR + const EShaderPlatform &realPlatform = FGenericDataDrivenShaderPlatformInfo::GetIsPreviewPlatform(platform) ? FGenericDataDrivenShaderPlatformInfo::GetPreviewShaderPlatformParent(platform) : platform; +#else + const EShaderPlatform &realPlatform = platform; +#endif + + const bool platformSupportsSM5OrEquivalent = IsFeatureLevelSupported(realPlatform, ERHIFeatureLevel::SM5); + const bool isStaticShaderPlatform = FStaticShaderPlatformNames::Get().IsStaticPlatform(realPlatform); if (isStaticShaderPlatform) { - const FName platformName = FStaticShaderPlatformNames::Get().GetPlatformName(platform); + const FName platformName = FStaticShaderPlatformNames::Get().GetPlatformName(realPlatform); // Special UE4 return ( @@ -69,16 +75,16 @@ bool _IsGpuSupportedOnPlatform(const EShaderPlatform &platform) false) && platformSupportsSM5OrEquivalent; } #if (ENGINE_MAJOR_VERSION == 5) - const bool platformSupportsSM6OrEquivalent = IsFeatureLevelSupported(platform, ERHIFeatureLevel::SM6); - return (platform == SP_PCD3D_SM5 && platformSupportsSM5OrEquivalent) || - (platform == SP_PCD3D_SM6 && platformSupportsSM6OrEquivalent); + const bool platformSupportsSM6OrEquivalent = IsFeatureLevelSupported(realPlatform, ERHIFeatureLevel::SM6); + return (realPlatform == SP_PCD3D_SM5 && platformSupportsSM5OrEquivalent) || + (realPlatform == SP_PCD3D_SM6 && platformSupportsSM6OrEquivalent); #else return ( # if 0 // GPU sim not supported on Xbox one for now - platform == SP_XBOXONE_D3D12 || + realPlatform == SP_XBOXONE_D3D12 || # endif - platform == SP_PCD3D_SM5 + realPlatform == SP_PCD3D_SM5 ) && platformSupportsSM5OrEquivalent; #endif // (ENGINE_MAJOR_VERSION == 5) diff --git a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSimInterfaces.cpp b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSimInterfaces.cpp index fdea54e..23a88d4 100644 --- a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSimInterfaces.cpp +++ b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSimInterfaces.cpp @@ -40,10 +40,10 @@ namespace PopcornFXGPU FString simInterfaceSource; if (!FFileHelper::LoadFileToString(simInterfaceSource, *simInterfacePath)) { - PopcornFX::CLog::Log(PK_ERROR, "Couldn't load sim interface source ('%s')", TCHAR_TO_ANSI(*simInterfacePath)); + PopcornFX::CLog::Log(PK_ERROR, "Couldn't load sim interface source ('%s')", TCHAR_TO_UTF8(*simInterfacePath)); return false; } - outKernelSource += TCHAR_TO_ANSI(*simInterfaceSource); + outKernelSource += ToPk(simInterfaceSource); return true; } @@ -160,7 +160,7 @@ namespace PopcornFXGPU #if (PK_GPU_D3D11 != 0) const PopcornFX::SBindingContextD3D11 &d3d11Context = context.ToD3D11(); - PopcornFX::SParticleStreamBuffer_D3D11 &viewConstantBuffer = FPopcornFXPlugin::Get().ViewConstantBuffer_D3D11(); + PopcornFX::SBuffer_D3D11 &viewConstantBuffer = FPopcornFXPlugin::Get().ViewConstantBuffer_D3D11(); if (viewConstantBuffer.Empty()) { ID3D11Device *device = null; diff --git a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.cpp b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.cpp index 040035b..38978eb 100644 --- a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.cpp +++ b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.cpp @@ -63,7 +63,7 @@ void UpdateBufferStats(TRefCountPtr Buffer, bool bAllocating) { } // //---------------------------------------------------------------------------- -FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SParticleStreamBuffer_D3D11 *stream, u32 stride, u8 pixelFormat) +FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SBuffer_D3D11 *stream, u32 stride, u8 pixelFormat) { #if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3) FRHICommandListBase &RHICmdList = FRHICommandListExecutor::GetImmediateCommandList(); @@ -89,9 +89,9 @@ FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SParticleStreamB //---------------------------------------------------------------------------- #if (ENGINE_MAJOR_VERSION == 5) -FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D11 *stream, u32 stride) +FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D11 *stream, u32 stride) #else -FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D11 *stream, u32 stride) +FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D11 *stream, u32 stride) #endif // (ENGINE_MAJOR_VERSION == 5) { D3D11_BUFFER_DESC desc; @@ -103,7 +103,7 @@ FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamB PK_ASSERT((desc.Usage & D3D11_USAGE_DYNAMIC) == 0); // no BUF_AnyDynamic PK_ASSERT((desc.CPUAccessFlags) == 0); // no BUF_AnyDynamic - // TODO: Unify SParticleStreamBuffer_D3D11 with other APIs, just provide a m_ByteSize member.. + // TODO: Unify SBuffer_D3D11 with other APIs, just provide a m_ByteSize member.. const u32 sizeInBytes = desc.ByteWidth; // Fixed #12899: removed BUF_UnorderedAccess | BUF_ByteAddressBuffer from the buffer usage, as it leads to crashes on some AMD GPU hardware. diff --git a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.h b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.h index c8ad681..a9678da 100644 --- a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.h +++ b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D11.h @@ -13,15 +13,15 @@ class FD3D11VertexBuffer; FWD_PK_API_BEGIN -struct SParticleStreamBuffer_D3D11; +struct SBuffer_D3D11; class CParticleStreamToRender_D3D11; FWD_PK_API_END -FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SParticleStreamBuffer_D3D11 *stream, u32 stride, u8 pixelFormat = PF_R32_FLOAT); +FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SBuffer_D3D11 *stream, u32 stride, u8 pixelFormat = PF_R32_FLOAT); #if (ENGINE_MAJOR_VERSION == 5) -FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D11 *stream, u32 stride); +FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D11 *stream, u32 stride); #else -FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D11 *stream, u32 stride); +FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D11 *stream, u32 stride); #endif // (ENGINE_MAJOR_VERSION == 5) //---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.cpp b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.cpp index 6ce8622..18e4363 100644 --- a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.cpp +++ b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.cpp @@ -330,7 +330,7 @@ inline FD3D12UnorderedAccessView* CreateUAV(D3D12_UNORDERED_ACCESS_VIEW_DESC& De // //---------------------------------------------------------------------------- -FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SParticleStreamBuffer_D3D12 *stream, u32 stride, u8 pixelFormat) +FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SBuffer_D3D12 *stream, u32 stride, u8 pixelFormat) { #if (ENGINE_MAJOR_VERSION == 5) FRHIBuffer *buffer = StreamBufferResourceToRHI(stream, stride); @@ -353,9 +353,9 @@ FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SParticleStreamB //---------------------------------------------------------------------------- #if (ENGINE_MAJOR_VERSION == 5) -FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D12 *stream, u32 stride) +FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D12 *stream, u32 stride) #else -FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D12 *stream, u32 stride) +FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D12 *stream, u32 stride) #endif // (ENGINE_MAJOR_VERSION == 5) { D3D12_RESOURCE_DESC desc = stream->m_Resource->GetDesc(); @@ -368,7 +368,7 @@ FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuff PK_ASSERT(desc.SampleDesc.Quality == 0); PK_ASSERT(desc.Layout == D3D12_TEXTURE_LAYOUT_ROW_MAJOR); PK_ASSERT(desc.Flags == D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - PK_ASSERT(stream->m_State == (D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // PK_BUFFER_GPU_D3D12_DEFAULT_STATE, currently not exposed + PK_ASSERT(stream->m_State == (D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) || stream->m_State == (D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_COPY_SOURCE)); // PK_BUFFER_GPU_D3D12_DEFAULT_STATE, currently not exposed FD3D12DynamicRHI *dynamicRHI = static_cast(GDynamicRHI); FD3D12Device *device = dynamicRHI->GetAdapter().GetDevice(0); diff --git a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.h b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.h index 2d98658..604e08e 100644 --- a/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.h +++ b/Source/PopcornFX/Private/GPUSim/PopcornFXGPUSim_D3D12.h @@ -13,15 +13,15 @@ class FD3D12VertexBuffer; FWD_PK_API_BEGIN -struct SParticleStreamBuffer_D3D12; +struct SBuffer_D3D12; class CParticleStreamToRender_D3D12; FWD_PK_API_END -FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SParticleStreamBuffer_D3D12 *stream, u32 stride, u8 pixelFormat = PF_R32_FLOAT); +FShaderResourceViewRHIRef StreamBufferSRVToRHI(const PopcornFX::SBuffer_D3D12 *stream, u32 stride, u8 pixelFormat = PF_R32_FLOAT); #if (ENGINE_MAJOR_VERSION == 5) -FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D12 *stream, u32 stride); +FRHIBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D12 *stream, u32 stride); #else -FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SParticleStreamBuffer_D3D12 *stream, u32 stride); +FRHIVertexBuffer *StreamBufferResourceToRHI(const PopcornFX::SBuffer_D3D12 *stream, u32 stride); #endif // (ENGINE_MAJOR_VERSION == 5) #endif // (PK_GPU_D3D12 == 1) diff --git a/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp b/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp index cd37dec..f7341cd 100644 --- a/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp +++ b/Source/PopcornFX/Private/HUD/PopcornFXHUDProfiler.cpp @@ -265,13 +265,13 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p const PopcornFX::Units::SValueAndNamedUnit readableTotalTimeCPU = PopcornFX::Units::AutoscaleTime(wallUpdateTimeCPU, 0.5f); //const PopcornFX::Units::SValueAndNamedUnit readableTotalTimeGPU = PopcornFX::Units::AutoscaleTime(totalUpdateTimeGPU, 0.5f); DrawBar(timexPos, timeCPUxPos - 1, yPos, wallUpdateTimeCPU / TimeLimitTotalSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTime.m_Value, ANSI_TO_TCHAR(readableTotalTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTime.m_Value, UTF8_TO_TCHAR(readableTotalTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); if (hasGPU) { DrawBar(timeCPUxPos, timeGPUxPos - 1, yPos, wallUpdateTimeCPU / CPUTimeLimitTotalSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTimeCPU.m_Value, ANSI_TO_TCHAR(readableTotalTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTimeCPU.m_Value, UTF8_TO_TCHAR(readableTotalTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); //DrawBar(timeGPUxPos, pCountCPUxPos - 1, yPos, totalUpdateTimeGPU / GPUTimeLimitTotalSeconds, lineHeight); - //Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTimeGPU.m_Value, ANSI_TO_TCHAR(readableTotalTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + //Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalTimeGPU.m_Value, UTF8_TO_TCHAR(readableTotalTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); } } // Counts @@ -360,13 +360,13 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p const PopcornFX::Units::SValueAndNamedUnit readableTimeGPU = PopcornFX::Units::AutoscaleTime(timeTotalGPU, 0.5f); DrawBar(timexPos, timeCPUxPos - 1, yPos, timeTotal / TimeLimitPerEffectSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTime.m_Value, ANSI_TO_TCHAR(readableTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTime.m_Value, UTF8_TO_TCHAR(readableTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); if (hasGPU) { DrawBar(timeCPUxPos, timeGPUxPos - 1, yPos, timeTotalCPU / CPUTimeLimitPerEffectSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTimeCPU.m_Value, ANSI_TO_TCHAR(readableTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTimeCPU.m_Value, UTF8_TO_TCHAR(readableTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); DrawBar(timeGPUxPos, pCountCPUxPos - 1, yPos, timeTotalGPU / GPUTimeLimitPerEffectSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTimeGPU.m_Value, ANSI_TO_TCHAR(readableTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTimeGPU.m_Value, UTF8_TO_TCHAR(readableTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); } } @@ -384,7 +384,7 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p } // Effect path - Canvas->DrawText(font, FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(allSceneTimings[iTiming].m_EffectPath.Data())), effectPathxPos, yPos, 1.f, 1.f, fri); + Canvas->DrawText(font, FString::Printf(TEXT("%s"), *ToUE(allSceneTimings[iTiming].m_EffectPath)), effectPathxPos, yPos, 1.f, 1.f, fri); yPos += lineHeight; if (yPos > maxDrawyPos) @@ -419,13 +419,13 @@ void APopcornFXHUDProfiler::DrawDebugHUD(UCanvas* inCanvas, APlayerController* p const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTimeCPU = PopcornFX::Units::AutoscaleTime(timeTotalCPU, 0.5f); const PopcornFX::Units::SValueAndNamedUnit readableTotalDisplayedTimeGPU = PopcornFX::Units::AutoscaleTime(timeTotalGPU, 0.5f); DrawBar(timexPos, timeCPUxPos - 1, yPos, timeTotal / TimeLimitTotalSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTime.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTime.m_Value, UTF8_TO_TCHAR(readableTotalDisplayedTime.m_UnitName)), timexPos, yPos, 1.f, 1.f, friNoShadow); if (hasGPU) { DrawBar(timeCPUxPos, timeGPUxPos - 1, yPos, timeTotalCPU / CPUTimeLimitTotalSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTimeCPU.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTimeCPU.m_Value, UTF8_TO_TCHAR(readableTotalDisplayedTimeCPU.m_UnitName)), timeCPUxPos, yPos, 1.f, 1.f, friNoShadow); DrawBar(timeGPUxPos, pCountCPUxPos - 1, yPos, timeTotalGPU / GPUTimeLimitTotalSeconds, lineHeight); - Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTimeGPU.m_Value, ANSI_TO_TCHAR(readableTotalDisplayedTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); + Canvas->DrawText(font, FString::Printf(TEXT("%.1f %s"), readableTotalDisplayedTimeGPU.m_Value, UTF8_TO_TCHAR(readableTotalDisplayedTimeGPU.m_UnitName)), timeGPUxPos, yPos, 1.f, 1.f, friNoShadow); } } diff --git a/Source/PopcornFX/Private/Internal/FileSystemController_UE.cpp b/Source/PopcornFX/Private/Internal/FileSystemController_UE.cpp index aecf67b..11c2aeb 100644 --- a/Source/PopcornFX/Private/Internal/FileSystemController_UE.cpp +++ b/Source/PopcornFX/Private/Internal/FileSystemController_UE.cpp @@ -31,7 +31,7 @@ using PopcornFX::PKMax; // static UObject *CFileSystemController_UE::LoadUObject(const CString &path, bool pathNotVirtual) { - UObject *object = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path.Data(), pathNotVirtual); + UObject *object = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path, pathNotVirtual); FS_DEBUG_LOG(PK_INFO, "FileSystem LoadUObject %s > %p", path.Data(), object); return object; } @@ -65,16 +65,15 @@ UPopcornFXFile *CFileSystemController_UE::FindDirectPopcornFXFile(UObject *uobj // //---------------------------------------------------------------------------- -CFileStreamFS_UE::CFileStreamFS_UE( - CFileSystemController_UE *controller, - PopcornFX::PFilePack pack, - const CString &path, - IFileSystem::EAccessPolicy mode, - UPopcornFXFile *file) - : CFileStream(controller, pack, path, mode) - , m_Mode(mode) - , m_File(file) - , m_Pos(0) +CFileStreamFS_UE::CFileStreamFS_UE( CFileSystemController_UE *controller, + PopcornFX::PFilePack pack, + const CString &path, + IFileSystem::EAccessPolicy mode, + UPopcornFXFile *file) +: CFileStream(controller, pack, path, mode) +, m_Mode(mode) +, m_File(file) +, m_Pos(0) { FILE_ASSERT(m_File != null); FS_DEBUG_LOG(PK_INFO, "ctor CFileStreamFS_UE %s filesize:%d", Path().Data(), CFileStreamFS_UE::SizeInBytes()); diff --git a/Source/PopcornFX/Private/Internal/ParticleScene.cpp b/Source/PopcornFX/Private/Internal/ParticleScene.cpp index 53d74ef..a76fae0 100644 --- a/Source/PopcornFX/Private/Internal/ParticleScene.cpp +++ b/Source/PopcornFX/Private/Internal/ParticleScene.cpp @@ -1872,7 +1872,7 @@ PopcornFX::TMemoryView CParticleScene::GetAudioSpectrum(Pop if (channelGroup.Empty() || m_FillAudioBuffers == null) return PopcornFX::TMemoryView(); - const FName channelName(ANSI_TO_TCHAR(channelGroup.ToString().Data())); + const FName channelName(*ToUE(channelGroup.ToString())); const float * const *rawSpectrumData = m_FillAudioBuffers->AsyncGetAudioSpectrum(channelName, outBaseCount); if (rawSpectrumData == null || outBaseCount == 0) return PopcornFX::TMemoryView(); @@ -1888,7 +1888,7 @@ PopcornFX::TMemoryView CParticleScene::GetAudioWaveform(Pop if (channelGroup.Empty() || m_FillAudioBuffers == null) return PopcornFX::TMemoryView(); - const FName channelName(ANSI_TO_TCHAR(channelGroup.ToString().Data())); + const FName channelName(*ToUE(channelGroup.ToString())); const float * const *rawWaveformData = m_FillAudioBuffers->AsyncGetAudioWaveform(channelName, outBaseCount); if (rawWaveformData == null || outBaseCount == 0) return PopcornFX::TMemoryView(); @@ -2946,7 +2946,7 @@ bool CParticleScene::RegisterEventListener(UPopcornFXEffect* particleEffect, Pop { if (!particleEffect->Effect()->RegisterEventCallback(broadcastCallback, eventNameID)) { - UE_LOG(LogPopcornFXScene, Warning, TEXT("Register Event Listener: Couldn't register callback to event '%s' on effect '%s'"), eventNameID.ToString().Data(), *particleEffect->GetName()); + UE_LOG(LogPopcornFXScene, Warning, TEXT("Register Event Listener: Couldn't register callback to event '%s' on effect '%s'"), *ToUE(eventNameID.ToString()), *particleEffect->GetName()); return false; } // add event name ID : don't register a callback several times for the same event @@ -3098,7 +3098,7 @@ bool CParticleScene::GetPayloadValue(const FName &payloadName, EPopcornFXPayload return false; } - const PopcornFX::CStringId payloadNameID(TCHAR_TO_ANSI(*payloadName.ToString())); // Expensive + const PopcornFX::CStringId payloadNameID(ToPk(payloadName.ToString())); // Expensive const PopcornFX::CGuid payloadIndex = m_CurrentPayloadView->m_Payloads.IndexOf(payloadNameID); if (!payloadIndex.Valid()) diff --git a/Source/PopcornFX/Private/Internal/PopcornFXLogs.cpp b/Source/PopcornFX/Private/Internal/PopcornFXLogs.cpp index 76e4c6b..9c1fb40 100644 --- a/Source/PopcornFX/Private/Internal/PopcornFXLogs.cpp +++ b/Source/PopcornFX/Private/Internal/PopcornFXLogs.cpp @@ -56,7 +56,7 @@ namespace if (!LogPopcornFX.IsSuppressed(kLogVerbosityToUE[level])) { const ELogVerbosity::Type logLevel = kLogVerbosityToUE[level]; - FMsg::Logf(__FILE__, __LINE__, LogPopcornFX.GetCategoryName(), logLevel, TEXT("%s"), ANSI_TO_TCHAR(s.Data())); + FMsg::Logf(__FILE__, __LINE__, LogPopcornFX.GetCategoryName(), logLevel, TEXT("%s"), UTF8_TO_TCHAR(s.Data())); } #endif } diff --git a/Source/PopcornFX/Private/Internal/ResourceHandlerImage_UE.cpp b/Source/PopcornFX/Private/Internal/ResourceHandlerImage_UE.cpp index 319dd0e..a7515ac 100644 --- a/Source/PopcornFX/Private/Internal/ResourceHandlerImage_UE.cpp +++ b/Source/PopcornFX/Private/Internal/ResourceHandlerImage_UE.cpp @@ -229,10 +229,10 @@ PopcornFX::CImage *CResourceHandlerImage_UE::NewFromPath(const PopcornFX::CStrin { PK_NAMEDSCOPEDPROFILE_C("CResourceHandlerImage_UE::NewFromPath", POPCORNFX_UE_PROFILER_COLOR); - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path.Data(), pathNotVirtual); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path, pathNotVirtual); if (obj == null) { - UE_LOG(LogPopcornFXResourceHandlerImage, Warning, TEXT("UObject not found \"%s\" %d"), ANSI_TO_TCHAR(path.Data()), pathNotVirtual); + UE_LOG(LogPopcornFXResourceHandlerImage, Warning, TEXT("UObject not found \"%s\" %d"), *ToUE(path), pathNotVirtual); return null; } UTexture *texture = Cast(obj); @@ -285,9 +285,7 @@ CResourceHandlerImage_UE::~CResourceHandlerImage_UE() for (CResourcesHashMap::ConstIterator it = m_Images.Begin(), itEnd = m_Images.End(); it != itEnd; ++it) { PK_ASSERT(it->m_ReferenceCount > 0); - UE_LOG(LogPopcornFXResourceHandlerImage, Warning, TEXT("Texture leak: \"%s\" %s"), - ANSI_TO_TCHAR(it.Key().Data()), - it->m_Virtual ? TEXT("(Virtual Texture)") : TEXT("")); + UE_LOG(LogPopcornFXResourceHandlerImage, Warning, TEXT("Texture leak: \"%s\" %s"), *ToUE(it.Key()), it->m_Virtual ? TEXT("(Virtual Texture)") : TEXT("")); } } @@ -308,9 +306,8 @@ void *CResourceHandlerImage_UE::Load( PopcornFX::CString _fullPath = resourcePath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -508,9 +505,8 @@ bool CResourceHandlerImage_UE::IsUsed(const PopcornFX::CString &virtualPath, boo { PopcornFX::CString _fullPath = virtualPath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -538,9 +534,8 @@ bool CResourceHandlerImage_UE::RegisterVirtualTexture(const PopcornFX::CString & PopcornFX::CString _fullPath = virtualPath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -552,7 +547,7 @@ bool CResourceHandlerImage_UE::RegisterVirtualTexture(const PopcornFX::CString & const u32 totalImageBytes = PopcornFX::CImage::GetFormatPixelBufferSizeInBytes(format, size); if (!PK_VERIFY(pixelsDataSizeInBytes >= totalImageBytes)) { - UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Invalid image byte size for virtual texture \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Invalid image byte size for virtual texture \"%s\""), *ToUE(virtualPath)); return false; } @@ -647,7 +642,8 @@ bool CResourceHandlerImage_UE::UnregisterVirtualTexture(const PopcornFX::CString PopcornFX::CString _fullPath = virtualPath; if (!pathNotVirtual) // if virtual path - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -660,12 +656,12 @@ bool CResourceHandlerImage_UE::UnregisterVirtualTexture(const PopcornFX::CString SResourceEntry *foundResource = m_Images.Find(fullPath); if (foundResource == null) { - UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Virtual Texture not found to Unregister \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Virtual Texture not found to Unregister \"%s\""), *ToUE(virtualPath)); return false; } if (!PK_VERIFY(foundResource->m_Virtual)) { - UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Texture is not a Virtual Texture to Unregister \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Texture is not a Virtual Texture to Unregister \"%s\""), *ToUE(virtualPath)); return false; } PK_ASSERT(foundResource->m_Image != null); @@ -701,7 +697,7 @@ bool CResourceHandlerImage_UE::UnregisterVirtualTexture(const PopcornFX::CString if (resource == null) { - UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Could not load true asset to replace Unregistered Virtual Texture, keeping old datas \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Could not load true asset to replace Unregistered Virtual Texture, keeping old datas \"%s\""), *ToUE(virtualPath)); return false; } PK_ASSERT(foundResource->m_Image != null); @@ -789,10 +785,10 @@ PopcornFX::CImageGPU_D3D11 *CResourceHandlerImage_UE_D3D11::NewFromPath(const P { PK_NAMEDSCOPEDPROFILE_C("CResourceHandlerImage_UE_D3D11::NewFromPath", POPCORNFX_UE_PROFILER_COLOR); - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path.Data(), pathNotVirtual); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path, pathNotVirtual); if (obj == null) { - UE_LOG(LogPopcornFXResourceHandlerImageGPU, Warning, TEXT("UObject not found \"%s\" %d"), ANSI_TO_TCHAR(path.Data()), pathNotVirtual); + UE_LOG(LogPopcornFXResourceHandlerImageGPU, Warning, TEXT("UObject not found \"%s\" %d"), *ToUE(path), pathNotVirtual); return null; } UTexture *texture = Cast(obj); @@ -840,9 +836,8 @@ void *CResourceHandlerImage_UE_D3D11::Load( PopcornFX::CString _fullPath = resourcePath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -1038,9 +1033,8 @@ bool CResourceHandlerImage_UE_D3D11::IsUsed(const PopcornFX::CString &virtualPat { PopcornFX::CString _fullPath = virtualPath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -1066,7 +1060,8 @@ bool CResourceHandlerImage_UE_D3D11::RegisterVirtualTexture(const PopcornFX::CSt PopcornFX::CString _fullPath = virtualPath; if (!pathNotVirtual) // if virtual path - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -1116,7 +1111,8 @@ bool CResourceHandlerImage_UE_D3D11::UnregisterVirtualTexture(const PopcornFX::C PopcornFX::CString _fullPath = virtualPath; if (!pathNotVirtual) // if virtual path - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) @@ -1128,12 +1124,12 @@ bool CResourceHandlerImage_UE_D3D11::UnregisterVirtualTexture(const PopcornFX::C SResourceEntry *foundResource = m_Images.Find(fullPath); if (foundResource == null) { - UE_LOG(LogPopcornFXResourceHandlerImageGPU, Error, TEXT("Virtual Texture GPU not found to Unregister \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImageGPU, Error, TEXT("Virtual Texture GPU not found to Unregister \"%s\""), *ToUE(virtualPath)); return false; } if (!PK_VERIFY(foundResource->m_Virtual)) { - UE_LOG(LogPopcornFXResourceHandlerImageGPU, Error, TEXT("Texture GPU is not a Virtual Texture to Unregister \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImageGPU, Error, TEXT("Texture GPU is not a Virtual Texture to Unregister \"%s\""), *ToUE(virtualPath)); return false; } PK_ASSERT(foundResource->m_Image != null); @@ -1170,7 +1166,7 @@ bool CResourceHandlerImage_UE_D3D11::UnregisterVirtualTexture(const PopcornFX::C if (resource == null) { - UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Could not load true asset to replace Unregistered Virtual Texture, keeping old datas \"%s\""), ANSI_TO_TCHAR(virtualPath.Data())); + UE_LOG(LogPopcornFXResourceHandlerImage, Error, TEXT("Could not load true asset to replace Unregistered Virtual Texture, keeping old datas \"%s\""), *ToUE(virtualPath)); return false; } PK_ASSERT(foundResource->m_Image != null); @@ -1267,10 +1263,10 @@ PopcornFX::CImageGPU_D3D12 *CResourceHandlerImage_UE_D3D12::NewFromPath(const Po { PK_NAMEDSCOPEDPROFILE_C("CResourceHandlerImage_UE_D3D12::NewFromPath", POPCORNFX_UE_PROFILER_COLOR); - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path.Data(), pathNotVirtual); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path, pathNotVirtual); if (obj == null) { - UE_LOG(LogPopcornFXResourceHandlerImageGPU, Warning, TEXT("UObject not found \"%s\" %d"), ANSI_TO_TCHAR(path.Data()), pathNotVirtual); + UE_LOG(LogPopcornFXResourceHandlerImageGPU, Warning, TEXT("UObject not found \"%s\" %d"), *ToUE(path), pathNotVirtual); return null; } UTexture *texture = Cast(obj); @@ -1318,9 +1314,8 @@ void *CResourceHandlerImage_UE_D3D12::Load( PopcornFX::CString _fullPath = resourcePath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) diff --git a/Source/PopcornFX/Private/Internal/ResourceHandlerMesh_UE.cpp b/Source/PopcornFX/Private/Internal/ResourceHandlerMesh_UE.cpp index 4328f65..5b410be 100644 --- a/Source/PopcornFX/Private/Internal/ResourceHandlerMesh_UE.cpp +++ b/Source/PopcornFX/Private/Internal/ResourceHandlerMesh_UE.cpp @@ -79,10 +79,10 @@ void *CResourceHandlerMesh_UE::Load( PK_ASSERT(resourceTypeID == PopcornFX::TResourceRouter::ResourceTypeID()); - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(resourcePath.Data(), pathNotVirtual); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(resourcePath, pathNotVirtual); if (obj == null) { - UE_LOG(LogPopcornFXResourceHandlerMesh, Warning, TEXT("UObject not found \"%s\""), ANSI_TO_TCHAR(resourcePath.Data())); + UE_LOG(LogPopcornFXResourceHandlerMesh, Warning, TEXT("UObject not found \"%s\""), *ToUE(resourcePath)); return null; } diff --git a/Source/PopcornFX/Private/Internal/ResourceHandlerVectorField_UE.cpp b/Source/PopcornFX/Private/Internal/ResourceHandlerVectorField_UE.cpp index d8f4232..e76ed64 100644 --- a/Source/PopcornFX/Private/Internal/ResourceHandlerVectorField_UE.cpp +++ b/Source/PopcornFX/Private/Internal/ResourceHandlerVectorField_UE.cpp @@ -119,10 +119,10 @@ PopcornFX::CVectorField *CResourceHandlerVectorField_UE::NewFromPath(const Popco { PK_NAMEDSCOPEDPROFILE_C("CResourceHandlerVectorField_UE::NewFromPath", POPCORNFX_UE_PROFILER_COLOR); - UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path.Data(), pathNotVirtual); + UObject *obj = FPopcornFXPlugin::Get().LoadUObjectFromPkPath(path, pathNotVirtual); if (obj == null) { - UE_LOG(LogPopcornFXResourceHandlerVectorField, Warning, TEXT("UObject not found \"%s\" %d"), ANSI_TO_TCHAR(path.Data()), pathNotVirtual); + UE_LOG(LogPopcornFXResourceHandlerVectorField, Warning, TEXT("UObject not found \"%s\" %d"), *ToUE(path), pathNotVirtual); return null; } UVectorFieldStatic *vectorFieldStatic = Cast(obj); @@ -157,9 +157,8 @@ void *CResourceHandlerVectorField_UE::Load( PopcornFX::CString _fullPath = resourcePath; if (!pathNotVirtual) // if virtual path - { - _fullPath = TCHAR_TO_ANSI(*FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath.Data(), true)); // prepend Pack Path - } + _fullPath = ToPk(FPopcornFXPlugin::Get().BuildPathFromPkPath(_fullPath, true)); // prepend Pack Path + PopcornFX::CFilePath::StripExtensionInPlace(_fullPath); const PopcornFX::CString &fullPath = _fullPath; if (!/*PK_VERIFY*/(!fullPath.Empty())) diff --git a/Source/PopcornFX/Private/Internal/Startup.cpp b/Source/PopcornFX/Private/Internal/Startup.cpp index fce4298..80ece0f 100644 --- a/Source/PopcornFX/Private/Internal/Startup.cpp +++ b/Source/PopcornFX/Private/Internal/Startup.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include +#include #include #include @@ -103,16 +105,34 @@ void AddDefaultGlobalListenersOverride(void *userHandle); #if (KR_PROFILER_ENABLED != 0) +bool g_RecordEffectNames = false; +thread_local u32 g_ProfileDepth = 0; +thread_local s32 g_RecordEffectName_Depth = -1; struct SUEStatIdKey { - const char *m_StatName = null; + PopcornFX::COwnedStringView m_StatName; - SUEStatIdKey() {} - SUEStatIdKey(const char *statName) : m_StatName(statName) {} + SUEStatIdKey() : m_StatName(PopcornFX::CString::EmptyString) { } + SUEStatIdKey(const PopcornFX::COwnedStringView &statName) + : m_StatName(statName) + { +#if (PK_CALL_SCOPE_ENABLED != 0) + if (g_RecordEffectNames && + (g_RecordEffectName_Depth == -1 || g_RecordEffectName_Depth == g_ProfileDepth)) + { + PopcornFX::TMemoryView stack = PopcornFX::CCallContext::ReadStack(); + if (!stack.Empty() && stack.Last() != null) + { + g_RecordEffectName_Depth = g_ProfileDepth; + m_StatName = PopcornFX::CString::Format("(%s) %s", stack.Last()->Message().Data(), statName.Data()); + } + } +#endif // (PK_CALL_SCOPE_ENABLED != 0) + } - bool Empty() const { return m_StatName == null; } + bool Empty() const { return m_StatName.Empty(); } - bool operator == (const SUEStatIdKey &other) const { return m_StatName == other.m_StatName; } + bool operator == (const SUEStatIdKey &other) const { return m_StatName.View() == other.m_StatName.View(); } bool operator != (const SUEStatIdKey &other) const { return !(*this == other); } }; @@ -121,7 +141,7 @@ struct SUEStatIdEntry SUEStatIdKey m_Key; TStatId m_StatId; - SUEStatIdEntry() {} + SUEStatIdEntry() { } SUEStatIdEntry(const SUEStatIdKey &key, TStatId value) : m_Key(key), m_StatId(value) {} bool operator == (const SUEStatIdKey &other) const { return m_Key == other; } @@ -137,7 +157,7 @@ class PopcornFX::TTypeHasher public: PK_INLINE static u32 Hash(const SUEStatIdKey &value) { - return _RawHasher::Hash(value.m_StatName, strlen(value.m_StatName));//sizeof(char*)); // hash pointer + return _RawHasher::Hash(value.m_StatName.Data(), value.m_StatName.Length()); } PK_INLINE static u32 Hash(const SUEStatIdEntry &value) { @@ -163,7 +183,7 @@ class PopcornFX::TFastHashMapTraits template SUEStatIdEntry const PopcornFX::TFastHashMapTraits::Invalid = SUEStatIdEntry(); template -SUEStatIdEntry const PopcornFX::TFastHashMapTraits::Probe = SUEStatIdEntry(SUEStatIdKey((const char*)1), TStatId()); +SUEStatIdEntry const PopcornFX::TFastHashMapTraits::Probe = SUEStatIdEntry(SUEStatIdKey("SUEStatIdKey"), TStatId()); struct SPopcornFXThreadProfileContext { @@ -269,8 +289,8 @@ namespace char _buffer[2048]; PrettyFormatAssert_Unsafe(_buffer, sizeof(_buffer), PK_ASSERT_CATCHER_ARGUMENTS); - const char *perttyMessage = _buffer; - UE_LOG(LogPopcornFXStartup, Warning, TEXT("%s"), ANSI_TO_TCHAR(perttyMessage)); + const char *prettyMessage = _buffer; + UE_LOG(LogPopcornFXStartup, Warning, TEXT("%s"), UTF8_TO_TCHAR(prettyMessage)); if (!IsClassLoaded() || !GetMutableDefault()->EnableAsserts) @@ -290,7 +310,7 @@ namespace // UE handles all WinProc messages then wait updates tasks before execute them >>> DEAD LOCK // GPumpingMessagesOutsideOfMainLoop = true should enqueue messages TGuardValue pumpMessageGuard(GPumpingMessagesOutsideOfMainLoop, true); - msgBoxRes = FPlatformMisc::MessageBoxExt(EAppMsgType::CancelRetryContinue, ANSI_TO_TCHAR(perttyMessage), TEXT("PopcornFX Assertion failed")); + msgBoxRes = FPlatformMisc::MessageBoxExt(EAppMsgType::CancelRetryContinue, UTF8_TO_TCHAR(prettyMessage), TEXT("PopcornFX Assertion failed")); } switch (msgBoxRes) { @@ -644,14 +664,14 @@ namespace if (success) { PK_ASSERT(nodeDescriptor != null); - const SUEStatIdKey key = SUEStatIdKey(nodeDescriptor->m_Name); + const SUEStatIdKey key = SUEStatIdKey(PopcornFX::COwnedStringView(PopcornFX::CStringView::FromNullTerminatedString(nodeDescriptor->m_Name))); PopcornFX::CGuid statId = ctx->m_StatsMap.IndexOf(key); if (!statId.Valid()) { - const FString statName = ANSI_TO_TCHAR(nodeDescriptor->m_Name); + const FString statName = *ToUE(key.m_StatName.View()); const TStatId newStatId = FDynamicStats::CreateStatId(statName); - statId = ctx->m_StatsMap.Insert(SUEStatIdEntry(SUEStatIdKey(nodeDescriptor->m_Name), newStatId)); + statId = ctx->m_StatsMap.Insert(SUEStatIdEntry(key, newStatId)); } success = statId.Valid(); @@ -675,6 +695,9 @@ namespace const FMinimalName statMinimalName = dynamicStatId.GetMinimalName(EMemoryOrder::Relaxed); const FName statName = MinimalNameToName(statMinimalName); FThreadStats::AddMessage(statName, EStatOperation::CycleScopeStart); +#if (PK_CALL_SCOPE_ENABLED != 0) + ++g_ProfileDepth; +#endif // (PK_CALL_SCOPE_ENABLED != 0) } } @@ -691,22 +714,24 @@ namespace POPCORNFX_PROFILERECORD_REENTRY_GUARD(return); + --g_ProfileDepth; + CWorkerThreadPool_UE *threadPool = static_cast(PopcornFX::Scheduler::ThreadPool().Get()); PK_ASSERT(threadPool != null); SPopcornFXThreadProfileContext *ctx = threadPool->GetCurrentThreadProfileContext(); if (ctx != null) // Can record { PK_ASSERT(nodeDescriptor != null); - const SUEStatIdKey key = SUEStatIdKey(nodeDescriptor->m_Name); + const SUEStatIdKey key = SUEStatIdKey(PopcornFX::COwnedStringView(PopcornFX::CStringView::FromNullTerminatedString(nodeDescriptor->m_Name))); const PopcornFX::CGuid statId = ctx->m_StatsMap.IndexOf(key); if (statId.Valid()) { if (GCycleStatsShouldEmitNamedEvents > 0) { -# if PK_HAS_CPUPROFILERTRACE +#if PK_HAS_CPUPROFILERTRACE if (UE_TRACE_CHANNELEXPR_IS_ENABLED(CpuChannel)) FCpuProfilerTrace::OutputEndEvent(); -# endif // PK_HAS_CPUPROFILERTRACE +#endif // PK_HAS_CPUPROFILERTRACE FPlatformMisc::EndNamedEvent(); } @@ -714,6 +739,10 @@ namespace const FMinimalName statMinimalName = dynamicStatId.GetMinimalName(EMemoryOrder::Relaxed); const FName statName = MinimalNameToName(statMinimalName); FThreadStats::AddMessage(statName, EStatOperation::CycleScopeEnd); +#if (PK_CALL_SCOPE_ENABLED != 0) + if (g_ProfileDepth == g_RecordEffectName_Depth) + g_RecordEffectName_Depth = -1; +#endif // (PK_CALL_SCOPE_ENABLED != 0) } } } @@ -763,11 +792,19 @@ bool PopcornFXStartup() #if (KR_PROFILER_ENABLED != 0) bool usePopcornFXTP = false; bool recordProfileMarkers = false; + bool recordEffectNames = false; + GConfig->GetBool(TEXT("PopcornFX"), TEXT("bUsePopcornFXWTP"), usePopcornFXTP, GEngineIni); GConfig->GetBool(TEXT("PopcornFX"), TEXT("bRecordProfileMarkers"), recordProfileMarkers, GEngineIni); +#if (PK_CALL_SCOPE_ENABLED != 0) + GConfig->GetBool(TEXT("PopcornFX"), TEXT("bRecordEffectNames"), recordEffectNames, GEngineIni); +#endif //(PK_CALL_SCOPE_ENABLED != 0) if (usePopcornFXTP) + { recordProfileMarkers = false; + recordEffectNames = false; + } if (recordProfileMarkers) { kernelConfiguration.m_ProfilerRecordArg = null; @@ -776,6 +813,7 @@ bool PopcornFXStartup() kernelConfiguration.m_ProfilerRecordMemoryTransaction = &PopcornFX_ProfileRecordMemoryTransaction; kernelConfiguration.m_ProfilerRecordThreadDependency = &PopcornFX_ProfileRecordThreadDependency; } + g_RecordEffectNames = recordEffectNames; #endif // (KR_PROFILER_ENABLED != 0) success = true; @@ -830,7 +868,6 @@ bool PopcornFXStartup() CCoordinateFrame::SetGlobalFrame(ECoordinateFrame::Frame_LeftHand_Z_Up); - // Register load tags success &= PopcornFX::CParticleManager::AddGlobalConstant(PopcornFX::CParticleManager::SElement("build.tags.low", 20)); success &= PopcornFX::CParticleManager::AddGlobalConstant(PopcornFX::CParticleManager::SElement("build.tags.medium", 21)); diff --git a/Source/PopcornFX/Private/Platforms/PopcornFXPlatformCommon.cpp b/Source/PopcornFX/Private/Platforms/PopcornFXPlatformCommon.cpp index 04bed7b..31ba019 100644 --- a/Source/PopcornFX/Private/Platforms/PopcornFXPlatformCommon.cpp +++ b/Source/PopcornFX/Private/Platforms/PopcornFXPlatformCommon.cpp @@ -237,7 +237,7 @@ bool CompileComputeShaderForAPI( const PopcornFX::CString &source, if (!modules.Num()) { - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: No target shader formats found"), ANSI_TO_TCHAR(apiName.Data())); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: No target shader formats found"), *ToUE(apiName)); return false; } @@ -290,17 +290,17 @@ bool CompileComputeShaderForAPI( const PopcornFX::CString &source, "// Layer: %s\n" "// Shader built for API: %s\n" "// Build tags: %s\n" - "// Shader kernel stage: %s\n" - , buildInfos.m_SourceEffect.Empty() ? "" : buildInfos.m_SourceEffect.ToString().Data() - , buildInfos.m_SourceLayerName.Empty() ? "" : buildInfos.m_SourceLayerName.ToString().Data() - , apiName.Data() - , allBuildTags.Data() - , kKernelStageNames[buildInfos.m_KernelStage])); + "// Shader kernel stage: %s\n", + buildInfos.m_SourceEffect.Empty() ? "" : buildInfos.m_SourceEffect.ToString().Data(), + buildInfos.m_SourceLayerName.Empty() ? "" : buildInfos.m_SourceLayerName.ToString().Data(), + apiName.Data(), + allBuildTags.Data(), + kKernelStageNames[buildInfos.m_KernelStage])); } - if (!FFileHelper::SaveStringToFile(ANSI_TO_TCHAR(finalSource.Data()), *srcFilePath)) + if (!FFileHelper::SaveStringToFile(ToUE(finalSource), *srcFilePath)) { - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't create temp source file"), ANSI_TO_TCHAR(apiName.Data())); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't create temp source file"), *ToUE(apiName)); return false; } @@ -329,7 +329,7 @@ bool CompileComputeShaderForAPI( const PopcornFX::CString &source, FShaderCompilerEnvironment mergedEnvironment; if (!shaderFormat->PreprocessShader(input, mergedEnvironment, preprocessorOutput)) { - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed preprocessing shader for %s"), ANSI_TO_TCHAR(apiName.Data())); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed preprocessing shader for %s"), *ToUE(apiName)); return false; } shaderFormat->CompilePreprocessedShader(input, preprocessorOutput, output, workingDirectory); @@ -350,14 +350,14 @@ bool CompileComputeShaderForAPI( const PopcornFX::CString &source, if (shaderCodeStart >= fullShaderCodeEnd || (fullShaderCodeEnd - shaderCodeStart) < bytecodeMagic.Length()) { - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't find %s header"), ANSI_TO_TCHAR(apiName.Data()), ANSI_TO_TCHAR(bytecodeMagic.Data())); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't find %s header"), *ToUE(apiName), *ToUE(bytecodeMagic)); return false; } for (u32 i = 0; i < bytecodeMagic.Length(); ++i) { if (shaderCodeStart[i] != bytecodeMagic[i]) { - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't find %s header"), ANSI_TO_TCHAR(apiName.Data()), ANSI_TO_TCHAR(bytecodeMagic.Data())); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't find %s header"), *ToUE(apiName), *ToUE(bytecodeMagic)); return false; } } @@ -380,14 +380,14 @@ bool CompileComputeShaderForAPI( const PopcornFX::CString &source, { const FString errorString = error.GetErrorString(); if (!errorString.IsEmpty()) - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: '%s'"), ANSI_TO_TCHAR(apiName.Data()), *errorString); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: '%s'"), *ToUE(apiName), *errorString); } return false; } } } - UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't find shader compiler module"), ANSI_TO_TCHAR(apiName.Data())); + UE_LOG(LogPopcornFXPlatformCommon, Verbose, TEXT("Failed compiling bytecodes for %s: couldn't find shader compiler module"), *ToUE(apiName)); return false; } #endif // (PK_COMPILE_GPU != 0) diff --git a/Source/PopcornFX/Private/PopcornFXFunctions.cpp b/Source/PopcornFX/Private/PopcornFXFunctions.cpp index 1fa6374..7526154 100644 --- a/Source/PopcornFX/Private/PopcornFXFunctions.cpp +++ b/Source/PopcornFX/Private/PopcornFXFunctions.cpp @@ -177,7 +177,7 @@ bool UPopcornFXFunctions::IsTextureCPUInUse(const FString &virtualPath) if (!PK_VERIFY(ihandler != null)) return false; CResourceHandlerImage_UE *handler = PopcornFX::checked_cast(ihandler); - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); + const PopcornFX::CString virtPath = ToPk(virtualPath); return handler->IsUsed(virtPath, false); } @@ -189,7 +189,7 @@ bool UPopcornFXFunctions::IsTextureGPUInUse(const FString &virtualPath) if (!PK_VERIFY(ihandler != null)) return false; CResourceHandlerImage_UE_D3D11 *handler = PopcornFX::checked_cast(ihandler); - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); + const PopcornFX::CString virtPath = ToPk(virtualPath); return handler->IsUsed(virtPath, false); #else return false; @@ -212,8 +212,7 @@ bool UPopcornFXFunctions::RegisterVirtualTextureOverride_CPU_FloatR(const FStri if (!PK_VERIFY(ihandler != null)) return false; CResourceHandlerImage_UE *handler = PopcornFX::checked_cast(ihandler); - - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); + const PopcornFX::CString virtPath = ToPk(virtualPath); const PopcornFX::CUint2 size(width, height); PK_ASSERT(pixels.GetTypeSize() == sizeof(float)); @@ -239,9 +238,9 @@ bool UPopcornFXFunctions::RegisterVirtualTextureOverride_CPU_FloatRGBA(const FS if (!PK_VERIFY(ihandler != null)) return false; CResourceHandlerImage_UE *handler = PopcornFX::checked_cast(ihandler); - - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); + const PopcornFX::CString virtPath = ToPk(virtualPath); const PopcornFX::CUint2 size(width, height); + PK_ASSERT(pixels.GetTypeSize() == sizeof(FLinearColor)); return handler->RegisterVirtualTexture( virtPath, false, @@ -258,7 +257,7 @@ bool UPopcornFXFunctions::UnregisterVirtualTextureOverride_CPU(const FString &v PopcornFX::IResourceHandler *ihandler = PopcornFX::Resource::DefaultManager()->FindHandler(); if (!PK_VERIFY(ihandler != null)) return false; - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); + const PopcornFX::CString virtPath = ToPk(virtualPath); CResourceHandlerImage_UE *handler = PopcornFX::checked_cast(ihandler); return handler->UnregisterVirtualTexture(virtPath, false); } @@ -276,12 +275,8 @@ bool UPopcornFXFunctions::RegisterVirtualTextureOverride_GPU(const FString &vir if (!PK_VERIFY(ihandler != null)) return false; CResourceHandlerImage_UE_D3D11 *handler = PopcornFX::checked_cast(ihandler); - - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); - - return handler->RegisterVirtualTexture( - virtPath, false, - texture); + const PopcornFX::CString virtPath = ToPk(virtualPath); + return handler->RegisterVirtualTexture(virtPath, false, texture); #else return false; #endif @@ -294,7 +289,7 @@ bool UPopcornFXFunctions::UnregisterVirtualTextureOverride_GPU(const FString &v PopcornFX::IResourceHandler *ihandler = PopcornFX::Resource::DefaultManager()->FindHandler(); if (!PK_VERIFY(ihandler != null)) return false; - const PopcornFX::CString virtPath = TCHAR_TO_ANSI(*virtualPath); + const PopcornFX::CString virtPath = ToPk(virtualPath); CResourceHandlerImage_UE_D3D11 *handler = PopcornFX::checked_cast(ihandler); return handler->UnregisterVirtualTexture(virtPath, false); #else diff --git a/Source/PopcornFX/Private/PopcornFXHelper.cpp b/Source/PopcornFX/Private/PopcornFXHelper.cpp index b745fba..2f651b1 100644 --- a/Source/PopcornFX/Private/PopcornFXHelper.cpp +++ b/Source/PopcornFX/Private/PopcornFXHelper.cpp @@ -7,10 +7,13 @@ #include "PopcornFXSDK.h" #include +#include #if WITH_EDITOR # include "Misc/MessageDialog.h" #endif +//---------------------------------------------------------------------------- + static const TCHAR *kHumanStr[] = { TEXT(" "), TEXT("k"), TEXT("m"), TEXT("g"), TEXT("t") }; @@ -37,6 +40,36 @@ const TCHAR *HumanReadS(float v, u32 base) return kHumanStr[i]; } +//---------------------------------------------------------------------------- + +PopcornFX::CString ToPk(const FString &str) +{ + return TCHAR_TO_UTF8(*str); +} + +//---------------------------------------------------------------------------- + +FString ToUE(const PopcornFX::CString &str) +{ + return UTF8_TO_TCHAR(str.Data()); +} + +//---------------------------------------------------------------------------- + +FString ToUE(const PopcornFX::CStringView &str) +{ + return UTF8_TO_TCHAR(str.Data()); +} + +//---------------------------------------------------------------------------- + +FString ToUE(const PopcornFX::CStringUnicode &str) +{ + return FString((const UTF16CHAR*)str.Data()); +} + +//---------------------------------------------------------------------------- + #if WITH_EDITOR EAppReturnType::Type OpenMessageBox(EAppMsgType::Type messageType, const FText& message, const FText& title) { @@ -47,3 +80,5 @@ EAppReturnType::Type OpenMessageBox(EAppMsgType::Type messageType, const FText& #endif // (ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 3) } #endif + +//---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/PopcornFXHelper.h b/Source/PopcornFX/Private/PopcornFXHelper.h index 3eb748c..5ad0645 100644 --- a/Source/PopcornFX/Private/PopcornFXHelper.h +++ b/Source/PopcornFX/Private/PopcornFXHelper.h @@ -14,10 +14,15 @@ #include "Math/IntPoint.h" #include "Math/Color.h" #include "Math/Box.h" +#include "Containers/UnrealString.h" #include "PopcornFXSDK.h" #include +__PK_API_BEGIN +class CStringUnicode; // Forward-declare +__PK_API_END + #ifndef POPCORNFX_UE_PROFILER_COLOR #define POPCORNFX_UE_PROFILER_COLOR CFloat3(1.0f, 0.5f, 0.0f) #endif @@ -35,6 +40,7 @@ PK_FORCEINLINE const _OutType &_Reinterpret(const _InType &vec) PK_FORCEINLINE const CFloat4 &ToPk(const FLinearColor &vec) { return _Reinterpret(vec); } PK_FORCEINLINE const CInt2 &ToPk(const FIntPoint& point) { return _Reinterpret(point); } +PK_FORCEINLINE const CUint4 &ToPk(const FIntVector4 &vec) { return _Reinterpret(vec); } // UE5 LWC: Keep reinterpret casts whenever possible PK_FORCEINLINE const FVector3f &ToUE(const CFloat3 &vec) { return _Reinterpret(vec); } @@ -93,6 +99,11 @@ PK_FORCEINLINE CFloat3 &ToPkRef(FVector3f &vec) return *reinterpret_cast(&vec); } +PopcornFX::CString ToPk(const FString &str); +FString ToUE(const PopcornFX::CString &str); +FString ToUE(const PopcornFX::CStringView &str); +FString ToUE(const PopcornFX::CStringUnicode &str); + float HumanReadF(float v, u32 base = 1024); const TCHAR *HumanReadS(float v, u32 base = 1024); static inline float SafeRcp(float v) { return v == 0.f ? 0.f : 1.f / v; } diff --git a/Source/PopcornFX/Private/PopcornFXPlugin.cpp b/Source/PopcornFX/Private/PopcornFXPlugin.cpp index 84be13b..3236167 100644 --- a/Source/PopcornFX/Private/PopcornFXPlugin.cpp +++ b/Source/PopcornFX/Private/PopcornFXPlugin.cpp @@ -595,7 +595,7 @@ void FPopcornFXPlugin::_UpdateSimInterfaceBindings(const FString &libraryDir) { simInterfaceMapper->Clear(); - const PopcornFX::CString pkLibDir = TCHAR_TO_ANSI(*libraryDir); + const PopcornFX::CString pkLibDir = ToPk(libraryDir); for (const SPopcornFXSimulationInterface &simInterface : kSimInterfaces) { @@ -639,10 +639,50 @@ PopcornFX::PFilePack FPopcornFXPlugin::FilePack() //---------------------------------------------------------------------------- +#if WITH_EDITOR +void FPopcornFXPlugin::RefreshFromEditorSettings() +{ + UPopcornFXSettingsEditor *editorSettings = GetMutableDefault(); + check(editorSettings); + m_SettingsEditor = editorSettings; + + if (m_BakeContext != null && + m_BakeContext->m_BakeContext != null && + m_BakeContext->m_BakeFSController != null) + { + m_BakeContext->m_BakeFSController->UnmountAllPacks(); + if (PK_VERIFY(m_BakeContext->m_BakeFSController->MountPack(ToPk(m_SettingsEditor->AbsSourcePackRootDir)) != null)) + { + if (editorSettings->bSourcePackFound) + { + // Only update bindings when pack is found. we don't want to spam errors for users not having the source pack available (which is legit). + // No source pack -> no effects import + { + // New project, lib dir might have changed, we need to update the sim interface bindings + FString libraryDir = editorSettings->AbsSourcePackLibraryDir; + if (PK_VERIFY(FPaths::MakePathRelativeTo(libraryDir, *editorSettings->AbsSourcePackRootDir))) + _UpdateSimInterfaceBindings(libraryDir); + else + UE_LOG(LogPopcornFXPlugin, Error, TEXT("Couldn't make LibraryDir relative path from source pack root directory. Sim interfaces will not be bound")); + } + } + } + } +} +#endif // WITH_EDITOR + +//---------------------------------------------------------------------------- + bool FPopcornFXPlugin::LoadSettingsAndPackIFN() { if (!m_LaunchedPopcornFX) // could happen on shutdown return false; + +#if WITH_EDITOR + // Lazy init IFN + BakeContext(); +#endif + if (m_Settings != null) { #if WITH_EDITOR @@ -652,37 +692,7 @@ bool FPopcornFXPlugin::LoadSettingsAndPackIFN() return m_RootPackLoaded; } #if WITH_EDITOR - { - UPopcornFXSettingsEditor *editorSettings = GetMutableDefault(); - check(editorSettings); - editorSettings->UpdateSourcePack(); - m_SettingsEditor = editorSettings; - - // Lazy init IFN - BakeContext(); - if (m_BakeContext != null && - m_BakeContext->m_BakeContext != null && - m_BakeContext->m_BakeFSController != null) - { - m_BakeContext->m_BakeFSController->UnmountAllPacks(); - if (PK_VERIFY(m_BakeContext->m_BakeFSController->MountPack(TCHAR_TO_ANSI(*m_SettingsEditor->SourcePackRootDir)) != null)) - { - if (editorSettings->bSourcePackFound) - { - // Only update bindings when pack is found. we don't want to spam errors for users not having the source pack available (which is legit). - // No source pack -> no effects import - { - // New project, lib dir might have changed, we need to update the sim interface bindings - FString libraryDir = editorSettings->SourcePackLibraryDir; - if (PK_VERIFY(FPaths::MakePathRelativeTo(libraryDir, *editorSettings->SourcePackRootDir))) - _UpdateSimInterfaceBindings(libraryDir); - else - UE_LOG(LogPopcornFXPlugin, Error, TEXT("Couldn't make LibraryDir relative path from source pack root directory. Sim interfaces will not be bound")); - } - } - } - } - } + RefreshFromEditorSettings(); PK_ASSERT(m_SettingsEditor != null); #endif m_Settings = GetMutableDefault(); @@ -697,14 +707,14 @@ bool FPopcornFXPlugin::LoadSettingsAndPackIFN() { PK_ASSERT(m_FilePack == null); - const PopcornFX::CString packPath = TCHAR_TO_ANSI(*m_Settings->PackMountPoint); + const PopcornFX::CString packPath = ToPk(m_Settings->PackMountPoint); PK_ASSERT(PopcornFX::File::DefaultFileSystem() != null); PopcornFX::PFilePack pack = PopcornFX::File::DefaultFileSystem()->MountPack(packPath); if (!PK_VERIFY(pack != null)) return false; m_FilePack = pack; - m_FilePackPath = ANSI_TO_TCHAR(m_FilePack->Path().Data()); + m_FilePackPath = ToUE(m_FilePack->Path()); m_FilePackPath /= ""; PK_ASSERT(m_FilePackPath[m_FilePackPath.Len() - 1] == '/'); m_RootPackLoaded = true; @@ -726,17 +736,20 @@ bool FPopcornFXPlugin::LoadSettingsAndPackIFN() FString FPopcornFXPlugin::BuildPathFromPkPath(const char *pkPath, bool prependPackPath) { - PK_NAMEDSCOPEDPROFILE_C("FPopcornFXPlugin::BuildPathFromPkPath", POPCORNFX_UE_PROFILER_COLOR); + return BuildPathFromPkPath(PopcornFX::CString(pkPath), prependPackPath); +} - if (!LoadSettingsAndPackIFN()) - return FString(); +//---------------------------------------------------------------------------- - if (!PK_VERIFY(FilePack() != null)) - { +FString FPopcornFXPlugin::BuildPathFromPkPath(const PopcornFX::CString &pkPath, bool prependPackPath) +{ + PK_NAMEDSCOPEDPROFILE_C("FPopcornFXPlugin::BuildPathFromPkPath", POPCORNFX_UE_PROFILER_COLOR); + + if (!LoadSettingsAndPackIFN() || + !PK_VERIFY(FilePack() != null)) return FString(); - } - PopcornFX::CString path(PopcornFX::CStringContainer::NewResizable(pkPath)); + PopcornFX::CString path = pkPath; if (path.Empty()) return FString(); if (prependPackPath) @@ -764,8 +777,7 @@ FString FPopcornFXPlugin::BuildPathFromPkPath(const char *pkPath, bool prependP else path.Append(path.Data(), path.Length() - 1 /*the '.'*/); - FString p = path.Data(); - return p; + return ToUE(path); } //---------------------------------------------------------------------------- @@ -815,7 +827,8 @@ PopcornFX::PBaseObjectFile FPopcornFXPlugin::LoadPkFile(const UPopcornFXFile *f const PopcornFX::CString pkPath = file->PkPath(); if (pkPath.Empty()) return null; - PopcornFX::PBaseObjectFile pkFile = PopcornFX::HBO::g_Context->LoadFile(pkPath.Data(), reload); + + PopcornFX::PBaseObjectFile pkFile = PopcornFX::HBO::g_Context->LoadFile(pkPath, reload); if (pkFile != null) _SetupFile(file, pkFile); return pkFile; @@ -847,7 +860,7 @@ UPopcornFXFile *FPopcornFXPlugin::GetPopcornFXFile(const PopcornFX::CBaseObject if (boFile->InternalUserData() == null) { - UObject *object = LoadUObjectFromPkPath(boFile->Path().Data(), false); + UObject *object = LoadUObjectFromPkPath(boFile->Path(), false); if (object == null) return null; UPopcornFXFile *file = Cast(object); @@ -859,16 +872,14 @@ UPopcornFXFile *FPopcornFXPlugin::GetPopcornFXFile(const PopcornFX::CBaseObject UPopcornFXFile *file = reinterpret_cast(boFile->InternalUserData()); - PK_ASSERT(Cast(LoadUObjectFromPkPath(boFile->Path().Data(), false)) == file); - + PK_ASSERT(Cast(LoadUObjectFromPkPath(boFile->Path(), false)) == file); check(file == null || file->IsBaseObject()); - return file; } //---------------------------------------------------------------------------- -UObject *FPopcornFXPlugin::LoadUObjectFromPkPath(const char *pkPath, bool pathNotVirtual) +UObject *FPopcornFXPlugin::LoadUObjectFromPkPath(const PopcornFX::CString &pkPath, bool pathNotVirtual) { LLM_SCOPE(ELLMTag::Particles); if (!m_LaunchedPopcornFX) // could happen at shutdown @@ -879,22 +890,22 @@ UObject *FPopcornFXPlugin::LoadUObjectFromPkPath(const char *pkPath, bool pathN #if WITH_EDITOR // Editor only (baking code is the only place where this occurs) - PopcornFX::CString ext = PopcornFX::CFilePath::ExtractExtension(pkPath); + PopcornFX::CStringView ext = PopcornFX::CFilePath::ExtractExtension(PopcornFX::CStringView(pkPath)); if (ext == "pkcf") return null; #endif // WITH_EDITOR - // // about BuildPathFromPkPath(..., __ bool prependPackPath __): - // // if pathNotVirtual: // real path // already prepended with "/Game/" // else // virtual path // no "/Game/", just "Particles/": so prendpend "/Game/" - FString p = BuildPathFromPkPath(pkPath, !pathNotVirtual); + + FString p = BuildPathFromPkPath(pkPath, !pathNotVirtual); if (p.IsEmpty()) return null; - UObject *anyObject = ::FindObject(null, *p); + + UObject *anyObject = ::FindObject(null, *p); if (anyObject == null) anyObject = ::LoadObject(null, *p); if (anyObject != null) @@ -935,7 +946,7 @@ void FPopcornFXPlugin::NotifyObjectChanged(UObject *object) if (!objectPath.StartsWith(m_FilePackPath)) return; const FString virtualPath = objectPath.Right(objectPath.Len() - m_FilePackPath.Len()); - const PopcornFX::CString virtualPathPk(TCHAR_TO_ANSI(*virtualPath)); + const PopcornFX::CString virtualPathPk(ToPk(virtualPath)); PopcornFX::Resource::DefaultManager()->NotifyResourceChanged(PopcornFX::CFilePackPath(m_FilePack, virtualPathPk)); } diff --git a/Source/PopcornFX/Private/PopcornFXPlugin.h b/Source/PopcornFX/Private/PopcornFXPlugin.h index 148926b..e077896 100644 --- a/Source/PopcornFX/Private/PopcornFXPlugin.h +++ b/Source/PopcornFX/Private/PopcornFXPlugin.h @@ -117,6 +117,7 @@ class FPopcornFXPlugin : public IPopcornFXPlugin * return the corresponding path for Unreal assets */ FString BuildPathFromPkPath(const char *pkPath, bool prependPackPath); + FString BuildPathFromPkPath(const PopcornFX::CString &pkPath, bool prependPackPath); PopcornFX::PBaseObjectFile FindPkFile(const UPopcornFXFile *file); PopcornFX::PBaseObjectFile LoadPkFile(const UPopcornFXFile *file, bool reload = false); @@ -124,7 +125,7 @@ class FPopcornFXPlugin : public IPopcornFXPlugin UPopcornFXFile *GetPopcornFXFile(const PopcornFX::CBaseObjectFile *file); - UObject *LoadUObjectFromPkPath(const char *pkPath, bool notVirtual); + UObject *LoadUObjectFromPkPath(const PopcornFX::CString &pkPath, bool notVirtual); void NotifyObjectChanged(UObject *object); @@ -194,7 +195,7 @@ class FPopcornFXPlugin : public IPopcornFXPlugin class FRHITexture2D *SceneDepthTexture() { return m_SceneDepthTexture; } class FRHITexture2D *SceneNormalTexture() { return m_SceneNormalTexture; } #if (PK_GPU_D3D11 != 0) - PopcornFX::SParticleStreamBuffer_D3D11 &ViewConstantBuffer_D3D11() { return m_ViewConstantBuffer_D3D11; } + PopcornFX::SBuffer_D3D11 &ViewConstantBuffer_D3D11() { return m_ViewConstantBuffer_D3D11; } #endif // (PK_GPU_D3D11 != 0) void SetViewUniformData(const SUEViewUniformData &viewUniformData) { m_ViewUniformData = viewUniformData; } const SUEViewUniformData &ViewUniformData() const { return m_ViewUniformData; } @@ -204,6 +205,10 @@ class FPopcornFXPlugin : public IPopcornFXPlugin void ActivateEffectsProfiler(bool activate); bool EffectsProfilerActive() const; +#if WITH_EDITOR + void RefreshFromEditorSettings(); +#endif + private: bool LoadSettingsAndPackIFN(); #if 0 @@ -231,7 +236,7 @@ class FPopcornFXPlugin : public IPopcornFXPlugin class FRHITexture2D *m_SceneDepthTexture; class FRHITexture2D *m_SceneNormalTexture; #if (PK_GPU_D3D11 != 0) - PopcornFX::SParticleStreamBuffer_D3D11 m_ViewConstantBuffer_D3D11; + PopcornFX::SBuffer_D3D11 m_ViewConstantBuffer_D3D11; #endif // (PK_GPU_D3D11 != 0) SUEViewUniformData m_ViewUniformData; FPostOpaqueRenderDelegate m_PostOpaqueRenderDelegate; diff --git a/Source/PopcornFX/Private/PopcornFXSettings.cpp b/Source/PopcornFX/Private/PopcornFXSettings.cpp index 03dcd1b..134371a 100644 --- a/Source/PopcornFX/Private/PopcornFXSettings.cpp +++ b/Source/PopcornFX/Private/PopcornFXSettings.cpp @@ -118,7 +118,7 @@ UMaterialInterface *UPopcornFXSettings::GetConfigDefaultMaterial(uint32 ePopcorn if (mat == null) { UE_LOG(LogPopcornFXSettings, Warning, TEXT("PopcornFX Config %s is invalid, falling back on PopcornFX Plugin's default one %s"), *FString(kMaterialTypeNames[materialType]), *FString(kPluginsDefaultMaterials[materialType])); - mat = ::LoadObject(null, ANSI_TO_TCHAR(kPluginsDefaultMaterials[materialType])); + mat = ::LoadObject(null, UTF8_TO_TCHAR(kPluginsDefaultMaterials[materialType])); PK_ASSERT(mat != null); } return mat; diff --git a/Source/PopcornFX/Private/PopcornFXSettingsEditor.cpp b/Source/PopcornFX/Private/PopcornFXSettingsEditor.cpp index 59ea7a3..f997664 100644 --- a/Source/PopcornFX/Private/PopcornFXSettingsEditor.cpp +++ b/Source/PopcornFX/Private/PopcornFXSettingsEditor.cpp @@ -8,7 +8,6 @@ #include "PopcornFXPlugin.h" #if WITH_EDITOR - # include "PopcornFXSDK.h" # include @@ -39,6 +38,7 @@ UPopcornFXSettingsEditor::UPopcornFXSettingsEditor(const FObjectInitializer& PCI , bRestartEmitterWhenAttributesChanged(false) #endif // WITH_EDITORONLY_DATA { +#if WITH_EDITORONLY_DATA static const FString kDefaultIncludes[] = { "*.pkfx", "*.pkat", "*.fbx", @@ -52,7 +52,7 @@ UPopcornFXSettingsEditor::UPopcornFXSettingsEditor(const FObjectInitializer& PCI "Editor/*", }; static uint32 kDefaultExcludesCount = sizeof(kDefaultExcludes) / sizeof(*kDefaultExcludes); -#if WITH_EDITORONLY_DATA + AutoReimportMirrorPackWildcards.SetNum(kDefaultIncludesCount + kDefaultExcludesCount); uint32 configwci = 0; for (uint32 i = 0; i < kDefaultIncludesCount; ++i, ++configwci) @@ -68,20 +68,25 @@ UPopcornFXSettingsEditor::UPopcornFXSettingsEditor(const FObjectInitializer& PCI #endif // WITH_EDITORONLY_DATA } -#if WITH_EDITOR - //---------------------------------------------------------------------------- -void UPopcornFXSettingsEditor::PostLoad() +#if WITH_EDITORONLY_DATA +void UPopcornFXSettingsEditor::PostInitProperties() { - Super::PostLoad(); + Super::PostInitProperties(); - // /!\ not actualy called when GetDefault is used - UpdateSourcePack(); + AbsSourcePackProjectFile = SourcePackProjectFile.IsEmpty() ? FString() : FPaths::ConvertRelativePathToFull(SourcePackProjectFile); + AbsSourcePackRootDir = SourcePackRootDir.IsEmpty() ? FString() : FPaths::ConvertRelativePathToFull(SourcePackRootDir); + AbsSourcePackLibraryDir = SourcePackLibraryDir.IsEmpty() ? FString() : FPaths::ConvertRelativePathToFull(SourcePackLibraryDir); + AbsSourcePackThumbnailsDir = SourcePackThumbnailsDir.IsEmpty() ? FString() : FPaths::ConvertRelativePathToFull(SourcePackThumbnailsDir); + AbsSourcePackCacheDir = SourcePackCacheDir.IsEmpty() ? FString() : FPaths::ConvertRelativePathToFull(SourcePackCacheDir); } +#endif // WITH_EDITORONLY_DATA //---------------------------------------------------------------------------- +#if WITH_EDITOR + void UPopcornFXSettingsEditor::PreEditChange(FProperty *propertyAboutToChange) { Super::PreEditChange(propertyAboutToChange); @@ -90,11 +95,11 @@ void UPopcornFXSettingsEditor::PreEditChange(FProperty *propertyAboutToChange) { if (propertyAboutToChange->GetName() == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXSettingsEditor, ImportSourcePack)) { - SourcePackRootDir_ToRemove = SourcePackRootDir; + SourcePackRootDir_ToRemove = AbsSourcePackRootDir; } else if (propertyAboutToChange->GetName() == GET_MEMBER_NAME_STRING_CHECKED(UPopcornFXSettingsEditor, bAddSourcePackToMonitoredDirectories)) { - SourcePackRootDir_ToRemove = SourcePackRootDir; + SourcePackRootDir_ToRemove = AbsSourcePackRootDir; } } } @@ -184,6 +189,8 @@ static bool operator == (const FAutoReimportWildcard &a, const FMyAutoReimportW return a.Wildcard == b.Wildcard && a.bInclude == b.bInclude; } +//---------------------------------------------------------------------------- + void UPopcornFXSettingsEditor::_CopyWildcards(FAutoReimportDirectoryConfig &config) { const u32 wildcardCount = AutoReimportMirrorPackWildcards.Num(); @@ -200,6 +207,8 @@ void UPopcornFXSettingsEditor::_CopyWildcards(FAutoReimportDirectoryConfig &conf } } +//---------------------------------------------------------------------------- + bool UPopcornFXSettingsEditor::_HasSameWildcards(const FAutoReimportDirectoryConfig &config) { const u32 wildcardCount = config.Wildcards.Num(); @@ -213,6 +222,8 @@ bool UPopcornFXSettingsEditor::_HasSameWildcards(const FAutoReimportDirectoryCon return true; } +//---------------------------------------------------------------------------- + void UPopcornFXSettingsEditor::ForceUpdateAutoReimportSettings() { UEditorLoadingSavingSettings *loadSaveSettings = GetMutableDefault(); @@ -223,18 +234,18 @@ void UPopcornFXSettingsEditor::ForceUpdateAutoReimportSettings() // Remove old one IFN if (!SourcePackRootDir_ToRemove.IsEmpty() && - SourcePackRootDir_ToRemove != SourcePackRootDir) + SourcePackRootDir_ToRemove != AbsSourcePackRootDir) { notify |= _RemoveAutoReimport(SourcePackRootDir_ToRemove); } SourcePackRootDir_ToRemove.Empty(); - const bool autoReimport = !SourcePackRootDir.IsEmpty() && bAddSourcePackToMonitoredDirectories; + const bool autoReimport = !AbsSourcePackRootDir.IsEmpty() && bAddSourcePackToMonitoredDirectories; if (!autoReimport) { // remove everything ! - notify |= _RemoveAutoReimport(SourcePackRootDir); + notify |= _RemoveAutoReimport(AbsSourcePackRootDir); } else { @@ -250,7 +261,7 @@ void UPopcornFXSettingsEditor::ForceUpdateAutoReimportSettings() for (int32 i = 0; i < loadSaveSettings->AutoReimportDirectorySettings.Num(); ++i) { const FAutoReimportDirectoryConfig &config = loadSaveSettings->AutoReimportDirectorySettings[i]; - if (config.SourceDirectory != SourcePackRootDir) + if (config.SourceDirectory != AbsSourcePackRootDir) continue; ++foundCount; if (foundCount > expectedCount) @@ -273,12 +284,12 @@ void UPopcornFXSettingsEditor::ForceUpdateAutoReimportSettings() if (hasChanged) { // remove all - notify |= _RemoveAutoReimport(SourcePackRootDir); + notify |= _RemoveAutoReimport(AbsSourcePackRootDir); const int32 diri = loadSaveSettings->AutoReimportDirectorySettings.Add(FAutoReimportDirectoryConfig()); check(diri >= 0); FAutoReimportDirectoryConfig &config = loadSaveSettings->AutoReimportDirectorySettings[diri]; - config.SourceDirectory = SourcePackRootDir; + config.SourceDirectory = AbsSourcePackRootDir; config.MountPoint = settings->PackMountPoint; _CopyWildcards(config); @@ -291,53 +302,58 @@ void UPopcornFXSettingsEditor::ForceUpdateAutoReimportSettings() _NotifyReimportManager(); } - //---------------------------------------------------------------------------- -static const FString kOldPopcornFXProjectFileName = "PopcornProject.xml"; -static const FString kPopcornFXProjectFileName = "PopcornProject.pkproj"; +static const FString kOldPopcornFXProjectFileName = "PopcornProject.xml"; +static const FString kPopcornFXProjectFileName = "PopcornProject.pkproj"; -// static -FString UPopcornFXSettingsEditor::FixAndAppendPopcornFXProjectFileName(const FString &path) +static FString FixAndAppendPopcornFXProjectFileName(const FString &path) { // fix old path if (path.EndsWith(kOldPopcornFXProjectFileName)) { - FString newPath = path; + FString newPath = path; newPath.RemoveAt(newPath.Len() - kOldPopcornFXProjectFileName.Len(), kOldPopcornFXProjectFileName.Len(), false); newPath /= kPopcornFXProjectFileName; return newPath; } - // append ifn + // append IFN if (!path.EndsWith(kPopcornFXProjectFileName)) return path / kPopcornFXProjectFileName; return path; } +//---------------------------------------------------------------------------- + void UPopcornFXSettingsEditor::UpdateSourcePack() { // if not in editor, do nothing, keep saved values - SourcePackProjectFile.Empty(); SourcePackRootDir.Empty(); SourcePackLibraryDir.Empty(); - SourcePackCacheDir.Empty(); SourcePackThumbnailsDir.Empty(); - bSourcePackFound = 0; + SourcePackCacheDir.Empty(); + + AbsSourcePackProjectFile.Empty(); + AbsSourcePackRootDir.Empty(); + AbsSourcePackLibraryDir.Empty(); + AbsSourcePackThumbnailsDir.Empty(); + AbsSourcePackCacheDir.Empty(); + + bSourcePackFound = false; if (!ImportSourcePack.IsEmpty()) { - FString projectFile = ImportSourcePack; + FString projectFile = ImportSourcePack; FPaths::NormalizeFilename(projectFile); FPaths::RemoveDuplicateSlashes(projectFile); - projectFile = FixAndAppendPopcornFXProjectFileName(projectFile); if (FPaths::IsRelative(projectFile)) projectFile = FPaths::ProjectDir() / projectFile; SourcePackProjectFile = projectFile; - int32 lastSlash = projectFile.Find("/", ESearchCase::CaseSensitive, ESearchDir::FromEnd); + int32 lastSlash = projectFile.Find("/", ESearchCase::CaseSensitive, ESearchDir::FromEnd); if (lastSlash != INDEX_NONE) SourcePackRootDir = projectFile.Left(lastSlash + 1); SourcePackLibraryDir = SourcePackRootDir / "Library"; @@ -346,29 +362,26 @@ void UPopcornFXSettingsEditor::UpdateSourcePack() if (FPaths::FileExists(projectFile)) { - bSourcePackFound = 1; - TArray fileContent; if (FFileHelper::LoadFileToArray(fileContent, *projectFile)) { PopcornFX::CConstMemoryStream stream(fileContent.GetData(), fileContent.Num()); - - PopcornFX::HBO::CContext *localBoContext = PK_NEW(PopcornFX::HBO::CContext()); + PopcornFX::HBO::CContext *localBoContext = PK_NEW(PopcornFX::HBO::CContext()); if (PK_VERIFY(localBoContext != null)) { PopcornFX::PProjectSettings projectSettings = PopcornFX::CProjectSettings::LoadFromStream(stream, localBoContext); if (projectSettings != null && projectSettings->General() != null) { - bSourcePackFound = 1; + bSourcePackFound = true; if (!projectSettings->General()->RootDir().Empty()) - SourcePackRootDir /= ANSI_TO_TCHAR(projectSettings->General()->RootDir().Data()); + SourcePackRootDir /= ToUE(projectSettings->General()->RootDir()); if (!projectSettings->General()->LibraryDir().Empty()) - SourcePackLibraryDir = SourcePackRootDir / ANSI_TO_TCHAR(projectSettings->General()->LibraryDir().Data()); + SourcePackLibraryDir = SourcePackRootDir / ToUE(projectSettings->General()->LibraryDir()); if (!projectSettings->General()->ThumbnailsDir().Empty()) - SourcePackThumbnailsDir = SourcePackRootDir / ANSI_TO_TCHAR(projectSettings->General()->ThumbnailsDir().Data()); + SourcePackThumbnailsDir = SourcePackRootDir / ToUE(projectSettings->General()->ThumbnailsDir()); if (!projectSettings->General()->EditorCacheDir().Empty()) - SourcePackCacheDir = SourcePackRootDir / ANSI_TO_TCHAR(projectSettings->General()->EditorCacheDir().Data()); + SourcePackCacheDir = SourcePackRootDir / ToUE(projectSettings->General()->EditorCacheDir()); localBoContext->UnloadAllFiles(); PK_DELETE(localBoContext); @@ -388,18 +401,42 @@ void UPopcornFXSettingsEditor::UpdateSourcePack() { // Log error } - SourcePackProjectFile = FPaths::ConvertRelativePathToFull(SourcePackProjectFile); - SourcePackRootDir = FPaths::ConvertRelativePathToFull(SourcePackRootDir); - SourcePackLibraryDir = FPaths::ConvertRelativePathToFull(SourcePackLibraryDir); - SourcePackThumbnailsDir = FPaths::ConvertRelativePathToFull(SourcePackThumbnailsDir); - SourcePackCacheDir = FPaths::ConvertRelativePathToFull(SourcePackCacheDir); + + // Can't use 'FPaths::CollapseRelativeDirectories()' to collapse '..' inside the path if they start with '..' + // So convert to PopcornFX strings and use CFilePath::Purify(), then convert back to FPath + SourcePackProjectFile = ToUE(PopcornFX::CFilePath::Purified(ToPk(SourcePackProjectFile))); + SourcePackRootDir = ToUE(PopcornFX::CFilePath::Purified(ToPk(SourcePackRootDir))); + SourcePackLibraryDir = ToUE(PopcornFX::CFilePath::Purified(ToPk(SourcePackLibraryDir))); + SourcePackThumbnailsDir = ToUE(PopcornFX::CFilePath::Purified(ToPk(SourcePackThumbnailsDir))); + SourcePackCacheDir = ToUE(PopcornFX::CFilePath::Purified(ToPk(SourcePackCacheDir))); + + AbsSourcePackProjectFile = FPaths::ConvertRelativePathToFull(SourcePackProjectFile); + AbsSourcePackRootDir = FPaths::ConvertRelativePathToFull(SourcePackRootDir); + AbsSourcePackLibraryDir = FPaths::ConvertRelativePathToFull(SourcePackLibraryDir); + AbsSourcePackThumbnailsDir = FPaths::ConvertRelativePathToFull(SourcePackThumbnailsDir); + AbsSourcePackCacheDir = FPaths::ConvertRelativePathToFull(SourcePackCacheDir); } // Avoid adding invalid source pack folders if (bSourcePackFound) - { ForceUpdateAutoReimportSettings(); - } + + // Fix #13209: Update bake context & other plugin-global things that depend on the project paths + FPopcornFXPlugin::Get().RefreshFromEditorSettings(); +} + +//---------------------------------------------------------------------------- + +static bool _IsValidSourcePack(const FString &path) +{ + FString projectFile = path; + FPaths::NormalizeFilename(projectFile); + FPaths::RemoveDuplicateSlashes(projectFile); + projectFile = FixAndAppendPopcornFXProjectFileName(projectFile); + if (FPaths::IsRelative(projectFile)) + projectFile = FPaths::ProjectDir() / projectFile; + + return FPaths::FileExists(projectFile); } //---------------------------------------------------------------------------- @@ -409,11 +446,10 @@ bool UPopcornFXSettingsEditor::AskForAValidSourcePackForIFN(const FString &sourc if (!PK_VERIFY(!sourceAssetPath.IsEmpty())) return false; - bool isValid = ValidSourcePack(); - if (isValid) + if (ValidSourcePack()) { const FString sourceAssetPathAbs = FPaths::ConvertRelativePathToFull(sourceAssetPath); - if (!sourceAssetPathAbs.StartsWith(SourcePackRootDir)) + if (!sourceAssetPathAbs.StartsWith(AbsSourcePackRootDir)) { UE_LOG(LogPopcornFXEditorSettings, Error, TEXT("Asset outside Source PopcornFX Project: '%s'"), *sourceAssetPath); const FText title = LOCTEXT("PopcornFXAssetOutsidePackTitle", "PopcornFX: Asset outside Source PopcornFX Project"); @@ -426,44 +462,62 @@ bool UPopcornFXSettingsEditor::AskForAValidSourcePackForIFN(const FString &sourc "Project Settings > PopcornFX Editor > Source PopcornFX Project path:\n" "{1}\n" "\n" - "Continue anyway ?\n"), FText::FromString(sourceAssetPath), FText::FromString(SourcePackRootDir)); + "Continue anyway ?\n"), FText::FromString(sourceAssetPathAbs), FText::FromString(AbsSourcePackRootDir)); return OpenMessageBox(EAppMsgType::YesNo, msg, title) == EAppReturnType::Yes; } return true; } - const FString oldImportSourcePath = ImportSourcePack; - if (!sourceAssetPath.IsEmpty()) + const FString oldImportSourcePath = ImportSourcePack; + bool isValid = false; + FString sourcePack = FPaths::ConvertRelativePathToFull(sourceAssetPath); + + static const FString kTrySubPaths[] = { + "PopcornFX", + "PopcornFX/Editor", + "Editor", + }; + + // GetPath will make it loop over all parent folders to find the right one IFP + while (!isValid && !sourcePack.IsEmpty()) { - ImportSourcePack = FPaths::ConvertRelativePathToFull(sourceAssetPath); - PK_ASSERT(!isValid); + FString newSourcePack = FPaths::GetPath(sourcePack); // gets dirname: removes last name in path, effectively does a ../ + if (!FPaths::IsRelative(newSourcePack)) + { + FString relativePath = newSourcePack; + const FString projectDir = FPaths::ProjectDir(); + + if (FPaths::MakePathRelativeTo(relativePath, *projectDir)) + newSourcePack = relativePath; + } - // GetPath will make it loop over all parent folders to find the right one IFP - while (!isValid) + if (newSourcePack.IsEmpty() || !PK_VERIFY(newSourcePack[newSourcePack.Len() - 1] != '/')) + break; + + sourcePack = newSourcePack; + isValid = _IsValidSourcePack(sourcePack); + if (!isValid) { - const FString sourcePack = ImportSourcePack; - FString newSourcePack = FPaths::GetPath(sourcePack); // dirname ! - // sanity checks ! - if (newSourcePack.Len() < 3 || // matches drive paths and too small to be valid - newSourcePack.Len() >= sourcePack.Len()) // GetPath does that too - break; - if (!FPaths::IsRelative(newSourcePack)) + for (const auto &subPath : kTrySubPaths) { - FString relativePath = newSourcePack; - const FString projectDir = FPaths::ProjectDir(); - - if (FPaths::MakePathRelativeTo(relativePath, *projectDir) && - relativePath.Len() > 1 && relativePath.Len() <= newSourcePack.Len()) // use it only if shorter + const FString tryPath = sourcePack / subPath; + isValid = _IsValidSourcePack(tryPath); + if (isValid) { - newSourcePack = relativePath; + sourcePack = tryPath; + break; } } - if (!PK_VERIFY(newSourcePack[newSourcePack.Len() - 1] != '/')) - break; - ImportSourcePack = newSourcePack; + } + + if (isValid) // Quick detection found a .pkproj, try the full-force resolve that will actually load it: + { + ImportSourcePack = sourcePack; UpdateSourcePack(); isValid = ValidSourcePack(); + if (!isValid) + sourcePack = newSourcePack; // revert the potential subpath & continue iterating downstream } } @@ -480,7 +534,6 @@ bool UPopcornFXSettingsEditor::AskForAValidSourcePackForIFN(const FString &sourc OpenMessageBox(EAppMsgType::Ok, text, title); SaveConfig(); // Force save - return true; } else { @@ -495,15 +548,16 @@ bool UPopcornFXSettingsEditor::AskForAValidSourcePackForIFN(const FString &sourc UE_LOG(LogPopcornFXEditorSettings, Error, TEXT("Source PopcornFX Project NOT found: '%s'"), *ImportSourcePack); const FText title = LOCTEXT("PopcornFXSourcePackNOTFoundTitle", "PopcornFX: Invalid Source PopcornFX Project path"); const FText msg = LOCTEXT( "PopcornFXSourcePackNOTFoundTitleMsg", - "Invalid Source PopcornFX Project path, and could automaticaly find one.\n\ - Please setup:\n\ - \n\ - Project Settings > PopcornFX > Source PopcornFX Project path\n\ - \n\ - Continue anyway ?\n"); + "Invalid Source PopcornFX Project path, and could not automatically find one.\n" + "Please setup:\n" + "\n" + "Project Settings > PopcornFX > Source PopcornFX Project path\n" + "\n" + "Continue anyway ?\n"); return OpenMessageBox(EAppMsgType::YesNo, msg, title) == EAppReturnType::Yes; } - return false; + + return isValid; } //---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/PopcornFXSettingsEditor.h b/Source/PopcornFX/Private/PopcornFXSettingsEditor.h index dab3c6b..fb460c2 100644 --- a/Source/PopcornFX/Private/PopcornFXSettingsEditor.h +++ b/Source/PopcornFX/Private/PopcornFXSettingsEditor.h @@ -78,22 +78,32 @@ class UPopcornFXSettingsEditor : public UObject UPROPERTY(Config, VisibleAnywhere, Category="SourcePack", DisplayName="Resolved Project File path") FString SourcePackProjectFile; + FString AbsSourcePackProjectFile; + /** Plugin internal: resolved root dir */ UPROPERTY(Config, VisibleAnywhere, Category="SourcePack", DisplayName="Resolved Root directory") FString SourcePackRootDir; + FString AbsSourcePackRootDir; + /** Plugin internal: resolved library dir */ UPROPERTY(Config, VisibleAnywhere, Category="SourcePack", DisplayName="Resolved Root directory") FString SourcePackLibraryDir; + FString AbsSourcePackLibraryDir; + /** Plugin internal: resolved thumbnails dir */ UPROPERTY(Config, VisibleAnywhere, Category="SourcePack", DisplayName="Resolved Thumbnails directory") FString SourcePackThumbnailsDir; + FString AbsSourcePackThumbnailsDir; + /** Plugin internal: resolved cache dir */ UPROPERTY(Config, VisibleAnywhere, Category="SourcePack", DisplayName="Resolved Cache directory") FString SourcePackCacheDir; + FString AbsSourcePackCacheDir; + /** Enables auto reimport/mirroring of Source PopcornFX Project assets. @@ -139,6 +149,9 @@ class UPopcornFXSettingsEditor : public UObject /** Check this to restart effects when their attributes are modified via the details panel (useful when tweaking attributes for infinite particles) */ UPROPERTY(Config, EditAnywhere, Category="Debug") uint32 bRestartEmitterWhenAttributesChanged : 1; + +private: + virtual void PostInitProperties() override; #endif // WITH_EDITORONLY_DATA #if WITH_EDITOR @@ -146,13 +159,10 @@ class UPopcornFXSettingsEditor : public UObject void UpdateSourcePack(); //bool ResolveSourcePackFromFilePathIFP(const FString &inFilePath); - bool ValidSourcePack() const { return !SourcePackRootDir.IsEmpty() && bSourcePackFound != 0; } + bool ValidSourcePack() const { return !AbsSourcePackRootDir.IsEmpty() && bSourcePackFound != 0; } bool AskForAValidSourcePackForIFN(const FString &sourceAssetPath); - static FString FixAndAppendPopcornFXProjectFileName(const FString &path); - private: - virtual void PostLoad() override; virtual void PreEditChange(FProperty *propertyAboutToChange) override; virtual void PostEditChangeProperty(struct FPropertyChangedEvent& propertyChangedEvent) override; diff --git a/Source/PopcornFX/Private/Render/AudioPools.cpp b/Source/PopcornFX/Private/Render/AudioPools.cpp index 1b901e9..36ab06e 100644 --- a/Source/PopcornFX/Private/Render/AudioPools.cpp +++ b/Source/PopcornFX/Private/Render/AudioPools.cpp @@ -257,7 +257,7 @@ bool CSoundDescriptorPool::Setup(CSoundDescriptorPoolCollection *poolCollection, const PopcornFX::SRendererFeaturePropertyValue *soundProperty = rendererData->m_Declaration.FindProperty(PopcornFX::BasicRendererProperties::SID_Sound_SoundData()); if (soundProperty == null || soundProperty->ValuePath().Empty()) return false; - m_SoundPath = FPopcornFXPlugin::Get().BuildPathFromPkPath(soundProperty->ValuePath().Data(), true); + m_SoundPath = FPopcornFXPlugin::Get().BuildPathFromPkPath(soundProperty->ValuePath(), true); if (GetOrLoadSound() == null) return false; diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.cpp b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.cpp index f0d4aa5..239a752 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.cpp +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.cpp @@ -185,6 +185,9 @@ bool CBatchDrawer_Billboard_CPUBB::_IsAdditionalInputSupported(const PopcornFX:: { if (fieldName == PopcornFX::BasicRendererProperties::SID_Emissive_EmissiveColor()) outStreamOffsetType = StreamOffset_EmissiveColors; + + if (fieldName == PopcornFX::BasicRendererProperties::SID_ComputeVelocity_PreviousPosition()) + outStreamOffsetType = StreamOffset_PreviousPosition; } else if (type == PopcornFX::BaseType_Float) { @@ -586,10 +589,14 @@ void CBatchDrawer_Billboard_CPUBB::_IssueDrawCall_Billboard(const SUERenderConte bool outputVelocity; sceneProxy->GetScene().GetPrimitiveUniformShaderParameters_RenderThread(sceneProxy->GetPrimitiveSceneInfo(), hasPrecomputedVolumetricLightmap, previousLocalToWorld, singleCaptureIndex, outputVelocity); + outputVelocity |= sceneProxy->AlwaysHasVelocity(); FMatrix localToWorld = FMatrix::Identity; if (view->GlobalScale() != 1.0f) + { localToWorld *= view->GlobalScale(); + previousLocalToWorld *= view->GlobalScale(); + } CRendererCache *matCache = static_cast(desc.m_RendererCaches.First().Get()); if (!PK_VERIFY(matCache != null)) @@ -664,6 +671,7 @@ void CBatchDrawer_Billboard_CPUBB::_IssueDrawCall_Billboard(const SUERenderConte vsUniformsBillboard.TotalParticleCount = desc.m_TotalParticleCount; vsUniformsBillboard.CapsulesOffset = m_CapsulesOffset; vsUniformsBillboard.InColorsOffset = m_AdditionalStreamOffsets[StreamOffset_Colors].OffsetForShaderConstant(); + vsUniformsBillboard.InPreviousPositionOffset = m_AdditionalStreamOffsets[StreamOffset_PreviousPosition].OffsetForShaderConstant(); vsUniformsBillboard.InEmissiveColorsOffset = m_AdditionalStreamOffsets[StreamOffset_EmissiveColors].OffsetForShaderConstant(); vsUniformsBillboard.InAlphaCursorsOffset = m_AdditionalStreamOffsets[StreamOffset_AlphaCursors].OffsetForShaderConstant(); vsUniformsBillboard.InDynamicParameter1sOffset = m_AdditionalStreamOffsets[StreamOffset_DynParam1s].OffsetForShaderConstant(); diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.h b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.h index 5c10503..c0f141b 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.h +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_CPU.h @@ -23,6 +23,7 @@ class CBatchDrawer_Billboard_CPUBB : public PopcornFX::CRendererBatchJobs_Billbo { StreamOffset_Colors = 0, StreamOffset_EmissiveColors, + StreamOffset_PreviousPosition, StreamOffset_AlphaCursors, StreamOffset_DynParam1s, StreamOffset_DynParam2s, diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.cpp b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.cpp index c21b367..cc0e3e6 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.cpp +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.cpp @@ -540,6 +540,8 @@ bool CBatchDrawer_Billboard_GPUBB::_IsAdditionalInputSupported(const PopcornFX:: { if (fieldName == PopcornFX::BasicRendererProperties::SID_Emissive_EmissiveColor()) outStreamOffsetType = StreamOffset_EmissiveColors; + if (fieldName == PopcornFX::BasicRendererProperties::SID_ComputeVelocity_PreviousPosition()) + outStreamOffsetType = StreamOffset_PreviousPosition; } else if (type == PopcornFX::BaseType_Float) { @@ -1084,7 +1086,10 @@ bool CBatchDrawer_Billboard_GPUBB::_FillDrawCallUniforms_GPU(u32 drId, return false; if ((m_ViewIndependentInputs & PopcornFX::Drawers::GenInput_ParticlePosition) != 0) + { m_StreamOffsets[StreamOffset_Positions] = stream->StreamOffset(br.m_PositionStreamId); + m_StreamOffsets[StreamOffset_Enabled] = stream->StreamOffset(br.m_EnabledStreamId); + } if ((m_ViewIndependentInputs & PopcornFX::Drawers::GenInput_ParticleSize) != 0) m_StreamOffsets[StreamOffset_Sizes] = stream->StreamOffset(br.m_SizeStreamId); else if ((m_ViewIndependentInputs & PopcornFX::Drawers::GenInput_ParticleSize2) != 0) @@ -1222,6 +1227,7 @@ void CBatchDrawer_Billboard_GPUBB::_IssueDrawCall_Billboard(const SUERenderConte vsUniformsGPUBillboard.CapsulesDC = m_CapsulesDC ? 1 : 0; vsUniformsGPUBillboard.HasSecondUVSet = m_HasAtlasBlending ? 1 : 0; vsUniformsGPUBillboard.InPositionsOffset = m_StreamOffsets[StreamOffset_Positions].Valid() ? static_cast(m_StreamOffsets[StreamOffset_Positions] / sizeof(float)) : -1; + vsUniformsGPUBillboard.InEnabledOffset = m_StreamOffsets[StreamOffset_Enabled].Valid() ? static_cast(m_StreamOffsets[StreamOffset_Enabled] / sizeof(float)) : -1; vsUniformsGPUBillboard.InSizesOffset = m_StreamOffsets[StreamOffset_Sizes].Valid() ? static_cast(m_StreamOffsets[StreamOffset_Sizes] / sizeof(float)) : -1; vsUniformsGPUBillboard.InSize2sOffset = m_StreamOffsets[StreamOffset_Size2s].Valid() ? static_cast(m_StreamOffsets[StreamOffset_Size2s] / sizeof(float)) : -1; vsUniformsGPUBillboard.InRotationsOffset = m_StreamOffsets[StreamOffset_Rotations].Valid() ? static_cast(m_StreamOffsets[StreamOffset_Rotations] / sizeof(float)) : -1; @@ -1229,6 +1235,7 @@ void CBatchDrawer_Billboard_GPUBB::_IssueDrawCall_Billboard(const SUERenderConte vsUniformsGPUBillboard.InAxis1sOffset = m_StreamOffsets[StreamOffset_Axis1s].Valid() ? static_cast(m_StreamOffsets[StreamOffset_Axis1s] / sizeof(float)) : -1; vsUniformsGPUBillboard.InTextureIDsOffset = m_AdditionalStreamOffsets[StreamOffset_TextureIDs].Valid() ? static_cast(m_AdditionalStreamOffsets[StreamOffset_TextureIDs] / sizeof(float)) : -1; vsUniformsGPUBillboard.InColorsOffset = m_AdditionalStreamOffsets[StreamOffset_Colors].Valid() ? static_cast(m_AdditionalStreamOffsets[StreamOffset_Colors] / sizeof(float)) : -1; + vsUniformsGPUBillboard.InPreviousPositionOffset = m_AdditionalStreamOffsets[StreamOffset_PreviousPosition].Valid() ? static_cast(m_AdditionalStreamOffsets[StreamOffset_PreviousPosition] / sizeof(float)) : -1; vsUniformsGPUBillboard.InEmissiveColorsOffset = m_AdditionalStreamOffsets[StreamOffset_EmissiveColors].Valid() ? static_cast(m_AdditionalStreamOffsets[StreamOffset_EmissiveColors] / sizeof(float)) : -1; vsUniformsGPUBillboard.InAlphaCursorsOffset = m_AdditionalStreamOffsets[StreamOffset_AlphaCursors].Valid() ? static_cast(m_AdditionalStreamOffsets[StreamOffset_AlphaCursors] / sizeof(float)) : -1; vsUniformsGPUBillboard.InDynamicParameter1sOffset = m_AdditionalStreamOffsets[StreamOffset_DynParam1s].Valid() ? static_cast(m_AdditionalStreamOffsets[StreamOffset_DynParam1s] / sizeof(float)) : -1; diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.h b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.h index 75803d0..2a75186 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.h +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Billboard_GPU.h @@ -112,6 +112,7 @@ class CBatchDrawer_Billboard_GPUBB : public PopcornFX::CRendererBatchJobs_Billbo enum EPopcornFXStreamOffsets { StreamOffset_Positions = 0, + StreamOffset_Enabled, StreamOffset_Sizes, StreamOffset_Size2s, StreamOffset_Rotations, @@ -124,6 +125,7 @@ class CBatchDrawer_Billboard_GPUBB : public PopcornFX::CRendererBatchJobs_Billbo { StreamOffset_Colors = 0, StreamOffset_EmissiveColors, + StreamOffset_PreviousPosition, StreamOffset_TextureIDs, StreamOffset_AlphaCursors, StreamOffset_DynParam1s, diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp index 942f9bd..3db462d 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.cpp @@ -197,6 +197,8 @@ bool CBatchDrawer_Ribbon_CPUBB::_IsAdditionalInputSupported(const PopcornFX::CSt { if (fieldName == PopcornFX::BasicRendererProperties::SID_Emissive_EmissiveColor()) outStreamOffsetType = StreamOffset_EmissiveColors; + if (fieldName == PopcornFX::BasicRendererProperties::SID_ComputeVelocity_PreviousPosition()) + outStreamOffsetType = StreamOffset_PreviousPosition; } else if (type == PopcornFX::BaseType_Float) { @@ -627,10 +629,14 @@ void CBatchDrawer_Ribbon_CPUBB::_IssueDrawCall_Ribbon(const SUERenderContext &re bool outputVelocity; sceneProxy->GetScene().GetPrimitiveUniformShaderParameters_RenderThread(sceneProxy->GetPrimitiveSceneInfo(), hasPrecomputedVolumetricLightmap, previousLocalToWorld, singleCaptureIndex, outputVelocity); + outputVelocity |= sceneProxy->AlwaysHasVelocity(); FMatrix localToWorld = FMatrix::Identity; if (view->GlobalScale() != 1.0f) + { localToWorld *= view->GlobalScale(); + previousLocalToWorld *= view->GlobalScale(); + } CRendererCache *matCache = static_cast(desc.m_RendererCaches.First().Get()); if (!PK_VERIFY(matCache != null)) @@ -710,6 +716,7 @@ void CBatchDrawer_Ribbon_CPUBB::_IssueDrawCall_Ribbon(const SUERenderContext &re vsUniformsbillboard.VPP = m_VPP; vsUniformsbillboard.InColorsOffset = m_AdditionalStreamOffsets[StreamOffset_Colors].OffsetForShaderConstant(); vsUniformsbillboard.InEmissiveColorsOffset = m_AdditionalStreamOffsets[StreamOffset_EmissiveColors].OffsetForShaderConstant(); + vsUniformsbillboard.InPreviousPositionOffset = m_AdditionalStreamOffsets[StreamOffset_PreviousPosition].OffsetForShaderConstant(); vsUniformsbillboard.InAlphaCursorsOffset = m_AdditionalStreamOffsets[StreamOffset_AlphaCursors].OffsetForShaderConstant(); vsUniformsbillboard.InDynamicParameter1sOffset = m_AdditionalStreamOffsets[StreamOffset_DynParam1s].OffsetForShaderConstant(); vsUniformsbillboard.InDynamicParameter2sOffset = m_AdditionalStreamOffsets[StreamOffset_DynParam2s].OffsetForShaderConstant(); diff --git a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h index 1ef1c5a..cedbcf2 100644 --- a/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h +++ b/Source/PopcornFX/Private/Render/BatchDrawer_Ribbon_CPU.h @@ -23,6 +23,7 @@ class CBatchDrawer_Ribbon_CPUBB : public PopcornFX::CRendererBatchJobs_Ribbon_CP { StreamOffset_Colors = 0, StreamOffset_EmissiveColors, + StreamOffset_PreviousPosition, StreamOffset_AlphaCursors, StreamOffset_DynParam1s, StreamOffset_DynParam2s, diff --git a/Source/PopcornFX/Private/Render/PopcornFXGPUVertexFactory.h b/Source/PopcornFX/Private/Render/PopcornFXGPUVertexFactory.h index b9a80b6..359bfba 100644 --- a/Source/PopcornFX/Private/Render/PopcornFXGPUVertexFactory.h +++ b/Source/PopcornFX/Private/Render/PopcornFXGPUVertexFactory.h @@ -24,6 +24,7 @@ BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FPopcornFXGPUBillboardVSUniforms, POPCORNFX SHADER_PARAMETER(int32, CapsulesDC) SHADER_PARAMETER(int32, HasSecondUVSet) SHADER_PARAMETER(int32, InPositionsOffset) + SHADER_PARAMETER(int32, InEnabledOffset) SHADER_PARAMETER(int32, InSizesOffset) SHADER_PARAMETER(int32, InSize2sOffset) SHADER_PARAMETER(int32, InRotationsOffset) @@ -32,6 +33,7 @@ BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FPopcornFXGPUBillboardVSUniforms, POPCORNFX SHADER_PARAMETER(int32, InTextureIDsOffset) SHADER_PARAMETER(int32, InColorsOffset) SHADER_PARAMETER(int32, InEmissiveColorsOffset) + SHADER_PARAMETER(int32, InPreviousPositionOffset) SHADER_PARAMETER(int32, InAlphaCursorsOffset) SHADER_PARAMETER(int32, InDynamicParameter1sOffset) SHADER_PARAMETER(int32, InDynamicParameter2sOffset) diff --git a/Source/PopcornFX/Private/Render/PopcornFXMeshVertexFactory.h b/Source/PopcornFX/Private/Render/PopcornFXMeshVertexFactory.h index 6f660d2..d3f13bf 100644 --- a/Source/PopcornFX/Private/Render/PopcornFXMeshVertexFactory.h +++ b/Source/PopcornFX/Private/Render/PopcornFXMeshVertexFactory.h @@ -21,6 +21,7 @@ BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FPopcornFXMeshVSUniforms, POPCORNFX_API) SHADER_PARAMETER(int32, InColorsOffset) SHADER_PARAMETER(int32, InEmissiveColorsOffset) SHADER_PARAMETER(int32, InAlphaCursorsOffset) + SHADER_PARAMETER(int32, InPreviousPositionOffset) SHADER_PARAMETER(int32, InTextureIDsOffset) SHADER_PARAMETER(int32, InVATCursorsOffset) SHADER_PARAMETER(int32, InDynamicParameter0sOffset) diff --git a/Source/PopcornFX/Private/Render/PopcornFXVertexFactory.h b/Source/PopcornFX/Private/Render/PopcornFXVertexFactory.h index 9206e8b..e0c619b 100644 --- a/Source/PopcornFX/Private/Render/PopcornFXVertexFactory.h +++ b/Source/PopcornFX/Private/Render/PopcornFXVertexFactory.h @@ -31,6 +31,7 @@ BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FPopcornFXBillboardVSUniforms, POPCORNFX_AP //SHADER_PARAMETER(int, InTextureIDsOffset) SHADER_PARAMETER(int32, InColorsOffset) SHADER_PARAMETER(int32, InEmissiveColorsOffset) + SHADER_PARAMETER(int32, InPreviousPositionOffset) SHADER_PARAMETER(int32, InAlphaCursorsOffset) SHADER_PARAMETER(int32, InDynamicParameter1sOffset) SHADER_PARAMETER(int32, InDynamicParameter2sOffset) diff --git a/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp b/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp index 6a5d879..39def44 100644 --- a/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp +++ b/Source/PopcornFX/Private/World/PopcornFXEmitterComponent.cpp @@ -32,6 +32,7 @@ #include #include +#include #include //---------------------------------------------------------------------------- @@ -363,9 +364,7 @@ void UPopcornFXEmitterComponent::CheckForErrors() if (filever.Empty()) filever = PopcornFX::SEngineVersion(1, 7, 3, 0); // bo file version did not exists - bool outOfDate = filever.Major() < current.Major(); - if (!outOfDate && filever.Minor() < current.Minor()) - outOfDate = true; + const bool outOfDate = filever.Lower_IgnorePatch(current); if (outOfDate) { FFormatNamedArguments Arguments; @@ -997,7 +996,7 @@ bool UPopcornFXEmitterComponent::RegisterEventListener(FPopcornFXRaiseEventSigna UE_LOG(LogPopcornFXEmitterComponent, Warning, TEXT("Register Event Listener: Empty EventName")); return false; } - const PopcornFX::CStringId eventNameId = PopcornFX::CStringId(TCHAR_TO_ANSI(*EventName.ToString())); + const PopcornFX::CStringId eventNameId = PopcornFX::CStringId(ToPk(EventName.ToString())); PK_ASSERT(!eventNameId.Empty()); if (!Delegate.IsBound()) @@ -1020,7 +1019,7 @@ void UPopcornFXEmitterComponent::UnregisterEventListener(FPopcornFXRaiseEventSig if (!PK_VERIFY(m_CurrentScene != null)) return; - const PopcornFX::CStringId eventNameId = PopcornFX::CStringId(TCHAR_TO_ANSI(*EventName.ToString())); + const PopcornFX::CStringId eventNameId = PopcornFX::CStringId(ToPk(EventName.ToString())); if (eventNameId.Empty()) { UE_LOG(LogPopcornFXEmitterComponent, Warning, TEXT("Unregister Event Listener: Empty EventName")); @@ -1139,6 +1138,9 @@ void UPopcornFXEmitterComponent::ApplyWorldOffset(const FVector &inOffset, bool void UPopcornFXEmitterComponent::Scene_PreUpdate(CParticleScene *scene, float deltaTime) { + using namespace PopcornFX; + PK_CALL_CONTEXT("Emitter", PopcornFX::CStringView(Effect->Effect()->ParticleEffectIFP()->File()->Path())); + PK_SCOPEDPROFILE(); LLM_SCOPE(ELLMTag::Particles); PK_ASSERT(!IsTemplate()); @@ -1244,6 +1246,14 @@ void UPopcornFXEmitterComponent::Scene_PostUpdate(CParticleScene *scene, float d { // Destroy component if instance was destroyed during update CheckForDead(); + +#if WITH_EDITOR + // This will be called after the update has been complete. + // Post-update the attributes if we have some: Needed to reset pulsed bool attributes + UPopcornFXAttributeList *attributeList = GetAttributeListIFP(); + if (attributeList != null && IsValid(attributeList)) + attributeList->ResetPulsedBoolAttributesIFN(); +#endif // WITH_EDITOR } //---------------------------------------------------------------------------- diff --git a/Source/PopcornFX/Private/World/PopcornFXSceneProxy.cpp b/Source/PopcornFX/Private/World/PopcornFXSceneProxy.cpp index c32ab37..2fb5929 100644 --- a/Source/PopcornFX/Private/World/PopcornFXSceneProxy.cpp +++ b/Source/PopcornFX/Private/World/PopcornFXSceneProxy.cpp @@ -23,9 +23,7 @@ FPopcornFXSceneProxy::FPopcornFXSceneProxy(UPopcornFXSceneComponent *component) bVerifyUsedMaterials = true; #if (ENGINE_MAJOR_VERSION == 5) -#if 0 bAlwaysHasVelocity = true; -#endif #endif // (ENGINE_MAJOR_VERSION == 5) } @@ -162,7 +160,7 @@ FPrimitiveViewRelevance FPopcornFXSceneProxy::GetViewRelevance(const FSceneView* viewRelevance.bHasVolumeMaterialDomain = true; viewRelevance.bTranslucentSelfShadow = true; - viewRelevance.bVelocityRelevance = DrawsVelocity(); + viewRelevance.bVelocityRelevance = true; return viewRelevance; } diff --git a/Source/PopcornFX/Public/Assets/PopcornFXEffect.h b/Source/PopcornFX/Public/Assets/PopcornFXEffect.h index d193cf2..f236847 100644 --- a/Source/PopcornFX/Public/Assets/PopcornFXEffect.h +++ b/Source/PopcornFX/Public/Assets/PopcornFXEffect.h @@ -61,7 +61,7 @@ class UPopcornFXEffect : public UPopcornFXFile private: void ClearEffect(); - bool LoadEffect(); + bool LoadEffect(bool forceImport = false); protected: #if WITH_EDITOR diff --git a/Source/PopcornFX/Public/PopcornFXAttributeList.h b/Source/PopcornFX/Public/PopcornFXAttributeList.h index 00bb1e0..48a59bf 100644 --- a/Source/PopcornFX/Public/PopcornFXAttributeList.h +++ b/Source/PopcornFX/Public/PopcornFXAttributeList.h @@ -259,6 +259,10 @@ class UPopcornFXAttributeList : public UObject template void SetAttributeDim(uint32 attributeId, uint32 dim, _Scalar value, bool fromUI = false); template _Scalar GetAttributeDim(uint32 attributeId, uint32 dim); + + void PulseBoolAttributeDim(uint32 attributeId, uint32 dim, bool fromUI = false); + + void ResetPulsedBoolAttributesIFN(); #endif // WITH_EDITOR uint32 FileVersionId() const { return m_FileVersionId; } @@ -310,6 +314,10 @@ class UPopcornFXAttributeList : public UObject bool m_RestartEmitter = false; // UPopcornFXSettingsEditor::bRestartEmitterWhenAttributesChanged #endif // WITH_EDITORONLY_DATA +#if WITH_EDITOR + bool m_HasPendingOneShotReset = false; +#endif // WITH_EDITOR + public: UPROPERTY(Category="PopcornFX Attributes", EditAnywhere, BlueprintReadOnly, EditFixedSize) TArray m_AttributesRawData; diff --git a/Source/PopcornFX/Public/PopcornFXAttributeSampler.h b/Source/PopcornFX/Public/PopcornFXAttributeSampler.h index eb2986e..d20de29 100644 --- a/Source/PopcornFX/Public/PopcornFXAttributeSampler.h +++ b/Source/PopcornFX/Public/PopcornFXAttributeSampler.h @@ -31,6 +31,7 @@ namespace EPopcornFXAttributeSamplerComponentType Shape, SkinnedMesh, Image, + Grid, Curve, AnimTrack, Turbulence, @@ -46,6 +47,7 @@ namespace EPopcornFXAttributeSamplerType None = 0, Shape, Image, + Grid, Curve, AnimTrack, Turbulence, diff --git a/Source/PopcornFX/Public/PopcornFXAttributeSamplerActor.h b/Source/PopcornFX/Public/PopcornFXAttributeSamplerActor.h index a545168..0405a17 100644 --- a/Source/PopcornFX/Public/PopcornFXAttributeSamplerActor.h +++ b/Source/PopcornFX/Public/PopcornFXAttributeSamplerActor.h @@ -45,7 +45,7 @@ class POPCORNFX_API APopcornFXAttributeSamplerActor : public AActor void ReloadSprite(); EPopcornFXAttributeSamplerComponentType::Type m_SamplerComponentType; - bool m_IsValidSpecializedActor = false; + bool m_IsValidSpecializedActor = false; }; /** Can override an Attribute Sampler **Shape** by a **UStaticMesh**. */ @@ -57,6 +57,9 @@ UCLASS() class POPCORNFX_API APopcornFXAttributeSamplerSkinnedMeshActor : public /** Can override an Attribute Sampler **Image** by a **UTexture**. */ UCLASS() class POPCORNFX_API APopcornFXAttributeSamplerImageActor : public APopcornFXAttributeSamplerActor { GENERATED_UCLASS_BODY() }; +/** Can override an Attribute Sampler **Grid** by a **UTexture**. */ +UCLASS() class POPCORNFX_API APopcornFXAttributeSamplerGridActor : public APopcornFXAttributeSamplerActor { GENERATED_UCLASS_BODY() }; + /** Can override an Attribute Sampler **Curve** by a **UCurve...**. */ UCLASS() class POPCORNFX_API APopcornFXAttributeSamplerCurveActor : public APopcornFXAttributeSamplerActor { GENERATED_UCLASS_BODY() }; diff --git a/Source/PopcornFX/Public/PopcornFXAttributeSamplerGrid.h b/Source/PopcornFX/Public/PopcornFXAttributeSamplerGrid.h new file mode 100644 index 0000000..c7ef387 --- /dev/null +++ b/Source/PopcornFX/Public/PopcornFXAttributeSamplerGrid.h @@ -0,0 +1,102 @@ +//---------------------------------------------------------------------------- +// Copyright Persistant Studios, SARL. All Rights Reserved. +// https://www.popcornfx.com/terms-and-conditions/ +//---------------------------------------------------------------------------- + +#pragma once + +#include "PopcornFXPublic.h" + +#include "PopcornFXTypes.h" +#include "PopcornFXAttributeSampler.h" + +#include "PopcornFXAttributeSamplerGrid.generated.h" + +FWD_PK_API_BEGIN +class CParticleSamplerDescriptor_Grid; +FWD_PK_API_END +// Statement to help the UE Header Parser not crash on FWD_PK_API_... +class FPopcornFXPlugin; + +// this forward declaration is here to help the UE Header Parser which seems to crash because of FWD_PK_API_... +class UPopcornFXAttributeSamplerGrid; + +struct FAttributeSamplerGridData; + +UENUM(BlueprintType) +enum class EPopcornFXGridDataType : uint8 +{ + R, + RG, + RGBA +}; + +/** Can override an Attribute Sampler **Grid** by a **UTexture**. */ +UCLASS(EditInlineNew, meta=(BlueprintSpawnableComponent), ClassGroup=PopcornFX) +class POPCORNFX_API UPopcornFXAttributeSamplerGrid : public UPopcornFXAttributeSampler +{ + GENERATED_UCLASS_BODY() + +public: + UFUNCTION(BlueprintCallable, Category="PopcornFX AttributeSampler") + void SetRenderTarget(class UTextureRenderTarget *InRenderTarget); + + UFUNCTION(BlueprintCallable, Category="PopcornFX AttributeSampler", meta=(UnsafeDuringActorConstruction="true")) + void SetAsMaterialTextureParameter(UMaterialInstanceDynamic *Material, FName ParameterName); + + /** If true, this grid attribute sampler is setup from a 2D or Volume render target asset instead of being setup through SizeX, SizeY, SizeZ & DataType. */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler") + uint32 bAssetGrid : 1; + + /** + If true, render target has its sRGB flag force enabled (or disabled if false). + Enable this if writes into the grid in the source effect(s) are not linear. + */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler") + uint32 bSRGB : 1; + + /** + 2D or Volume Render target asset used by the grid attribute sampler. + Note: this is only supported by GPU simulated particles (binding this sampler on an effect with CPU simulated particles will fallback to sampling the default resource defined in the effect). + */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler") + class UTextureRenderTarget *RenderTarget; + + /** Grid Dimensions (Width) */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler", meta=(ClampMin="1", ClampMax="4096")) + int32 SizeX; + + /** Grid Dimensions (Height) */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler", meta=(ClampMin="1", ClampMax="4096")) + int32 SizeY; + + /** Grid Dimensions (Depth) */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler", meta=(ClampMin="1", ClampMax="4096")) + int32 SizeZ; + + /** Grid Data Type */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="PopcornFX AttributeSampler") + EPopcornFXGridDataType DataType; + + // overrides + void OnUnregister() override; + void BeginDestroy() override; + + class UTexture *GridTexture(); + +#if WITH_EDITOR + void PostEditChangeProperty(FPropertyChangedEvent& propertyChangedEvent) override; +#endif // WITH_EDITOR + + // PopcornFX Internal + virtual PopcornFX::CParticleSamplerDescriptor *_AttribSampler_SetupSamplerDescriptor(FPopcornFXSamplerDesc &desc, const PopcornFX::CResourceDescriptor *defaultSampler) override; + +private: + bool RebuildGridSampler(); + bool _RebuildGridSampler(); + + UPROPERTY(Transient) + UTexture *m_GridTexture; + + FAttributeSamplerGridData *m_Data; +}; diff --git a/Source/PopcornFX/Public/PopcornFXEmitterComponent.h b/Source/PopcornFX/Public/PopcornFXEmitterComponent.h index 76e1d02..948f3ad 100644 --- a/Source/PopcornFX/Public/PopcornFXEmitterComponent.h +++ b/Source/PopcornFX/Public/PopcornFXEmitterComponent.h @@ -151,7 +151,7 @@ class POPCORNFX_API UPopcornFXEmitterComponent : public USceneComponent // Stops all layers/emitters of this instance, and kills all particles spawned by this effect instance // The kill will be processed during the next medium-collection update. - UFUNCTION(BlueprintCallable, Category = "PopcornFX|Emitter", meta = (Keywords = "popcornfx particle emitter effect system kill", UnsafeDuringActorConstruction = "true")) + UFUNCTION(BlueprintCallable, Category = "PopcornFX|Emitter", meta = (Keywords="popcornfx particle emitter effect system kill", UnsafeDuringActorConstruction = "true")) void KillParticles(); /** Get whether the emitter is still emitting particles or not */ diff --git a/Source/PopcornFX/Public/PopcornFXSettings.h b/Source/PopcornFX/Public/PopcornFXSettings.h index c49169e..07f7a8a 100644 --- a/Source/PopcornFX/Public/PopcornFXSettings.h +++ b/Source/PopcornFX/Public/PopcornFXSettings.h @@ -330,6 +330,5 @@ class UPopcornFXSettings : public UObject virtual void PostEditChangeProperty(struct FPropertyChangedEvent& propertyChangedEvent) override; #endif - void UpdateSourcePack(); UMaterialInterface *GetConfigDefaultMaterial(uint32 ePopcornFXMaterialType) const; }; diff --git a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h index 007c734..9858d7c 100644 --- a/Source/PopcornFX/Public/PopcornFXVersionGenerated.h +++ b/Source/PopcornFX/Public/PopcornFXVersionGenerated.h @@ -6,6 +6,6 @@ #pragma once #define POPCORNFX_PLUGIN_VERSION_MAJOR 2 -#define POPCORNFX_PLUGIN_VERSION_MINOR 18 -#define POPCORNFX_PLUGIN_VERSION_PATCH 6 +#define POPCORNFX_PLUGIN_VERSION_MINOR 19 +#define POPCORNFX_PLUGIN_VERSION_PATCH 0 #define POPCORNFX_PLUGIN_VERSION_TAG ""