** DANGER someone should stress test more ** release unused physics meshs, including unmanaged memory allocations (allocated by managed code)
parent
307c45af2a
commit
36a1248b31
|
@ -37,6 +37,8 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
|
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
|
||||||
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
|
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
|
||||||
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical,bool convex);
|
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical,bool convex);
|
||||||
|
void ReleaseMesh(IMesh mesh);
|
||||||
|
void ExpireReleaseMeshs();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values for level of detail to be passed to the mesher.
|
// Values for level of detail to be passed to the mesher.
|
||||||
|
|
|
@ -79,5 +79,7 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
public void ReleaseMesh(IMesh mesh) { }
|
||||||
|
public void ExpireReleaseMeshs() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -763,5 +763,7 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
public void ReleaseMesh(IMesh imesh) { }
|
||||||
|
public void ExpireReleaseMeshs() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,8 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
IntPtr m_indicesPtr = IntPtr.Zero;
|
IntPtr m_indicesPtr = IntPtr.Zero;
|
||||||
int m_indexCount = 0;
|
int m_indexCount = 0;
|
||||||
public float[] m_normals;
|
public float[] m_normals;
|
||||||
Vector3 _centroid;
|
Vector3 m_centroid;
|
||||||
int _centroidDiv;
|
int m_centroidDiv;
|
||||||
|
|
||||||
private class vertexcomp : IEqualityComparer<Vertex>
|
private class vertexcomp : IEqualityComparer<Vertex>
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,6 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
int c = v.Z.GetHashCode();
|
int c = v.Z.GetHashCode();
|
||||||
return (a << 16) ^ (b << 8) ^ c;
|
return (a << 16) ^ (b << 8) ^ c;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mesh()
|
public Mesh()
|
||||||
|
@ -74,8 +73,18 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
|
|
||||||
m_vertices = new Dictionary<Vertex, int>(vcomp);
|
m_vertices = new Dictionary<Vertex, int>(vcomp);
|
||||||
m_triangles = new List<Triangle>();
|
m_triangles = new List<Triangle>();
|
||||||
_centroid = Vector3.Zero;
|
m_centroid = Vector3.Zero;
|
||||||
_centroidDiv = 0;
|
m_centroidDiv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int RefCount { get; set; }
|
||||||
|
|
||||||
|
public ulong Key { get; set; }
|
||||||
|
|
||||||
|
public void Scale(Vector3 scale)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mesh Clone()
|
public Mesh Clone()
|
||||||
|
@ -86,8 +95,8 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
{
|
{
|
||||||
result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
|
result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
|
||||||
}
|
}
|
||||||
result._centroid = _centroid;
|
result.m_centroid = m_centroid;
|
||||||
result._centroidDiv = _centroidDiv;
|
result.m_centroidDiv = m_centroidDiv;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,41 +118,41 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
|
|
||||||
if (m_vertices.Count == 0)
|
if (m_vertices.Count == 0)
|
||||||
{
|
{
|
||||||
_centroidDiv = 0;
|
m_centroidDiv = 0;
|
||||||
_centroid = Vector3.Zero;
|
m_centroid = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_vertices.ContainsKey(triangle.v1))
|
if (!m_vertices.ContainsKey(triangle.v1))
|
||||||
{
|
{
|
||||||
m_vertices[triangle.v1] = m_vertices.Count;
|
m_vertices[triangle.v1] = m_vertices.Count;
|
||||||
_centroid.X += triangle.v1.X;
|
m_centroid.X += triangle.v1.X;
|
||||||
_centroid.Y += triangle.v1.Y;
|
m_centroid.Y += triangle.v1.Y;
|
||||||
_centroid.Z += triangle.v1.Z;
|
m_centroid.Z += triangle.v1.Z;
|
||||||
_centroidDiv++;
|
m_centroidDiv++;
|
||||||
}
|
}
|
||||||
if (!m_vertices.ContainsKey(triangle.v2))
|
if (!m_vertices.ContainsKey(triangle.v2))
|
||||||
{
|
{
|
||||||
m_vertices[triangle.v2] = m_vertices.Count;
|
m_vertices[triangle.v2] = m_vertices.Count;
|
||||||
_centroid.X += triangle.v2.X;
|
m_centroid.X += triangle.v2.X;
|
||||||
_centroid.Y += triangle.v2.Y;
|
m_centroid.Y += triangle.v2.Y;
|
||||||
_centroid.Z += triangle.v2.Z;
|
m_centroid.Z += triangle.v2.Z;
|
||||||
_centroidDiv++;
|
m_centroidDiv++;
|
||||||
}
|
}
|
||||||
if (!m_vertices.ContainsKey(triangle.v3))
|
if (!m_vertices.ContainsKey(triangle.v3))
|
||||||
{
|
{
|
||||||
m_vertices[triangle.v3] = m_vertices.Count;
|
m_vertices[triangle.v3] = m_vertices.Count;
|
||||||
_centroid.X += triangle.v3.X;
|
m_centroid.X += triangle.v3.X;
|
||||||
_centroid.Y += triangle.v3.Y;
|
m_centroid.Y += triangle.v3.Y;
|
||||||
_centroid.Z += triangle.v3.Z;
|
m_centroid.Z += triangle.v3.Z;
|
||||||
_centroidDiv++;
|
m_centroidDiv++;
|
||||||
}
|
}
|
||||||
m_triangles.Add(triangle);
|
m_triangles.Add(triangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetCentroid()
|
public Vector3 GetCentroid()
|
||||||
{
|
{
|
||||||
if (_centroidDiv > 0)
|
if (m_centroidDiv > 0)
|
||||||
return new Vector3(_centroid.X / _centroidDiv, _centroid.Y / _centroidDiv, _centroid.Z / _centroidDiv);
|
return new Vector3(m_centroid.X / m_centroidDiv, m_centroid.Y / m_centroidDiv, m_centroid.Z / m_centroidDiv);
|
||||||
else
|
else
|
||||||
return Vector3.Zero;
|
return Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
|
private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
|
||||||
|
|
||||||
private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
|
private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
|
||||||
|
private Dictionary<ulong, Mesh> m_uniqueReleasedMeshes = new Dictionary<ulong, Mesh>();
|
||||||
|
|
||||||
public Meshmerizer(IConfigSource config)
|
public Meshmerizer(IConfigSource config)
|
||||||
{
|
{
|
||||||
|
@ -986,6 +987,8 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
return CreateMesh(primName, primShape, size, lod, false,false);
|
return CreateMesh(primName, primShape, size, lod, false,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Vector3 m_MeshUnitSize = new Vector3(0.5f, 0.5f, 0.5f);
|
||||||
|
|
||||||
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
|
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
|
||||||
{
|
{
|
||||||
#if SPAM
|
#if SPAM
|
||||||
|
@ -995,17 +998,60 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
Mesh mesh = null;
|
Mesh mesh = null;
|
||||||
ulong key = 0;
|
ulong key = 0;
|
||||||
|
|
||||||
// If this mesh has been created already, return it instead of creating another copy
|
|
||||||
// For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
|
|
||||||
key = primShape.GetMeshKey(size, lod, convex);
|
|
||||||
if (m_uniqueMeshes.TryGetValue(key, out mesh))
|
|
||||||
return mesh;
|
|
||||||
|
|
||||||
if (size.X < 0.01f) size.X = 0.01f;
|
if (size.X < 0.01f) size.X = 0.01f;
|
||||||
if (size.Y < 0.01f) size.Y = 0.01f;
|
if (size.Y < 0.01f) size.Y = 0.01f;
|
||||||
if (size.Z < 0.01f) size.Z = 0.01f;
|
if (size.Z < 0.01f) size.Z = 0.01f;
|
||||||
|
|
||||||
|
// try to find a identical mesh on meshs in use
|
||||||
|
key = primShape.GetMeshKey(size, lod, convex);
|
||||||
|
|
||||||
|
lock (m_uniqueMeshes)
|
||||||
|
{
|
||||||
|
m_uniqueMeshes.TryGetValue(key, out mesh);
|
||||||
|
|
||||||
|
if (mesh != null)
|
||||||
|
{
|
||||||
|
mesh.RefCount++;
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to find a identical mesh on meshs recently released
|
||||||
|
lock (m_uniqueReleasedMeshes)
|
||||||
|
{
|
||||||
|
m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
|
||||||
|
if (mesh != null)
|
||||||
|
{
|
||||||
|
m_uniqueReleasedMeshes.Remove(key);
|
||||||
|
lock (m_uniqueMeshes)
|
||||||
|
m_uniqueMeshes.Add(key, mesh);
|
||||||
|
mesh.RefCount = 1;
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Mesh UnitSizeMesh = null;
|
||||||
|
ulong unitsizekey = 0;
|
||||||
|
|
||||||
|
unitsizekey = primShape.GetMeshKey(m_MeshUnitSize, lod, convex);
|
||||||
|
|
||||||
|
lock(m_uniqueMeshes)
|
||||||
|
m_uniqueMeshes.TryGetValue(unitsizekey, out UnitSizeMesh);
|
||||||
|
|
||||||
|
if (UnitSizeMesh !=null)
|
||||||
|
{
|
||||||
|
UnitSizeMesh.RefCount++;
|
||||||
|
mesh = UnitSizeMesh.Clone();
|
||||||
|
mesh.Key = key;
|
||||||
|
mesh.Scale(size);
|
||||||
|
mesh.RefCount++;
|
||||||
|
lock(m_uniqueMeshes)
|
||||||
|
m_uniqueMeshes.Add(key, mesh);
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
*/
|
||||||
mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod,convex);
|
mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod,convex);
|
||||||
|
// mesh.Key = unitsizekey;
|
||||||
|
|
||||||
if (mesh != null)
|
if (mesh != null)
|
||||||
{
|
{
|
||||||
|
@ -1021,11 +1067,68 @@ namespace OpenSim.Region.Physics.Meshing
|
||||||
|
|
||||||
// trim the vertex and triangle lists to free up memory
|
// trim the vertex and triangle lists to free up memory
|
||||||
mesh.TrimExcess();
|
mesh.TrimExcess();
|
||||||
|
mesh.Key = key;
|
||||||
|
mesh.RefCount++;
|
||||||
|
|
||||||
m_uniqueMeshes.Add(key, mesh);
|
lock(m_uniqueMeshes)
|
||||||
|
m_uniqueMeshes.Add(key, mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ReleaseMesh(IMesh imesh)
|
||||||
|
{
|
||||||
|
if (imesh == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Mesh mesh = (Mesh)imesh;
|
||||||
|
|
||||||
|
int curRefCount = mesh.RefCount;
|
||||||
|
curRefCount--;
|
||||||
|
|
||||||
|
if (curRefCount > 0)
|
||||||
|
{
|
||||||
|
mesh.RefCount = curRefCount;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (m_uniqueMeshes)
|
||||||
|
{
|
||||||
|
mesh.RefCount = 0;
|
||||||
|
m_uniqueMeshes.Remove(mesh.Key);
|
||||||
|
lock (m_uniqueReleasedMeshes)
|
||||||
|
m_uniqueReleasedMeshes.Add(mesh.Key, mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExpireReleaseMeshs()
|
||||||
|
{
|
||||||
|
if (m_uniqueMeshes.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<Mesh> meshstodelete = new List<Mesh>();
|
||||||
|
int refcntr;
|
||||||
|
|
||||||
|
lock (m_uniqueReleasedMeshes)
|
||||||
|
{
|
||||||
|
foreach (Mesh m in m_uniqueReleasedMeshes.Values)
|
||||||
|
{
|
||||||
|
refcntr = m.RefCount;
|
||||||
|
refcntr--;
|
||||||
|
if (refcntr > -6)
|
||||||
|
m.RefCount = refcntr;
|
||||||
|
else
|
||||||
|
meshstodelete.Add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Mesh m in meshstodelete)
|
||||||
|
{
|
||||||
|
m_uniqueReleasedMeshes.Remove(m.Key);
|
||||||
|
m.releaseSourceMeshData();
|
||||||
|
m.releasePinned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ using OdeAPI;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Physics.Manager;
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.OdePlugin
|
namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
public class OdePrim : PhysicsActor
|
public class OdePrim : PhysicsActor
|
||||||
|
@ -538,24 +537,6 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
IMesh mesh = null;
|
|
||||||
if (_parent_scene.needsMeshing(value))
|
|
||||||
{
|
|
||||||
bool convex;
|
|
||||||
if (m_shapetype == 0)
|
|
||||||
convex = false;
|
|
||||||
else
|
|
||||||
convex = true;
|
|
||||||
mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, (int)LevelOfDetail.High, true, convex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mesh != null)
|
|
||||||
{
|
|
||||||
lock (m_meshlock)
|
|
||||||
m_mesh = mesh;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
AddChange(changes.Shape, value);
|
AddChange(changes.Shape, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1357,7 +1338,6 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
|
|
||||||
IMesh mesh = null;
|
IMesh mesh = null;
|
||||||
|
|
||||||
|
|
||||||
lock (m_meshlock)
|
lock (m_meshlock)
|
||||||
{
|
{
|
||||||
if (m_mesh == null)
|
if (m_mesh == null)
|
||||||
|
@ -1403,7 +1383,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
hasOOBoffsetFromMesh = true;
|
hasOOBoffsetFromMesh = true;
|
||||||
|
|
||||||
mesh.releaseSourceMeshData();
|
mesh.releaseSourceMeshData();
|
||||||
m_mesh = null;
|
m_mesh = mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr geo = IntPtr.Zero;
|
IntPtr geo = IntPtr.Zero;
|
||||||
|
@ -1545,7 +1525,10 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
d.GeomTriMeshDataDestroy(_triMeshData);
|
d.GeomTriMeshDataDestroy(_triMeshData);
|
||||||
_triMeshData = IntPtr.Zero;
|
_triMeshData = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// catch (System.AccessViolationException)
|
// catch (System.AccessViolationException)
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -1559,6 +1542,13 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction BAD {0}", Name);
|
m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction BAD {0}", Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_mesh != null)
|
||||||
|
{
|
||||||
|
_parent_scene.mesher.ReleaseMesh(m_mesh);
|
||||||
|
m_mesh = null;
|
||||||
|
}
|
||||||
|
|
||||||
Body = IntPtr.Zero;
|
Body = IntPtr.Zero;
|
||||||
hasOOBoffsetFromMesh = false;
|
hasOOBoffsetFromMesh = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,8 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
private float metersInSpace = 25.6f;
|
private float metersInSpace = 25.6f;
|
||||||
private float m_timeDilation = 1.0f;
|
private float m_timeDilation = 1.0f;
|
||||||
|
|
||||||
DateTime m_lastframe;
|
private DateTime m_lastframe;
|
||||||
|
private DateTime m_lastMeshExpire;
|
||||||
|
|
||||||
public float gravityx = 0f;
|
public float gravityx = 0f;
|
||||||
public float gravityy = 0f;
|
public float gravityy = 0f;
|
||||||
|
@ -203,6 +204,8 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
private float waterlevel = 0f;
|
private float waterlevel = 0f;
|
||||||
private int framecount = 0;
|
private int framecount = 0;
|
||||||
|
|
||||||
|
private int m_meshExpireCntr;
|
||||||
|
|
||||||
// private IntPtr WaterGeom = IntPtr.Zero;
|
// private IntPtr WaterGeom = IntPtr.Zero;
|
||||||
// private IntPtr WaterHeightmapData = IntPtr.Zero;
|
// private IntPtr WaterHeightmapData = IntPtr.Zero;
|
||||||
// private GCHandle WaterMapHandler = new GCHandle();
|
// private GCHandle WaterMapHandler = new GCHandle();
|
||||||
|
@ -263,7 +266,6 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
const int maxContactsbeforedeath = 4000;
|
const int maxContactsbeforedeath = 4000;
|
||||||
private volatile int m_global_contactcount = 0;
|
private volatile int m_global_contactcount = 0;
|
||||||
|
|
||||||
|
|
||||||
private IntPtr contactgroup;
|
private IntPtr contactgroup;
|
||||||
|
|
||||||
public ContactData[] m_materialContactsData = new ContactData[8];
|
public ContactData[] m_materialContactsData = new ContactData[8];
|
||||||
|
@ -594,6 +596,7 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
m_lastframe = DateTime.UtcNow;
|
m_lastframe = DateTime.UtcNow;
|
||||||
|
m_lastMeshExpire = m_lastframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void waitForSpaceUnlock(IntPtr space)
|
internal void waitForSpaceUnlock(IntPtr space)
|
||||||
|
@ -1768,9 +1771,9 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
{
|
{
|
||||||
|
|
||||||
DateTime now = DateTime.UtcNow;
|
DateTime now = DateTime.UtcNow;
|
||||||
TimeSpan SinceLastFrame = now - m_lastframe;
|
TimeSpan timedif = now - m_lastframe;
|
||||||
m_lastframe = now;
|
m_lastframe = now;
|
||||||
timeStep = (float)SinceLastFrame.TotalSeconds;
|
timeStep = (float)timedif.TotalSeconds;
|
||||||
|
|
||||||
// acumulate time so we can reduce error
|
// acumulate time so we can reduce error
|
||||||
step_time += timeStep;
|
step_time += timeStep;
|
||||||
|
@ -1972,6 +1975,14 @@ namespace OpenSim.Region.Physics.OdePlugin
|
||||||
_badCharacter.Clear();
|
_badCharacter.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timedif = now - m_lastMeshExpire;
|
||||||
|
|
||||||
|
if (timedif.Seconds > 10)
|
||||||
|
{
|
||||||
|
mesher.ExpireReleaseMeshs();
|
||||||
|
m_lastMeshExpire = now;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
|
int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
|
||||||
int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
|
int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);
|
||||||
|
|
Loading…
Reference in New Issue