You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
8.2 KiB
287 lines
8.2 KiB
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
using Mapbox.Map;
|
|
using Mapbox.Unity.MeshGeneration.Modifiers;
|
|
using Mapbox.Unity.MeshGeneration.Data;
|
|
using Mapbox.Unity.MeshGeneration.Components;
|
|
|
|
namespace Mapbox.Unity.MeshGeneration.Modifiers
|
|
{
|
|
/// <summary>
|
|
/// Merged Modifier Stack, just like regular Modifier stack, creates a game object from features. But the difference is, regular modifier stack creates a game object for each given faeture meanwhile Merged Modifier Stack merges meshes and creates one game object for all features (until the 65k vertex limit).
|
|
/// It has extremely higher performance compared to regular modifier stack but since it merged all entities together, it also loses all individual entity data & makes it harder to interact with them.
|
|
/// It pools and merges objects based on the tile contains them.
|
|
/// </summary>
|
|
[CreateAssetMenu(menuName = "Mapbox/Modifiers/Merged Modifier Stack")]
|
|
public class MergedModifierStack : ModifierStackBase
|
|
{
|
|
private Dictionary<UnityTile, int> _cacheVertexCount = new Dictionary<UnityTile, int>();
|
|
private Dictionary<UnityTile, List<MeshData>> _cached = new Dictionary<UnityTile, List<MeshData>>();
|
|
private Dictionary<UnityTile, int> _buildingCount = new Dictionary<UnityTile, int>();
|
|
|
|
private Dictionary<UnityTile, List<VectorEntity>> _activeObjects = new Dictionary<UnityTile, List<VectorEntity>>();
|
|
private MeshData _tempMeshData;
|
|
private MeshFilter _tempMeshFilter;
|
|
private GameObject _tempGameObject;
|
|
private VectorEntity _tempVectorEntity;
|
|
private MeshData _temp2MeshData;
|
|
private ObjectPool<VectorEntity> _pool;
|
|
private ObjectPool<List<VectorEntity>> _listPool;
|
|
private ObjectPool<List<MeshData>> _meshDataPool;
|
|
|
|
private int _counter, _counter2;
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
//we'll use this to concat building data until it reaches 65000 verts
|
|
_pool = new ObjectPool<VectorEntity>(() =>
|
|
{
|
|
_tempGameObject = new GameObject();
|
|
_tempMeshFilter = _tempGameObject.AddComponent<MeshFilter>();
|
|
_tempMeshFilter.sharedMesh = new Mesh();
|
|
_tempVectorEntity = new VectorEntity()
|
|
{
|
|
GameObject = _tempGameObject,
|
|
Transform = _tempGameObject.transform,
|
|
MeshFilter = _tempMeshFilter,
|
|
MeshRenderer = _tempGameObject.AddComponent<MeshRenderer>(),
|
|
Mesh = _tempMeshFilter.sharedMesh
|
|
};
|
|
return _tempVectorEntity;
|
|
});
|
|
_listPool = new ObjectPool<List<VectorEntity>>(() => { return new List<VectorEntity>(); });
|
|
_meshDataPool = new ObjectPool<List<MeshData>>(() => { return new List<MeshData>(); });
|
|
_tempMeshData = new MeshData();
|
|
}
|
|
|
|
public override void OnUnregisterTile(UnityTile tile)
|
|
{
|
|
//removing all caches
|
|
if (_activeObjects.ContainsKey(tile))
|
|
{
|
|
_counter = _activeObjects[tile].Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
if (null != _activeObjects[tile][i].GameObject)
|
|
{
|
|
_activeObjects[tile][i].GameObject.SetActive(false);
|
|
}
|
|
_pool.Put(_activeObjects[tile][i]);
|
|
}
|
|
_activeObjects[tile].Clear();
|
|
//pooling these lists as they'll reused anyway, saving hundreds of list instantiations
|
|
_listPool.Put(_activeObjects[tile]);
|
|
_activeObjects.Remove(tile);
|
|
}
|
|
|
|
//reset all counters
|
|
if (_cacheVertexCount.ContainsKey(tile))
|
|
{
|
|
_cacheVertexCount.Remove(tile);
|
|
}
|
|
if (_cached.ContainsKey(tile))
|
|
{
|
|
_cached[tile].Clear();
|
|
_meshDataPool.Put(_cached[tile]);
|
|
_cached.Remove(tile);
|
|
}
|
|
if (_buildingCount.ContainsKey(tile))
|
|
{
|
|
_buildingCount.Remove(tile);
|
|
}
|
|
}
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
//init is also used for reloading map/ location change, so reseting everything here
|
|
_cacheVertexCount.Clear();
|
|
_cached.Clear();
|
|
_buildingCount.Clear();
|
|
_pool.Clear();
|
|
|
|
_counter = MeshModifiers.Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
MeshModifiers[i].Initialize();
|
|
}
|
|
|
|
_counter = GoModifiers.Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
GoModifiers[i].Initialize();
|
|
}
|
|
}
|
|
|
|
public override GameObject Execute(UnityTile tile, VectorFeatureUnity feature, MeshData meshData, GameObject parent = null, string type = "")
|
|
{
|
|
base.Execute(tile, feature, meshData, parent, type);
|
|
|
|
if (!_cacheVertexCount.ContainsKey(tile))
|
|
{
|
|
_cacheVertexCount.Add(tile, 0);
|
|
_cached.Add(tile, _meshDataPool.GetObject());
|
|
_buildingCount.Add(tile, 0);
|
|
}
|
|
|
|
_buildingCount[tile]++;
|
|
_counter = MeshModifiers.Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
if (MeshModifiers[i] != null && MeshModifiers[i].Active)
|
|
{
|
|
MeshModifiers[i].Run(feature, meshData, tile);
|
|
}
|
|
}
|
|
|
|
GameObject go = null;
|
|
//65000 is the vertex limit for meshes, keep stashing it until that
|
|
_counter = meshData.Vertices.Count;
|
|
if (_cacheVertexCount[tile] + _counter < 65000)
|
|
{
|
|
_cacheVertexCount[tile] += _counter;
|
|
_cached[tile].Add(meshData);
|
|
}
|
|
else
|
|
{
|
|
go = End(tile, parent, type);
|
|
}
|
|
|
|
return go;
|
|
}
|
|
|
|
|
|
public GameObject End(UnityTile tile, GameObject parent, string name = "")
|
|
{
|
|
var c2 = 0;
|
|
if (_cached.ContainsKey(tile))
|
|
{
|
|
_tempMeshData.Clear();
|
|
|
|
//concat mesh data into _tempMeshData
|
|
_counter = _cached[tile].Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
_temp2MeshData = _cached[tile][i];
|
|
if (_temp2MeshData.Vertices.Count <= 3)
|
|
continue;
|
|
|
|
var st = _tempMeshData.Vertices.Count;
|
|
_tempMeshData.Vertices.AddRange(_temp2MeshData.Vertices);
|
|
_tempMeshData.Normals.AddRange(_temp2MeshData.Normals);
|
|
|
|
c2 = _temp2MeshData.UV.Count;
|
|
for (int j = 0; j < c2; j++)
|
|
{
|
|
if (_tempMeshData.UV.Count <= j)
|
|
{
|
|
_tempMeshData.UV.Add(new List<Vector2>(_temp2MeshData.UV[j].Count));
|
|
}
|
|
}
|
|
|
|
c2 = _temp2MeshData.UV.Count;
|
|
for (int j = 0; j < c2; j++)
|
|
{
|
|
_tempMeshData.UV[j].AddRange(_temp2MeshData.UV[j]);
|
|
}
|
|
|
|
c2 = _temp2MeshData.Triangles.Count;
|
|
for (int j = 0; j < c2; j++)
|
|
{
|
|
if (_tempMeshData.Triangles.Count <= j)
|
|
{
|
|
_tempMeshData.Triangles.Add(new List<int>(_temp2MeshData.Triangles[j].Count));
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < c2; j++)
|
|
{
|
|
for (int k = 0; k < _temp2MeshData.Triangles[j].Count; k++)
|
|
{
|
|
_tempMeshData.Triangles[j].Add(_temp2MeshData.Triangles[j][k] + st);
|
|
}
|
|
}
|
|
}
|
|
|
|
//update pooled vector entity with new data
|
|
if (_tempMeshData.Vertices.Count > 3)
|
|
{
|
|
_cached[tile].Clear();
|
|
_cacheVertexCount[tile] = 0;
|
|
_tempVectorEntity = null;
|
|
_tempVectorEntity = _pool.GetObject();
|
|
_tempVectorEntity.GameObject.SetActive(true);
|
|
_tempVectorEntity.Mesh.Clear();
|
|
|
|
_tempVectorEntity.GameObject.name = name;
|
|
_tempVectorEntity.Mesh.subMeshCount = _tempMeshData.Triangles.Count;
|
|
_tempVectorEntity.Mesh.SetVertices(_tempMeshData.Vertices);
|
|
_tempVectorEntity.Mesh.SetNormals(_tempMeshData.Normals);
|
|
|
|
_counter = _tempMeshData.Triangles.Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
_tempVectorEntity.Mesh.SetTriangles(_tempMeshData.Triangles[i], i);
|
|
}
|
|
|
|
_counter = _tempMeshData.UV.Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
_tempVectorEntity.Mesh.SetUVs(i, _tempMeshData.UV[i]);
|
|
}
|
|
|
|
_tempVectorEntity.GameObject.transform.SetParent(tile.transform, false);
|
|
|
|
if (!_activeObjects.ContainsKey(tile))
|
|
{
|
|
_activeObjects.Add(tile, _listPool.GetObject());
|
|
}
|
|
_activeObjects[tile].Add(_tempVectorEntity);
|
|
|
|
_counter = GoModifiers.Count;
|
|
for (int i = 0; i < _counter; i++)
|
|
{
|
|
if (GoModifiers[i].Active)
|
|
{
|
|
GoModifiers[i].Run(_tempVectorEntity, tile);
|
|
}
|
|
}
|
|
|
|
return _tempVectorEntity.GameObject;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override void Clear()
|
|
{
|
|
foreach (var vectorEntity in _pool.GetQueue())
|
|
{
|
|
if (vectorEntity.Mesh != null)
|
|
{
|
|
vectorEntity.Mesh.Destroy(true);
|
|
}
|
|
|
|
vectorEntity.GameObject.Destroy();
|
|
}
|
|
|
|
foreach (var tileTuple in _activeObjects)
|
|
{
|
|
foreach (var vectorEntity in tileTuple.Value)
|
|
{
|
|
if (vectorEntity.Mesh != null)
|
|
{
|
|
vectorEntity.Mesh.Destroy(true);
|
|
|
|
}
|
|
vectorEntity.GameObject.Destroy();
|
|
}
|
|
}
|
|
_pool.Clear();
|
|
_activeObjects.Clear();
|
|
_pool.Clear();
|
|
}
|
|
}
|
|
}
|
|
|