| 823 | #if TERRAIN_EDITING |
| 824 | |
| 825 | bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap, const byte* holesMask, bool forceUseVirtualStorage) |
| 826 | { |
| 827 | PROFILE_CPU_NAMED("Terrain.Setup"); |
| 828 | PROFILE_MEM(LevelTerrain); |
| 829 | if (heightMap == nullptr) |
| 830 | { |
| 831 | LOG(Warning, "Cannot create terrain without a heightmap specified."); |
| 832 | return true; |
| 833 | } |
| 834 | TerrainDataUpdateInfo info(this); |
| 835 | if (heightMapLength != info.HeightmapLength) |
| 836 | { |
| 837 | LOG(Warning, "Invalid heightmap length. Terrain of chunk size equal {0} uses heightmap of size {1}x{1} (heightmap array length must be {2}). Input heightmap has length {3}.", info.ChunkSize, info.HeightmapSize, info.HeightmapLength, heightMapLength); |
| 838 | return true; |
| 839 | } |
| 840 | const PixelFormat pixelFormat = PixelFormat::R8G8B8A8_UNorm; |
| 841 | |
| 842 | // Input heightmap data overlaps on chunk edges but it needs to be duplicated for chunks (each chunk has own scale-bias for height values normalization) |
| 843 | const int32 pixelStride = PixelFormatExtensions::SizeInBytes(pixelFormat); |
| 844 | const int32 lodCount = Math::Min<int32>(_terrain->_lodCount, MipLevelsCount(info.VertexCountEdge) - 2); |
| 845 | |
| 846 | // Process heightmap to get per-patch height normalization values |
| 847 | float chunkOffsets[Terrain::ChunksCount]; |
| 848 | float chunkHeights[Terrain::ChunksCount]; |
| 849 | CalculateHeightmapRange(_terrain, info, heightMap, chunkOffsets, chunkHeights); |
| 850 | |
| 851 | // Prepare |
| 852 | #if USE_EDITOR |
| 853 | const bool useVirtualStorage = Editor::IsPlayMode || forceUseVirtualStorage; |
| 854 | #else |
| 855 | const bool useVirtualStorage = true; |
| 856 | #endif |
| 857 | #if USE_EDITOR |
| 858 | String heightMapPath, heightFieldPath; |
| 859 | if (!useVirtualStorage) |
| 860 | { |
| 861 | if (!_terrain->GetScene()) |
| 862 | { |
| 863 | LOG(Error, "Cannot create non-virtual terrain. Add terrain actor to scene first (needs scene folder path for target assets location)."); |
| 864 | return true; |
| 865 | } |
| 866 | const String cacheDir = _terrain->GetScene()->GetDataFolderPath() / TEXT("Terrain/") / _terrain->GetID().ToString(Guid::FormatType::N); |
| 867 | |
| 868 | // Prepare asset paths for the non-virtual assets |
| 869 | heightMapPath = cacheDir + String::Format(TEXT("_{0:2}_{1:2}_Heightmap.{2}"), _x, _z, ASSET_FILES_EXTENSION); |
| 870 | heightFieldPath = cacheDir + String::Format(TEXT("_{0:2}_{1:2}_Heightfield.{2}"), _x, _z, ASSET_FILES_EXTENSION); |
| 871 | } |
| 872 | #endif |
| 873 | |
| 874 | // Create heightmap texture data source container |
| 875 | auto initData = New<TextureBase::InitData>(); |
| 876 | initData->Format = pixelFormat; |
| 877 | initData->Width = info.TextureSize; |
| 878 | initData->Height = info.TextureSize; |
| 879 | initData->ArraySize = 1; |
| 880 | initData->Mips.Resize(lodCount); |
| 881 | |
| 882 | // Allocate top mip data |
no test coverage detected