1
0

BSShapes.cs 58 KB

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