ODEMeshWorker.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. /*
  2. * AJLDuarte 2012
  3. */
  4. using System;
  5. using OpenSim.Framework;
  6. using OpenSim.Region.PhysicsModules.SharedBase;
  7. using log4net;
  8. using Nini.Config;
  9. using OpenMetaverse;
  10. namespace OpenSim.Region.PhysicsModule.ubOde
  11. {
  12. public enum MeshState : byte
  13. {
  14. noNeed = 0,
  15. loadingAsset = 1,
  16. AssetOK = 0x0f, // 00001111
  17. NeedMask = 0x30, // 00110000
  18. needMesh = 0x10, // 00010000
  19. needAsset = 0x20, // 00100000
  20. FailMask = 0xC0, // 11000000
  21. AssetFailed = 0x40, // 01000000
  22. MeshFailed = 0x80, // 10000000
  23. MeshNoColide = FailMask | needAsset
  24. }
  25. public enum meshWorkerCmnds : byte
  26. {
  27. nop = 0,
  28. addnew,
  29. changefull,
  30. changesize,
  31. changeshapetype,
  32. getmesh,
  33. }
  34. public class ODEPhysRepData
  35. {
  36. public PhysicsActor actor;
  37. public PrimitiveBaseShape pbs;
  38. public IMesh mesh;
  39. public Vector3 size;
  40. public Vector3 OBB;
  41. public Vector3 OBBOffset;
  42. public float volume;
  43. public byte shapetype;
  44. public bool hasOBB;
  45. public bool hasMeshVolume;
  46. public bool isTooSmall;
  47. public MeshState meshState;
  48. public UUID? assetID;
  49. public meshWorkerCmnds comand;
  50. }
  51. public class ODEMeshWorker
  52. {
  53. private readonly ILog m_log;
  54. private readonly ODEScene m_scene;
  55. private readonly IMesher m_mesher;
  56. public bool meshSculptedPrim = true;
  57. public float meshSculptLOD = 32;
  58. public float MeshSculptphysicalLOD = 32;
  59. public float MinSizeToMeshmerize = 0.1f;
  60. //private static ObjectJobEngine<ODEPhysRepData> workQueue;
  61. private ObjectJobEngine workQueue;
  62. private bool m_running;
  63. private readonly object m_threadLock = new();
  64. public ODEMeshWorker(ODEScene pScene, ILog pLog, IMesher pMesher, IConfig pConfig)
  65. {
  66. m_scene = pScene;
  67. m_log = pLog;
  68. m_mesher = pMesher;
  69. if (pConfig is not null)
  70. {
  71. meshSculptedPrim = pConfig.GetBoolean("mesh_sculpted_prim", meshSculptedPrim);
  72. meshSculptLOD = pConfig.GetFloat("mesh_lod", meshSculptLOD);
  73. MinSizeToMeshmerize = pConfig.GetFloat("mesh_min_size", MinSizeToMeshmerize);
  74. MeshSculptphysicalLOD = pConfig.GetFloat("mesh_physical_lod", MeshSculptphysicalLOD);
  75. }
  76. m_running = true;
  77. Util.FireAndForget(DoCacheExpire, null, "OdeCacheExpire", false);
  78. lock(m_threadLock)
  79. {
  80. workQueue ??= new ObjectJobEngine(DoWork, "OdeMeshWorker");
  81. }
  82. }
  83. private void DoCacheExpire(object o)
  84. {
  85. m_mesher.ExpireFileCache();
  86. }
  87. private void Enqueue(ODEPhysRepData rep)
  88. {
  89. workQueue.Enqueue(rep);
  90. }
  91. private void DoWork(object rep)
  92. {
  93. if (m_running && rep is ODEPhysRepData nextRep && m_scene.haveActor(nextRep.actor))
  94. {
  95. switch (nextRep.comand)
  96. {
  97. case meshWorkerCmnds.changefull:
  98. case meshWorkerCmnds.changeshapetype:
  99. case meshWorkerCmnds.changesize:
  100. GetMesh(nextRep);
  101. if (CreateActorPhysRep(nextRep) && m_scene.haveActor(nextRep.actor))
  102. m_scene.AddChange(nextRep.actor, changes.PhysRepData, nextRep);
  103. break;
  104. case meshWorkerCmnds.getmesh:
  105. DoRepDataGetMesh(nextRep);
  106. break;
  107. }
  108. }
  109. }
  110. public void Stop()
  111. {
  112. try
  113. {
  114. m_running = false;
  115. workQueue.Dispose();
  116. workQueue = null;
  117. }
  118. catch
  119. {
  120. }
  121. }
  122. public void ChangeActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs,
  123. Vector3 size, byte shapetype)
  124. {
  125. ODEPhysRepData repData = new()
  126. {
  127. actor = actor,
  128. pbs = pbs,
  129. size = size,
  130. shapetype = shapetype
  131. };
  132. CheckMesh(repData);
  133. CalcVolumeData(repData);
  134. m_scene.AddChange(actor, changes.PhysRepData, repData);
  135. return;
  136. }
  137. public ODEPhysRepData NewActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs,
  138. Vector3 size, byte shapetype)
  139. {
  140. ODEPhysRepData repData = new()
  141. {
  142. actor = actor,
  143. pbs = pbs,
  144. size = size,
  145. shapetype = shapetype
  146. };
  147. CheckMesh(repData);
  148. CalcVolumeData(repData);
  149. m_scene.AddChange(actor, changes.AddPhysRep, repData);
  150. return repData;
  151. }
  152. public void RequestMesh(ODEPhysRepData repData)
  153. {
  154. repData.mesh = null;
  155. if (repData.meshState == MeshState.needAsset)
  156. {
  157. PrimitiveBaseShape pbs = repData.pbs;
  158. // check if we got outdated
  159. if (!pbs.SculptEntry || pbs.SculptTexture.IsZero())
  160. {
  161. repData.meshState = MeshState.noNeed;
  162. return;
  163. }
  164. repData.assetID = pbs.SculptTexture;
  165. repData.meshState = MeshState.loadingAsset;
  166. repData.comand = meshWorkerCmnds.getmesh;
  167. Enqueue(repData);
  168. }
  169. }
  170. // creates and prepares a mesh to use and calls parameters estimation
  171. public bool CreateActorPhysRep(ODEPhysRepData repData)
  172. {
  173. IMesh mesh = repData.mesh;
  174. if (mesh is not null)
  175. {
  176. mesh.getVertexListAsPtrToFloatArray(out _, out _, out int vertexCount);
  177. mesh.getIndexListAsPtrToIntArray(out _, out _, out int indexCount);
  178. if (vertexCount == 0 || indexCount == 0)
  179. {
  180. m_log.WarnFormat("[PHYSICS]: Invalid mesh data on prim {0} mesh UUID {1}",
  181. repData.actor.Name, repData.pbs.SculptTexture.ToString());
  182. repData.meshState = MeshState.MeshFailed;
  183. repData.hasOBB = false;
  184. repData.mesh = null;
  185. m_scene.mesher.ReleaseMesh(mesh);
  186. }
  187. else
  188. {
  189. repData.OBBOffset = mesh.GetCentroid();
  190. repData.OBB = mesh.GetOBB();
  191. repData.hasOBB = true;
  192. mesh.releaseSourceMeshData();
  193. }
  194. }
  195. CalcVolumeData(repData);
  196. return true;
  197. }
  198. public void AssetLoaded(ODEPhysRepData repData)
  199. {
  200. if (m_scene.haveActor(repData.actor))
  201. {
  202. if (needsMeshing(repData)) // no need for pbs now?
  203. {
  204. repData.comand = meshWorkerCmnds.changefull;
  205. Enqueue(repData);
  206. }
  207. }
  208. else
  209. repData.pbs.SculptData = Array.Empty<byte>();
  210. }
  211. public void DoRepDataGetMesh(ODEPhysRepData repData)
  212. {
  213. if (!repData.pbs.SculptEntry)
  214. return;
  215. if (repData.meshState != MeshState.loadingAsset)
  216. return;
  217. if (repData.assetID is null || repData.assetID.Value.IsZero())
  218. return;
  219. if (repData.assetID != repData.pbs.SculptTexture)
  220. return;
  221. // check if it is in cache
  222. GetMesh(repData);
  223. if (repData.meshState != MeshState.needAsset)
  224. {
  225. CreateActorPhysRep(repData);
  226. m_scene.AddChange(repData.actor, changes.PhysRepData, repData);
  227. return;
  228. }
  229. RequestAssetDelegate assetProvider = m_scene.RequestAssetMethod;
  230. if (assetProvider is null)
  231. return;
  232. ODEAssetRequest asr = new(this, assetProvider, repData, m_log);
  233. }
  234. /// <summary>
  235. /// Routine to figure out if we need to mesh this prim with our mesher
  236. /// </summary>
  237. /// <param name="pbs"></param>
  238. /// <returns></returns>
  239. public bool needsMeshing(ODEPhysRepData repData)
  240. {
  241. PrimitiveBaseShape pbs = repData.pbs;
  242. // check sculpts or meshs
  243. Vector3 scale = pbs.Scale;
  244. if(scale.X <= MinSizeToMeshmerize &&
  245. scale.Y <= MinSizeToMeshmerize &&
  246. scale.Z <= MinSizeToMeshmerize)
  247. {
  248. repData.isTooSmall = true;
  249. return false;
  250. }
  251. if (pbs.SculptEntry)
  252. {
  253. if (meshSculptedPrim)
  254. return true;
  255. if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs
  256. return true;
  257. return false;
  258. }
  259. // convex shapes have no holes
  260. ushort profilehollow = pbs.ProfileHollow;
  261. if(repData.shapetype == 2)
  262. profilehollow = 0;
  263. // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
  264. if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
  265. || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
  266. && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
  267. {
  268. if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
  269. && profilehollow == 0
  270. && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
  271. && pbs.PathBegin == 0 && pbs.PathEnd == 0
  272. && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
  273. && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
  274. && pbs.PathShearX == 0 && pbs.PathShearY == 0)
  275. {
  276. return false;
  277. }
  278. }
  279. // following code doesn't give meshs to boxes and spheres ever
  280. // and it's odd.. so for now just return true if asked to force meshs
  281. // hopefully mesher will fail if doesn't suport so things still get basic boxes
  282. int iPropertiesNotSupportedDefault = 0;
  283. if (profilehollow != 0)
  284. iPropertiesNotSupportedDefault++;
  285. if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
  286. iPropertiesNotSupportedDefault++;
  287. if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
  288. iPropertiesNotSupportedDefault++;
  289. if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
  290. iPropertiesNotSupportedDefault++;
  291. if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
  292. iPropertiesNotSupportedDefault++;
  293. if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
  294. iPropertiesNotSupportedDefault++;
  295. if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
  296. iPropertiesNotSupportedDefault++;
  297. if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
  298. iPropertiesNotSupportedDefault++;
  299. if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
  300. iPropertiesNotSupportedDefault++;
  301. // test for torus
  302. if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
  303. {
  304. if (pbs.PathCurve == (byte)Extrusion.Curve1)
  305. {
  306. iPropertiesNotSupportedDefault++;
  307. }
  308. }
  309. else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
  310. {
  311. if (pbs.PathCurve == (byte)Extrusion.Straight)
  312. {
  313. iPropertiesNotSupportedDefault++;
  314. }
  315. // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
  316. else if (pbs.PathCurve == (byte)Extrusion.Curve1)
  317. {
  318. iPropertiesNotSupportedDefault++;
  319. }
  320. }
  321. else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
  322. {
  323. if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
  324. {
  325. iPropertiesNotSupportedDefault++;
  326. }
  327. }
  328. else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
  329. {
  330. if (pbs.PathCurve == (byte)Extrusion.Straight)
  331. {
  332. iPropertiesNotSupportedDefault++;
  333. }
  334. else if (pbs.PathCurve == (byte)Extrusion.Curve1)
  335. {
  336. iPropertiesNotSupportedDefault++;
  337. }
  338. }
  339. if (iPropertiesNotSupportedDefault == 0)
  340. {
  341. return false;
  342. }
  343. return true;
  344. }
  345. // see if we need a mesh and if so if we have a cached one
  346. // called with a new repData
  347. public void CheckMesh(ODEPhysRepData repData)
  348. {
  349. PhysicsActor actor = repData.actor;
  350. PrimitiveBaseShape pbs = repData.pbs;
  351. if (!needsMeshing(repData))
  352. {
  353. repData.meshState = MeshState.noNeed;
  354. repData.hasOBB = false;
  355. return;
  356. }
  357. Vector3 size = repData.size;
  358. int clod = (int)LevelOfDetail.High;
  359. byte shapetype = repData.shapetype;
  360. bool convex = shapetype == 2;
  361. IMesh mesh = m_mesher.GetMesh(actor.Name, pbs, size, clod, true, convex);
  362. if (mesh is null)
  363. {
  364. if (pbs.SculptEntry)
  365. {
  366. if (pbs.SculptTexture.IsNotZero())
  367. {
  368. repData.assetID = pbs.SculptTexture;
  369. repData.meshState = MeshState.needAsset;
  370. }
  371. else
  372. repData.meshState = MeshState.MeshFailed;
  373. return;
  374. }
  375. else
  376. {
  377. repData.meshState = MeshState.needMesh;
  378. mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true);
  379. if (mesh is null)
  380. {
  381. repData.meshState = MeshState.MeshFailed;
  382. return;
  383. }
  384. }
  385. }
  386. repData.meshState = MeshState.AssetOK;
  387. repData.mesh = mesh;
  388. repData.OBB = mesh.GetOBB();
  389. repData.OBBOffset = mesh.GetCentroid();
  390. repData.hasOBB = true;
  391. if (pbs.SculptEntry)
  392. {
  393. repData.assetID = pbs.SculptTexture;
  394. }
  395. pbs.SculptData = Array.Empty<byte>();
  396. return ;
  397. }
  398. public void GetMesh(ODEPhysRepData repData)
  399. {
  400. PhysicsActor actor = repData.actor;
  401. PrimitiveBaseShape pbs = repData.pbs;
  402. repData.mesh = null;
  403. repData.hasOBB = false;
  404. if (!needsMeshing(repData))
  405. {
  406. repData.meshState = MeshState.noNeed;
  407. return;
  408. }
  409. if (repData.meshState == MeshState.MeshFailed)
  410. return;
  411. if (pbs.SculptEntry)
  412. {
  413. if (repData.meshState == MeshState.AssetFailed)
  414. {
  415. if (pbs.SculptTexture == repData.assetID)
  416. return;
  417. }
  418. }
  419. repData.meshState = MeshState.noNeed;
  420. Vector3 size = repData.size;
  421. byte shapetype = repData.shapetype;
  422. bool convex;
  423. int clod = (int)LevelOfDetail.High;
  424. if (shapetype == 0)
  425. convex = false;
  426. else
  427. {
  428. convex = true;
  429. if (pbs.SculptType != (byte)SculptType.Mesh)
  430. clod = (int)LevelOfDetail.Low;
  431. }
  432. IMesh mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true);
  433. if (mesh is null)
  434. {
  435. if (pbs.SculptEntry)
  436. {
  437. if (pbs.SculptTexture.IsZero())
  438. return;
  439. repData.assetID = pbs.SculptTexture;
  440. if (pbs.SculptData is null || pbs.SculptData.Length == 0)
  441. {
  442. repData.meshState = MeshState.needAsset;
  443. return;
  444. }
  445. }
  446. }
  447. repData.mesh = mesh;
  448. repData.pbs.SculptData = Utils.EmptyBytes;
  449. if (mesh is null)
  450. {
  451. if (pbs.SculptEntry)
  452. repData.meshState = MeshState.AssetFailed;
  453. else
  454. repData.meshState = MeshState.MeshFailed;
  455. return;
  456. }
  457. repData.meshState = MeshState.AssetOK;
  458. return;
  459. }
  460. private static void CalculateBasicPrimVolume(ODEPhysRepData repData)
  461. {
  462. Vector3 _size = repData.size;
  463. float volume = _size.X * _size.Y * _size.Z; // default
  464. if(repData.isTooSmall)
  465. {
  466. repData.volume = volume;
  467. return;
  468. }
  469. PrimitiveBaseShape _pbs = repData.pbs;
  470. float tmp;
  471. float hollowAmount = ((float)_pbs.ProfileHollow) * 2.0e-5f;
  472. float hollowVolume = hollowAmount * hollowAmount;
  473. switch (_pbs.ProfileShape)
  474. {
  475. case ProfileShape.Square:
  476. // default box
  477. if (_pbs.PathCurve == (byte)Extrusion.Straight)
  478. {
  479. if (hollowAmount > 0.0)
  480. {
  481. switch (_pbs.HollowShape)
  482. {
  483. case HollowShape.Square:
  484. case HollowShape.Same:
  485. break;
  486. case HollowShape.Circle:
  487. hollowVolume *= 0.78539816339f;
  488. break;
  489. case HollowShape.Triangle:
  490. hollowVolume *= (0.5f * .5f);
  491. break;
  492. default:
  493. hollowVolume = 0;
  494. break;
  495. }
  496. volume *= (1.0f - hollowVolume);
  497. }
  498. }
  499. else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  500. {
  501. //a tube
  502. volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
  503. tmp = 1.0f - 2.0e-2f * (float)(200 - _pbs.PathScaleY);
  504. volume -= volume * tmp * tmp;
  505. if (hollowAmount > 0.0)
  506. {
  507. hollowVolume *= hollowAmount;
  508. switch (_pbs.HollowShape)
  509. {
  510. case HollowShape.Square:
  511. case HollowShape.Same:
  512. break;
  513. case HollowShape.Circle:
  514. hollowVolume *= 0.78539816339f;
  515. break;
  516. case HollowShape.Triangle:
  517. hollowVolume *= 0.5f * 0.5f;
  518. break;
  519. default:
  520. hollowVolume = 0;
  521. break;
  522. }
  523. volume *= (1.0f - hollowVolume);
  524. }
  525. }
  526. break;
  527. case ProfileShape.Circle:
  528. if (_pbs.PathCurve == (byte)Extrusion.Straight)
  529. {
  530. volume *= 0.78539816339f; // elipse base
  531. if (hollowAmount > 0.0)
  532. {
  533. switch (_pbs.HollowShape)
  534. {
  535. case HollowShape.Same:
  536. case HollowShape.Circle:
  537. break;
  538. case HollowShape.Square:
  539. hollowVolume *= 0.5f * 2.5984480504799f;
  540. break;
  541. case HollowShape.Triangle:
  542. hollowVolume *= .5f * 1.27323954473516f;
  543. break;
  544. default:
  545. hollowVolume = 0;
  546. break;
  547. }
  548. volume *= (1.0f - hollowVolume);
  549. }
  550. }
  551. else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  552. {
  553. volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
  554. tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
  555. volume *= (1.0f - tmp * tmp);
  556. if (hollowAmount > 0.0)
  557. {
  558. // calculate the hollow volume by it's shape compared to the prim shape
  559. hollowVolume *= hollowAmount;
  560. switch (_pbs.HollowShape)
  561. {
  562. case HollowShape.Same:
  563. case HollowShape.Circle:
  564. break;
  565. case HollowShape.Square:
  566. hollowVolume *= 0.5f * 2.5984480504799f;
  567. break;
  568. case HollowShape.Triangle:
  569. hollowVolume *= .5f * 1.27323954473516f;
  570. break;
  571. default:
  572. hollowVolume = 0;
  573. break;
  574. }
  575. volume *= (1.0f - hollowVolume);
  576. }
  577. }
  578. break;
  579. case ProfileShape.HalfCircle:
  580. if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  581. {
  582. volume *= 0.5236f;
  583. if (hollowAmount > 0.0)
  584. {
  585. hollowVolume *= hollowAmount;
  586. switch (_pbs.HollowShape)
  587. {
  588. case HollowShape.Circle:
  589. case HollowShape.Triangle: // diference in sl is minor and odd
  590. case HollowShape.Same:
  591. break;
  592. case HollowShape.Square:
  593. hollowVolume *= 0.909f;
  594. break;
  595. //case HollowShape.Triangle:
  596. // hollowVolume *= .827f;
  597. // break;
  598. default:
  599. hollowVolume = 0;
  600. break;
  601. }
  602. volume *= (1.0f - hollowVolume);
  603. }
  604. }
  605. break;
  606. case ProfileShape.EquilateralTriangle:
  607. if (_pbs.PathCurve == (byte)Extrusion.Straight)
  608. {
  609. volume *= 0.32475953f;
  610. if (hollowAmount > 0.0)
  611. {
  612. // calculate the hollow volume by it's shape compared to the prim shape
  613. switch (_pbs.HollowShape)
  614. {
  615. case HollowShape.Same:
  616. case HollowShape.Triangle:
  617. hollowVolume *= .25f;
  618. break;
  619. case HollowShape.Square:
  620. hollowVolume *= 0.499849f * 3.07920140172638f;
  621. break;
  622. case HollowShape.Circle:
  623. // Hollow shape is a perfect cyllinder in respect to the cube's scale
  624. // Cyllinder hollow volume calculation
  625. hollowVolume *= 0.1963495f * 3.07920140172638f;
  626. break;
  627. default:
  628. hollowVolume = 0;
  629. break;
  630. }
  631. volume *= (1.0f - hollowVolume);
  632. }
  633. }
  634. else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  635. {
  636. volume *= 0.32475953f;
  637. volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
  638. tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
  639. volume *= (1.0f - tmp * tmp);
  640. if (hollowAmount > 0.0)
  641. {
  642. hollowVolume *= hollowAmount;
  643. switch (_pbs.HollowShape)
  644. {
  645. case HollowShape.Same:
  646. case HollowShape.Triangle:
  647. hollowVolume *= .25f;
  648. break;
  649. case HollowShape.Square:
  650. hollowVolume *= 0.499849f * 3.07920140172638f;
  651. break;
  652. case HollowShape.Circle:
  653. hollowVolume *= 0.1963495f * 3.07920140172638f;
  654. break;
  655. default:
  656. hollowVolume = 0;
  657. break;
  658. }
  659. volume *= (1.0f - hollowVolume);
  660. }
  661. }
  662. break;
  663. default:
  664. break;
  665. }
  666. float taperX1;
  667. float taperY1;
  668. float taperX;
  669. float taperY;
  670. float pathBegin;
  671. float pathEnd;
  672. float profileBegin;
  673. float profileEnd;
  674. if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
  675. {
  676. taperX1 = _pbs.PathScaleX * 0.01f;
  677. if (taperX1 > 1.0f)
  678. taperX1 = 2.0f - taperX1;
  679. taperX = 1.0f - taperX1;
  680. taperY1 = _pbs.PathScaleY * 0.01f;
  681. if (taperY1 > 1.0f)
  682. taperY1 = 2.0f - taperY1;
  683. taperY = 1.0f - taperY1;
  684. }
  685. else
  686. {
  687. taperX = _pbs.PathTaperX * 0.01f;
  688. if (taperX < 0.0f)
  689. taperX = -taperX;
  690. taperX1 = 1.0f - taperX;
  691. taperY = _pbs.PathTaperY * 0.01f;
  692. if (taperY < 0.0f)
  693. taperY = -taperY;
  694. taperY1 = 1.0f - taperY;
  695. }
  696. volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
  697. pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
  698. pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
  699. volume *= (pathEnd - pathBegin);
  700. // this is crude aproximation
  701. profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
  702. profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
  703. volume *= (profileEnd - profileBegin);
  704. repData.volume = volume;
  705. }
  706. private static void CalcVolumeData(ODEPhysRepData repData)
  707. {
  708. if (!repData.hasOBB)
  709. {
  710. repData.OBB = repData.size * 0.5f;
  711. repData.OBBOffset = Vector3.Zero;
  712. }
  713. CalculateBasicPrimVolume(repData);
  714. }
  715. }
  716. public class ODEAssetRequest
  717. {
  718. private readonly ODEMeshWorker m_worker;
  719. private readonly ILog m_log;
  720. private readonly ODEPhysRepData repData;
  721. public ODEAssetRequest(ODEMeshWorker pWorker, RequestAssetDelegate provider,
  722. ODEPhysRepData pRepData, ILog plog)
  723. {
  724. m_worker = pWorker;
  725. m_log = plog;
  726. repData = pRepData;
  727. repData.meshState = MeshState.loadingAsset;
  728. provider((UUID)repData.assetID, ODEassetReceived);
  729. }
  730. void ODEassetReceived(AssetBase asset)
  731. {
  732. repData.meshState = MeshState.AssetFailed;
  733. if (asset is not null)
  734. {
  735. if (asset.Data is not null && asset.Data.Length > 0)
  736. {
  737. repData.meshState = MeshState.noNeed;
  738. if (!repData.pbs.SculptEntry)
  739. return;
  740. if (repData.pbs.SculptTexture != repData.assetID)
  741. return;
  742. //repData.pbs.SculptData = new byte[asset.Data.Length];
  743. //asset.Data.CopyTo(repData.pbs.SculptData,0);
  744. repData.pbs.SculptData = asset.Data;
  745. repData.meshState = MeshState.AssetOK;
  746. m_worker.AssetLoaded(repData);
  747. }
  748. else
  749. m_log.WarnFormat("[PHYSICS]: asset provider returned invalid mesh data for prim {0} asset UUID {1}.",
  750. repData.actor.Name, asset.ID.ToString());
  751. }
  752. else
  753. m_log.WarnFormat("[PHYSICS]: asset provider returned null asset for mesh of prim {0}.",
  754. repData.actor.Name);
  755. }
  756. }
  757. }