ODEMeshWorker.cs 32 KB

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