I have transparent textures and would like to display them with a custom background.
Step 1: Create the new texture
UTexture2D* UClass1::CreateTexture(const FIntPoint& size, EPixelFormat pixelFormat)
{
auto newTexture = UTexture2D::CreateTransient(size.X, size.Y, pixelFormat);
newTexture->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
newTexture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
newTexture->SRGB = 0;
newTexture->AddToRoot();
newTexture->UpdateResource();
return newTexture;
}
Step 2: Blank this texture with a custom color
void UClass1::BlankTexture(UTexture2D* texture, const FColor& pixelColor)
{
const auto DestWidth = texture->GetSizeX();
const auto DestHeight = texture->GetSizeY();
const auto BytesPerPixel = 4;
const auto BufferSize = DestWidth * DestHeight * BytesPerPixel;
auto newTextureBuffer = new uint8[BufferSize];
int destPixelIndex = 0;
for (int y = 0; y < DestHeight; y++)
{
for (int x = 0; x < DestWidth; x++)
{
newTextureBuffer[destPixelIndex++] = pixelColor.B;
newTextureBuffer[destPixelIndex++] = pixelColor.G;
newTextureBuffer[destPixelIndex++] = pixelColor.R;
newTextureBuffer[destPixelIndex++] = pixelColor.A;
}
}
texture->UpdateResource();
auto updateTextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, DestWidth, DestHeight);
const auto BufferPitch = DestWidth * BytesPerPixel;
texture->UpdateTextureRegions(0, 1, updateTextureRegion, BufferPitch, BytesPerPixel, newTextureBuffer, &CleanMemory);
}
Step 3: Test
auto sourceTexture = LoadObject<UTexture2D>(nullptr, TEXT("/Game/Materials/Textures/T_Whatever.T_Whatever"));
auto newTexture = CreateTexture(FIntPoint(sourceTexture->GetSizeX(), sourceTexture->GetSizeY()), sourceTexture->PlatformData->PixelFormat);
BlankTexture(newTexture, FColor::FromHex("#00CC00FF"));
imageWidget->SetBrushFromTexture(newTexture);
At this point, it works. It shows an image filled with my color (green in this case)
Now, to copy the sourceTexture, I lock its PlatformData->Mips[0]->BulkData which gives me a pointer to its FColor structures. Fine.
For pixels that are transparent, I want to use the pixels of the background (the texture I created) so I also lock its BulkData.
auto sourceMipMap = &sourceTexture->PlatformData->Mips[0];
auto sourceRawImageData = &sourceMipMap->BulkData;
auto sourceFormatedImageData = static_cast<FColor*>(sourceRawImageData->Lock(LOCK_READ_ONLY));
auto backgroundMipMap = &backgroundTexture->PlatformData->Mips[0];
auto backgroundRawImageData = &backgroundMipMap->BulkData;
auto backgroundFormatedImageData = static_cast<FColor*>(backgroundRawImageData->Lock(LOCK_READ_ONLY));
I expected the data of backgroundFormatedImageData to also be FColor structures but when I look at the memory that points to it, the bytes represent another memory address which leads to another, and another… So it seems the BulkData of the texture I created is invalid but when I called UImage::SetBrushFromTexture() with it, UE knew what to do with it and worked fine. Me, on the other hand, have no idea how to fetch the pixel colors of it.
Another thing I find odd is that the Mip[0].SizeZ = 1 in my source texture compared to my own/new texture which has 0. Is something missing?