JiNanCementPlantForUnity/Assets/3rdParty/Obi2/Scripts/Collisions/ColliderTrackers/Trackers3D/ObiMeshShapeTracker.cs

132 lines
3.0 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
namespace Obi{
public class ObiMeshShapeTracker : ObiShapeTracker
{
private class MeshDataHandles{
private int refCount = 1;
private GCHandle verticesHandle;
private GCHandle indicesHandle;
public int RefCount{
get{return refCount;}
}
public IntPtr VerticesAddress{
get{return verticesHandle.AddrOfPinnedObject();}
}
public IntPtr IndicesAddress{
get{return indicesHandle.AddrOfPinnedObject();}
}
public void FromMesh(Mesh mesh){
Oni.UnpinMemory(verticesHandle);
Oni.UnpinMemory(indicesHandle);
verticesHandle = Oni.PinMemory(mesh.vertices);
indicesHandle = Oni.PinMemory(mesh.triangles);
}
public void Ref(){
refCount++;
}
public void Unref(){
refCount--;
if (refCount <= 0){
refCount = 0;
Oni.UnpinMemory(verticesHandle);
Oni.UnpinMemory(indicesHandle);
}
}
}
private static Dictionary<Mesh,MeshDataHandles> meshDataCache = new Dictionary<Mesh,MeshDataHandles>();
private bool meshDataHasChanged = false;
private MeshDataHandles handles;
public ObiMeshShapeTracker(MeshCollider collider){
this.collider = collider;
adaptor.is2D = false;
oniShape = Oni.CreateShape(Oni.ShapeType.TriangleMesh);
UpdateMeshData();
}
/**
* Updates mesh data, in case the collider mesh had its vertices modified, or is an entirely different mesh.
*/
public void UpdateMeshData(){
MeshCollider meshCollider = collider as MeshCollider;
if (meshCollider != null){
Mesh mesh = meshCollider.sharedMesh;
// Decrease reference count of current handles:
if (handles != null)
handles.Unref();
MeshDataHandles newHandles;
// if handles do not exist for this mesh, create them:
if (!meshDataCache.TryGetValue(mesh,out newHandles)){
handles = new MeshDataHandles();
meshDataCache[mesh] = handles;
}
// if the handles already exist, increase their reference count and set them as the current handles.
else{
newHandles.Ref();
handles = newHandles;
}
// Update handles from mesh:
handles.FromMesh(meshCollider.sharedMesh);
meshDataHasChanged = true;
}
}
public override void UpdateIfNeeded (){
MeshCollider meshCollider = collider as MeshCollider;
if (meshCollider != null){
Mesh mesh = meshCollider.sharedMesh;
if (mesh != null && meshDataHasChanged){
meshDataHasChanged = false;
adaptor.Set(handles.VerticesAddress,handles.IndicesAddress,mesh.vertexCount,mesh.triangles.Length);
Oni.UpdateShape(oniShape,ref adaptor);
}
}
}
public override void Destroy(){
base.Destroy();
MeshCollider meshCollider = collider as MeshCollider;
if (meshCollider != null && handles != null){
handles.Unref(); // Decrease handles refcount.
if (handles.RefCount <= 0)
meshDataCache.Remove(meshCollider.sharedMesh);
}
}
}
}