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.
 
 
 
mapbox-sdk/Unity/MeshGeneration/Modifiers/MergedModifierStack.cs

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();
}
}
}