@ -5,7 +5,6 @@
* SPDX - License - Identifier : Apache - 2.0 OR MIT
*
*/
# include "DecalTextureArray.h"
# include <Atom/RPI.Public/Image/ImageSystemInterface.h>
# include <Atom/RPI.Reflect/Image/StreamingImageAssetCreator.h>
@ -24,7 +23,16 @@ namespace AZ
{
namespace
{
static const char * BaseColorTextureMapName = " baseColor.textureMap " ;
static AZ : : Name GetMapName ( const DecalMapType mapType )
{
// Using local static to avoid cost of creating AZ::Name. Also so that this can be called from other static functions
static AZStd : : array < AZ : : Name , DecalMapType_Num > mapNames =
{
AZ : : Name ( " baseColor.textureMap " ) ,
AZ : : Name ( " normal.textureMap " )
} ;
return mapNames [ mapType ] ;
}
static AZ : : Data : : AssetId GetImagePoolId ( )
{
@ -40,6 +48,7 @@ namespace AZ
return asset ;
}
// Extract exactly which texture asset we need to load from the given material and map type (diffuse, normal, etc).
static AZ : : Data : : Asset < AZ : : RPI : : StreamingImageAsset > GetStreamingImageAsset ( const AZ : : RPI : : MaterialAsset & materialAsset , const AZ : : Name & propertyName )
{
if ( ! materialAsset . IsReady ( ) )
@ -78,11 +87,6 @@ namespace AZ
const AZ : : RPI : : MaterialAsset * materialAsset = materialAssetData . GetAs < AZ : : RPI : : MaterialAsset > ( ) ;
return GetStreamingImageAsset ( * materialAsset , propertyName ) ;
}
AZ : : Data : : Asset < AZ : : RPI : : StreamingImageAsset > GetBaseColorImageAsset ( const AZ : : Data : : Asset < Data : : AssetData > materialAssetData )
{
return GetStreamingImageAsset ( materialAssetData , AZ : : Name ( BaseColorTextureMapName ) ) ;
}
}
int DecalTextureArray : : FindMaterial ( const AZ : : Data : : AssetId materialAssetId ) const
@ -103,7 +107,7 @@ namespace AZ
{
AZ_Error ( " DecalTextureArray " , FindMaterial ( materialAssetId ) = = - 1 , " Adding material when it already exists in the array " ) ;
// Invalidate the existing texture array, as we need to repack it taking into account the new material.
m_textureArrayPacked = nullptr ;
AZStd: : fill ( m_textureArrayPacked . begin ( ) , m_textureArrayPacked . end ( ) , nullptr ) ;
MaterialData materialData ;
materialData . m_materialAssetId = materialAssetId ;
@ -122,42 +126,42 @@ namespace AZ
return m_materials [ index ] . m_materialAssetId ;
}
RHI : : Size DecalTextureArray : : GetImageDimensions ( ) const
RHI : : Size DecalTextureArray : : GetImageDimensions ( const DecalMapType mapType ) const
{
AZ_Assert ( m_materials . size ( ) > 0 , " GetImageDimensions() cannot be called until at least one material has been added " ) ;
const int iter = m_materials . begin ( ) ;
// All textures in a texture array must have the same size, so just pick the first
const MaterialData & firstMaterial = m_materials [ iter ] ;
const auto & baseColorAsset = Get BaseColor ImageAsset( firstMaterial . m_materialAssetData ) ;
const auto & baseColorAsset = Get Streaming ImageAsset( firstMaterial . m_materialAssetData , GetMapName ( mapType ) ) ;
return baseColorAsset - > GetImageDescriptor ( ) . m_size ;
}
const AZ : : Data : : Instance < AZ : : RPI : : StreamingImage > & DecalTextureArray : : GetPackedTexture ( ) const
const AZ : : Data : : Instance < AZ : : RPI : : StreamingImage > & DecalTextureArray : : GetPackedTexture ( const DecalMapType mapType ) const
{
return m_textureArrayPacked ;
return m_textureArrayPacked [mapType ] ;
}
bool DecalTextureArray : : IsValidDecalMaterial ( const AZ : : RPI : : MaterialAsset & materialAsset )
{
return GetStreamingImageAsset ( materialAsset , AZ: : Name ( BaseColorTextureMapNam e) ) . IsReady ( ) ;
return GetStreamingImageAsset ( materialAsset , GetMapName( DecalMapType_Diffus e) ) . IsReady ( ) ;
}
AZ : : Data : : Asset < AZ : : RPI : : ImageMipChainAsset > DecalTextureArray : : BuildPackedMipChainAsset ( const size_t numTexturesToCreate )
AZ : : Data : : Asset < AZ : : RPI : : ImageMipChainAsset > DecalTextureArray : : BuildPackedMipChainAsset ( const DecalMapType mapType , const size_t numTexturesToCreate )
{
RPI : : ImageMipChainAssetCreator assetCreator ;
const uint32_t mipLevels = GetNumMipLevels ( ) ;
const uint32_t mipLevels = GetNumMipLevels ( mapType ) ;
assetCreator . Begin ( Data : : AssetId ( AZ : : Uuid : : CreateRandom ( ) ) , stat ic_cast< uint16_t > ( mipLevels ) , aznumeric_cast < uint16_t > ( numTexturesToCreate ) ) ;
assetCreator . Begin ( Data : : AssetId ( AZ : : Uuid : : CreateRandom ( ) ) , aznumer ic_cast< uint16_t > ( mipLevels ) , aznumeric_cast < uint16_t > ( numTexturesToCreate ) ) ;
for ( uint32_t mipLevel = 0 ; mipLevel < mipLevels ; + + mipLevel )
{
const auto & layout = GetLayout ( m ipLevel) ;
const auto & layout = GetLayout ( m apType, m ipLevel) ;
assetCreator . BeginMip ( layout ) ;
for ( int i = 0 ; i < m_materials . array_size ( ) ; + + i )
{
const auto raw Data = GetRawImageData ( i , mipLevel ) ;
assetCreator . AddSubImage ( rawData. data ( ) , raw Data. size ( ) ) ;
const auto image Data = GetRawImageData ( GetMapName ( mapType ) , i , mipLevel ) ;
assetCreator . AddSubImage ( imageData. data ( ) , image Data. size ( ) ) ;
}
assetCreator . EndMip ( ) ;
@ -169,10 +173,12 @@ namespace AZ
return AZStd : : move ( asset ) ;
}
RHI : : ImageDescriptor DecalTextureArray : : CreatePackedImageDescriptor ( const uint16_t arraySize , const uint16_t mipLevels ) const
RHI : : ImageDescriptor DecalTextureArray : : CreatePackedImageDescriptor (
const DecalMapType mapType , const uint16_t arraySize , const uint16_t mipLevels ) const
{
const RHI : : Size imageDimensions = GetImageDimensions ( ) ;
RHI : : ImageDescriptor imageDescriptor = RHI : : ImageDescriptor : : Create2DArray ( RHI : : ImageBindFlags : : ShaderRead , imageDimensions . m_width , imageDimensions . m_height , arraySize , GetFormat ( ) ) ;
const RHI : : Size imageDimensions = GetImageDimensions ( mapType ) ;
RHI : : ImageDescriptor imageDescriptor = RHI : : ImageDescriptor : : Create2DArray (
RHI : : ImageBindFlags : : ShaderRead , imageDimensions . m_width , imageDimensions . m_height , arraySize , GetFormat ( mapType ) ) ;
imageDescriptor . m_mipLevels = mipLevels ;
return imageDescriptor ;
}
@ -189,21 +195,34 @@ namespace AZ
}
const size_t numTexturesToCreate = m_materials . array_size ( ) ;
const auto mipChainAsset = BuildPackedMipChainAsset ( numTexturesToCreate ) ;
RHI : : ImageViewDescriptor imageViewDescriptor ;
imageViewDescriptor . m_isArray = true ;
RPI : : StreamingImageAssetCreator assetCreator ;
assetCreator . Begin ( Data : : AssetId ( Uuid : : CreateRandom ( ) ) ) ;
assetCreator . SetPoolAssetId ( GetImagePoolId ( ) ) ;
assetCreator . SetFlags ( RPI : : StreamingImageFlags : : None ) ;
assetCreator . SetImageDescriptor ( CreatePackedImageDescriptor ( aznumeric_cast < uint16_t > ( numTexturesToCreate ) , GetNumMipLevels ( ) ) ) ;
assetCreator . SetImageViewDescriptor ( imageViewDescriptor ) ;
assetCreator . AddMipChainAsset ( * mipChainAsset ) ;
Data : : Asset < RPI : : StreamingImageAsset > packedAsset ;
const bool createdOk = assetCreator . End ( packedAsset ) ;
AZ_Error ( " TextureArrayData " , createdOk , " Pack() call failed. " ) ;
m_textureArrayPacked = createdOk ? RPI : : StreamingImage : : FindOrCreate ( packedAsset ) : nullptr ;
for ( int i = 0 ; i < DecalMapType_Num ; + + i )
{
const DecalMapType mapType = aznumeric_cast < DecalMapType > ( i ) ;
if ( ! AreAllTextureMapsPresent ( mapType ) )
{
AZ_Warning ( " DecalTextureArray " , true , " Missing decal texture maps for %s. Please make sure all maps of this type are present. \n " , GetMapName ( mapType ) . GetCStr ( ) ) ;
m_textureArrayPacked [ i ] = nullptr ;
continue ;
}
const auto mipChainAsset = BuildPackedMipChainAsset ( mapType , numTexturesToCreate ) ;
RHI : : ImageViewDescriptor imageViewDescriptor ;
imageViewDescriptor . m_isArray = true ;
RPI : : StreamingImageAssetCreator assetCreator ;
assetCreator . Begin ( Data : : AssetId ( Uuid : : CreateRandom ( ) ) ) ;
assetCreator . SetPoolAssetId ( GetImagePoolId ( ) ) ;
assetCreator . SetFlags ( RPI : : StreamingImageFlags : : None ) ;
assetCreator . SetImageDescriptor (
CreatePackedImageDescriptor ( mapType , aznumeric_cast < uint16_t > ( numTexturesToCreate ) , GetNumMipLevels ( mapType ) ) ) ;
assetCreator . SetImageViewDescriptor ( imageViewDescriptor ) ;
assetCreator . AddMipChainAsset ( * mipChainAsset ) ;
Data : : Asset < RPI : : StreamingImageAsset > packedAsset ;
const bool createdOk = assetCreator . End ( packedAsset ) ;
AZ_Error ( " TextureArrayData " , createdOk , " Pack() call failed. " ) ;
m_textureArrayPacked [ i ] = createdOk ? RPI : : StreamingImage : : FindOrCreate ( packedAsset ) : nullptr ;
}
// Free unused memory
ClearAssets ( ) ;
@ -225,29 +244,30 @@ namespace AZ
}
}
uint16_t DecalTextureArray : : GetNumMipLevels ( ) const
uint16_t DecalTextureArray : : GetNumMipLevels ( const DecalMapType mapType ) const
{
AZ_Assert ( m_materials . size ( ) > 0 , " GetNumMipLevels() cannot be called until at least one material has been added " ) ;
// All decals in a texture array must have the same number of mips, so just pick the first
const int iter = m_materials . begin ( ) ;
const MaterialData & firstMaterial = m_materials [ iter ] ;
const auto & baseColorAsset = GetBaseColor ImageAsset( firstMaterial . m_materialAssetData ) ;
return baseColor Asset- > GetImageDescriptor ( ) . m_mipLevels ;
const auto & imageAsset = GetStreaming ImageAsset( firstMaterial . m_materialAssetData , GetMapName ( mapType ) ) ;
return image Asset- > GetImageDescriptor ( ) . m_mipLevels ;
}
RHI : : ImageSubresourceLayout DecalTextureArray : : GetLayout ( int mip ) const
RHI : : ImageSubresourceLayout DecalTextureArray : : GetLayout ( const DecalMapType mapType , int mip ) const
{
AZ_Assert ( m_materials . size ( ) > 0 , " GetLayout() cannot be called unless at least one material has been added " ) ;
const int iter = m_materials . begin ( ) ;
const auto & descriptor = GetBaseColorImageAsset ( m_materials [ iter ] . m_materialAssetData ) - > GetImageDescriptor ( ) ;
const auto & descriptor =
GetStreamingImageAsset ( m_materials [ iter ] . m_materialAssetData , GetMapName ( mapType ) ) - > GetImageDescriptor ( ) ;
RHI : : Size mipSize = descriptor . m_size ;
mipSize . m_width > > = mip ;
mipSize . m_height > > = mip ;
return AZ : : RHI : : GetImageSubresourceLayout ( mipSize , descriptor . m_format ) ;
}
AZStd : : array_view < uint8_t > DecalTextureArray : : GetRawImageData ( int arrayLevel , const int mip ) const
AZStd : : array_view < uint8_t > DecalTextureArray : : GetRawImageData ( const AZ : : Name & mapName , int arrayLevel , const int mip ) const
{
// We always want to provide valid data to the AssetCreator for each texture.
// If this spot in the array is empty, just provide some random image as filler.
@ -257,17 +277,20 @@ namespace AZ
{
arrayLevel = m_materials . begin ( ) ;
}
const auto image = GetBaseColorImageAsset ( m_materials [ arrayLevel ] . m_materialAssetData ) ;
const auto image = GetStreamingImageAsset ( m_materials [ arrayLevel ] . m_materialAssetData , mapName ) ;
if ( ! image )
{
return { } ;
}
const auto srcData = image - > GetSubImageData ( mip , 0 ) ;
return srcData ;
}
AZ : : RHI : : Format DecalTextureArray : : GetFormat ( ) const
AZ : : RHI : : Format DecalTextureArray : : GetFormat ( const DecalMapType mapType ) const
{
AZ_Assert ( m_materials . size ( ) > 0 , " GetFormat() can only be called after at least one material has been added. " ) ;
const int iter = m_materials . begin ( ) ;
const auto & baseColorAsset = Get BaseColor ImageAsset( m_materials [ iter ] . m_materialAssetData ) ;
const auto & baseColorAsset = Get Streaming ImageAsset( m_materials [ iter ] . m_materialAssetData , GetMapName ( mapType ) ) ;
return baseColorAsset - > GetImageDescriptor ( ) . m_format ;
}
@ -290,6 +313,25 @@ namespace AZ
return id . IsValid ( ) & & materialData . m_materialAssetData . IsReady ( ) ;
}
bool DecalTextureArray : : AreAllTextureMapsPresent ( const DecalMapType mapType ) const
{
int iter = m_materials . begin ( ) ;
while ( iter ! = - 1 )
{
if ( ! IsTextureMapPresentInMaterial ( m_materials [ iter ] , mapType ) )
{
return false ;
}
iter = m_materials . next ( iter ) ;
}
return true ;
}
bool DecalTextureArray : : IsTextureMapPresentInMaterial ( const MaterialData & materialData , const DecalMapType mapType ) const
{
return GetStreamingImageAsset ( materialData . m_materialAssetData , GetMapName ( mapType ) ) . IsReady ( ) ;
}
void DecalTextureArray : : ClearAssets ( )
{
int iter = m_materials . begin ( ) ;
@ -330,7 +372,8 @@ namespace AZ
if ( m_materials . size ( ) = = 0 )
return false ;
return m_textureArrayPacked = = nullptr ;
// We pack all diffuse/normal/etc in one go, so just check to see if the diffusemaps need packing
return m_textureArrayPacked [ DecalMapType_Diffuse ] = = nullptr ;
}
}