aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorTeravus Ovares2009-04-10 23:26:42 +0000
committerTeravus Ovares2009-04-10 23:26:42 +0000
commit474b982eba66306c100b2cd00b6a49b76870afc4 (patch)
treeff07bcaab82a181f25e97ec6aa0da872bdc7c81b
parentAdd XmlRpcGridRouter, a module that communicates URIs for XMLRPC channels (diff)
downloadopensim-SC_OLD-474b982eba66306c100b2cd00b6a49b76870afc4.zip
opensim-SC_OLD-474b982eba66306c100b2cd00b6a49b76870afc4.tar.gz
opensim-SC_OLD-474b982eba66306c100b2cd00b6a49b76870afc4.tar.bz2
opensim-SC_OLD-474b982eba66306c100b2cd00b6a49b76870afc4.tar.xz
* Adds Physical/Active Linkset support to BulletDotNETPlugin
-rw-r--r--OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs376
1 files changed, 268 insertions, 108 deletions
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs
index bf44a0f..0f54a9f 100644
--- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs
+++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs
@@ -35,6 +35,7 @@ using OpenMetaverse;
35using BulletDotNET; 35using BulletDotNET;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Region.Physics.Manager; 37using OpenSim.Region.Physics.Manager;
38using OpenSim.Region.Physics.Meshing;
38 39
39namespace OpenSim.Region.Physics.BulletDotNETPlugin 40namespace OpenSim.Region.Physics.BulletDotNETPlugin
40{ 41{
@@ -325,12 +326,12 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
325 } 326 }
326 public override void link(PhysicsActor obj) 327 public override void link(PhysicsActor obj)
327 { 328 {
328 //TODO: 329 m_taintparent = obj;
329 } 330 }
330 331
331 public override void delink() 332 public override void delink()
332 { 333 {
333 //TODO: 334 m_taintparent = null;
334 } 335 }
335 336
336 public override void LockAngularMotion(PhysicsVector axis) 337 public override void LockAngularMotion(PhysicsVector axis)
@@ -729,6 +730,17 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
729 changeadd(timestep); 730 changeadd(timestep);
730 } 731 }
731 732
733 if (prim_geom == null)
734 {
735 CreateGeom(IntPtr.Zero, primMesh);
736
737 if (IsPhysical)
738 SetBody(Mass);
739 else
740 SetBody(0);
741 m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT");
742 }
743
732 if (prim_geom.Handle == IntPtr.Zero) 744 if (prim_geom.Handle == IntPtr.Zero)
733 { 745 {
734 CreateGeom(IntPtr.Zero, primMesh); 746 CreateGeom(IntPtr.Zero, primMesh);
@@ -953,24 +965,9 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
953 // TODO: dispose parts that make up body 965 // TODO: dispose parts that make up body
954 } 966 }
955 m_log.Debug("[PHYSICS]: _________ChangePhysics"); 967 m_log.Debug("[PHYSICS]: _________ChangePhysics");
956 if (_parent_scene.needsMeshing(_pbs))
957 {
958 // Don't need to re-enable body.. it's done in SetMesh
959 float meshlod = _parent_scene.meshSculptLOD;
960 968
961 if (IsPhysical) 969 ProcessGeomCreation();
962 meshlod = _parent_scene.MeshSculptphysicalLOD;
963 970
964 IMesh mesh = _parent_scene.mesher.CreateMesh(SOPName, _pbs, _size, meshlod, IsPhysical);
965 // createmesh returns null when it doesn't mesh.
966 CreateGeom(IntPtr.Zero, mesh);
967 }
968 else
969 {
970 _mesh = null;
971 CreateGeom(IntPtr.Zero, null);
972 }
973 SetCollisionShape(prim_geom);
974 if (m_isphysical) 971 if (m_isphysical)
975 SetBody(Mass); 972 SetBody(Mass);
976 else 973 else
@@ -981,6 +978,71 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
981 m_taintPhysics = m_isphysical; 978 m_taintPhysics = m_isphysical;
982 } 979 }
983 980
981
982
983 internal void ProcessGeomCreation()
984 {
985 if (_parent_scene.needsMeshing(_pbs))
986 {
987 ProcessGeomCreationAsTriMesh(PhysicsVector.Zero,Quaternion.Identity);
988 // createmesh returns null when it doesn't mesh.
989 CreateGeom(IntPtr.Zero, _mesh);
990 }
991 else
992 {
993 _mesh = null;
994 CreateGeom(IntPtr.Zero, null);
995 }
996 SetCollisionShape(prim_geom);
997 }
998
999 internal bool NeedsMeshing()
1000 {
1001 return _parent_scene.needsMeshing(_pbs);
1002 }
1003
1004 internal void ProcessGeomCreationAsTriMesh(PhysicsVector positionOffset, Quaternion orientation)
1005 {
1006 // Don't need to re-enable body.. it's done in SetMesh
1007 float meshlod = _parent_scene.meshSculptLOD;
1008
1009 if (IsPhysical)
1010 meshlod = _parent_scene.MeshSculptphysicalLOD;
1011
1012 IMesh mesh = _parent_scene.mesher.CreateMesh(SOPName, _pbs, _size, meshlod, IsPhysical);
1013 if (!positionOffset.IsIdentical(PhysicsVector.Zero,0.001f) || orientation != Quaternion.Identity)
1014 {
1015 if (mesh is Mesh)
1016 {
1017 float[] xyz = new float[3];
1018 xyz[0] = positionOffset.X;
1019 xyz[1] = positionOffset.Y;
1020 xyz[2] = positionOffset.Z;
1021
1022 Matrix4 m4 = Matrix4.CreateFromQuaternion(orientation);
1023
1024 float[,] matrix = new float[3,3];
1025
1026 matrix[0, 0] = m4.M11;
1027 matrix[0, 1] = m4.M12;
1028 matrix[0, 2] = m4.M13;
1029 matrix[1, 0] = m4.M21;
1030 matrix[1, 1] = m4.M22;
1031 matrix[1, 2] = m4.M23;
1032 matrix[2, 0] = m4.M31;
1033 matrix[2, 1] = m4.M32;
1034 matrix[2, 2] = m4.M33;
1035
1036 Mesh mesh2 = (Mesh) mesh;
1037 mesh2.TransformLinear(matrix, xyz);
1038 mesh = (IMesh)mesh2;
1039 }
1040
1041 }
1042
1043 _mesh = mesh;
1044 }
1045
984 private void changesize(float timestep) 1046 private void changesize(float timestep)
985 { 1047 {
986 if (Body != null) 1048 if (Body != null)
@@ -997,23 +1059,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
997 m_log.Debug("[PHYSICS]: _________ChangeSize"); 1059 m_log.Debug("[PHYSICS]: _________ChangeSize");
998 SetCollisionShape(null); 1060 SetCollisionShape(null);
999 // Construction of new prim 1061 // Construction of new prim
1000 if (_parent_scene.needsMeshing(_pbs)) 1062 ProcessGeomCreation();
1001 {
1002 // Don't need to re-enable body.. it's done in SetMesh
1003 float meshlod = _parent_scene.meshSculptLOD;
1004
1005 if (IsPhysical)
1006 meshlod = _parent_scene.MeshSculptphysicalLOD;
1007
1008 IMesh mesh = _parent_scene.mesher.CreateMesh(SOPName, _pbs, _size, meshlod, IsPhysical);
1009 // createmesh returns null when it doesn't mesh.
1010 CreateGeom(IntPtr.Zero, mesh);
1011 }
1012 else
1013 {
1014 _mesh = null;
1015 CreateGeom(IntPtr.Zero, null);
1016 }
1017 1063
1018 if (IsPhysical) 1064 if (IsPhysical)
1019 SetBody(Mass); 1065 SetBody(Mass);
@@ -1068,23 +1114,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1068 if (_size.Z <= 0) _size.Z = 0.01f; 1114 if (_size.Z <= 0) _size.Z = 0.01f;
1069 // Construction of new prim 1115 // Construction of new prim
1070 1116
1071 if (_parent_scene.needsMeshing(_pbs)) 1117 ProcessGeomCreation();
1072 {
1073 // Don't need to re-enable body.. it's done in SetMesh
1074 float meshlod = _parent_scene.meshSculptLOD;
1075
1076 if (IsPhysical)
1077 meshlod = _parent_scene.MeshSculptphysicalLOD;
1078 1118
1079 IMesh mesh = _parent_scene.mesher.CreateMesh(SOPName, _pbs, _size, meshlod, IsPhysical);
1080 // createmesh returns null when it doesn't mesh.
1081 CreateGeom(IntPtr.Zero, mesh);
1082 }
1083 else
1084 {
1085 _mesh = null;
1086 CreateGeom(IntPtr.Zero, null);
1087 }
1088 tempPosition1.setValue(_position.X, _position.Y, _position.Z); 1119 tempPosition1.setValue(_position.X, _position.Y, _position.Z);
1089 if (tempOrientation1.Handle != IntPtr.Zero) 1120 if (tempOrientation1.Handle != IntPtr.Zero)
1090 tempOrientation1.Dispose(); 1121 tempOrientation1.Dispose();
@@ -1262,7 +1293,52 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1262 1293
1263 private void changelink(float timestep) 1294 private void changelink(float timestep)
1264 { 1295 {
1265 // TODO: throw new NotImplementedException(); 1296 if (IsPhysical)
1297 {
1298 // Construction of new prim
1299 if (Body != null)
1300 {
1301 if (Body.Handle != IntPtr.Zero)
1302 {
1303 _parent_scene.removeFromWorld(this, Body);
1304 //Body.Dispose();
1305 }
1306 //Body = null;
1307 // TODO: dispose parts that make up body
1308 }
1309
1310 if (_parent == null && m_taintparent != null)
1311 {
1312
1313 if (m_taintparent is BulletDotNETPrim)
1314 {
1315 BulletDotNETPrim obj = (BulletDotNETPrim)m_taintparent;
1316 obj.ParentPrim(this);
1317 childPrim = true;
1318
1319 }
1320 }
1321 else if (_parent != null && m_taintparent == null)
1322 {
1323 if (_parent is BulletDotNETPrim)
1324 {
1325 BulletDotNETPrim obj = (BulletDotNETPrim)_parent;
1326 obj.ChildDelink(obj);
1327
1328 childPrim = false;
1329 }
1330 }
1331
1332 if (m_taintparent != null)
1333 {
1334 m_taintparent.Position.Z = m_taintparent.Position.Z + 0.02f;
1335 _parent_scene.AddPhysicsActorTaint(m_taintparent);
1336 }
1337 }
1338 _parent = m_taintparent;
1339
1340 m_taintPhysics = m_isphysical;
1341
1266 } 1342 }
1267 1343
1268 private void changefloatonwater(float timestep) 1344 private void changefloatonwater(float timestep)
@@ -1854,7 +1930,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1854 m_log.Debug("[PHYSICS]: _________CreateGeom"); 1930 m_log.Debug("[PHYSICS]: _________CreateGeom");
1855 if (p_mesh != null) 1931 if (p_mesh != null)
1856 { 1932 {
1857 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); 1933 //_mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1934 _mesh = p_mesh;
1858 setMesh(_parent_scene, _mesh); 1935 setMesh(_parent_scene, _mesh);
1859 1936
1860 } 1937 }
@@ -1867,12 +1944,16 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1867 if (((_size.X / 2f) > 0f)) 1944 if (((_size.X / 2f) > 0f))
1868 { 1945 {
1869 //SetGeom to a Regular Sphere 1946 //SetGeom to a Regular Sphere
1870 tempSize1.setValue(_size.X * 0.5f, _size.Y * 0.5f, _size.Z * 0.5f); 1947 if (tempSize1 == null)
1948 tempSize1 = new btVector3(0, 0, 0);
1949 tempSize1.setValue(_size.X * 0.5f,_size.Y * 0.5f, _size.Z * 0.5f);
1871 SetCollisionShape(new btSphereShape(_size.X*0.5f)); 1950 SetCollisionShape(new btSphereShape(_size.X*0.5f));
1872 } 1951 }
1873 else 1952 else
1874 { 1953 {
1875 // uses halfextents 1954 // uses halfextents
1955 if (tempSize1 == null)
1956 tempSize1 = new btVector3(0, 0, 0);
1876 tempSize1.setValue(_size.X*0.5f, _size.Y*0.5f, _size.Z*0.5f); 1957 tempSize1.setValue(_size.X*0.5f, _size.Y*0.5f, _size.Z*0.5f);
1877 SetCollisionShape(new btBoxShape(tempSize1)); 1958 SetCollisionShape(new btBoxShape(tempSize1));
1878 } 1959 }
@@ -1880,6 +1961,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1880 else 1961 else
1881 { 1962 {
1882 // uses halfextents 1963 // uses halfextents
1964 if (tempSize1 == null)
1965 tempSize1 = new btVector3(0, 0, 0);
1883 tempSize1.setValue(_size.X * 0.5f, _size.Y * 0.5f, _size.Z * 0.5f); 1966 tempSize1.setValue(_size.X * 0.5f, _size.Y * 0.5f, _size.Z * 0.5f);
1884 SetCollisionShape(new btBoxShape(tempSize1)); 1967 SetCollisionShape(new btBoxShape(tempSize1));
1885 } 1968 }
@@ -1887,6 +1970,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1887 } 1970 }
1888 else 1971 else
1889 { 1972 {
1973 if (tempSize1 == null)
1974 tempSize1 = new btVector3(0, 0, 0);
1890 // uses halfextents 1975 // uses halfextents
1891 tempSize1.setValue(_size.X * 0.5f, _size.Y * 0.5f, _size.Z * 0.5f); 1976 tempSize1.setValue(_size.X * 0.5f, _size.Y * 0.5f, _size.Z * 0.5f);
1892 SetCollisionShape(new btBoxShape(tempSize1)); 1977 SetCollisionShape(new btBoxShape(tempSize1));
@@ -1975,72 +2060,134 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
1975 2060
1976 public void SetBody(float mass) 2061 public void SetBody(float mass)
1977 { 2062 {
1978 //m_log.DebugFormat("[PHYSICS]: SetBody! {0}",mass); 2063
1979 /* 2064 if (!IsPhysical || childrenPrim.Count == 0)
1980 if (Body != null && Body.Handle != IntPtr.Zero)
1981 { 2065 {
1982 DisposeOfBody(); 2066 if (tempMotionState1 != null && tempMotionState1.Handle != IntPtr.Zero)
1983 } 2067 tempMotionState1.Dispose();
1984 */ 2068 if (tempTransform2 != null && tempTransform2.Handle != IntPtr.Zero)
1985 if (tempMotionState1 != null && tempMotionState1.Handle != IntPtr.Zero) 2069 tempTransform2.Dispose();
1986 tempMotionState1.Dispose(); 2070 if (tempOrientation2 != null && tempOrientation2.Handle != IntPtr.Zero)
1987 if (tempTransform2 != null && tempTransform2.Handle != IntPtr.Zero) 2071 tempOrientation2.Dispose();
1988 tempTransform2.Dispose();
1989 if (tempOrientation2 != null && tempOrientation2.Handle != IntPtr.Zero)
1990 tempOrientation2.Dispose();
1991 2072
1992 if (tempPosition2 != null && tempPosition2.Handle != IntPtr.Zero) 2073 if (tempPosition2 != null && tempPosition2.Handle != IntPtr.Zero)
1993 tempPosition2.Dispose(); 2074 tempPosition2.Dispose();
1994 2075
1995 tempOrientation2 = new btQuaternion(_orientation.X, _orientation.Y, _orientation.Z, _orientation.W); 2076 tempOrientation2 = new btQuaternion(_orientation.X, _orientation.Y, _orientation.Z, _orientation.W);
1996 tempPosition2 = new btVector3(_position.X, _position.Y, _position.Z); 2077 tempPosition2 = new btVector3(_position.X, _position.Y, _position.Z);
1997 tempTransform2 = new btTransform(tempOrientation2, tempPosition2); 2078 tempTransform2 = new btTransform(tempOrientation2, tempPosition2);
1998 tempMotionState1 = new btDefaultMotionState(tempTransform2, _parent_scene.TransZero); 2079 tempMotionState1 = new btDefaultMotionState(tempTransform2, _parent_scene.TransZero);
1999 if (tempInertia1 != null && tempInertia1.Handle != IntPtr.Zero) 2080 if (tempInertia1 != null && tempInertia1.Handle != IntPtr.Zero)
2000 tempInertia1.Dispose(); 2081 tempInertia1.Dispose();
2001 tempInertia1 = new btVector3(0, 0, 0); 2082 tempInertia1 = new btVector3(0, 0, 0);
2002 /*
2003 if (prim_geom.Handle == IntPtr.Zero)
2004 {
2005 m_log.Warn("[PHYSICS]:PrimGeom is Disposed!");
2006 if (_parent_scene.needsMeshing(_pbs))
2007 {
2008 // Don't need to re-enable body.. it's done in SetMesh
2009 float meshlod = _parent_scene.meshSculptLOD;
2010 2083
2011 if (IsPhysical)
2012 meshlod = _parent_scene.MeshSculptphysicalLOD;
2013 2084
2014 IMesh mesh = _parent_scene.mesher.CreateMesh(SOPName, _pbs, _size, meshlod, IsPhysical); 2085 prim_geom.calculateLocalInertia(mass, tempInertia1);
2015 // createmesh returns null when it doesn't mesh. 2086
2016 CreateGeom(IntPtr.Zero, mesh); 2087 if (mass != 0)
2017 } 2088 _parent_scene.addActivePrim(this);
2018 else 2089 else
2090 _parent_scene.remActivePrim(this);
2091
2092 // Body = new btRigidBody(mass, tempMotionState1, prim_geom);
2093 //else
2094 Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1);
2095
2096 if (prim_geom is btGImpactMeshShape)
2019 { 2097 {
2020 _mesh = null; 2098 ((btGImpactMeshShape) prim_geom).setLocalScaling(new btVector3(1, 1, 1));
2021 CreateGeom(IntPtr.Zero, null); 2099 ((btGImpactMeshShape) prim_geom).updateBound();
2022 } 2100 }
2023 2101 _parent_scene.AddPrimToScene(this);
2024 } 2102 }
2025 */ 2103 else
2104 {
2105 bool hasTrimesh = false;
2106 lock (childrenPrim)
2107 {
2108 foreach (BulletDotNETPrim chld in childrenPrim)
2109 {
2110 if (chld == null)
2111 continue;
2112
2113 if (chld.NeedsMeshing())
2114 hasTrimesh = true;
2115 }
2116 }
2026 2117
2027 prim_geom.calculateLocalInertia(mass, tempInertia1); 2118 //if (hasTrimesh)
2119 //{
2120 ProcessGeomCreationAsTriMesh(PhysicsVector.Zero, Quaternion.Identity);
2121 // createmesh returns null when it doesn't mesh.
2122
2028 2123
2029 if (mass != 0) 2124 if (_mesh is Mesh)
2030 _parent_scene.addActivePrim(this); 2125 {
2031 else 2126 }
2032 _parent_scene.remActivePrim(this); 2127 else
2128 {
2129 m_log.Warn("[PHYSICS]: Can't link a OpenSim.Region.Physics.Meshing.Mesh object");
2130 return;
2131 }
2132 Mesh pMesh = (Mesh) _mesh;
2133
2134 foreach (BulletDotNETPrim chld in childrenPrim)
2135 {
2136 if (chld == null)
2137 continue;
2138 PhysicsVector offset = chld.Position - Position;
2139 Vector3 pos = new Vector3(offset.X, offset.Y, offset.Z);
2140 pos *= Quaternion.Inverse(Orientation);
2141 //pos *= Orientation;
2142 offset.setValues(pos.X, pos.Y, pos.Z);
2143 chld.ProcessGeomCreationAsTriMesh(offset, chld.Orientation);
2144 if (chld._mesh is Mesh)
2145 {
2146 pMesh.Append((Mesh)chld._mesh);
2147 }
2033 2148
2034 // Body = new btRigidBody(mass, tempMotionState1, prim_geom); 2149 }
2035 //else 2150 setMesh(_parent_scene, pMesh);
2036 Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); 2151
2152 //}
2037 2153
2038 if (prim_geom is btGImpactMeshShape) 2154 if (tempMotionState1 != null && tempMotionState1.Handle != IntPtr.Zero)
2039 { 2155 tempMotionState1.Dispose();
2040 ((btGImpactMeshShape) prim_geom).setLocalScaling(new btVector3(1, 1, 1)); 2156 if (tempTransform2 != null && tempTransform2.Handle != IntPtr.Zero)
2041 ((btGImpactMeshShape) prim_geom).updateBound(); 2157 tempTransform2.Dispose();
2158 if (tempOrientation2 != null && tempOrientation2.Handle != IntPtr.Zero)
2159 tempOrientation2.Dispose();
2160
2161 if (tempPosition2 != null && tempPosition2.Handle != IntPtr.Zero)
2162 tempPosition2.Dispose();
2163
2164 tempOrientation2 = new btQuaternion(_orientation.X, _orientation.Y, _orientation.Z, _orientation.W);
2165 tempPosition2 = new btVector3(_position.X, _position.Y, _position.Z);
2166 tempTransform2 = new btTransform(tempOrientation2, tempPosition2);
2167 tempMotionState1 = new btDefaultMotionState(tempTransform2, _parent_scene.TransZero);
2168 if (tempInertia1 != null && tempInertia1.Handle != IntPtr.Zero)
2169 tempInertia1.Dispose();
2170 tempInertia1 = new btVector3(0, 0, 0);
2171
2172
2173 prim_geom.calculateLocalInertia(mass, tempInertia1);
2174
2175 if (mass != 0)
2176 _parent_scene.addActivePrim(this);
2177 else
2178 _parent_scene.remActivePrim(this);
2179
2180 // Body = new btRigidBody(mass, tempMotionState1, prim_geom);
2181 //else
2182 Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1);
2183
2184 if (prim_geom is btGImpactMeshShape)
2185 {
2186 ((btGImpactMeshShape)prim_geom).setLocalScaling(new btVector3(1, 1, 1));
2187 ((btGImpactMeshShape)prim_geom).updateBound();
2188 }
2189 _parent_scene.AddPrimToScene(this);
2042 } 2190 }
2043 _parent_scene.AddPrimToScene(this);
2044 } 2191 }
2045 2192
2046 private void DisposeOfBody() 2193 private void DisposeOfBody()
@@ -2096,9 +2243,22 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
2096 2243
2097 } 2244 }
2098 2245
2099 private void ParentPrim(BulletDotNETPrim prm) 2246 internal void ParentPrim(BulletDotNETPrim prm)
2100 { 2247 {
2101 // TODO: Parent Linking algorithm. Use btComplexObject 2248 if (prm == null)
2249 return;
2250
2251
2252
2253 lock (childrenPrim)
2254 {
2255 if (!childrenPrim.Contains(prm))
2256 {
2257 childrenPrim.Add(prm);
2258 }
2259 }
2260
2261
2102 } 2262 }
2103 2263
2104 public void disableBody() 2264 public void disableBody()