| 666 | } |
| 667 | |
| 668 | bool CookCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initData, int32 collisionLod, Array<byte>* collisionData) |
| 669 | { |
| 670 | #if COMPILE_WITH_PHYSICS_COOKING |
| 671 | info.GetSplatMaps(); |
| 672 | PROFILE_CPU_NAMED("Terrain.CookCollision"); |
| 673 | |
| 674 | // Prepare data |
| 675 | const int32 collisionLOD = Math::Clamp<int32>(collisionLod, 0, initData->Mips.Count() - 1); |
| 676 | const int32 collisionLODInv = (int32)Math::Pow(2.0f, (float)collisionLOD); |
| 677 | const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1; |
| 678 | const int32 heightFieldSize = heightFieldChunkSize * Terrain::ChunksCountEdge + 1; |
| 679 | const int32 heightFieldLength = heightFieldSize * heightFieldSize; |
| 680 | GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PhysicsBackend::HeightFieldSample); |
| 681 | PhysicsBackend::HeightFieldSample sample; |
| 682 | Platform::MemoryClear(&sample, sizeof(PhysicsBackend::HeightFieldSample)); |
| 683 | Platform::MemoryClear(heightFieldData, sizeof(PhysicsBackend::HeightFieldSample) * heightFieldLength); |
| 684 | |
| 685 | // Setup terrain collision information |
| 686 | const auto& mip = initData->Mips[collisionLOD]; |
| 687 | const int32 vertexCountEdgeMip = info.VertexCountEdge >> collisionLOD; |
| 688 | const int32 textureSizeMip = info.TextureSize >> collisionLOD; |
| 689 | for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++) |
| 690 | { |
| 691 | const int32 chunkTextureX = chunkX * vertexCountEdgeMip; |
| 692 | const int32 chunkStartX = chunkX * heightFieldChunkSize; |
| 693 | for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++) |
| 694 | { |
| 695 | const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip; |
| 696 | const int32 chunkStartZ = chunkZ * heightFieldChunkSize; |
| 697 | for (int32 z = 0; z < vertexCountEdgeMip; z++) |
| 698 | { |
| 699 | const int32 heightmapZ = chunkStartZ + z; |
| 700 | for (int32 x = 0; x < vertexCountEdgeMip; x++) |
| 701 | { |
| 702 | const int32 heightmapX = chunkStartX + x; |
| 703 | |
| 704 | const int32 textureIndex = (chunkTextureZ + z) * textureSizeMip + chunkTextureX + x; |
| 705 | const Color32 raw = mip.Data.Get<Color32>()[textureIndex]; |
| 706 | sample.Height = int16(TERRAIN_PATCH_COLLISION_QUANTIZATION * ReadNormalizedHeight(raw)); |
| 707 | sample.MaterialIndex0 = sample.MaterialIndex1 = GetPhysicalMaterial(raw, info, chunkZ, chunkX, z * collisionLODInv, x * collisionLODInv); |
| 708 | |
| 709 | const int32 dstIndex = (heightmapX * heightFieldSize) + heightmapZ; |
| 710 | heightFieldData[dstIndex] = sample; |
| 711 | } |
| 712 | } |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | // Cook height field |
| 717 | MemoryWriteStream outputStream; |
| 718 | if (CollisionCooking::CookHeightField(heightFieldSize, heightFieldSize, heightFieldData, outputStream)) |
| 719 | return true; |
| 720 | |
| 721 | // Write results |
| 722 | collisionData->Resize(sizeof(TerrainCollisionDataHeader) + outputStream.GetPosition(), false); |
| 723 | const auto header = (TerrainCollisionDataHeader*)collisionData->Get(); |
| 724 | header->CheckOldMagicNumber = MAX_int32; |
| 725 | header->Version = TerrainCollisionDataHeader::CurrentVersion; |
no test coverage detected