110 lines
3.1 KiB
C#
110 lines
3.1 KiB
C#
using Cryville.EEW.Core.Map;
|
|
using Poly2Tri;
|
|
using System.Buffers;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using Color = UnityEngine.Color;
|
|
|
|
namespace Cryville.EEW.Unity.Map {
|
|
[RequireComponent(typeof(MeshFilter))]
|
|
[RequireComponent(typeof(MeshRenderer))]
|
|
class PolygonRenderer : MonoBehaviour {
|
|
Material _sharedMaterial;
|
|
public Material Material {
|
|
get => _meshRenderer.sharedMaterial;
|
|
set {
|
|
if (value == _sharedMaterial) return;
|
|
if (_sharedMaterial != null) Destroy(_meshRenderer.sharedMaterial);
|
|
_sharedMaterial = value;
|
|
if (_sharedMaterial == null) return;
|
|
_meshRenderer.sharedMaterial = Instantiate(_sharedMaterial);
|
|
_meshRenderer.sharedMaterial.color = m_color;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
Color m_color = Color.white;
|
|
public Color Color {
|
|
get => m_color;
|
|
set {
|
|
if (m_color == value) return;
|
|
m_color = value;
|
|
_meshRenderer.material.color = value;
|
|
}
|
|
}
|
|
|
|
Mesh _mesh;
|
|
MeshFilter _meshFilter;
|
|
MeshRenderer _meshRenderer;
|
|
void Awake() {
|
|
_meshFilter = GetComponent<MeshFilter>();
|
|
_meshRenderer = GetComponent<MeshRenderer>();
|
|
if (!_meshFilter.mesh) {
|
|
_meshFilter.mesh = new();
|
|
}
|
|
_mesh = _meshFilter.mesh;
|
|
if (_sharedMaterial == null && _meshRenderer.sharedMaterial != null) {
|
|
_sharedMaterial = _meshRenderer.sharedMaterial;
|
|
_meshRenderer.sharedMaterial = Instantiate(_sharedMaterial);
|
|
_meshRenderer.sharedMaterial.color = m_color;
|
|
}
|
|
}
|
|
void OnDestroy() {
|
|
Destroy(_mesh);
|
|
Destroy(Material);
|
|
}
|
|
public void SetPolygon(IEnumerable<IEnumerable<PointF>> polygon) {
|
|
_mesh.Clear();
|
|
|
|
Polygon convertedPolygon = null;
|
|
foreach (var loop in polygon) {
|
|
var convertedLoop = new Polygon(loop.Select(p => {
|
|
var v = MapTileUtils.WorldToTilePos(p).ToVector2();
|
|
return new PolygonPoint(v.x, v.y);
|
|
}));
|
|
if (convertedPolygon is null) {
|
|
convertedPolygon = convertedLoop;
|
|
}
|
|
else {
|
|
convertedPolygon.AddHole(convertedLoop);
|
|
}
|
|
}
|
|
|
|
var tcx = new DTSweepContext();
|
|
tcx.PrepareTriangulation(convertedPolygon);
|
|
DTSweep.Triangulate(tcx);
|
|
|
|
var codeToIndex = new Dictionary<uint, int>();
|
|
int vertexCount = convertedPolygon.Points.Count;
|
|
if (convertedPolygon.Holes != null) {
|
|
foreach (var hole in convertedPolygon.Holes) {
|
|
vertexCount += hole.Points.Count;
|
|
}
|
|
}
|
|
var vertices = ArrayPool<Vector3>.Shared.Rent(vertexCount);
|
|
var triangles = ArrayPool<int>.Shared.Rent(convertedPolygon.Triangles.Count * 3);
|
|
int vi = 0, ii = 0;
|
|
foreach (var tri in convertedPolygon.Triangles) {
|
|
for (int i = 2; i >= 0; --i) {
|
|
var p = tri.Points[i];
|
|
if (!codeToIndex.TryGetValue(p.VertexCode, out int index)) {
|
|
codeToIndex.Add(p.VertexCode, index = vi++);
|
|
vertices[index] = new(p.Xf, p.Yf);
|
|
}
|
|
triangles[ii++] = index;
|
|
}
|
|
}
|
|
|
|
_mesh.SetVertices(vertices, 0, vi);
|
|
_mesh.SetTriangles(triangles, 0, ii, 0);
|
|
_mesh.RecalculateNormals();
|
|
_mesh.RecalculateBounds();
|
|
|
|
ArrayPool<int>.Shared.Return(triangles);
|
|
ArrayPool<Vector3>.Shared.Return(vertices);
|
|
}
|
|
}
|
|
}
|