void FDistanceFieldVolumeTextureAtlas::UpdateAllocations()
{
	if (PendingAllocations.Num() > 0)
	{
		// Sort largest to smallest for best packing
		PendingAllocations.Sort(FCompareVolumeAllocation());

		for (int32 AllocationIndex = 0; AllocationIndex < PendingAllocations.Num(); AllocationIndex++)
		{
			FDistanceFieldVolumeTexture* Texture = PendingAllocations[AllocationIndex];
			const FIntVector Size = Texture->VolumeData.Size;

			if (!BlockAllocator.AddElement((uint32&)Texture->AtlasAllocationMin.X, (uint32&)Texture->AtlasAllocationMin.Y, (uint32&)Texture->AtlasAllocationMin.Z, Size.X, Size.Y, Size.Z))
			{
				UE_LOG(LogStaticMesh,Error,TEXT("Failed to allocate %ux%ux%u in distance field atlas"), Size.X, Size.Y, Size.Z);
				PendingAllocations.RemoveAt(AllocationIndex);
				AllocationIndex--;
			}
		}

		if (!VolumeTextureRHI
			|| BlockAllocator.GetSizeX() > VolumeTextureRHI->GetSizeX()
			|| BlockAllocator.GetSizeY() > VolumeTextureRHI->GetSizeY()
			|| BlockAllocator.GetSizeZ() > VolumeTextureRHI->GetSizeZ())
		{
			if (CurrentAllocations.Num() > 0)
			{
				static const auto CVarXY = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.DistanceFields.AtlasSizeXY"));
				const int32 AtlasXY = CVarXY->GetValueOnAnyThread();

				static const auto CVarZ = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.DistanceFields.AtlasSizeZ"));
				const int32 AtlasZ = CVarZ->GetValueOnAnyThread();

				// Remove all allocations from the layout so we have a clean slate
				BlockAllocator = FTextureLayout3d(0, 0, 0, AtlasXY, AtlasXY, AtlasZ, false, false);
				
				Generation++;

				// Re-upload all textures since we had to reallocate
				PendingAllocations.Append(CurrentAllocations);
				CurrentAllocations.Empty();

				// Sort largest to smallest for best packing
				PendingAllocations.Sort(FCompareVolumeAllocation());

				// Add all allocations back to the layout
				for (int32 AllocationIndex = 0; AllocationIndex < PendingAllocations.Num(); AllocationIndex++)
				{
					FDistanceFieldVolumeTexture* Texture = PendingAllocations[AllocationIndex];
					const FIntVector Size = Texture->VolumeData.Size;

					if (!BlockAllocator.AddElement((uint32&)Texture->AtlasAllocationMin.X, (uint32&)Texture->AtlasAllocationMin.Y, (uint32&)Texture->AtlasAllocationMin.Z, Size.X, Size.Y, Size.Z))
					{
						UE_LOG(LogStaticMesh,Error,TEXT("Failed to allocate %ux%ux%u in distance field atlas"), Size.X, Size.Y, Size.Z);
						PendingAllocations.RemoveAt(AllocationIndex);
						AllocationIndex--;
					}
				}
			}

			FRHIResourceCreateInfo CreateInfo;

			VolumeTextureRHI = RHICreateTexture3D(
				BlockAllocator.GetSizeX(), 
				BlockAllocator.GetSizeY(), 
				BlockAllocator.GetSizeZ(), 
				Format,
				1,
				TexCreate_ShaderResource,
				CreateInfo);

			UE_LOG(LogStaticMesh,Log,TEXT("Allocated %s"), *GetSizeString());
		}

		for (int32 AllocationIndex = 0; AllocationIndex < PendingAllocations.Num(); AllocationIndex++)
		{
			FDistanceFieldVolumeTexture* Texture = PendingAllocations[AllocationIndex];
			const FIntVector Size = Texture->VolumeData.Size;

			const FUpdateTextureRegion3D UpdateRegion(
				Texture->AtlasAllocationMin.X,
				Texture->AtlasAllocationMin.Y,
				Texture->AtlasAllocationMin.Z,
				0,
				0,
				0,
				Size.X,
				Size.Y,
				Size.Z);

			const int32 FormatSize = GPixelFormats[Format].BlockBytes;

			// Update the volume texture atlas
			RHIUpdateTexture3D(VolumeTextureRHI, 0, UpdateRegion, Size.X * FormatSize, Size.X * Size.Y * FormatSize, (const uint8*)Texture->VolumeData.DistanceFieldVolume.GetData());
		}

		CurrentAllocations.Append(PendingAllocations);
		PendingAllocations.Empty();
	}	
}
FFluidSimulationShaderInstance::FFluidSimulationShaderInstance(int32 SizeX, int32 SizeY, int32 SizeZ, ERHIFeatureLevel::Type ShaderFeatureLevel)
{
	FeatureLevel = ShaderFeatureLevel;

	ConstantParameters = FFluidSimulationShaderConstantParameters();
	VariableParameters = FFluidSimulationShaderVariableParameters();

	bIsShaderExecuting = false;
	bIsUnloading = false;
	
	FRHIResourceCreateInfo CreateInfo;
	
	PressureIn = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_R32_UINT, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	PressureOut = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_R32_UINT, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	Divergence = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_R32_UINT, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	VelocityIn = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_A32B32G32R32F, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	VelocityOut = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_A32B32G32R32F, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	DensityIn = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_A32B32G32R32F, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	DensityOut = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_A32B32G32R32F, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	TemperatureIn = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_R32_UINT, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	TemperatureOut = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_R32_UINT, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	Obstacle = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_R32_UINT, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	VorticityIn = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_A32B32G32R32F, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	VorticityOut = RHICreateTexture3D(SizeX, SizeY, SizeZ, PF_A32B32G32R32F, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);

	PressureInUAV = RHICreateUnorderedAccessView(PressureIn);
	PressureOutUAV = RHICreateUnorderedAccessView(PressureOut);
	DivergenceUAV = RHICreateUnorderedAccessView(Divergence);
	VelocityInUAV = RHICreateUnorderedAccessView(VelocityIn);
	VelocityOutUAV = RHICreateUnorderedAccessView(VelocityOut);
	DensityInUAV = RHICreateUnorderedAccessView(DensityIn);
	DensityOutUAV = RHICreateUnorderedAccessView(DensityOut);
	TemperatureInUAV = RHICreateUnorderedAccessView(TemperatureIn);
	TemperatureOutUAV = RHICreateUnorderedAccessView(TemperatureOut);
	ObstacleUAV = RHICreateUnorderedAccessView(Obstacle);
	VorticityInUAV = RHICreateUnorderedAccessView(VorticityIn);
	VorticityOutUAV = RHICreateUnorderedAccessView(VorticityOut);

	PressureInSRV = RHICreateShaderResourceView(PressureIn, 0);
	PressureOutSRV = RHICreateShaderResourceView(PressureOut, 0);
	DivergenceSRV = RHICreateShaderResourceView(Divergence, 0);
	VelocityInSRV = RHICreateShaderResourceView(VelocityIn, 0);
	VelocityOutSRV = RHICreateShaderResourceView(VelocityOut, 0);
	DensityInSRV = RHICreateShaderResourceView(DensityIn, 0);
	DensityOutSRV = RHICreateShaderResourceView(DensityOut, 0);
	TemperatureInSRV = RHICreateShaderResourceView(TemperatureIn, 0);
	TemperatureOutSRV = RHICreateShaderResourceView(TemperatureOut, 0);
	ObstacleSRV = RHICreateShaderResourceView(Obstacle, 0);
	VorticityInSRV = RHICreateShaderResourceView(VorticityIn, 0);
	VorticityOutSRV = RHICreateShaderResourceView(VorticityOut, 0);

	GEngine->FluidSimDensitySRV = RHICreateShaderResourceView(DensityIn, 0);

	// Set up walls of simulation
	ExecuteObstaclesShader();
}