因为项目中用到了Gif格式的图片作为loading界面的资源,但UE本身不支持该格式,所以只能找找看是否有大佬写过相应的插件,果然被我找到了,是一个叫AnimatedTexture的插件。
虚幻4动画贴图插件 | 游戏程序员的自我修养
不过原插件Gift图的tick是在游戏线程中进行的。因为我们项目里面的loading是阻塞游戏线程加载,所以想要在加载界面中使用这个插件,就需要对原插件进行一部分修改,让Gif图资源在游戏线程阻塞时,也能够更新texture。
这里将原有的AnimatedTexture2D继承FTickableGameObject,修改为FAnimatedTextureResource继承FTickableObjectRenderThread,这样就可以在渲染线程中进行tick。我为了减小资源文件大小,把原有的导入时解析,改为了资源加载后解析。
同时对资源tick进行了一定优化,仅在纹理可见时才进行tick,不可见一段时间后不在进行纹理更新。
这里给出修改后的插件地址:
https://github.com/sorkNasrk/AnimatedTexture
多线程上可能没有做过多的保护,后期需要再优化一些
删除了原有的AnimatedGIFDecoder, UAnimatedTextureSource:
其中主要修改代码如下:
AnimatedTexture2D.h
/**
* Copyright 2019 Neil Fang. All Rights Reserved.
*
* Animated Texture from GIF file
*
* Created by Neil Fang
* GitHub Repo: https://github.com/neil3d/UnrealAnimatedTexturePlugin
* GitHub Page: http://neil3d.github.io
*
*/
#pragma once
#include "CoreMinimal.h"
#include "Tickable.h" // Engine
#include "Engine/Texture.h" // Engine
#include "AnimatedTexture2D.generated.h"
class FAnimatedTextureResource;
ANIMATEDTEXTURE_API bool isGifData(const void* data);
USTRUCT()
struct FGIFFrame
{
GENERATED_BODY()
public:
UPROPERTY()
float Time; // next frame delay in sec
UPROPERTY()
uint32 Index; // 0-based index of the current frame
UPROPERTY()
uint32 Width; // current frame width
UPROPERTY()
uint32 Height; // current frame height
UPROPERTY()
uint32 OffsetX; // current frame horizontal offset
UPROPERTY()
uint32 OffsetY; // current frame vertical offset
UPROPERTY()
bool Interlacing; // see: https://en.wikipedia.org/wiki/GIF#Interlacing
UPROPERTY()
uint8 Mode; // next frame (sic next, not current) blending mode
UPROPERTY()
int16 TransparentIndex; // 0-based transparent color index (or ?1 when transparency is disabled)
UPROPERTY()
TArray<uint8> PixelIndices; // pixel indices for the current frame
UPROPERTY()
TArray<FColor> Palette; // the current palette
FGIFFrame() :Time(0), Index(0), Width(0), Height(0), OffsetX(0), OffsetY(0),
Interlacing(false), Mode(0), TransparentIndex(-1)
{}
};
/**
*
*/
UCLASS(BlueprintType, Category = AnimatedTexture, hideCategories = (Adjustments, Compression, LevelOfDetail))
class ANIMATEDTEXTURE_API UAnimatedTexture2D : public UTexture
{
GENERATED_BODY()
public:
friend FAnimatedTextureResource;
UAnimatedTexture2D(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture, meta = (DisplayName = "X-axis Tiling Method"), AssetRegistrySearchable, AdvancedDisplay)
TEnumAsByte<enum TextureAddress> AddressX;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture, meta = (DisplayName = "Y-axis Tiling Method"), AssetRegistrySearchable, AdvancedDisplay)
TEnumAsByte<enum TextureAddress> AddressY;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture)
bool SupportsTransparency = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture)
float DefaultFrameDelay = 1.0f / 10; // used while Frame.Delay==0
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture)
float PlayRate = 1.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture)
bool bLooping = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AnimatedTexture)
bool bAlwaysTickEvenNoSee = false;
UPROPERTY(VisibleAnywhere, Transient,Category = AnimatedTexture)
int FrameNum;
virtual void PostLoad() override;
virtual void BeginDestroy() override;
bool ImportGIF(const uint8* Buffer, uint32 BufferSize);
void ResetToInVaildGif()
{
GlobalWidth = 0;
GlobalHeight = 0;
Background = 0;
Duration = 0.0f;
Frames.Empty();
FrameNum = 0;
}
void Import_Init(uint32 InGlobalWidth, uint32 InGlobalHeight, uint8 InBackground, uint32 InFrameCount);
int GetFrameCount() const
{
return Frames.Num();
}
FGIFFrame& GetFrame(int32 Index) {
return Frames[Index];
}
float GetFrameDelay(int FrameIndex) const
{
const FGIFFrame& Frame = Frames[FrameIndex];
return Frame.Time;
}
float GetTotalDuration() const { return Duration; }
void Import_Finished();
void PostInitProperties() override;
private:
bool ParseRawData();
public:
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
void Play();
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
void PlayFromStart();
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
void Stop();
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
bool IsPlaying() const { return bPlaying; }
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
void SetLooping(bool bNewLooping) { bLooping = bNewLooping; }
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
bool IsLooping() const { return bLooping; }
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
void SetPlayRate(float NewRate) { PlayRate = NewRate; }
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
float GetPlayRate() const { return PlayRate; }
UFUNCTION(BlueprintCallable, Category = AnimatedTexture)
float GetAnimationLength() const;
//~ Begin UTexture Interface.
virtual float GetSurfaceWidth() const override;
virtual float GetSurfaceHeight() const override;
virtual FTextureResource* CreateResource() override;
virtual EMaterialValueType GetMaterialType() const override { return MCT_Texture2D; }
virtual uint32 CalcTextureMemorySizeEnum(ETextureMipCount Enum) const override;
//~ End UTexture Interface.
//~ Begin UObject Interface.
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif // WITH_EDITOR
virtual void GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) override;
//~ End UObject Interface.
protected:
UPROPERTY()
bool bPlaying = true;
private:
//UPROPERTY()
uint32 GlobalWidth = 0;
//UPROPERTY()
uint32 GlobalHeight = 0;
//UPROPERTY()
uint8 Background = 0; // 0-based background color index for the current palette
//UPROPERTY()
float Duration = 0.0f;
//UPROPERTY()
TArray<FGIFFrame> Frames;
UPROPERTY()
TArray<uint8> RawData;
};
AnimatedTexture2D.cpp
// Copyright 2019 Neil Fang. All Rights Reserved.
#include "AnimatedTexture2D.h"
#include "AnimatedTextureResource.h"
#include "gif_load/gif_load.h" // from: https://github.com/hidefromkgb/gif_load
bool isGifData(const void* data) {
return FMemory::Memcmp(data, "GIF", 3) == 0;
}
//ANIMATEDTEXTURE_API bool LoadGIFBinary(UAnimatedTexture2D* OutGIF, const uint8* Buffer, uint32 BufferSize);
void GIFFrameLoader1(void* data, struct GIF_WHDR* whdr)
{
UAnimatedTexture2D* OutGIF = (UAnimatedTexture2D*)data;
//-- init on first frame
if (OutGIF->GetFrameCount() == 0) {
OutGIF->Import_Init(whdr->xdim, whdr->ydim, whdr->bkgd, whdr->nfrm);
}
//-- import frame
int FrameIndex = whdr->ifrm;
check(OutGIF->GetFrameCount() == whdr->nfrm);
check(FrameIndex >= 0 && FrameIndex < OutGIF->GetFrameCount());
FGIFFrame& Frame = OutGIF->GetFrame(FrameIndex);
//-- copy properties
if (whdr->time >= 0)
Frame.Time = whdr->time * 0.01f; // 1 GIF time units = 10 msec
else
Frame.Time = (-whdr->time - 1) * 0.01f;
/** [TODO:] the frame is assumed to be inside global bounds,
however it might exceed them in some GIFs; fix me. **/
Frame.Index = whdr->ifrm;
Frame.Width = whdr->frxd;
Frame.Height = whdr->fryd;
Frame.OffsetX = whdr->frxo;
Frame.OffsetY = whdr->fryo;
Frame.Interlacing = whdr->intr != 0;
Frame.Mode = whdr->mode;
Frame.TransparentIndex = whdr->tran;
//-- copy pixel data
int NumPixel = Frame.Width * Frame.Height;
Frame.PixelIndices.SetNumUninitialized(NumPixel);
FMemory::Memcpy(Frame.PixelIndices.GetData(), whdr->bptr, NumPixel);
//-- copy pal
int PaletteSize = whdr->clrs;
Frame.Palette.Init(FColor(0, 0, 0, 255), PaletteSize);
for (int i = 0; i < PaletteSize; i++)
{
FColor& uc = Frame.Palette[i];
uc.R = whdr->cpal[i].R;
uc.G = whdr->cpal[i].G;
uc.B = whdr->cpal[i].B;
}// end of for
}
bool LoadGIFBinary(UAnimatedTexture2D* OutGIF, const uint8* Buffer, uint32 BufferSize)
{
int Ret = GIF_Load((void*)Buffer, BufferSize, GIFFrameLoader1, 0, (void*)OutGIF, 0L);
OutGIF->Import_Finished();
if (Ret < 0) {
UE_LOG(LogTexture, Warning, TEXT("gif format error."));
return false;
}
return true;
}
float UAnimatedTexture2D::GetSurfaceWidth() const
{
return GlobalWidth;
}
float UAnimatedTexture2D::GetSurfaceHeight() const
{
return GlobalHeight;
}
FTextureResource* UAnimatedTexture2D::CreateResource()
{
FTextureResource* NewResource = new FAnimatedTextureResource(this);
return NewResource;
}
uint32 UAnimatedTexture2D::CalcTextureMemorySizeEnum(ETextureMipCount Enum) const
{
if(GlobalWidth>0 && GlobalHeight>0)
{
uint32 Flags = SRGB ? TexCreate_SRGB : 0;
uint32 NumMips = 1;
uint32 NumSamples = 1;
uint32 TextureAlign;
FRHIResourceCreateInfo CreateInfo;
uint32 Size = (uint32)RHICalcTexture2DPlatformSize(GlobalWidth, GlobalHeight, PF_B8G8R8A8, 1, 1, (ETextureCreateFlags)Flags, FRHIResourceCreateInfo(), TextureAlign);
return Size;
}
return 4;
}
#if WITH_EDITOR
void UAnimatedTexture2D::PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
bool RequiresNotifyMaterials = false;
bool ResetAnimState = false;
UProperty* PropertyThatChanged = PropertyChangedEvent.Property;
if (PropertyThatChanged)
{
const FName PropertyName = PropertyThatChanged->GetFName();
static const FName SupportsTransparencyName = GET_MEMBER_NAME_CHECKED(UAnimatedTexture2D, SupportsTransparency);
if (PropertyName == SupportsTransparencyName)
{
RequiresNotifyMaterials = true;
ResetAnimState = true;
}
}// end of if(prop is valid)
if (ResetAnimState)
{
//AnimState = FAnmatedTextureState();
//AnimSource->DecodeFrameToRHI(Resource, AnimState, SupportsTransparency);
}
if (RequiresNotifyMaterials)
NotifyMaterials();
}
#endif // WITH_EDITOR
void UAnimatedTexture2D::GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize)
{
Super::GetResourceSizeEx(CumulativeResourceSize);
//if (CumulativeResourceSize.GetResourceSizeMode() == EResourceSizeMode::Exclusive)
{
CumulativeResourceSize.AddDedicatedSystemMemoryBytes(Frames.GetAllocatedSize());
for (auto& Frame: Frames)
{
CumulativeResourceSize.AddDedicatedSystemMemoryBytes(Frame.Palette.GetAllocatedSize());
CumulativeResourceSize.AddDedicatedSystemMemoryBytes(Frame.PixelIndices.GetAllocatedSize());
}
}
}
float UAnimatedTexture2D::GetAnimationLength() const
{
return Duration;
}
UAnimatedTexture2D::UAnimatedTexture2D(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
:Super(ObjectInitializer)
{
}
void UAnimatedTexture2D::PostLoad()
{
ParseRawData();
Super::PostLoad();
}
void UAnimatedTexture2D::BeginDestroy()
{
Super::BeginDestroy();
}
bool UAnimatedTexture2D::ImportGIF(const uint8* Buffer, uint32 BufferSize)
{
Frames.Empty();
RawData.SetNumUninitialized(BufferSize);
FMemory::Memcpy(RawData.GetData(), Buffer, BufferSize);
return ParseRawData();
}
void UAnimatedTexture2D::Import_Init(uint32 InGlobalWidth, uint32 InGlobalHeight, uint8 InBackground, uint32 InFrameCount)
{
GlobalWidth = InGlobalWidth;
GlobalHeight = InGlobalHeight;
Background = InBackground;
Frames.SetNum(InFrameCount);
FrameNum = InFrameCount;
}
void UAnimatedTexture2D::Import_Finished()
{
Duration = 0.0f;
for (const auto& Frm : Frames)
Duration += Frm.Time;
}
void UAnimatedTexture2D::PostInitProperties()
{
Super::PostInitProperties();
}
bool UAnimatedTexture2D::ParseRawData()
{
int Ret = GIF_Load((void*)RawData.GetData(), RawData.Num(), GIFFrameLoader1, 0, (void*)this, 0L);
this->Import_Finished();
if (Ret < 0) {
UE_LOG(LogTexture, Warning, TEXT("gif format error."));
return false;
}
return true;
}
void UAnimatedTexture2D::Play()
{
bPlaying = true;
}
void UAnimatedTexture2D::PlayFromStart()
{
bPlaying = true;
}
void UAnimatedTexture2D::Stop()
{
bPlaying = false;
}
AnimatedTextureResource.h
/**
* Copyright 2019 Neil Fang. All Rights Reserved.
*
* Animated Texture from GIF file
*
* Created by Neil Fang
* GitHub Repo: https://github.com/neil3d/UnrealAnimatedTexturePlugin
* GitHub Page: http://neil3d.github.io
*
*/
#pragma once
#include "CoreMinimal.h"
#include "TextureResource.h" // Engine
class UAnimatedTexture2D;
struct FAnmatedTextureState {
int CurrentFrame;
float FrameTime;
FAnmatedTextureState() :CurrentFrame(0), FrameTime(0) {}
};
/**
* FTextureResource implementation for animated 2D textures
*/
class FAnimatedTextureResource : public FTextureResource, public FTickableObjectRenderThread
{
public:
FAnimatedTextureResource(UAnimatedTexture2D* InOwner);
//~ Begin FTextureResource Interface.
virtual uint32 GetSizeX() const override;
virtual uint32 GetSizeY() const override;
virtual void InitRHI() override;
virtual void ReleaseRHI() override;
//~ End FTextureResource Interface.
//~ Begin FTickableObjectRenderThread Interface.
virtual void Tick(float DeltaTime) override;
virtual bool IsTickable() const override
{
return true;
}
virtual TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(UAnimatedTexture2D, STATGROUP_Tickables);
}
//~ End FTickableObjectRenderThread Interface.
bool TickAnim(float DeltaTime);
void DecodeFrameToRHI();
private:
int32 GetDefaultMipMapBias() const;
void CreateSamplerStates(float MipMapBias);
private:
UAnimatedTexture2D* Owner;
FAnmatedTextureState AnimState;
TArray<FColor> FrameBuffer[2];
uint32 LastFrame;
};
?AnimatedTextureResource.cpp
// Copyright 2019 Neil Fang. All Rights Reserved.
#include "AnimatedTextureResource.h"
#include "AnimatedTexture2D.h"
#include "AnimatedTextureModule.h"
#include "DeviceProfiles/DeviceProfile.h" // Engine
#include "DeviceProfiles/DeviceProfileManager.h" // Engine
#include "gif_load/gif_load.h" // from: https://github.com/hidefromkgb/gif_load
FAnimatedTextureResource::FAnimatedTextureResource(UAnimatedTexture2D * InOwner)
:FTickableObjectRenderThread(false, true),
Owner(InOwner),
LastFrame(0)
{
}
uint32 FAnimatedTextureResource::GetSizeX() const
{
if (Owner)
{
return Owner->GlobalWidth;
}
else
{
return 2;
}
}
uint32 FAnimatedTextureResource::GetSizeY() const
{
if (Owner)
{
return Owner->GlobalHeight;
}
else
{
return 2;
}
}
void FAnimatedTextureResource::InitRHI()
{
//-- create FSamplerStateRHIRef FTexture::SamplerStateRHI
CreateSamplerStates(
GetDefaultMipMapBias()
);
//-- create FTextureRHIRef FTexture::TextureRHI
//uint32 TexCreateFlags = Owner->SRGB ? TexCreate_SRGB : 0;
uint32 Flags = Owner->SRGB ? TexCreate_SRGB : 0;
uint32 NumMips = 1;
uint32 NumSamples = 1;
FRHIResourceCreateInfo CreateInfo;
TextureRHI = RHICreateTexture2D(FMath::Max(GetSizeX(),1u), FMath::Max(GetSizeY(), 1u), (uint8)PF_B8G8R8A8, NumMips, NumSamples, (ETextureCreateFlags)Flags, CreateInfo);
TextureRHI->SetName(Owner->GetFName());
//TRefCountPtr<FRHITexture2D> ShaderTexture2D;
//TRefCountPtr<FRHITexture2D> RenderableTexture;
//FRHIResourceCreateInfo CreateInfo = { FClearValueBinding(FLinearColor(0.0f, 0.0f, 0.0f)) };
//RHICreateTargetableShaderResource2D(
// GetSizeX(),
// GetSizeY(),
// PF_B8G8R8A8,
// 1,
// TexCreate_None,
// TexCreate_RenderTargetable,
// false,
// CreateInfo,
// RenderableTexture,
// ShaderTexture2D
//);
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI, TextureRHI);
if(Owner->GlobalHeight > 0 && Owner->GlobalWidth > 0)
{
DecodeFrameToRHI();
}
Register();
}
void FAnimatedTextureResource::ReleaseRHI()
{
Unregister();
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI, nullptr);
FTextureResource::ReleaseRHI();
}
void FAnimatedTextureResource::Tick(float DeltaTime)
{
float duration = FApp::GetCurrentTime() - Owner->GetLastRenderTimeForStreaming();
bool bShouldTick = Owner->bAlwaysTickEvenNoSee || duration < 2.5f;
if(bShouldTick && Owner && Owner->IsPlaying() && Owner->GlobalHeight >0 && Owner->GlobalWidth > 0)
{
TickAnim(DeltaTime * Owner->PlayRate);
}
}
bool FAnimatedTextureResource::TickAnim(float DeltaTime)
{
bool NextFrame = false;
float FrameDelay = Owner->GetFrameDelay(AnimState.CurrentFrame);
if (FrameDelay == 0.0f)
FrameDelay = Owner->DefaultFrameDelay;
AnimState.FrameTime += DeltaTime;
// skip long duration
float Duration = Owner->GetTotalDuration();
if (AnimState.FrameTime > Duration)
{
float N = FMath::TruncToFloat(AnimState.FrameTime / Duration);
AnimState.FrameTime -= N * Duration;
}
// step to next frame
if (AnimState.FrameTime > FrameDelay) {
AnimState.CurrentFrame++;
AnimState.FrameTime -= FrameDelay;
NextFrame = true;
// loop
int NumFrame = Owner->GetFrameCount();
if (AnimState.CurrentFrame >= NumFrame)
AnimState.CurrentFrame = Owner->bLooping ? 0 : NumFrame - 1;
}
if(NextFrame)
{
DecodeFrameToRHI();
}
return NextFrame;
}
int32 FAnimatedTextureResource::GetDefaultMipMapBias() const
{
return 0;
}
void FAnimatedTextureResource::CreateSamplerStates(float MipMapBias)
{
FSamplerStateInitializerRHI SamplerStateInitializer
(
(ESamplerFilter)UDeviceProfileManager::Get().GetActiveProfile()->GetTextureLODSettings()->GetSamplerFilter(Owner),
Owner->AddressX == TA_Wrap ? AM_Wrap : (Owner->AddressX == TA_Clamp ? AM_Clamp : AM_Mirror),
Owner->AddressY == TA_Wrap ? AM_Wrap : (Owner->AddressY == TA_Clamp ? AM_Clamp : AM_Mirror),
AM_Wrap,
MipMapBias
);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
FSamplerStateInitializerRHI DeferredPassSamplerStateInitializer
(
(ESamplerFilter)UDeviceProfileManager::Get().GetActiveProfile()->GetTextureLODSettings()->GetSamplerFilter(Owner),
Owner->AddressX == TA_Wrap ? AM_Wrap : (Owner->AddressX == TA_Clamp ? AM_Clamp : AM_Mirror),
Owner->AddressY == TA_Wrap ? AM_Wrap : (Owner->AddressY == TA_Clamp ? AM_Clamp : AM_Mirror),
AM_Wrap,
MipMapBias,
1,
0,
2
);
DeferredPassSamplerStateRHI = RHICreateSamplerState(DeferredPassSamplerStateInitializer);
}
void FAnimatedTextureResource::DecodeFrameToRHI()
{
if (FrameBuffer[0].Num() != Owner->GlobalHeight * Owner->GlobalWidth) {
LastFrame = 0;
FColor BGColor(0L);
const FGIFFrame& GIFFrame = Owner->Frames[0];
if (!Owner->SupportsTransparency)
BGColor = GIFFrame.Palette[Owner->Background];
for (int i = 0; i < 2; i++)
FrameBuffer[i].Init(BGColor, Owner->GlobalHeight * Owner->GlobalWidth);
}
bool FirstFrame = AnimState.CurrentFrame == 0;
FTexture2DRHIRef Texture2DRHI = TextureRHI->GetTexture2D();
if (!Texture2DRHI)
return;
FGIFFrame& GIFFrame = Owner->Frames[AnimState.CurrentFrame];
uint32& InLastFrame = LastFrame;
bool bSupportsTransparency = Owner->SupportsTransparency;
FColor* PICT = FrameBuffer[InLastFrame].GetData();
uint32 InBackground = Owner->Background;
TArray<FColor>& Pal = GIFFrame.Palette;
uint32 TexWidth = Texture2DRHI->GetSizeX();
uint32 TexHeight = Texture2DRHI->GetSizeY();
//-- decode to frame buffer
uint32 DDest = TexWidth * GIFFrame.OffsetY + GIFFrame.OffsetX;
uint32 Src = 0;
uint32 Iter = GIFFrame.Interlacing ? 0 : 4;
uint32 Fin = !Iter ? 4 : 5;
for (; Iter < Fin; Iter++) // interlacing support
{
uint32 YOffset = 16U >> ((Iter > 1) ? Iter : 1);
for (uint32 Y = (8 >> Iter) & 7; Y < GIFFrame.Height; Y += YOffset)
{
for (uint32 X = 0; X < GIFFrame.Width; X++)
{
uint32 TexIndex = TexWidth * Y + X + DDest;
uint8 ColorIndex = GIFFrame.PixelIndices[Src];
if (ColorIndex != GIFFrame.TransparentIndex)
PICT[TexIndex] = Pal[ColorIndex];
else
{
int a = 0;
a++;
}
Src++;
}// end of for(x)
}// end of for(y)
}// end of for(iter)
//-- write texture
uint32 DestPitch = 0;
FColor* SrcBuffer = PICT;
FColor* DestBuffer = (FColor*)RHILockTexture2D(Texture2DRHI, 0, RLM_WriteOnly, DestPitch, false);
if (DestBuffer)
{
uint32 MaxRow = TexHeight;
int ColorSize = sizeof(FColor);
//UE_LOG(LogTemp, Log, TEXT("%d"), ssss);
if (DestPitch == TexWidth * ColorSize)
{
FMemory::Memcpy(DestBuffer, SrcBuffer, DestPitch * MaxRow);
}
else
{
// copy row by row
uint32 SrcPitch = TexWidth * ColorSize;
uint32 Pitch = FMath::Min(DestPitch, SrcPitch);
for (uint32 y = 0; y < MaxRow; y++)
{
FMemory::Memcpy(DestBuffer, SrcBuffer, Pitch);
DestBuffer += DestPitch / ColorSize;
SrcBuffer += SrcPitch / ColorSize;
}// end of for
}// end of else
RHIUnlockTexture2D(Texture2DRHI, 0, false);
}// end of if
else
{
UE_LOG(LogAnimTexture, Warning, TEXT("Unable to lock texture for write"));
}// end of else
//-- frame blending
EGIF_Mode Mode = (EGIF_Mode)GIFFrame.Mode;
if (Mode == GIF_PREV && FirstFrame) // loop restart
Mode = GIF_BKGD;
switch (Mode)
{
case GIF_NONE:
case GIF_CURR:
break;
case GIF_BKGD: // restore background
{
FColor BGColor(0L);
if (bSupportsTransparency)
{
if (GIFFrame.TransparentIndex == -1)
BGColor = GIFFrame.Palette[InBackground];
else
BGColor = GIFFrame.Palette[GIFFrame.TransparentIndex];
BGColor.A = 0;
}
else
{
BGColor = GIFFrame.Palette[InBackground];
}
uint32 BGWidth = GIFFrame.Width;
uint32 BGHeight = GIFFrame.Height;
uint32 XDest = DDest;
if (FirstFrame)
{
BGWidth = TexWidth;
BGHeight = TexHeight;
XDest = 0;
}
for (uint32 Y = 0; Y < BGHeight; Y++)
{
for (uint32 X = 0; X < BGWidth; X++)
{
PICT[TexWidth * Y + X + XDest] = BGColor;
}// end of for(x)
}// end of for(y)
}
break;
case GIF_PREV: // restore prevous frame
InLastFrame = (InLastFrame + 1) % 2;
break;
default:
UE_LOG(LogAnimTexture, Warning, TEXT("Unknown GIF Mode"));
break;
}//end of switch
}
|