/** * Writes the data for a single mip-level into a destination buffer. * @param FaceIndex The index of the face of the mip-level to read. * @param MipIndex The index of the mip-level to read. * @param Dest The address of the destination buffer to receive the mip-level's data. * @param DestPitch Number of bytes per row */ void GetData( int32 FaceIndex, int32 MipIndex, void* Dest, uint32 DestPitch ) { check( MipData[FaceIndex][MipIndex] ); // for platforms that returned 0 pitch from Lock, we need to just use the bulk data directly, never do // runtime block size checking, conversion, or the like if (DestPitch == 0) { FMemory::Memcpy(Dest, MipData[FaceIndex][MipIndex], Owner->PlatformData->Mips[MipIndex].BulkData.GetBulkDataSize() / 6); } else { EPixelFormat PixelFormat = Owner->GetPixelFormat(); uint32 NumRows = 0; uint32 SrcPitch = 0; uint32 BlockSizeX = GPixelFormats[PixelFormat].BlockSizeX; // Block width in pixels uint32 BlockSizeY = GPixelFormats[PixelFormat].BlockSizeY; // Block height in pixels uint32 BlockBytes = GPixelFormats[PixelFormat].BlockBytes; FIntPoint MipExtent = CalcMipMapExtent(Owner->GetSizeX(), Owner->GetSizeY(), PixelFormat, MipIndex); uint32 NumColumns = (MipExtent.X + BlockSizeX - 1) / BlockSizeX; // Num-of columns in the source data (in blocks) NumRows = (MipExtent.Y + BlockSizeY - 1) / BlockSizeY; // Num-of rows in the source data (in blocks) SrcPitch = NumColumns * BlockBytes; // Num-of bytes per row in the source data SIZE_T MipSizeInBytes = CalcTextureMipMapSize(MipExtent.X, MipExtent.Y, PixelFormat, 0); if (SrcPitch == DestPitch) { // Copy data, not taking into account stride! FMemory::Memcpy(Dest, MipData[FaceIndex][MipIndex], MipSizeInBytes); } else { // Copy data, taking the stride into account! uint8 *Src = (uint8*) MipData[FaceIndex][MipIndex]; uint8 *Dst = (uint8*) Dest; for ( uint32 Row=0; Row < NumRows; ++Row ) { FMemory::Memcpy( Dst, Src, SrcPitch ); Src += SrcPitch; Dst += DestPitch; } check( (PTRINT(Src) - PTRINT(MipData[FaceIndex][MipIndex])) == PTRINT(MipSizeInBytes) ); } } FMemory::Free( MipData[FaceIndex][MipIndex] ); MipData[FaceIndex][MipIndex] = NULL; }
/** * Iterate through all textures used by the material and return the maximum texture resolution used * (ideally this could be made dependent of the material property) * * @param MaterialInterface The material to scan for texture size * * @return Size (width and height) */ FIntPoint FindMaxTextureSize(UMaterialInterface* InMaterialInterface, FIntPoint MinimumSize = FIntPoint(1, 1)) const { // static lod settings so that we only initialize them once UTextureLODSettings* GameTextureLODSettings = UDeviceProfileManager::Get().GetActiveProfile()->GetTextureLODSettings(); TArray<UTexture*> MaterialTextures; InMaterialInterface->GetUsedTextures(MaterialTextures, EMaterialQualityLevel::Num, false, GMaxRHIFeatureLevel, false); // find the largest texture in the list (applying it's LOD bias) FIntPoint MaxSize = MinimumSize; for (int32 TexIndex = 0; TexIndex < MaterialTextures.Num(); TexIndex++) { UTexture* Texture = MaterialTextures[TexIndex]; if (Texture == NULL) { continue; } // get the max size of the texture FIntPoint LocalSize(0, 0); if (Texture->IsA(UTexture2D::StaticClass())) { UTexture2D* Tex2D = (UTexture2D*)Texture; LocalSize = FIntPoint(Tex2D->GetSizeX(), Tex2D->GetSizeY()); } else if (Texture->IsA(UTextureCube::StaticClass())) { UTextureCube* TexCube = (UTextureCube*)Texture; LocalSize = FIntPoint(TexCube->GetSizeX(), TexCube->GetSizeY()); } int32 LocalBias = GameTextureLODSettings->CalculateLODBias(Texture); // bias the texture size based on LOD group FIntPoint BiasedLocalSize(LocalSize.X >> LocalBias, LocalSize.Y >> LocalBias); MaxSize.X = FMath::Max(BiasedLocalSize.X, MaxSize.X); MaxSize.Y = FMath::Max(BiasedLocalSize.Y, MaxSize.Y); } return MaxSize; }