ODESitAvatar.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 copyright
  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. // Ubit Umarov 2012
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Reflection;
  31. using System.Runtime.InteropServices;
  32. using System.Text;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.PhysicsModules.SharedBase;
  35. using OdeAPI;
  36. using log4net;
  37. using OpenMetaverse;
  38. namespace OpenSim.Region.PhysicsModule.ubOde
  39. {
  40. /// <summary>
  41. /// </summary>
  42. public class ODESitAvatar
  43. {
  44. private ODEScene m_scene;
  45. private ODERayCastRequestManager m_raymanager;
  46. public ODESitAvatar(ODEScene pScene, ODERayCastRequestManager raymanager)
  47. {
  48. m_scene = pScene;
  49. m_raymanager = raymanager;
  50. }
  51. private static Vector3 SitAjust = new Vector3(0, 0, 0.4f);
  52. private const RayFilterFlags RaySitFlags = RayFilterFlags.AllPrims | RayFilterFlags.ClosestHit;
  53. private void RotAroundZ(float x, float y, ref Quaternion ori)
  54. {
  55. double ang = Math.Atan2(y, x);
  56. ang *= 0.5d;
  57. float s = (float)Math.Sin(ang);
  58. float c = (float)Math.Cos(ang);
  59. ori.X = 0;
  60. ori.Y = 0;
  61. ori.Z = s;
  62. ori.W = c;
  63. }
  64. public void Sit(PhysicsActor actor, Vector3 avPos, Vector3 avCameraPosition, Vector3 offset, Vector3 avOffset, SitAvatarCallback PhysicsSitResponse)
  65. {
  66. if (!m_scene.haveActor(actor) || !(actor is OdePrim) || ((OdePrim)actor).prim_geom == IntPtr.Zero)
  67. {
  68. PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity);
  69. return;
  70. }
  71. IntPtr geom = ((OdePrim)actor).prim_geom;
  72. Vector3 geopos = d.GeomGetPositionOMV(geom);
  73. Quaternion geomOri = d.GeomGetQuaternionOMV(geom);
  74. // Vector3 geopos = actor.Position;
  75. // Quaternion geomOri = actor.Orientation;
  76. Quaternion geomInvOri = Quaternion.Conjugate(geomOri);
  77. Quaternion ori = Quaternion.Identity;
  78. Vector3 rayDir = geopos + offset - avCameraPosition;
  79. float raylen = rayDir.Length();
  80. if (raylen < 0.001f)
  81. {
  82. PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity);
  83. return;
  84. }
  85. float t = 1 / raylen;
  86. rayDir.X *= t;
  87. rayDir.Y *= t;
  88. rayDir.Z *= t;
  89. raylen += 30f; // focal point may be far
  90. List<ContactResult> rayResults;
  91. rayResults = m_scene.RaycastActor(actor, avCameraPosition, rayDir, raylen, 1, RaySitFlags);
  92. if (rayResults.Count == 0)
  93. {
  94. /* if this fundamental ray failed, then just fail so user can try another spot and not be sitted far on a big prim
  95. d.AABB aabb;
  96. d.GeomGetAABB(geom, out aabb);
  97. offset = new Vector3(avOffset.X, 0, aabb.MaxZ + avOffset.Z - geopos.Z);
  98. ori = geomInvOri;
  99. offset *= geomInvOri;
  100. PhysicsSitResponse(1, actor.LocalID, offset, ori);
  101. */
  102. PhysicsSitResponse(0, actor.LocalID, offset, ori);
  103. return;
  104. }
  105. int status = 1;
  106. offset = rayResults[0].Pos - geopos;
  107. d.GeomClassID geoclass = d.GeomGetClass(geom);
  108. if (geoclass == d.GeomClassID.SphereClass)
  109. {
  110. float r = d.GeomSphereGetRadius(geom);
  111. offset.Normalize();
  112. offset *= r;
  113. RotAroundZ(offset.X, offset.Y, ref ori);
  114. if (r < 0.4f)
  115. {
  116. offset = new Vector3(0, 0, r);
  117. }
  118. else
  119. {
  120. if (offset.Z < 0.4f)
  121. {
  122. t = offset.Z;
  123. float rsq = r * r;
  124. t = 1.0f / (rsq - t * t);
  125. offset.X *= t;
  126. offset.Y *= t;
  127. offset.Z = 0.4f;
  128. t = rsq - 0.16f;
  129. offset.X *= t;
  130. offset.Y *= t;
  131. }
  132. else if (r > 0.8f && offset.Z > 0.8f * r)
  133. {
  134. status = 3;
  135. avOffset.X = -avOffset.X;
  136. avOffset.Z *= 1.6f;
  137. }
  138. }
  139. offset += avOffset * ori;
  140. ori = geomInvOri * ori;
  141. offset *= geomInvOri;
  142. PhysicsSitResponse(status, actor.LocalID, offset, ori);
  143. return;
  144. }
  145. Vector3 norm = rayResults[0].Normal;
  146. if (norm.Z < -0.4f)
  147. {
  148. PhysicsSitResponse(0, actor.LocalID, offset, Quaternion.Identity);
  149. return;
  150. }
  151. float SitNormX = -rayDir.X;
  152. float SitNormY = -rayDir.Y;
  153. Vector3 pivot = geopos + offset;
  154. float edgeNormalX = norm.X;
  155. float edgeNormalY = norm.Y;
  156. float edgeDirX = -rayDir.X;
  157. float edgeDirY = -rayDir.Y;
  158. Vector3 edgePos = rayResults[0].Pos;
  159. float edgeDist = float.MaxValue;
  160. bool foundEdge = false;
  161. if (norm.Z < 0.5f)
  162. {
  163. float rayDist = 4.0f;
  164. for (int i = 0; i < 6; i++)
  165. {
  166. pivot.X -= 0.01f * norm.X;
  167. pivot.Y -= 0.01f * norm.Y;
  168. pivot.Z -= 0.01f * norm.Z;
  169. rayDir.X = -norm.X * norm.Z;
  170. rayDir.Y = -norm.Y * norm.Z;
  171. rayDir.Z = 1.0f - norm.Z * norm.Z;
  172. rayDir.Normalize();
  173. rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims);
  174. if (rayResults.Count == 0)
  175. break;
  176. if (Math.Abs(rayResults[0].Normal.Z) < 0.7f)
  177. {
  178. rayDist -= rayResults[0].Depth;
  179. if (rayDist < 0f)
  180. break;
  181. pivot = rayResults[0].Pos;
  182. norm = rayResults[0].Normal;
  183. edgeNormalX = norm.X;
  184. edgeNormalY = norm.Y;
  185. edgeDirX = -rayDir.X;
  186. edgeDirY = -rayDir.Y;
  187. }
  188. else
  189. {
  190. foundEdge = true;
  191. edgePos = rayResults[0].Pos;
  192. break;
  193. }
  194. }
  195. if (!foundEdge)
  196. {
  197. PhysicsSitResponse(0, actor.LocalID, offset, ori);
  198. return;
  199. }
  200. avOffset.X *= 0.5f;
  201. }
  202. else if (norm.Z > 0.866f)
  203. {
  204. float toCamBaseX = avCameraPosition.X - pivot.X;
  205. float toCamBaseY = avCameraPosition.Y - pivot.Y;
  206. float toCamX = toCamBaseX;
  207. float toCamY = toCamBaseY;
  208. for (int j = 0; j < 4; j++)
  209. {
  210. float rayDist = 1.0f;
  211. float curEdgeDist = 0.0f;
  212. for (int i = 0; i < 3; i++)
  213. {
  214. pivot.Z -= 0.01f;
  215. rayDir.X = toCamX;
  216. rayDir.Y = toCamY;
  217. rayDir.Z = (-toCamX * norm.X - toCamY * norm.Y) / norm.Z;
  218. rayDir.Normalize();
  219. rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims);
  220. if (rayResults.Count == 0)
  221. break;
  222. curEdgeDist += rayResults[0].Depth;
  223. if (rayResults[0].Normal.Z > 0.5f)
  224. {
  225. rayDist -= rayResults[0].Depth;
  226. if (rayDist < 0f)
  227. break;
  228. pivot = rayResults[0].Pos;
  229. norm = rayResults[0].Normal;
  230. }
  231. else
  232. {
  233. foundEdge = true;
  234. if (curEdgeDist < edgeDist)
  235. {
  236. edgeDist = curEdgeDist;
  237. edgeNormalX = rayResults[0].Normal.X;
  238. edgeNormalY = rayResults[0].Normal.Y;
  239. edgeDirX = rayDir.X;
  240. edgeDirY = rayDir.Y;
  241. edgePos = rayResults[0].Pos;
  242. }
  243. break;
  244. }
  245. }
  246. if (foundEdge && edgeDist < 0.2f)
  247. break;
  248. pivot = geopos + offset;
  249. switch (j)
  250. {
  251. case 0:
  252. toCamX = -toCamBaseY;
  253. toCamY = toCamBaseX;
  254. break;
  255. case 1:
  256. toCamX = toCamBaseY;
  257. toCamY = -toCamBaseX;
  258. break;
  259. case 2:
  260. toCamX = -toCamBaseX;
  261. toCamY = -toCamBaseY;
  262. break;
  263. default:
  264. break;
  265. }
  266. }
  267. if (!foundEdge)
  268. {
  269. avOffset.X = -avOffset.X;
  270. avOffset.Z *= 1.6f;
  271. RotAroundZ(SitNormX, SitNormY, ref ori);
  272. offset += avOffset * ori;
  273. ori = geomInvOri * ori;
  274. offset *= geomInvOri;
  275. PhysicsSitResponse(3, actor.LocalID, offset, ori);
  276. return;
  277. }
  278. avOffset.X *= 0.5f;
  279. }
  280. SitNormX = edgeNormalX;
  281. SitNormY = edgeNormalY;
  282. if (edgeDirX * SitNormX + edgeDirY * SitNormY < 0)
  283. {
  284. SitNormX = -SitNormX;
  285. SitNormY = -SitNormY;
  286. }
  287. RotAroundZ(SitNormX, SitNormY, ref ori);
  288. offset = edgePos + avOffset * ori;
  289. offset -= geopos;
  290. ori = geomInvOri * ori;
  291. offset *= geomInvOri;
  292. PhysicsSitResponse(1, actor.LocalID, offset, ori);
  293. return;
  294. }
  295. }
  296. }