aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorUbitUmarov2012-08-06 09:06:46 +0100
committerUbitUmarov2012-08-06 09:06:46 +0100
commit36a1248b317cd80717fef6bc7c8fab318172a075 (patch)
treec81fc363cfc52d9b3faec5ccb0693f2173650bc0
parentbug fix: keep sculpt bitmaps border pixels during resolution scaling. (diff)
downloadopensim-SC_OLD-36a1248b317cd80717fef6bc7c8fab318172a075.zip
opensim-SC_OLD-36a1248b317cd80717fef6bc7c8fab318172a075.tar.gz
opensim-SC_OLD-36a1248b317cd80717fef6bc7c8fab318172a075.tar.bz2
opensim-SC_OLD-36a1248b317cd80717fef6bc7c8fab318172a075.tar.xz
** DANGER someone should stress test more ** release unused physics meshs, including unmanaged memory allocations (allocated by managed code)
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/ZeroMesher.cs2
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs2
-rw-r--r--OpenSim/Region/Physics/UbitMeshing/Mesh.cs55
-rw-r--r--OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs117
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs32
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs19
7 files changed, 174 insertions, 55 deletions
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
index c32cf38..19aa747 100644
--- a/OpenSim/Region/Physics/Manager/IMesher.cs
+++ b/OpenSim/Region/Physics/Manager/IMesher.cs
@@ -37,6 +37,8 @@ namespace OpenSim.Region.Physics.Manager
37 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); 37 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); 38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical,bool convex); 39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical,bool convex);
40 void ReleaseMesh(IMesh mesh);
41 void ExpireReleaseMeshs();
40 } 42 }
41 43
42 // Values for level of detail to be passed to the mesher. 44 // Values for level of detail to be passed to the mesher.
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
index 8a3b50b..f555cb9 100644
--- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs
+++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
@@ -79,5 +79,7 @@ namespace OpenSim.Region.Physics.Manager
79 79
80 return null; 80 return null;
81 } 81 }
82 public void ReleaseMesh(IMesh mesh) { }
83 public void ExpireReleaseMeshs() { }
82 } 84 }
83} 85}
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index 825b858..3c4f737 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -763,5 +763,7 @@ namespace OpenSim.Region.Physics.Meshing
763 763
764 return mesh; 764 return mesh;
765 } 765 }
766 public void ReleaseMesh(IMesh imesh) { }
767 public void ExpireReleaseMeshs() { }
766 } 768 }
767} 769}
diff --git a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs
index c715642..0727802 100644
--- a/OpenSim/Region/Physics/UbitMeshing/Mesh.cs
+++ b/OpenSim/Region/Physics/UbitMeshing/Mesh.cs
@@ -46,8 +46,8 @@ namespace OpenSim.Region.Physics.Meshing
46 IntPtr m_indicesPtr = IntPtr.Zero; 46 IntPtr m_indicesPtr = IntPtr.Zero;
47 int m_indexCount = 0; 47 int m_indexCount = 0;
48 public float[] m_normals; 48 public float[] m_normals;
49 Vector3 _centroid; 49 Vector3 m_centroid;
50 int _centroidDiv; 50 int m_centroidDiv;
51 51
52 private class vertexcomp : IEqualityComparer<Vertex> 52 private class vertexcomp : IEqualityComparer<Vertex>
53 { 53 {
@@ -65,7 +65,6 @@ namespace OpenSim.Region.Physics.Meshing
65 int c = v.Z.GetHashCode(); 65 int c = v.Z.GetHashCode();
66 return (a << 16) ^ (b << 8) ^ c; 66 return (a << 16) ^ (b << 8) ^ c;
67 } 67 }
68
69 } 68 }
70 69
71 public Mesh() 70 public Mesh()
@@ -74,8 +73,18 @@ namespace OpenSim.Region.Physics.Meshing
74 73
75 m_vertices = new Dictionary<Vertex, int>(vcomp); 74 m_vertices = new Dictionary<Vertex, int>(vcomp);
76 m_triangles = new List<Triangle>(); 75 m_triangles = new List<Triangle>();
77 _centroid = Vector3.Zero; 76 m_centroid = Vector3.Zero;
78 _centroidDiv = 0; 77 m_centroidDiv = 0;
78 }
79
80 public int RefCount { get; set; }
81
82 public ulong Key { get; set; }
83
84 public void Scale(Vector3 scale)
85 {
86
87
79 } 88 }
80 89
81 public Mesh Clone() 90 public Mesh Clone()
@@ -86,8 +95,8 @@ namespace OpenSim.Region.Physics.Meshing
86 { 95 {
87 result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); 96 result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
88 } 97 }
89 result._centroid = _centroid; 98 result.m_centroid = m_centroid;
90 result._centroidDiv = _centroidDiv; 99 result.m_centroidDiv = m_centroidDiv;
91 return result; 100 return result;
92 } 101 }
93 102
@@ -109,41 +118,41 @@ namespace OpenSim.Region.Physics.Meshing
109 118
110 if (m_vertices.Count == 0) 119 if (m_vertices.Count == 0)
111 { 120 {
112 _centroidDiv = 0; 121 m_centroidDiv = 0;
113 _centroid = Vector3.Zero; 122 m_centroid = Vector3.Zero;
114 } 123 }
115 124
116 if (!m_vertices.ContainsKey(triangle.v1)) 125 if (!m_vertices.ContainsKey(triangle.v1))
117 { 126 {
118 m_vertices[triangle.v1] = m_vertices.Count; 127 m_vertices[triangle.v1] = m_vertices.Count;
119 _centroid.X += triangle.v1.X; 128 m_centroid.X += triangle.v1.X;
120 _centroid.Y += triangle.v1.Y; 129 m_centroid.Y += triangle.v1.Y;
121 _centroid.Z += triangle.v1.Z; 130 m_centroid.Z += triangle.v1.Z;
122 _centroidDiv++; 131 m_centroidDiv++;
123 } 132 }
124 if (!m_vertices.ContainsKey(triangle.v2)) 133 if (!m_vertices.ContainsKey(triangle.v2))
125 { 134 {
126 m_vertices[triangle.v2] = m_vertices.Count; 135 m_vertices[triangle.v2] = m_vertices.Count;
127 _centroid.X += triangle.v2.X; 136 m_centroid.X += triangle.v2.X;
128 _centroid.Y += triangle.v2.Y; 137 m_centroid.Y += triangle.v2.Y;
129 _centroid.Z += triangle.v2.Z; 138 m_centroid.Z += triangle.v2.Z;
130 _centroidDiv++; 139 m_centroidDiv++;
131 } 140 }
132 if (!m_vertices.ContainsKey(triangle.v3)) 141 if (!m_vertices.ContainsKey(triangle.v3))
133 { 142 {
134 m_vertices[triangle.v3] = m_vertices.Count; 143 m_vertices[triangle.v3] = m_vertices.Count;
135 _centroid.X += triangle.v3.X; 144 m_centroid.X += triangle.v3.X;
136 _centroid.Y += triangle.v3.Y; 145 m_centroid.Y += triangle.v3.Y;
137 _centroid.Z += triangle.v3.Z; 146 m_centroid.Z += triangle.v3.Z;
138 _centroidDiv++; 147 m_centroidDiv++;
139 } 148 }
140 m_triangles.Add(triangle); 149 m_triangles.Add(triangle);
141 } 150 }
142 151
143 public Vector3 GetCentroid() 152 public Vector3 GetCentroid()
144 { 153 {
145 if (_centroidDiv > 0) 154 if (m_centroidDiv > 0)
146 return new Vector3(_centroid.X / _centroidDiv, _centroid.Y / _centroidDiv, _centroid.Z / _centroidDiv); 155 return new Vector3(m_centroid.X / m_centroidDiv, m_centroid.Y / m_centroidDiv, m_centroid.Z / m_centroidDiv);
147 else 156 else
148 return Vector3.Zero; 157 return Vector3.Zero;
149 } 158 }
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
index 3b1bdfb..a894e5f 100644
--- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
@@ -83,6 +83,7 @@ namespace OpenSim.Region.Physics.Meshing
83 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh 83 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
84 84
85 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); 85 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
86 private Dictionary<ulong, Mesh> m_uniqueReleasedMeshes = new Dictionary<ulong, Mesh>();
86 87
87 public Meshmerizer(IConfigSource config) 88 public Meshmerizer(IConfigSource config)
88 { 89 {
@@ -986,6 +987,8 @@ namespace OpenSim.Region.Physics.Meshing
986 return CreateMesh(primName, primShape, size, lod, false,false); 987 return CreateMesh(primName, primShape, size, lod, false,false);
987 } 988 }
988 989
990 private static Vector3 m_MeshUnitSize = new Vector3(0.5f, 0.5f, 0.5f);
991
989 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) 992 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
990 { 993 {
991#if SPAM 994#if SPAM
@@ -995,17 +998,60 @@ namespace OpenSim.Region.Physics.Meshing
995 Mesh mesh = null; 998 Mesh mesh = null;
996 ulong key = 0; 999 ulong key = 0;
997 1000
998 // If this mesh has been created already, return it instead of creating another copy
999 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
1000 key = primShape.GetMeshKey(size, lod, convex);
1001 if (m_uniqueMeshes.TryGetValue(key, out mesh))
1002 return mesh;
1003
1004 if (size.X < 0.01f) size.X = 0.01f; 1001 if (size.X < 0.01f) size.X = 0.01f;
1005 if (size.Y < 0.01f) size.Y = 0.01f; 1002 if (size.Y < 0.01f) size.Y = 0.01f;
1006 if (size.Z < 0.01f) size.Z = 0.01f; 1003 if (size.Z < 0.01f) size.Z = 0.01f;
1007 1004
1005 // try to find a identical mesh on meshs in use
1006 key = primShape.GetMeshKey(size, lod, convex);
1007
1008 lock (m_uniqueMeshes)
1009 {
1010 m_uniqueMeshes.TryGetValue(key, out mesh);
1011
1012 if (mesh != null)
1013 {
1014 mesh.RefCount++;
1015 return mesh;
1016 }
1017 }
1018
1019 // try to find a identical mesh on meshs recently released
1020 lock (m_uniqueReleasedMeshes)
1021 {
1022 m_uniqueReleasedMeshes.TryGetValue(key, out mesh);
1023 if (mesh != null)
1024 {
1025 m_uniqueReleasedMeshes.Remove(key);
1026 lock (m_uniqueMeshes)
1027 m_uniqueMeshes.Add(key, mesh);
1028 mesh.RefCount = 1;
1029 return mesh;
1030 }
1031 }
1032/*
1033 Mesh UnitSizeMesh = null;
1034 ulong unitsizekey = 0;
1035
1036 unitsizekey = primShape.GetMeshKey(m_MeshUnitSize, lod, convex);
1037
1038 lock(m_uniqueMeshes)
1039 m_uniqueMeshes.TryGetValue(unitsizekey, out UnitSizeMesh);
1040
1041 if (UnitSizeMesh !=null)
1042 {
1043 UnitSizeMesh.RefCount++;
1044 mesh = UnitSizeMesh.Clone();
1045 mesh.Key = key;
1046 mesh.Scale(size);
1047 mesh.RefCount++;
1048 lock(m_uniqueMeshes)
1049 m_uniqueMeshes.Add(key, mesh);
1050 return mesh;
1051 }
1052*/
1008 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod,convex); 1053 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod,convex);
1054// mesh.Key = unitsizekey;
1009 1055
1010 if (mesh != null) 1056 if (mesh != null)
1011 { 1057 {
@@ -1021,11 +1067,68 @@ namespace OpenSim.Region.Physics.Meshing
1021 1067
1022 // trim the vertex and triangle lists to free up memory 1068 // trim the vertex and triangle lists to free up memory
1023 mesh.TrimExcess(); 1069 mesh.TrimExcess();
1070 mesh.Key = key;
1071 mesh.RefCount++;
1024 1072
1025 m_uniqueMeshes.Add(key, mesh); 1073 lock(m_uniqueMeshes)
1074 m_uniqueMeshes.Add(key, mesh);
1026 } 1075 }
1027 1076
1028 return mesh; 1077 return mesh;
1029 } 1078 }
1079
1080 public void ReleaseMesh(IMesh imesh)
1081 {
1082 if (imesh == null)
1083 return;
1084
1085 Mesh mesh = (Mesh)imesh;
1086
1087 int curRefCount = mesh.RefCount;
1088 curRefCount--;
1089
1090 if (curRefCount > 0)
1091 {
1092 mesh.RefCount = curRefCount;
1093 return;
1094 }
1095
1096 lock (m_uniqueMeshes)
1097 {
1098 mesh.RefCount = 0;
1099 m_uniqueMeshes.Remove(mesh.Key);
1100 lock (m_uniqueReleasedMeshes)
1101 m_uniqueReleasedMeshes.Add(mesh.Key, mesh);
1102 }
1103 }
1104
1105 public void ExpireReleaseMeshs()
1106 {
1107 if (m_uniqueMeshes.Count == 0)
1108 return;
1109
1110 List<Mesh> meshstodelete = new List<Mesh>();
1111 int refcntr;
1112
1113 lock (m_uniqueReleasedMeshes)
1114 {
1115 foreach (Mesh m in m_uniqueReleasedMeshes.Values)
1116 {
1117 refcntr = m.RefCount;
1118 refcntr--;
1119 if (refcntr > -6)
1120 m.RefCount = refcntr;
1121 else
1122 meshstodelete.Add(m);
1123 }
1124
1125 foreach (Mesh m in meshstodelete)
1126 {
1127 m_uniqueReleasedMeshes.Remove(m.Key);
1128 m.releaseSourceMeshData();
1129 m.releasePinned();
1130 }
1131 }
1132 }
1030 } 1133 }
1031} 1134}
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
index a3534a4..fbc6134 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
@@ -57,7 +57,6 @@ using OdeAPI;
57using OpenSim.Framework; 57using OpenSim.Framework;
58using OpenSim.Region.Physics.Manager; 58using OpenSim.Region.Physics.Manager;
59 59
60
61namespace OpenSim.Region.Physics.OdePlugin 60namespace OpenSim.Region.Physics.OdePlugin
62{ 61{
63 public class OdePrim : PhysicsActor 62 public class OdePrim : PhysicsActor
@@ -538,24 +537,6 @@ namespace OpenSim.Region.Physics.OdePlugin
538 { 537 {
539 set 538 set
540 { 539 {
541/*
542 IMesh mesh = null;
543 if (_parent_scene.needsMeshing(value))
544 {
545 bool convex;
546 if (m_shapetype == 0)
547 convex = false;
548 else
549 convex = true;
550 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, (int)LevelOfDetail.High, true, convex);
551 }
552
553 if (mesh != null)
554 {
555 lock (m_meshlock)
556 m_mesh = mesh;
557 }
558*/
559 AddChange(changes.Shape, value); 540 AddChange(changes.Shape, value);
560 } 541 }
561 } 542 }
@@ -1357,7 +1338,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1357 1338
1358 IMesh mesh = null; 1339 IMesh mesh = null;
1359 1340
1360
1361 lock (m_meshlock) 1341 lock (m_meshlock)
1362 { 1342 {
1363 if (m_mesh == null) 1343 if (m_mesh == null)
@@ -1403,7 +1383,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1403 hasOOBoffsetFromMesh = true; 1383 hasOOBoffsetFromMesh = true;
1404 1384
1405 mesh.releaseSourceMeshData(); 1385 mesh.releaseSourceMeshData();
1406 m_mesh = null; 1386 m_mesh = mesh;
1407 } 1387 }
1408 1388
1409 IntPtr geo = IntPtr.Zero; 1389 IntPtr geo = IntPtr.Zero;
@@ -1545,7 +1525,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1545 d.GeomTriMeshDataDestroy(_triMeshData); 1525 d.GeomTriMeshDataDestroy(_triMeshData);
1546 _triMeshData = IntPtr.Zero; 1526 _triMeshData = IntPtr.Zero;
1547 } 1527 }
1528
1548 } 1529 }
1530
1531
1549 // catch (System.AccessViolationException) 1532 // catch (System.AccessViolationException)
1550 catch (Exception e) 1533 catch (Exception e)
1551 { 1534 {
@@ -1559,6 +1542,13 @@ namespace OpenSim.Region.Physics.OdePlugin
1559 { 1542 {
1560 m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction BAD {0}", Name); 1543 m_log.ErrorFormat("[PHYSICS]: PrimGeom destruction BAD {0}", Name);
1561 } 1544 }
1545
1546 if (m_mesh != null)
1547 {
1548 _parent_scene.mesher.ReleaseMesh(m_mesh);
1549 m_mesh = null;
1550 }
1551
1562 Body = IntPtr.Zero; 1552 Body = IntPtr.Zero;
1563 hasOOBoffsetFromMesh = false; 1553 hasOOBoffsetFromMesh = false;
1564 } 1554 }
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
index f3ac3ca..3ee5198 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
@@ -194,7 +194,8 @@ namespace OpenSim.Region.Physics.OdePlugin
194 private float metersInSpace = 25.6f; 194 private float metersInSpace = 25.6f;
195 private float m_timeDilation = 1.0f; 195 private float m_timeDilation = 1.0f;
196 196
197 DateTime m_lastframe; 197 private DateTime m_lastframe;
198 private DateTime m_lastMeshExpire;
198 199
199 public float gravityx = 0f; 200 public float gravityx = 0f;
200 public float gravityy = 0f; 201 public float gravityy = 0f;
@@ -203,6 +204,8 @@ namespace OpenSim.Region.Physics.OdePlugin
203 private float waterlevel = 0f; 204 private float waterlevel = 0f;
204 private int framecount = 0; 205 private int framecount = 0;
205 206
207 private int m_meshExpireCntr;
208
206// private IntPtr WaterGeom = IntPtr.Zero; 209// private IntPtr WaterGeom = IntPtr.Zero;
207// private IntPtr WaterHeightmapData = IntPtr.Zero; 210// private IntPtr WaterHeightmapData = IntPtr.Zero;
208// private GCHandle WaterMapHandler = new GCHandle(); 211// private GCHandle WaterMapHandler = new GCHandle();
@@ -263,7 +266,6 @@ namespace OpenSim.Region.Physics.OdePlugin
263 const int maxContactsbeforedeath = 4000; 266 const int maxContactsbeforedeath = 4000;
264 private volatile int m_global_contactcount = 0; 267 private volatile int m_global_contactcount = 0;
265 268
266
267 private IntPtr contactgroup; 269 private IntPtr contactgroup;
268 270
269 public ContactData[] m_materialContactsData = new ContactData[8]; 271 public ContactData[] m_materialContactsData = new ContactData[8];
@@ -594,6 +596,7 @@ namespace OpenSim.Region.Physics.OdePlugin
594 } 596 }
595 597
596 m_lastframe = DateTime.UtcNow; 598 m_lastframe = DateTime.UtcNow;
599 m_lastMeshExpire = m_lastframe;
597 } 600 }
598 601
599 internal void waitForSpaceUnlock(IntPtr space) 602 internal void waitForSpaceUnlock(IntPtr space)
@@ -1768,9 +1771,9 @@ namespace OpenSim.Region.Physics.OdePlugin
1768 { 1771 {
1769 1772
1770 DateTime now = DateTime.UtcNow; 1773 DateTime now = DateTime.UtcNow;
1771 TimeSpan SinceLastFrame = now - m_lastframe; 1774 TimeSpan timedif = now - m_lastframe;
1772 m_lastframe = now; 1775 m_lastframe = now;
1773 timeStep = (float)SinceLastFrame.TotalSeconds; 1776 timeStep = (float)timedif.TotalSeconds;
1774 1777
1775 // acumulate time so we can reduce error 1778 // acumulate time so we can reduce error
1776 step_time += timeStep; 1779 step_time += timeStep;
@@ -1972,6 +1975,14 @@ namespace OpenSim.Region.Physics.OdePlugin
1972 _badCharacter.Clear(); 1975 _badCharacter.Clear();
1973 } 1976 }
1974 } 1977 }
1978
1979 timedif = now - m_lastMeshExpire;
1980
1981 if (timedif.Seconds > 10)
1982 {
1983 mesher.ExpireReleaseMeshs();
1984 m_lastMeshExpire = now;
1985 }
1975/* 1986/*
1976 int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); 1987 int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace);
1977 int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); 1988 int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace);