#pragma once #include "CoreMinimal.h" #include "RenderingCommon.h" #include "SlateUpdatableTexture.h" #include "Thread/ThreadMessage.h" #include "Misc/CallRateLimiter.h" struct FImageData { TArray Data; FIntPoint TextureSize = FIntPoint::ZeroValue; bool Resize(FIntPoint NewSize) { if (NewSize == TextureSize) return false; if (NewSize.X <= 0 || NewSize.Y <= 0) return false; TextureSize = NewSize; Data.SetNumZeroed(TextureSize.X * TextureSize.Y * 4); return true; } void ClearColor(const FColor& Color) { for (int32 x = 0; x < TextureSize.X; ++x) { for (int32 y = 0; y < TextureSize.Y; ++y) { DrawPixel(x, y, Color); } } } void DrawPixel(const FIntPoint& Pos, const FColor& Color) { DrawPixel(Pos.X, Pos.Y, Color); } void DrawPixel(int32 X, int32 Y, const FColor& Color) { #if UE_BUILD_DEBUG const bool Error = X < 0 || X >= TextureSize.X || Y < 0 || Y >= TextureSize.Y; ensureMsgf(!Error, TEXT("X: %d, Y: %d, TextureSize: %d, %d"), X, Y, TextureSize.X, TextureSize.Y); if (Error) return; #endif const int32 Pixel = X + Y * TextureSize.X; uint8* Ptr = Data.GetData() + Pixel * 4; *Ptr++ = Color.R; *Ptr++ = Color.G; *Ptr++ = Color.B; *Ptr = Color.A; } void DrawLine(const FIntPoint& P1, const FIntPoint& P2, const FColor& Color) { int32 x1 = P1.X; int32 y1 = P1.Y; const int32& x2 = P2.X; const int32& y2 = P2.Y; const int dx = abs(x2 - x1); const int dy = abs(y2 - y1); const int sx = (x1 < x2) ? 1 : -1; const int sy = (y1 < y2) ? 1 : -1; int err = dx - dy; while (true) { DrawPixel(x1, y1, Color); if (x1 == x2 && y1 == y2) break; int e2 = 2 * err; if (e2 > -dy) { err -= dy; x1 += sx; } if (e2 < dx) { err += dx; y1 += sy; } } } FColor& operator[](int32 PixelIndex) { return *(FColor*)(Data.GetData() + PixelIndex * 4); } }; DECLARE_DELEGATE_OneParam(FUpdatableImageDataEvent, FImageData&) class FUpdatableTexture : public ISlateViewport, public TSharedFromThis { FRIEND_THREAD_MESSAGE(UpdatableTexture) public: FUpdatableTexture(FIntPoint InTextureSize); void Resize(FIntPoint NewSize); void RequestUpdate(bool Async = true); virtual FIntPoint GetSize() const override { return Data.TextureSize; } virtual FSlateShaderResource* GetViewportRenderTargetTexture() const override { return Texture->GetSlateResource(); } virtual bool RequiresVsync() const override { return false; } ISlateViewport* GetViewportInterface() { return this; } FUpdatableImageDataEvent RedrawImage; FSimpleDelegate OnOverRedraw; private: FCallOnce UpdateCaller; void Update(); // 只能在主线程调用 void AsyncUpdate(); FSlateUpdatableTexture* Texture; FImageData Data; bool ReSized = false; FIntPoint NextSize; };