BSShapes.cs 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyrightD
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Text;
  30. using OpenSim.Framework;
  31. using OpenSim.Region.Physics.Manager;
  32. using OpenSim.Region.Physics.Meshing;
  33. using OpenSim.Region.Physics.ConvexDecompositionDotNet;
  34. using OMV = OpenMetaverse;
  35. namespace OpenSim.Region.Physics.BulletSPlugin
  36. {
  37. public abstract class BSShape
  38. {
  39. private static string LogHeader = "[BULLETSIM SHAPE]";
  40. public int referenceCount { get; set; }
  41. public DateTime lastReferenced { get; set; }
  42. public BulletShape physShapeInfo { get; set; }
  43. public BSShape()
  44. {
  45. referenceCount = 1;
  46. lastReferenced = DateTime.Now;
  47. physShapeInfo = new BulletShape();
  48. }
  49. public BSShape(BulletShape pShape)
  50. {
  51. referenceCount = 1;
  52. lastReferenced = DateTime.Now;
  53. physShapeInfo = pShape;
  54. }
  55. // Get another reference to this shape.
  56. public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
  57. // Called when this shape is being used again.
  58. // Used internally. External callers should call instance.GetReference() to properly copy/reference
  59. // the shape.
  60. protected virtual void IncrementReference()
  61. {
  62. referenceCount++;
  63. lastReferenced = DateTime.Now;
  64. }
  65. // Called when this shape is being used again.
  66. protected virtual void DecrementReference()
  67. {
  68. referenceCount--;
  69. lastReferenced = DateTime.Now;
  70. }
  71. // Release the use of a physical shape.
  72. public abstract void Dereference(BSScene physicsScene);
  73. // Return 'true' if there is an allocated physics physical shape under this class instance.
  74. public virtual bool HasPhysicalShape
  75. {
  76. get
  77. {
  78. if (physShapeInfo != null)
  79. return physShapeInfo.HasPhysicalShape;
  80. return false;
  81. }
  82. }
  83. public virtual BSPhysicsShapeType ShapeType
  84. {
  85. get
  86. {
  87. BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
  88. if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
  89. ret = physShapeInfo.shapeType;
  90. return ret;
  91. }
  92. }
  93. // Returns a string for debugging that uniquily identifies the memory used by this instance
  94. public virtual string AddrString
  95. {
  96. get
  97. {
  98. if (physShapeInfo != null)
  99. return physShapeInfo.AddrString;
  100. return "unknown";
  101. }
  102. }
  103. public override string ToString()
  104. {
  105. StringBuilder buff = new StringBuilder();
  106. if (physShapeInfo == null)
  107. {
  108. buff.Append("<noPhys");
  109. }
  110. else
  111. {
  112. buff.Append("<phy=");
  113. buff.Append(physShapeInfo.ToString());
  114. }
  115. buff.Append(",c=");
  116. buff.Append(referenceCount.ToString());
  117. buff.Append(">");
  118. return buff.ToString();
  119. }
  120. #region Common shape routines
  121. // Create a hash of all the shape parameters to be used as a key for this particular shape.
  122. public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
  123. {
  124. // level of detail based on size and type of the object
  125. float lod = BSParam.MeshLOD;
  126. if (pbs.SculptEntry)
  127. lod = BSParam.SculptLOD;
  128. // Mega prims usually get more detail because one can interact with shape approximations at this size.
  129. float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
  130. if (maxAxis > BSParam.MeshMegaPrimThreshold)
  131. lod = BSParam.MeshMegaPrimLOD;
  132. retLod = lod;
  133. return pbs.GetMeshKey(size, lod);
  134. }
  135. // The creation of a mesh or hull can fail if an underlying asset is not available.
  136. // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
  137. // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
  138. // The first case causes the asset to be fetched. The second case requires
  139. // us to not loop forever.
  140. // Called after creating a physical mesh or hull. If the physical shape was created,
  141. // just return.
  142. public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
  143. {
  144. // If the shape was successfully created, nothing more to do
  145. if (newShape.HasPhysicalShape)
  146. return newShape;
  147. // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
  148. // fetched but we end up here again, the meshing of the asset must have failed.
  149. // Prevent trying to keep fetching the mesh by declaring failure.
  150. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
  151. {
  152. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
  153. physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
  154. LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
  155. physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
  156. prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
  157. }
  158. else
  159. {
  160. // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
  161. if (prim.BaseShape.SculptEntry
  162. && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
  163. && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
  164. && prim.BaseShape.SculptTexture != OMV.UUID.Zero
  165. )
  166. {
  167. physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
  168. prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
  169. // Multiple requestors will know we're waiting for this asset
  170. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
  171. BSPhysObject xprim = prim;
  172. Util.FireAndForget(delegate
  173. {
  174. // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
  175. RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
  176. if (assetProvider != null)
  177. {
  178. BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
  179. assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
  180. {
  181. // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
  182. bool assetFound = false;
  183. string mismatchIDs = String.Empty; // DEBUG DEBUG
  184. if (asset != null && yprim.BaseShape.SculptEntry)
  185. {
  186. if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
  187. {
  188. yprim.BaseShape.SculptData = asset.Data;
  189. // This will cause the prim to see that the filler shape is not the right
  190. // one and try again to build the object.
  191. // No race condition with the normal shape setting since the rebuild is at taint time.
  192. yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
  193. yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
  194. assetFound = true;
  195. }
  196. else
  197. {
  198. mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
  199. }
  200. }
  201. if (!assetFound)
  202. {
  203. yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
  204. }
  205. physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
  206. yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
  207. });
  208. }
  209. else
  210. {
  211. xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
  212. physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
  213. LogHeader, physicsScene.Name);
  214. }
  215. });
  216. }
  217. else
  218. {
  219. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
  220. {
  221. physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
  222. LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
  223. physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
  224. prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
  225. }
  226. }
  227. }
  228. // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
  229. BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
  230. physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
  231. return fillShape.physShapeInfo;
  232. }
  233. #endregion // Common shape routines
  234. }
  235. // ============================================================================================================
  236. public class BSShapeNull : BSShape
  237. {
  238. public BSShapeNull() : base()
  239. {
  240. }
  241. public static BSShape GetReference() { return new BSShapeNull(); }
  242. public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
  243. public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
  244. }
  245. // ============================================================================================================
  246. public class BSShapeNative : BSShape
  247. {
  248. private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
  249. public BSShapeNative(BulletShape pShape) : base(pShape)
  250. {
  251. }
  252. public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
  253. BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
  254. {
  255. // Native shapes are not shared and are always built anew.
  256. return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
  257. }
  258. public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
  259. {
  260. // Native shapes are not shared so we return a new shape.
  261. BSShape ret = null;
  262. lock (physShapeInfo)
  263. {
  264. ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
  265. physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
  266. }
  267. return ret;
  268. }
  269. // Make this reference to the physical shape go away since native shapes are not shared.
  270. public override void Dereference(BSScene physicsScene)
  271. {
  272. // Native shapes are not tracked and are released immediately
  273. lock (physShapeInfo)
  274. {
  275. if (physShapeInfo.HasPhysicalShape)
  276. {
  277. physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
  278. physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
  279. }
  280. physShapeInfo.Clear();
  281. // Garbage collection will free up this instance.
  282. }
  283. }
  284. private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
  285. BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
  286. {
  287. BulletShape newShape;
  288. ShapeData nativeShapeData = new ShapeData();
  289. nativeShapeData.Type = shapeType;
  290. nativeShapeData.ID = prim.LocalID;
  291. nativeShapeData.Scale = prim.Scale;
  292. nativeShapeData.Size = prim.Scale;
  293. nativeShapeData.MeshKey = (ulong)shapeKey;
  294. nativeShapeData.HullKey = (ulong)shapeKey;
  295. if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
  296. {
  297. newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
  298. physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
  299. }
  300. else
  301. {
  302. newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
  303. }
  304. if (!newShape.HasPhysicalShape)
  305. {
  306. physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
  307. LogHeader, prim.LocalID, shapeType);
  308. }
  309. newShape.shapeType = shapeType;
  310. newShape.isNativeShape = true;
  311. newShape.shapeKey = (UInt64)shapeKey;
  312. return newShape;
  313. }
  314. }
  315. // ============================================================================================================
  316. public class BSShapeMesh : BSShape
  317. {
  318. private static string LogHeader = "[BULLETSIM SHAPE MESH]";
  319. public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
  320. public BSShapeMesh(BulletShape pShape) : base(pShape)
  321. {
  322. }
  323. public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
  324. {
  325. float lod;
  326. System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
  327. BSShapeMesh retMesh = null;
  328. lock (Meshes)
  329. {
  330. if (Meshes.TryGetValue(newMeshKey, out retMesh))
  331. {
  332. // The mesh has already been created. Return a new reference to same.
  333. retMesh.IncrementReference();
  334. }
  335. else
  336. {
  337. retMesh = new BSShapeMesh(new BulletShape());
  338. // An instance of this mesh has not been created. Build and remember same.
  339. BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
  340. // Check to see if mesh was created (might require an asset).
  341. newShape = VerifyMeshCreated(physicsScene, newShape, prim);
  342. if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
  343. {
  344. // If a mesh was what was created, remember the built shape for later sharing.
  345. // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
  346. Meshes.Add(newMeshKey, retMesh);
  347. }
  348. retMesh.physShapeInfo = newShape;
  349. }
  350. }
  351. physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
  352. return retMesh;
  353. }
  354. public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
  355. {
  356. // Another reference to this shape is just counted.
  357. IncrementReference();
  358. return this;
  359. }
  360. public override void Dereference(BSScene physicsScene)
  361. {
  362. lock (Meshes)
  363. {
  364. this.DecrementReference();
  365. physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
  366. // TODO: schedule aging and destruction of unused meshes.
  367. }
  368. }
  369. // Loop through all the known meshes and return the description based on the physical address.
  370. public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
  371. {
  372. bool ret = false;
  373. BSShapeMesh foundDesc = null;
  374. lock (Meshes)
  375. {
  376. foreach (BSShapeMesh sm in Meshes.Values)
  377. {
  378. if (sm.physShapeInfo.ReferenceSame(pShape))
  379. {
  380. foundDesc = sm;
  381. ret = true;
  382. break;
  383. }
  384. }
  385. }
  386. outMesh = foundDesc;
  387. return ret;
  388. }
  389. public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
  390. private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
  391. PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
  392. {
  393. return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
  394. (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) );
  395. }
  396. // Code that uses the mesher to create the index/vertices info for a trimesh shape.
  397. // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
  398. // The actual build call is passed so this logic can be used by several of the shapes that use a
  399. // simple mesh as their base shape.
  400. public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
  401. PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
  402. {
  403. BulletShape newShape = new BulletShape();
  404. IMesh meshData = null;
  405. lock (physicsScene.mesher)
  406. {
  407. meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
  408. false, // say it is not physical so a bounding box is not built
  409. false // do not cache the mesh and do not use previously built versions
  410. );
  411. }
  412. if (meshData != null)
  413. {
  414. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
  415. {
  416. // Release the fetched asset data once it has been used.
  417. pbs.SculptData = new byte[0];
  418. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
  419. }
  420. int[] indices = meshData.getIndexListAsInt();
  421. int realIndicesIndex = indices.Length;
  422. float[] verticesAsFloats = meshData.getVertexListAsFloat();
  423. if (BSParam.ShouldRemoveZeroWidthTriangles)
  424. {
  425. // Remove degenerate triangles. These are triangles with two of the vertices
  426. // are the same. This is complicated by the problem that vertices are not
  427. // made unique in sculpties so we have to compare the values in the vertex.
  428. realIndicesIndex = 0;
  429. for (int tri = 0; tri < indices.Length; tri += 3)
  430. {
  431. // Compute displacements into vertex array for each vertex of the triangle
  432. int v1 = indices[tri + 0] * 3;
  433. int v2 = indices[tri + 1] * 3;
  434. int v3 = indices[tri + 2] * 3;
  435. // Check to see if any two of the vertices are the same
  436. if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
  437. && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
  438. && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
  439. || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
  440. && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
  441. && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
  442. || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
  443. && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
  444. && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
  445. )
  446. {
  447. // None of the vertices of the triangles are the same. This is a good triangle;
  448. indices[realIndicesIndex + 0] = indices[tri + 0];
  449. indices[realIndicesIndex + 1] = indices[tri + 1];
  450. indices[realIndicesIndex + 2] = indices[tri + 2];
  451. realIndicesIndex += 3;
  452. }
  453. }
  454. }
  455. physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
  456. BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
  457. if (realIndicesIndex != 0)
  458. {
  459. newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
  460. }
  461. else
  462. {
  463. // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
  464. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
  465. physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
  466. LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name);
  467. physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
  468. }
  469. }
  470. newShape.shapeKey = newMeshKey;
  471. return newShape;
  472. }
  473. }
  474. // ============================================================================================================
  475. public class BSShapeHull : BSShape
  476. {
  477. private static string LogHeader = "[BULLETSIM SHAPE HULL]";
  478. public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
  479. public BSShapeHull(BulletShape pShape) : base(pShape)
  480. {
  481. }
  482. public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
  483. {
  484. float lod;
  485. System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
  486. BSShapeHull retHull = null;
  487. lock (Hulls)
  488. {
  489. if (Hulls.TryGetValue(newHullKey, out retHull))
  490. {
  491. // The mesh has already been created. Return a new reference to same.
  492. retHull.IncrementReference();
  493. }
  494. else
  495. {
  496. retHull = new BSShapeHull(new BulletShape());
  497. // An instance of this mesh has not been created. Build and remember same.
  498. BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
  499. // Check to see if hull was created (might require an asset).
  500. newShape = VerifyMeshCreated(physicsScene, newShape, prim);
  501. if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
  502. {
  503. // If a mesh was what was created, remember the built shape for later sharing.
  504. Hulls.Add(newHullKey, retHull);
  505. }
  506. retHull.physShapeInfo = newShape;
  507. }
  508. }
  509. physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
  510. return retHull;
  511. }
  512. public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
  513. {
  514. // Another reference to this shape is just counted.
  515. IncrementReference();
  516. return this;
  517. }
  518. public override void Dereference(BSScene physicsScene)
  519. {
  520. lock (Hulls)
  521. {
  522. this.DecrementReference();
  523. physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
  524. // TODO: schedule aging and destruction of unused meshes.
  525. }
  526. }
  527. List<ConvexResult> m_hulls;
  528. private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
  529. PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
  530. {
  531. BulletShape newShape = new BulletShape();
  532. IMesh meshData = null;
  533. List<List<OMV.Vector3>> allHulls = null;
  534. lock (physicsScene.mesher)
  535. {
  536. // Pass true for physicalness as this prevents the creation of bounding box which is not needed
  537. meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
  538. // If we should use the asset's hull info, fetch it out of the locked mesher
  539. if (meshData != null && BSParam.ShouldUseAssetHulls)
  540. {
  541. Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
  542. if (realMesher != null)
  543. {
  544. allHulls = realMesher.GetConvexHulls(size);
  545. }
  546. if (allHulls == null)
  547. {
  548. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
  549. }
  550. }
  551. }
  552. // If there is hull data in the mesh asset, build the hull from that
  553. if (allHulls != null && BSParam.ShouldUseAssetHulls)
  554. {
  555. int hullCount = allHulls.Count;
  556. int totalVertices = 1; // include one for the count of the hulls
  557. // Using the structure described for HACD hulls, create the memory sturcture
  558. // to pass the hull data to the creater.
  559. foreach (List<OMV.Vector3> hullVerts in allHulls)
  560. {
  561. totalVertices += 4; // add four for the vertex count and centroid
  562. totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
  563. }
  564. float[] convHulls = new float[totalVertices];
  565. convHulls[0] = (float)hullCount;
  566. int jj = 1;
  567. foreach (List<OMV.Vector3> hullVerts in allHulls)
  568. {
  569. convHulls[jj + 0] = hullVerts.Count;
  570. convHulls[jj + 1] = 0f; // centroid x,y,z
  571. convHulls[jj + 2] = 0f;
  572. convHulls[jj + 3] = 0f;
  573. jj += 4;
  574. foreach (OMV.Vector3 oneVert in hullVerts)
  575. {
  576. convHulls[jj + 0] = oneVert.X;
  577. convHulls[jj + 1] = oneVert.Y;
  578. convHulls[jj + 2] = oneVert.Z;
  579. jj += 3;
  580. }
  581. }
  582. // create the hull data structure in Bullet
  583. newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
  584. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
  585. prim.LocalID, hullCount, totalVertices, newShape);
  586. }
  587. // If no hull specified in the asset and we should use Bullet's HACD approximation...
  588. if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
  589. {
  590. // Build the hull shape from an existing mesh shape.
  591. // The mesh should have already been created in Bullet.
  592. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
  593. BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
  594. if (meshShape.physShapeInfo.HasPhysicalShape)
  595. {
  596. HACDParams parms;
  597. parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
  598. parms.minClusters = BSParam.BHullMinClusters;
  599. parms.compacityWeight = BSParam.BHullCompacityWeight;
  600. parms.volumeWeight = BSParam.BHullVolumeWeight;
  601. parms.concavity = BSParam.BHullConcavity;
  602. parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
  603. parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
  604. parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
  605. parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
  606. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
  607. newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
  608. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
  609. // Now done with the mesh shape.
  610. meshShape.Dereference(physicsScene);
  611. }
  612. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
  613. }
  614. // If no other hull specifications, use our HACD hull approximation.
  615. if (!newShape.HasPhysicalShape && meshData != null)
  616. {
  617. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
  618. {
  619. // Release the fetched asset data once it has been used.
  620. pbs.SculptData = new byte[0];
  621. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
  622. }
  623. int[] indices = meshData.getIndexListAsInt();
  624. List<OMV.Vector3> vertices = meshData.getVertexList();
  625. //format conversion from IMesh format to DecompDesc format
  626. List<int> convIndices = new List<int>();
  627. List<float3> convVertices = new List<float3>();
  628. for (int ii = 0; ii < indices.GetLength(0); ii++)
  629. {
  630. convIndices.Add(indices[ii]);
  631. }
  632. foreach (OMV.Vector3 vv in vertices)
  633. {
  634. convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
  635. }
  636. uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
  637. if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
  638. {
  639. // Simple primitive shapes we know are convex so they are better implemented with
  640. // fewer hulls.
  641. // Check for simple shape (prim without cuts) and reduce split parameter if so.
  642. if (BSShapeCollection.PrimHasNoCuts(pbs))
  643. {
  644. maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
  645. }
  646. }
  647. // setup and do convex hull conversion
  648. m_hulls = new List<ConvexResult>();
  649. DecompDesc dcomp = new DecompDesc();
  650. dcomp.mIndices = convIndices;
  651. dcomp.mVertices = convVertices;
  652. dcomp.mDepth = maxDepthSplit;
  653. dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
  654. dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
  655. dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
  656. dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
  657. ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
  658. // create the hull into the _hulls variable
  659. convexBuilder.process(dcomp);
  660. physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
  661. BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
  662. // Convert the vertices and indices for passing to unmanaged.
  663. // The hull information is passed as a large floating point array.
  664. // The format is:
  665. // convHulls[0] = number of hulls
  666. // convHulls[1] = number of vertices in first hull
  667. // convHulls[2] = hull centroid X coordinate
  668. // convHulls[3] = hull centroid Y coordinate
  669. // convHulls[4] = hull centroid Z coordinate
  670. // convHulls[5] = first hull vertex X
  671. // convHulls[6] = first hull vertex Y
  672. // convHulls[7] = first hull vertex Z
  673. // convHulls[8] = second hull vertex X
  674. // ...
  675. // convHulls[n] = number of vertices in second hull
  676. // convHulls[n+1] = second hull centroid X coordinate
  677. // ...
  678. //
  679. // TODO: is is very inefficient. Someday change the convex hull generator to return
  680. // data structures that do not need to be converted in order to pass to Bullet.
  681. // And maybe put the values directly into pinned memory rather than marshaling.
  682. int hullCount = m_hulls.Count;
  683. int totalVertices = 1; // include one for the count of the hulls
  684. foreach (ConvexResult cr in m_hulls)
  685. {
  686. totalVertices += 4; // add four for the vertex count and centroid
  687. totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
  688. }
  689. float[] convHulls = new float[totalVertices];
  690. convHulls[0] = (float)hullCount;
  691. int jj = 1;
  692. foreach (ConvexResult cr in m_hulls)
  693. {
  694. // copy vertices for index access
  695. float3[] verts = new float3[cr.HullVertices.Count];
  696. int kk = 0;
  697. foreach (float3 ff in cr.HullVertices)
  698. {
  699. verts[kk++] = ff;
  700. }
  701. // add to the array one hull's worth of data
  702. convHulls[jj++] = cr.HullIndices.Count;
  703. convHulls[jj++] = 0f; // centroid x,y,z
  704. convHulls[jj++] = 0f;
  705. convHulls[jj++] = 0f;
  706. foreach (int ind in cr.HullIndices)
  707. {
  708. convHulls[jj++] = verts[ind].x;
  709. convHulls[jj++] = verts[ind].y;
  710. convHulls[jj++] = verts[ind].z;
  711. }
  712. }
  713. // create the hull data structure in Bullet
  714. newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
  715. }
  716. newShape.shapeKey = newHullKey;
  717. return newShape;
  718. }
  719. // Callback from convex hull creater with a newly created hull.
  720. // Just add it to our collection of hulls for this shape.
  721. private void HullReturn(ConvexResult result)
  722. {
  723. m_hulls.Add(result);
  724. return;
  725. }
  726. // Loop through all the known hulls and return the description based on the physical address.
  727. public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
  728. {
  729. bool ret = false;
  730. BSShapeHull foundDesc = null;
  731. lock (Hulls)
  732. {
  733. foreach (BSShapeHull sh in Hulls.Values)
  734. {
  735. if (sh.physShapeInfo.ReferenceSame(pShape))
  736. {
  737. foundDesc = sh;
  738. ret = true;
  739. break;
  740. }
  741. }
  742. }
  743. outHull = foundDesc;
  744. return ret;
  745. }
  746. }
  747. // ============================================================================================================
  748. public class BSShapeCompound : BSShape
  749. {
  750. private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
  751. public BSShapeCompound(BulletShape pShape) : base(pShape)
  752. {
  753. }
  754. public static BSShape GetReference(BSScene physicsScene)
  755. {
  756. // Base compound shapes are not shared so this returns a raw shape.
  757. // A built compound shape can be reused in linksets.
  758. return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
  759. }
  760. public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
  761. {
  762. // Calling this reference means we want another handle to an existing compound shape
  763. // (usually linksets) so return this copy.
  764. IncrementReference();
  765. return this;
  766. }
  767. // Dereferencing a compound shape releases the hold on all the child shapes.
  768. public override void Dereference(BSScene physicsScene)
  769. {
  770. lock (physShapeInfo)
  771. {
  772. this.DecrementReference();
  773. physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
  774. if (referenceCount <= 0)
  775. {
  776. if (!physicsScene.PE.IsCompound(physShapeInfo))
  777. {
  778. // Failed the sanity check!!
  779. physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
  780. LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
  781. physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
  782. BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
  783. return;
  784. }
  785. int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
  786. physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
  787. BSScene.DetailLogZero, physShapeInfo, numChildren);
  788. // Loop through all the children dereferencing each.
  789. for (int ii = numChildren - 1; ii >= 0; ii--)
  790. {
  791. BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
  792. DereferenceAnonCollisionShape(physicsScene, childShape);
  793. }
  794. physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
  795. }
  796. }
  797. }
  798. private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
  799. {
  800. BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
  801. return cShape;
  802. }
  803. // Sometimes we have a pointer to a collision shape but don't know what type it is.
  804. // Figure out type and call the correct dereference routine.
  805. // Called at taint-time.
  806. private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
  807. {
  808. // TODO: figure a better way to go through all the shape types and find a possible instance.
  809. BSShapeMesh meshDesc;
  810. if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
  811. {
  812. meshDesc.Dereference(physicsScene);
  813. }
  814. else
  815. {
  816. BSShapeHull hullDesc;
  817. if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
  818. {
  819. hullDesc.Dereference(physicsScene);
  820. }
  821. else
  822. {
  823. BSShapeConvexHull chullDesc;
  824. if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc))
  825. {
  826. chullDesc.Dereference(physicsScene);
  827. }
  828. else
  829. {
  830. BSShapeGImpact gImpactDesc;
  831. if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
  832. {
  833. gImpactDesc.Dereference(physicsScene);
  834. }
  835. else
  836. {
  837. // Didn't find it in the lists of specific types. It could be compound.
  838. if (physicsScene.PE.IsCompound(pShape))
  839. {
  840. BSShapeCompound recursiveCompound = new BSShapeCompound(pShape);
  841. recursiveCompound.Dereference(physicsScene);
  842. }
  843. else
  844. {
  845. // If none of the above, maybe it is a simple native shape.
  846. if (physicsScene.PE.IsNativeShape(pShape))
  847. {
  848. BSShapeNative nativeShape = new BSShapeNative(pShape);
  849. nativeShape.Dereference(physicsScene);
  850. }
  851. }
  852. }
  853. }
  854. }
  855. }
  856. }
  857. }
  858. // ============================================================================================================
  859. public class BSShapeConvexHull : BSShape
  860. {
  861. private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
  862. public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
  863. public BSShapeConvexHull(BulletShape pShape) : base(pShape)
  864. {
  865. }
  866. public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
  867. {
  868. float lod;
  869. System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
  870. physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
  871. prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
  872. BSShapeConvexHull retConvexHull = null;
  873. lock (ConvexHulls)
  874. {
  875. if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
  876. {
  877. // The mesh has already been created. Return a new reference to same.
  878. retConvexHull.IncrementReference();
  879. }
  880. else
  881. {
  882. retConvexHull = new BSShapeConvexHull(new BulletShape());
  883. BulletShape convexShape = null;
  884. // Get a handle to a mesh to build the hull from
  885. BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
  886. if (baseMesh.physShapeInfo.isNativeShape)
  887. {
  888. // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
  889. // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
  890. // get back to this code with a buildable mesh.
  891. // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
  892. convexShape = baseMesh.physShapeInfo;
  893. }
  894. else
  895. {
  896. convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
  897. convexShape.shapeKey = newMeshKey;
  898. ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
  899. }
  900. // Done with the base mesh
  901. baseMesh.Dereference(physicsScene);
  902. retConvexHull.physShapeInfo = convexShape;
  903. }
  904. }
  905. return retConvexHull;
  906. }
  907. public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
  908. {
  909. // Calling this reference means we want another handle to an existing shape
  910. // (usually linksets) so return this copy.
  911. IncrementReference();
  912. return this;
  913. }
  914. // Dereferencing a compound shape releases the hold on all the child shapes.
  915. public override void Dereference(BSScene physicsScene)
  916. {
  917. lock (ConvexHulls)
  918. {
  919. this.DecrementReference();
  920. physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
  921. // TODO: schedule aging and destruction of unused meshes.
  922. }
  923. }
  924. // Loop through all the known hulls and return the description based on the physical address.
  925. public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
  926. {
  927. bool ret = false;
  928. BSShapeConvexHull foundDesc = null;
  929. lock (ConvexHulls)
  930. {
  931. foreach (BSShapeConvexHull sh in ConvexHulls.Values)
  932. {
  933. if (sh.physShapeInfo.ReferenceSame(pShape))
  934. {
  935. foundDesc = sh;
  936. ret = true;
  937. break;
  938. }
  939. }
  940. }
  941. outHull = foundDesc;
  942. return ret;
  943. }
  944. }
  945. // ============================================================================================================
  946. public class BSShapeGImpact : BSShape
  947. {
  948. private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
  949. public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
  950. public BSShapeGImpact(BulletShape pShape) : base(pShape)
  951. {
  952. }
  953. public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
  954. {
  955. float lod;
  956. System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
  957. physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
  958. prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
  959. BSShapeGImpact retGImpact = null;
  960. lock (GImpacts)
  961. {
  962. if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
  963. {
  964. // The mesh has already been created. Return a new reference to same.
  965. retGImpact.IncrementReference();
  966. }
  967. else
  968. {
  969. retGImpact = new BSShapeGImpact(new BulletShape());
  970. BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
  971. // Check to see if mesh was created (might require an asset).
  972. newShape = VerifyMeshCreated(physicsScene, newShape, prim);
  973. newShape.shapeKey = newMeshKey;
  974. if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
  975. {
  976. // If a mesh was what was created, remember the built shape for later sharing.
  977. // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
  978. GImpacts.Add(newMeshKey, retGImpact);
  979. }
  980. retGImpact.physShapeInfo = newShape;
  981. }
  982. }
  983. return retGImpact;
  984. }
  985. private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
  986. PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
  987. {
  988. return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
  989. (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) );
  990. }
  991. public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
  992. {
  993. // Calling this reference means we want another handle to an existing shape
  994. // (usually linksets) so return this copy.
  995. IncrementReference();
  996. return this;
  997. }
  998. // Dereferencing a compound shape releases the hold on all the child shapes.
  999. public override void Dereference(BSScene physicsScene)
  1000. {
  1001. lock (GImpacts)
  1002. {
  1003. this.DecrementReference();
  1004. physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
  1005. // TODO: schedule aging and destruction of unused meshes.
  1006. }
  1007. }
  1008. // Loop through all the known hulls and return the description based on the physical address.
  1009. public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
  1010. {
  1011. bool ret = false;
  1012. BSShapeGImpact foundDesc = null;
  1013. lock (GImpacts)
  1014. {
  1015. foreach (BSShapeGImpact sh in GImpacts.Values)
  1016. {
  1017. if (sh.physShapeInfo.ReferenceSame(pShape))
  1018. {
  1019. foundDesc = sh;
  1020. ret = true;
  1021. break;
  1022. }
  1023. }
  1024. }
  1025. outHull = foundDesc;
  1026. return ret;
  1027. }
  1028. }
  1029. // ============================================================================================================
  1030. public class BSShapeAvatar : BSShape
  1031. {
  1032. private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
  1033. public BSShapeAvatar() : base()
  1034. {
  1035. }
  1036. public static BSShape GetReference(BSPhysObject prim)
  1037. {
  1038. return new BSShapeNull();
  1039. }
  1040. public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
  1041. {
  1042. return new BSShapeNull();
  1043. }
  1044. public override void Dereference(BSScene physicsScene) { }
  1045. // From the front:
  1046. // A---A
  1047. // / \
  1048. // B-------B
  1049. // / \ +Z
  1050. // C-----------C |
  1051. // \ / -Y --+-- +Y
  1052. // \ / |
  1053. // \ / -Z
  1054. // D-----D
  1055. // \ /
  1056. // E-E
  1057. // From the top A and E are just lines.
  1058. // B, C and D are hexagons:
  1059. //
  1060. // C1--C2 +X
  1061. // / \ |
  1062. // C0 C3 -Y --+-- +Y
  1063. // \ / |
  1064. // C5--C4 -X
  1065. // Zero goes directly through the middle so the offsets are from that middle axis
  1066. // and up and down from a middle horizon (A and E are the same distance from the zero).
  1067. // The height, width and depth is one. All scaling is done by the simulator.
  1068. // Z component -- how far the level is from the middle zero
  1069. private const float Aup = 0.5f;
  1070. private const float Bup = 0.4f;
  1071. private const float Cup = 0.3f;
  1072. private const float Dup = -0.4f;
  1073. private const float Eup = -0.5f;
  1074. // Y component -- distance from center to x0 and x3
  1075. private const float Awid = 0.25f;
  1076. private const float Bwid = 0.3f;
  1077. private const float Cwid = 0.5f;
  1078. private const float Dwid = 0.3f;
  1079. private const float Ewid = 0.2f;
  1080. // Y component -- distance from center to x1, x2, x4 and x5
  1081. private const float Afwid = 0.0f;
  1082. private const float Bfwid = 0.2f;
  1083. private const float Cfwid = 0.4f;
  1084. private const float Dfwid = 0.2f;
  1085. private const float Efwid = 0.0f;
  1086. // X component -- distance from zero to the front or back of a level
  1087. private const float Adep = 0f;
  1088. private const float Bdep = 0.3f;
  1089. private const float Cdep = 0.5f;
  1090. private const float Ddep = 0.2f;
  1091. private const float Edep = 0f;
  1092. private OMV.Vector3[] avatarVertices = {
  1093. new OMV.Vector3( 0.0f, -Awid, Aup), // A0
  1094. new OMV.Vector3( 0.0f, +Awid, Aup), // A3
  1095. new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
  1096. new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
  1097. new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
  1098. new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
  1099. new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
  1100. new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
  1101. new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
  1102. new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
  1103. new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
  1104. new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
  1105. new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
  1106. new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
  1107. new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
  1108. new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
  1109. new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
  1110. new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
  1111. new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
  1112. new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
  1113. new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
  1114. new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
  1115. };
  1116. // Offsets of the vertices in the vertices array
  1117. private enum Ind : int
  1118. {
  1119. A0, A3,
  1120. B0, B1, B2, B3, B4, B5,
  1121. C0, C1, C2, C3, C4, C5,
  1122. D0, D1, D2, D3, D4, D5,
  1123. E0, E3
  1124. }
  1125. // Comments specify trianges and quads in clockwise direction
  1126. private Ind[] avatarIndices = {
  1127. Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
  1128. Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
  1129. Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
  1130. Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
  1131. Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
  1132. Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
  1133. Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
  1134. Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
  1135. Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
  1136. Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
  1137. Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
  1138. Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
  1139. Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
  1140. Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
  1141. Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
  1142. Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
  1143. Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
  1144. Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
  1145. Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
  1146. Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
  1147. Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
  1148. Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
  1149. Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
  1150. Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
  1151. };
  1152. }
  1153. }