Sure! Another user requested it as well. The way of doing it I mentioned in my last post isn’t as good as the method I came up with (which uses a render command to actually update the texture, which means its outside the game thread and shouldn’t cause any hanging there).
Currently this is untested, so let me know if you run into problems and I’ll do what I can to fix them (more info to debug the better), though it should work.
I’ll be adding this code to my TextureFromDisk plugin repo, as well as passing it off to if he’d like to include it in his BP library (which is better maintained across versions than my plugin repo), but I’ll share it here just to get it out quickly.
The first thing is to add this function to your code:
A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums (UpdateTextureRegions is what you want)
Next, here’s the declaration for the Blueprint node function:
/** Updates a UTexture2D* from an FColor array.
* Update texture from color data.
* @param ColorData Array of FColors to update this texture with. Array is assumed to be the same dimensions as texture, otherwise this call will fail.
* @param Texture Texture to update.
*/
UFUNCTION(BlueprintCallable, Category = "TextureFromDisk")
static void UpdateTextureFromColorData(TArray<FColor>& ColorData, UTexture2D* Texture);
And the definition:
void UTextureFromDiskFunctionLibrary::UpdateTextureFromColorData(TArray<FColor>& ColorData, UTexture2D* Texture)
{
// Sanity checks.
if (!Texture)
return;
if (ColorData.Num() <= 0)
return;
// Update region.
FUpdateTextureRegion2D *region = new FUpdateTextureRegion2D(0, 0, 0, 0, Texture->GetSurfaceWidth(), Texture->GetSurfaceHeight());
// Call the render command.
UpdateTextureRegions(Texture, 0, 1, region, Texture->GetSurfaceWidth() * 4, 4, (uint8*)ColorData.GetTypedData(), false);
}
You’ll want to get a blank texture of whatever size you need set up first, along with a material. Then you’ll need an array of FColors, which should be sized the same as the number of pixels in your Texture2D (width * height = number of elements).
When your user clicks or what not, update the FColors at the correct X/Y locations. Then call the Blueprint node there and pass in the color array and Texture.
Right now it’s set up to update the entire texture at once, due to the warning mentioned on the wiki page for the Dynamic Textures code. I haven’t tested whether or not it actually works with sub regions correctly, but it should be easy to extend to do that.
Edit: Right now the way it’s set up it will leak the FUpdateTexture2D - so you may want to change UpdateTextureRegions to free the FUpdateTextureRegion2D but NOT the SrcData pointer, because that refers to your TArray of FColors, which you don’t want freed.
To fix that, change this in UpdateTextureRegions
if (bFreeData)
{
FMemory::Free(RegionData->Regions);
FMemory::Free(RegionData->SrcData);
}
to this:
if (bFreeData)
{
FMemory::Free(RegionData->Regions);
}
If you change this, make sure to change the last parameter for UpdateTextureRegions to be true, so it will actually free the FUpdateTextureRegion2D.