AronaSlate/Source/Arona/Render/UpdatableTexture.h
2024-01-25 11:21:15 +08:00

125 lines
2.8 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "RenderingCommon.h"
#include "SlateUpdatableTexture.h"
#include "Thread/ThreadMessage.h"
#include "Misc/CallRateLimiter.h"
struct FImageData
{
TArray<uint8> 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<FUpdatableTexture>
{
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;
};