CCCPaste

a26be6f0748be

using System;
using System.Collections.Generic;
using GamePlay;
using R3;
using Reflex.Attributes;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using VoxelMap;
namespace UI
{
public class WorldMap : MonoBehaviour
{
private const int ColumnPerFrame = 1;

private const string ClearHeight = "ClearHeight";
private const string UpdateHeight = "UpdateHeight";
private const string UpdateChunk = "UpdateChunk";

private static readonly int HeightBuffer = Shader.PropertyToID("HeightBuffer");
private static readonly int VertexBuffer = Shader.PropertyToID("VertexBuffer");
private static readonly int MapTexture = Shader.PropertyToID("MapTexture");
private static readonly int MeshPositionOffset = Shader.PropertyToID("MeshPositionOffset");
private static readonly int ChunkSize = Shader.PropertyToID("ChunkSize");

[SerializeField] private ComputeShader computeShader;
[SerializeField] private RawImage mapImage;

private MapProvider _mapProvider;
private EntityContainerService _entityContainer;

private ComputeBuffer _heightBuffer;
private int _updateHeightKernel;
private int _updateChunkKernel;
private int _clearHeightKernel;

[field: SerializeField] public CanvasGroup CanvasGroup { get; private set; }
public RenderTexture MainTexture { get; private set; }
private readonly Queue<(int x, int z)> _regeneratingColumns = new Queue<(int x, int z)>();


[Inject]
private void Construct(MapProvider mapProvider)
{
_mapProvider = mapProvider;

_heightBuffer = new ComputeBuffer(Chunk.ChunkSizeSquared, sizeof(uint));
_clearHeightKernel = computeShader.FindKernel(ClearHeight);
_updateHeightKernel = computeShader.FindKernel(UpdateHeight);
_updateChunkKernel = computeShader.FindKernel(UpdateChunk);

computeShader.SetFloat(ChunkSize, Chunk.ChunkSize);
}

public void Initialize()
{
if (MainTexture != null)
{
MainTexture.Release();
}

MainTexture = new RenderTexture(_mapProvider.Map.Width, _mapProvider.Map.Depth, 0, RenderTextureFormat.ARGB32)
{
enableRandomWrite = true,
filterMode = FilterMode.Point
};

MainTexture.Create();
mapImage.texture = MainTexture;

_mapProvider.Map.ChunkUpdated.Subscribe(OnChunkUpdated).AddTo(_mapProvider.Map);

_regeneratingColumns.Clear();

for (int x = 0; x < _mapProvider.Map.Width / Chunk.ChunkSize; x++)
{
for (var z = 0; z < _mapProvider.Map.Depth / Chunk.ChunkSize; z++)
{
_regeneratingColumns.Enqueue((x, z));
}
}
}

private void Update()
{
if (_mapProvider.Map == null)
{
return;
}

for (var i = 0; i < Math.Min(_regeneratingColumns.Count, ColumnPerFrame); i++)
{
(int x, int z) = _regeneratingColumns.Dequeue();
RefreshChunkColumn(x, z);
}
}

private void RefreshChunkColumn(int x, int z)
{
computeShader.SetBuffer(_clearHeightKernel, HeightBuffer, _heightBuffer);
computeShader.Dispatch(_clearHeightKernel, Chunk.ChunkSize / 8, Chunk.ChunkSize / 8, 1);

for (var y = 0; y < _mapProvider.Map.Height / Chunk.ChunkSize; y++)
{
int chunkIndex = GetChunkIndex(x, y, z);
Chunk chunk = _mapProvider.Map.Chunks[chunkIndex];

if (chunk.Mesh.vertexCount == 0)
{
continue;
}

chunk.Mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
using GraphicsBuffer vertexBuffer = chunk.Mesh.GetVertexBuffer(0);

int quadCount = chunk.Mesh.vertexCount / 4;

computeShader.SetBuffer(_updateHeightKernel, VertexBuffer, vertexBuffer);
computeShader.SetBuffer(_updateHeightKernel, HeightBuffer, _heightBuffer);
computeShader.SetFloats(MeshPositionOffset, chunk.Position.x, chunk.Position.y, chunk.Position.z);
computeShader.Dispatch(_updateHeightKernel, Mathf.Max(1, quadCount / 16), 1, 1);

computeShader.SetBuffer(_updateChunkKernel, VertexBuffer, vertexBuffer);
computeShader.SetBuffer(_updateChunkKernel, HeightBuffer, _heightBuffer);
computeShader.SetTexture(_updateChunkKernel, MapTexture, MainTexture);
computeShader.SetFloats(MeshPositionOffset, chunk.Position.x, chunk.Position.y, chunk.Position.z);
computeShader.Dispatch(_updateChunkKernel, Mathf.Max(1, quadCount / 16), 1, 1);
}
}

private void OnChunkUpdated(Chunk chunk)
{
_regeneratingColumns.Enqueue((chunk.Position.x / Chunk.ChunkSize, chunk.Position.z / Chunk.ChunkSize));
}

private int GetChunkIndex(int x, int y, int z)
{
return x * (_mapProvider.Map.Height * _mapProvider.Map.Depth / Chunk.ChunkSizeSquared)
+ y * (_mapProvider.Map.Depth / Chunk.ChunkSize) + z;
}

private void OnDestroy()
{
_heightBuffer.Release();
MainTexture.Release();
}
}
}