BSShapes.cs 59 KB

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