BSShapes.cs 69 KB

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