ODEMeshWorker.cs 32 KB

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