77#include " RHIResources.h"
88#include " TextureResource.h"
99#include " Engine/Texture2D.h"
10+ #include " Engine/World.h"
11+ #include " Kismet/KismetRenderingLibrary.h"
12+ #include " Materials/MaterialInterface.h"
1013
1114// Virtual destructor, unregister data
1215SCustomShapeButton::~SCustomShapeButton ()
1316{
1417 RawColorsPtr.Reset ();
18+
19+ if (IsValid (RenderTarget.Get ()))
20+ {
21+ RenderTarget->ConditionalBeginDestroy ();
22+ RenderTarget.Reset ();
23+ }
1524}
1625
1726/* * Allows button to be hovered. */
@@ -35,6 +44,34 @@ void SCustomShapeButton::SetCanHover(bool bAllow)
3544 TryDetectOnHovered ();
3645}
3746
47+ // Updates the internal texture size
48+ void SCustomShapeButton::SetTextureSize (const FIntPoint& InSize)
49+ {
50+ if (!ensureMsgf (InSize.X > 0 && InSize.Y > 0 , TEXT (" ASSERT: [%i] %hs:\n Texture Size is not valid!" ), __LINE__, __FUNCTION__)
51+ || TextureRes == InSize)
52+ {
53+ // Is already set
54+ return ;
55+ }
56+
57+ TextureRes = InSize;
58+
59+ if (!RawColorsPtr)
60+ {
61+ RawColorsPtr = MakeShared<TArray<FColor>, ESPMode::ThreadSafe>();
62+ }
63+ }
64+
65+ // Forces to update the Raw Colors (pixels data) about current image
66+ void SCustomShapeButton::ForceUpdateImage ()
67+ {
68+ if (RawColorsPtr)
69+ {
70+ RawColorsPtr->Empty ();
71+ TryUpdateRawColorsOnce ();
72+ }
73+ }
74+
3875FReply SCustomShapeButton::OnMouseButtonDown (const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
3976{
4077 UpdateMouseData (MyGeometry, MouseEvent);
@@ -118,8 +155,7 @@ bool SCustomShapeButton::IsAlphaPixelHovered() const
118155 }
119156
120157 const TArray<FColor>* RawColors = RawColorsPtr.Get ();
121- if (!RawColors
122- || !RawColors->Num ())
158+ if (!RawColors)
123159 {
124160 // Raw Colors are not set
125161 return false ;
@@ -139,65 +175,98 @@ bool SCustomShapeButton::IsAlphaPixelHovered() const
139175 return false ;
140176 }
141177
142- constexpr int32 Alpha = 1 ;
143- const bool bIsAlphaPixelHovered = RawColorsArray[BufferPosition].A > Alpha;
144- return bIsAlphaPixelHovered;
178+ const uint8 HoveredPixel = RawColorsArray[BufferPosition].A ;
179+ const uint8 HoveredPixelNormalized = HoveredPixel > 0 ? 1 : 0 ;
180+
181+ constexpr uint8 TextureAlpha = 1 ;
182+ constexpr uint8 MaterialAlpha = 0 ;
183+
184+ return HoveredPixelNormalized == (RenderTarget ? MaterialAlpha : TextureAlpha);
145185}
146186
147- // Set once on render thread the buffer data about all pixels of current texture if was not set before
187+ // Set once on render thread the buffer data about all pixels of current image if was not set before
148188void SCustomShapeButton::TryUpdateRawColorsOnce ()
149189{
150- if (RawColorsPtr)
190+ if (RawColorsPtr && !RawColorsPtr-> IsEmpty () )
151191 {
152- // Is already valid
192+ // Buffer data was already created ( valid) AND contains pixels
153193 return ;
154194 }
155195
156196 const FSlateBrush* ImageBrush = GetBorderImage ();
157- const UTexture2D* ButtonTexture = ImageBrush ? Cast<UTexture2D>( ImageBrush->GetResourceObject () ) : nullptr ;
158- if (!ensureMsgf (ButtonTexture , TEXT (" %s: 'HitTexture ' is null, most likely no texture is set in the Button Style" ), *FString (__FUNCTION__)))
197+ UObject* InImage = ImageBrush ? ImageBrush->GetResourceObject () : nullptr ;
198+ if (!ensureMsgf (InImage , TEXT (" %s: 'InImage ' is null, most likely no texture is set in the Button Style" ), *FString (__FUNCTION__)))
159199 {
160200 return ;
161201 }
162202
163- TextureRes = FIntPoint (ButtonTexture->GetSizeX (), ButtonTexture->GetSizeY ());
203+ if (const UTexture2D* Texture = Cast<UTexture2D>(InImage))
204+ {
205+ UpdateRawColors_Texture (*Texture);
206+ }
207+ else if (UMaterialInterface* Material = Cast<UMaterialInterface>(InImage))
208+ {
209+ UpdateRawColors_Material (*Material);
210+ }
211+ else
212+ {
213+ ensureMsgf (false , TEXT (" ASSERT: [%i] %hs:\n 'No image' is set!" ), __LINE__, __FUNCTION__);
214+ }
215+ }
164216
165- // Create
166- RawColorsPtr = MakeShared<TArray<FColor>, ESPMode::ThreadSafe>();
167- RawColorsPtr->SetNum (TextureRes.X * TextureRes.Y );
217+ // Copies the buffer data from the texture
218+ void SCustomShapeButton::UpdateRawColors_Texture (const UTexture2D& Texture)
219+ {
220+ SetTextureSize (FIntPoint (Texture.GetSizeX (), Texture.GetSizeY ()));
168221
169222 // Get Raw Colors data on Render thread
170- const TWeakPtr<TArray<FColor>, ESPMode::ThreadSafe> InOutRawColorsWeakPtr = RawColorsPtr;
171- const TWeakObjectPtr<const UTexture2D> WeakTexture = ButtonTexture;
172- ENQUEUE_RENDER_COMMAND (TryUpdateRawColorsOnce)([InOutRawColorsWeakPtr, WeakTexture](FRHICommandListImmediate&)
223+ const TWeakPtr<TArray<FColor>> InOutRawColorsWeakPtr = RawColorsPtr;
224+ const TWeakObjectPtr<const UTexture2D> WeakTexture = &Texture;
225+ const FIntRect TextureSize (0 , 0 , TextureRes.X , TextureRes.Y );
226+ ENQUEUE_RENDER_COMMAND (TryUpdateRawColorsOnce)([InOutRawColorsWeakPtr, WeakTexture, TextureSize](FRHICommandListImmediate& RHICmdList)
173227 {
174228 TArray<FColor>* RawColors = InOutRawColorsWeakPtr.Pin ().Get ();
175- if (!ensureMsgf (RawColors, TEXT (" %s : 'RawColors' is null, can not obtain its data" ), * FString ( __FUNCTION__) ))
229+ if (!ensureMsgf (RawColors, TEXT (" %hs : 'RawColors' is null, can not obtain its data" ), __FUNCTION__))
176230 {
177231 return ;
178232 }
179233
180234 const UTexture2D* Texture2D = WeakTexture.Get ();
181235 const FTextureResource* TextureResource = Texture2D ? Texture2D->GetResource () : nullptr ;
182236 FRHITexture2D* RHITexture2D = TextureResource ? TextureResource->GetTexture2DRHI () : nullptr ;
183- if (! ensureMsgf (RHITexture2D, TEXT (" %s : 'RHITexture2D' is not valid" ), * FString ( __FUNCTION__) ))
237+ if (ensureMsgf (RHITexture2D, TEXT (" %hs : 'RHITexture2D' is not valid" ), __FUNCTION__))
184238 {
185- return ;
239+ // Copy data to cache
240+ RHICmdList.ReadSurfaceData (RHITexture2D, TextureSize, /* out*/ *RawColors, FReadSurfaceDataFlags ());
186241 }
242+ });
243+ }
187244
188- // Lock
189- uint32 DestPitch = 0 ;
190- constexpr int32 MipIndex = 0 ;
191- constexpr bool bLockWithinMipTail = false ;
192- const uint8* MappedTextureMemory = static_cast <const uint8*>(RHILockTexture2D (RHITexture2D, MipIndex, RLM_ReadOnly, DestPitch, bLockWithinMipTail));
245+ // Copies the buffer data from the material
246+ void SCustomShapeButton::UpdateRawColors_Material (UMaterialInterface& Material)
247+ {
248+ checkf (GWorld, TEXT (" ERROR: [%i] %hs:\n 'GWorld' is null!" ), __LINE__, __FUNCTION__);
193249
194- // Copy data
195- const int32 Count = RawColors->Num () * sizeof (FColor);
196- FMemory::Memcpy (/* dest*/ RawColors->GetData (), /* source*/ MappedTextureMemory, Count);
250+ const FSlateBrush* Image = GetBorderImage ();
251+ checkf (Image, TEXT (" ERROR: [%i] %hs:\n 'Image' is null!" ), __LINE__, __FUNCTION__);
252+ const FVector2f ImageSize = Image->GetImageSize ();
253+ SetTextureSize (FIntPoint (ImageSize.X , ImageSize.Y ));
254+ checkf (RawColorsPtr.Get (), TEXT (" ERROR: [%i] %hs:\n 'RawColorsPtr' was not created!" ), __LINE__, __FUNCTION__);
197255
198- // Unlock
199- RHIUnlockTexture2D (RHITexture2D, MipIndex, bLockWithinMipTail);
200- });
256+ // Create new Render Target
257+ if (!RenderTarget)
258+ {
259+ RenderTarget = TStrongObjectPtr (UKismetRenderingLibrary::CreateRenderTarget2D (GWorld, TextureRes.X , TextureRes.Y ));
260+ }
261+
262+ // Clear created Render Target now before rendering material
263+ UKismetRenderingLibrary::ClearRenderTarget2D (GWorld, RenderTarget.Get ());
264+
265+ // Render our material first before copying pixels data
266+ UKismetRenderingLibrary::DrawMaterialToRenderTarget (GWorld, RenderTarget.Get (), &Material);
267+
268+ // Copy pixels data from Render Target to our cache
269+ UKismetRenderingLibrary::ReadRenderTarget (GWorld, RenderTarget.Get (), /* out*/ *RawColorsPtr);
201270}
202271
203272// Try register On Hovered and On Unhovered events
0 commit comments