PageRenderTime 88ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/Aurora/Region/SceneObjectGroup.cs

https://bitbucket.org/VirtualReality/software-testing
C# | 4443 lines | 3090 code | 440 blank | 913 comment | 667 complexity | eb39fe50da51eea0a51eb78162e0ea63 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.org/, 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 Aurora-Sim 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 Aurora.Framework;
  28. using Aurora.Framework.ClientInterfaces;
  29. using Aurora.Framework.ConsoleFramework;
  30. using Aurora.Framework.Modules;
  31. using Aurora.Framework.Physics;
  32. using Aurora.Framework.PresenceInfo;
  33. using Aurora.Framework.SceneInfo;
  34. using Aurora.Framework.SceneInfo.Entities;
  35. using Aurora.Framework.Serialization;
  36. using Aurora.Framework.Utilities;
  37. using OpenMetaverse;
  38. using OpenMetaverse.Packets;
  39. using OpenMetaverse.StructuredData;
  40. using ProtoBuf;
  41. using System;
  42. using System.Collections.Generic;
  43. using System.Drawing;
  44. using System.Linq;
  45. using System.Xml.Serialization;
  46. using GridRegion = Aurora.Framework.Services.GridRegion;
  47. namespace Aurora.Region
  48. {
  49. internal struct scriptPosTarget
  50. {
  51. public uint handle;
  52. public Vector3 targetPos;
  53. public float tolerance;
  54. }
  55. internal struct scriptRotTarget
  56. {
  57. public uint handle;
  58. public Quaternion targetRot;
  59. public float tolerance;
  60. }
  61. /// <summary>
  62. /// A scene object group is conceptually an object in the scene. The object is constituted of SceneObjectParts
  63. /// (often known as prims), one of which is considered the root part.
  64. /// </summary>
  65. [Serializable, ProtoContract()]
  66. public partial class SceneObjectGroup : ISceneEntity
  67. //(ISceneObject implements ISceneEntity and IEntity)
  68. {
  69. private readonly List<uint> m_lastColliders = new List<uint>();
  70. private readonly Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>();
  71. private readonly Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>();
  72. [XmlIgnore] private bool m_ValidgrpOOB; // control recalcutation
  73. [XmlIgnore] private float m_grpBSphereRadiusSQ; // the square of the radius of a sphere containing the oob
  74. [XmlIgnore] private Vector3 m_grpOOBoffset; // the position center of the bounding box relative to it's Position
  75. [XmlIgnore] private Vector3 m_grpOOBsize;
  76. // the size of a bounding box oriented as prim, is future will consider cutted prims, meshs etc
  77. public bool IsInTransit { get; set; }
  78. private UUID m_lastParcelUUID = UUID.Zero;
  79. private Vector3 m_lastSignificantPosition = Vector3.Zero;
  80. protected Dictionary<UUID, SceneObjectPart> m_parts = new Dictionary<UUID, SceneObjectPart>();
  81. //Same as m_parts, but this is used for fast linear operations
  82. protected List<SceneObjectPart> m_partsList = new List<SceneObjectPart>();
  83. //This is the lock for m_parts and m_partsList
  84. protected object m_partsLock = new object();
  85. protected ulong m_regionHandle;
  86. protected SceneObjectPart m_rootPart;
  87. private bool m_scriptListens_atRotTarget;
  88. private bool m_scriptListens_atTarget;
  89. private bool m_scriptListens_notAtRotTarget;
  90. private bool m_scriptListens_notAtTarget;
  91. #region Properties
  92. private List<ISceneChildEntity> m_LoopSoundSlavePrims = new List<ISceneChildEntity>();
  93. private List<ISceneChildEntity> m_PlaySoundSlavePrims = new List<ISceneChildEntity>();
  94. /// <summary>
  95. /// Added because the Parcel code seems to use it
  96. /// but not sure a object should have this
  97. /// as what does it tell us? that some avatar has selected it (but not what Avatar/user)
  98. /// think really there should be a list (or whatever) in each scenepresence
  99. /// saying what prim(s) that user has selected.
  100. /// </summary>
  101. protected bool m_isSelected;
  102. protected Quaternion m_rotation = Quaternion.Identity;
  103. public SceneObjectPart[] Parts
  104. {
  105. get { return m_partsList.ToArray(); }
  106. }
  107. /// <value>
  108. /// The parts of this scene object group. You must lock this property before using it.
  109. /// </value>
  110. [ProtoMember(1)]
  111. public List<SceneObjectPart> ChildrenList
  112. {
  113. get { return m_partsList; }
  114. set { m_partsList = value; }
  115. }
  116. /// <value>
  117. /// The root part of this scene object
  118. /// </value>
  119. public SceneObjectPart RootPart
  120. {
  121. get { return m_rootPart; }
  122. }
  123. public Color Color
  124. {
  125. get { return m_rootPart.Color; }
  126. set
  127. {
  128. if (m_rootPart != null)
  129. m_rootPart.UpdateColor(value, true);
  130. }
  131. }
  132. public string Text
  133. {
  134. get
  135. {
  136. string returnstr = m_rootPart.Text;
  137. if (returnstr.Length > 255)
  138. {
  139. returnstr = returnstr.Substring(0, 255);
  140. }
  141. return returnstr;
  142. }
  143. set
  144. {
  145. if (m_rootPart != null && m_rootPart.Text != value)
  146. m_rootPart.Text = value;
  147. }
  148. }
  149. public ISceneChildEntity PlaySoundMasterPrim { get; set; }
  150. public List<ISceneChildEntity> PlaySoundSlavePrims
  151. {
  152. get { return m_PlaySoundSlavePrims; }
  153. set { m_PlaySoundSlavePrims = value; }
  154. }
  155. public UUID RegionUUID
  156. {
  157. get
  158. {
  159. if (m_scene != null)
  160. {
  161. return m_scene.RegionInfo.RegionID;
  162. }
  163. return UUID.Zero;
  164. }
  165. }
  166. /// <summary>
  167. /// The name of an object grouping is always the same as its root part
  168. /// </summary>
  169. public override string Name
  170. {
  171. get
  172. {
  173. if (RootPart == null)
  174. return String.Empty;
  175. return RootPart.Name;
  176. }
  177. set { RootPart.Name = value; }
  178. }
  179. /// <summary>
  180. /// Number of prims in this group
  181. /// </summary>
  182. public int PrimCount
  183. {
  184. get { return m_parts.Count; }
  185. }
  186. public override Quaternion Rotation
  187. {
  188. get { return m_rotation; }
  189. set
  190. {
  191. HasGroupChanged = true;
  192. m_rotation = value;
  193. }
  194. }
  195. public Quaternion GroupRotation
  196. {
  197. get { return m_rootPart.GetRotationOffset(); }
  198. }
  199. public UUID GroupID
  200. {
  201. get { return m_rootPart.GroupID; }
  202. set
  203. {
  204. HasGroupChanged = true;
  205. m_rootPart.GroupID = value;
  206. }
  207. }
  208. public List<ISceneChildEntity> ChildrenEntities()
  209. {
  210. return new List<SceneObjectPart>(m_partsList).Cast<ISceneChildEntity>().ToList();
  211. }
  212. public List<UUID> SitTargetAvatar
  213. {
  214. get
  215. {
  216. List<UUID> sittingAvatars = new List<UUID>();
  217. foreach (var prim in ChildrenEntities())
  218. sittingAvatars.AddRange(new List<UUID>(prim.SitTargetAvatar));
  219. return sittingAvatars;
  220. }
  221. }
  222. /// <summary>
  223. /// The absolute position of this scene object in the scene
  224. /// </summary>
  225. public override Vector3 AbsolutePosition
  226. {
  227. get { return m_rootPart.GroupPosition; }
  228. set { SetAbsolutePosition(true, value); }
  229. }
  230. public override uint LocalId
  231. {
  232. get { return m_rootPart.LocalId; }
  233. set { m_rootPart.LocalId = value; }
  234. }
  235. public override UUID UUID
  236. {
  237. get { return m_rootPart.UUID; }
  238. set { Scene.SceneGraph.UpdateEntity(this, value); }
  239. }
  240. public UUID OwnerID
  241. {
  242. get { return m_rootPart.OwnerID; }
  243. set
  244. {
  245. HasGroupChanged = true;
  246. m_rootPart.OwnerID = value;
  247. }
  248. }
  249. public float Damage
  250. {
  251. get { return m_rootPart.Damage; }
  252. set
  253. {
  254. HasGroupChanged = true;
  255. m_rootPart.Damage = value;
  256. }
  257. }
  258. public bool IsSelected
  259. {
  260. get { return m_isSelected; }
  261. set
  262. {
  263. m_isSelected = value;
  264. // Tell physics engine that group is selected
  265. if (m_rootPart.PhysActor != null)
  266. {
  267. m_rootPart.PhysActor.Selected = value;
  268. // Pass it on to the children.
  269. #if (!ISWIN)
  270. foreach (SceneObjectPart child in ChildrenList)
  271. {
  272. if (child.PhysActor != null)
  273. {
  274. child.PhysActor.Selected = value;
  275. }
  276. }
  277. #else
  278. foreach (SceneObjectPart child in ChildrenList.Where(child => child.PhysActor != null))
  279. {
  280. child.PhysActor.Selected = value;
  281. }
  282. #endif
  283. }
  284. }
  285. }
  286. public ISceneChildEntity LoopSoundMasterPrim { get; set; }
  287. public List<ISceneChildEntity> LoopSoundSlavePrims
  288. {
  289. get { return m_LoopSoundSlavePrims; }
  290. set { m_LoopSoundSlavePrims = value; }
  291. }
  292. public bool ContainsPart(UUID partID)
  293. {
  294. return m_parts.ContainsKey(partID);
  295. }
  296. /// <summary>
  297. /// Check both the attachment property and the relevant properties of the underlying root part.
  298. /// </summary>
  299. /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't
  300. /// have the IsAttachment property yet checked.
  301. ///
  302. /// FIXME: However, this should be fixed so that this property
  303. /// propertly reflects the underlying status.
  304. /// <returns></returns>
  305. public bool IsAttachmentCheckFull()
  306. {
  307. return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
  308. }
  309. // The UUID for the Region this Object is in.
  310. #endregion
  311. #region Constructors
  312. public SceneObjectGroup()
  313. {
  314. }
  315. /// <summary>
  316. /// THIS IS ONLY FOR SERIALIZATION AND AS A BASE CONSTRUCTOR
  317. /// </summary>
  318. public SceneObjectGroup(IScene scene)
  319. {
  320. m_scene = scene;
  321. }
  322. /// <summary>
  323. /// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
  324. /// The original SceneObjectPart will be used rather than a copy, preserving
  325. /// its existing localID and UUID.
  326. /// </summary>
  327. public SceneObjectGroup(SceneObjectPart part, IScene scene) : this(scene)
  328. {
  329. SetRootPart(part);
  330. part.Scale = part.Shape.Scale; // temporary hack to update oobb
  331. m_ValidgrpOOB = false;
  332. }
  333. public SceneObjectGroup(SceneObjectPart part, IScene scene, bool AddToScene)
  334. : this(scene)
  335. {
  336. if (!AddToScene)
  337. m_isDeleted = true;
  338. SetRootPart(part);
  339. part.Scale = part.Shape.Scale; // temporary hack to update oobb
  340. m_ValidgrpOOB = false;
  341. }
  342. /// <summary>
  343. /// Constructor. This object is added to the scene later via AttachToScene()
  344. /// </summary>
  345. public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape, string name,
  346. IScene scene) : this(scene)
  347. {
  348. SceneObjectPart part = new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero, name);
  349. SetRootPart(part);
  350. //This has to be set, otherwise it will break things like rezzing objects in an area where crossing is disabled, but rez isn't
  351. m_lastSignificantPosition = pos;
  352. m_ValidgrpOOB = false;
  353. }
  354. public void SetFromItemID(UUID itemID, UUID assetID)
  355. {
  356. foreach (SceneObjectPart part in m_partsList)
  357. {
  358. part.FromUserInventoryItemID = itemID;
  359. part.FromUserInventoryAssetID = assetID;
  360. }
  361. }
  362. /// <summary>
  363. /// Attach this object to a scene. It will also now apply to agents.
  364. /// </summary>
  365. /// <param name="scene"></param>
  366. public void AttachToScene(IScene scene)
  367. {
  368. m_scene = scene;
  369. if (m_rootPart.Shape == null)
  370. {
  371. MainConsole.Instance.Warn("[SceneObjectGroup]: Found null shape for prim " + UUID +
  372. ", creating default box shape");
  373. m_rootPart.Shape = new PrimitiveBaseShape();
  374. }
  375. IOpenRegionSettingsModule WSModule = Scene.RequestModuleInterface<IOpenRegionSettingsModule>();
  376. if (WSModule != null)
  377. {
  378. foreach (SceneObjectPart part in ChildrenList)
  379. {
  380. //It's being rezzed, add it to the scene if it doesn't already have a rez date
  381. if (part.Rezzed != Util.ToDateTime(Util.EnvironmentTickCount()))
  382. part.Rezzed = DateTime.UtcNow;
  383. if (part.Shape == null)
  384. continue;
  385. Vector3 scale = part.Shape.Scale;
  386. if (WSModule.MinimumPrimScale != -1)
  387. {
  388. if (scale.X < WSModule.MinimumPrimScale)
  389. scale.X = WSModule.MinimumPrimScale;
  390. if (scale.Y < WSModule.MinimumPrimScale)
  391. scale.Y = WSModule.MinimumPrimScale;
  392. if (scale.Z < WSModule.MinimumPrimScale)
  393. scale.Z = WSModule.MinimumPrimScale;
  394. }
  395. if (part.ParentGroup.RootPart.PhysActor != null && part.ParentGroup.RootPart.PhysActor.IsPhysical &&
  396. WSModule.MaximumPhysPrimScale != -1)
  397. {
  398. if (scale.X > WSModule.MaximumPhysPrimScale)
  399. scale.X = WSModule.MaximumPhysPrimScale;
  400. if (scale.Y > WSModule.MaximumPhysPrimScale)
  401. scale.Y = WSModule.MaximumPhysPrimScale;
  402. if (scale.Z > WSModule.MaximumPhysPrimScale)
  403. scale.Z = WSModule.MaximumPhysPrimScale;
  404. }
  405. if (WSModule.MaximumPrimScale != -1)
  406. {
  407. if (scale.X > WSModule.MaximumPrimScale)
  408. scale.X = WSModule.MaximumPrimScale;
  409. if (scale.Y > WSModule.MaximumPrimScale)
  410. scale.Y = WSModule.MaximumPrimScale;
  411. if (scale.Z > WSModule.MaximumPrimScale)
  412. scale.Z = WSModule.MaximumPrimScale;
  413. }
  414. part.Scale = scale;
  415. }
  416. }
  417. //Trigger our event
  418. Scene.EventManager.TriggerObjectBeingAddedToScene(this);
  419. RebuildPhysicalRepresentation(false);
  420. m_ValidgrpOOB = false;
  421. }
  422. public Vector3 GroupScale()
  423. {
  424. if (m_partsList.Count == 1)
  425. return RootPart.Scale;
  426. Vector3 minScale = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  427. Vector3 maxScale = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  428. Vector3 finalScale;
  429. foreach (SceneObjectPart part in m_partsList)
  430. {
  431. Vector3 partscale = part.Scale*0.5f;
  432. // not assuming root is at index 0
  433. if (part.ParentID == 0) // root is in local frame of reference, partscale.? are positive, no rotations
  434. {
  435. // if root is always at index 0 this can be just assigns
  436. if (partscale.X > maxScale.X)
  437. maxScale.X = partscale.X;
  438. if (partscale.Y > maxScale.Y)
  439. maxScale.Y = partscale.Y;
  440. if (partscale.Z > maxScale.Z)
  441. maxScale.Z = partscale.Z;
  442. partscale = -partscale;
  443. if (partscale.X < minScale.X)
  444. minScale.X = partscale.X;
  445. if (partscale.Y < minScale.Y)
  446. minScale.Y = partscale.Y;
  447. if (partscale.Z < minScale.Z)
  448. minScale.Z = partscale.Z;
  449. }
  450. else // prims are in their local frame of reference
  451. {
  452. Vector3 partoffset = part.OffsetPosition;
  453. Quaternion partrot = part.GetRotationOffset();
  454. // bring into this frame
  455. partscale *= partrot;
  456. partoffset *= partrot;
  457. partoffset += part.OffsetPosition;
  458. // now just 2 vertices in a diagonal
  459. Vector3 deltam = partoffset - partscale;
  460. Vector3 deltaM = partoffset + partscale;
  461. if (deltaM.X > deltam.X) // right vertices order for extrem X
  462. {
  463. if (deltam.X < minScale.X)
  464. minScale.X = deltam.X;
  465. if (deltaM.X > maxScale.X)
  466. maxScale.X = deltaM.X;
  467. }
  468. else // nopes inverse one
  469. {
  470. if (deltaM.X < minScale.X)
  471. minScale.X = deltaM.X;
  472. if (deltam.X > maxScale.X)
  473. maxScale.X = deltam.X;
  474. }
  475. if (deltaM.Y > deltam.Y)
  476. {
  477. if (deltam.Y < minScale.Y)
  478. minScale.Y = deltam.Y;
  479. if (deltaM.Y > maxScale.Y)
  480. maxScale.Y = deltaM.Y;
  481. }
  482. else
  483. {
  484. if (deltaM.Y < minScale.Y)
  485. minScale.Y = deltaM.Y;
  486. if (deltam.Y > maxScale.Y)
  487. maxScale.Y = deltam.Y;
  488. }
  489. if (deltaM.Z > deltam.Z)
  490. {
  491. if (deltam.Z < minScale.Z)
  492. minScale.Z = deltam.Z;
  493. if (deltaM.Z > maxScale.Z)
  494. maxScale.Z = deltaM.Z;
  495. }
  496. else
  497. {
  498. if (deltaM.Z < minScale.Z)
  499. minScale.Z = deltaM.Z;
  500. if (deltam.Z > maxScale.Z)
  501. maxScale.Z = deltam.Z;
  502. }
  503. }
  504. }
  505. finalScale.X = Math.Abs(maxScale.X - minScale.X);
  506. finalScale.Y = Math.Abs(maxScale.Y - minScale.Y);
  507. finalScale.Z = Math.Abs(maxScale.Z - minScale.Z);
  508. return finalScale;
  509. }
  510. public override int GetHashCode()
  511. {
  512. return UUID.GetHashCode();
  513. }
  514. public bool IsPhysical()
  515. {
  516. return ((RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics);
  517. }
  518. public void UpdateOOBfromOOBs()
  519. {
  520. if (m_partsList.Count == 1)
  521. {
  522. SceneObjectPart part = m_partsList.First();
  523. m_grpOOBsize = part.OOBsize;
  524. m_grpOOBoffset = part.OOBoffset;
  525. m_grpBSphereRadiusSQ = part.BSphereRadiusSQ;
  526. m_ValidgrpOOB = true;
  527. return;
  528. }
  529. Vector3 minScale = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  530. Vector3 maxScale = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  531. foreach (SceneObjectPart part in m_partsList)
  532. {
  533. Vector3 partscale = part.OOBsize; // (oobsize == vector with box vertice with all coords positive)
  534. Vector3 partoffset = part.OOBoffset;
  535. // not assuming root is at index 0
  536. Vector3 deltam;
  537. Vector3 deltaM;
  538. if (part.ParentID == 0) // root is in local frame of reference, partscale.? are positive, no rotations
  539. {
  540. //2 vertices in the right extrem sides:
  541. deltam = partoffset - partscale;
  542. deltaM = partoffset + partscale;
  543. // if root is always at index 0 this can be just assigns
  544. if (deltam.X < minScale.X)
  545. minScale.X = deltam.X;
  546. if (deltam.Y < minScale.Y)
  547. minScale.Y = deltam.Y;
  548. if (deltam.Z < minScale.Z)
  549. minScale.Z = deltam.Z;
  550. if (deltaM.X > maxScale.X)
  551. maxScale.X = deltaM.X;
  552. if (deltaM.Y > maxScale.Y)
  553. maxScale.Y = deltaM.Y;
  554. if (deltaM.Z > maxScale.Z)
  555. maxScale.Z = deltaM.Z;
  556. }
  557. else // prims are in their local frame of reference
  558. {
  559. // bring into this frame
  560. Quaternion partrot = part.GetRotationOffset();
  561. partscale *= partrot;
  562. partoffset *= partrot;
  563. partoffset += part.OffsetPosition;
  564. // now just 2 vertices in a diagonal
  565. deltam = partoffset - partscale;
  566. deltaM = partoffset + partscale;
  567. if (deltaM.X > deltam.X) // right vertices order for extrem X
  568. {
  569. if (deltam.X < minScale.X)
  570. minScale.X = deltam.X;
  571. if (deltaM.X > maxScale.X)
  572. maxScale.X = deltaM.X;
  573. }
  574. else // nopes inverse one
  575. {
  576. if (deltaM.X < minScale.X)
  577. minScale.X = deltaM.X;
  578. if (deltam.X > maxScale.X)
  579. maxScale.X = deltam.X;
  580. }
  581. if (deltaM.Y > deltam.Y)
  582. {
  583. if (deltam.Y < minScale.Y)
  584. minScale.Y = deltam.Y;
  585. if (deltaM.Y > maxScale.Y)
  586. maxScale.Y = deltaM.Y;
  587. }
  588. else
  589. {
  590. if (deltaM.Y < minScale.Y)
  591. minScale.Y = deltaM.Y;
  592. if (deltam.Y > maxScale.Y)
  593. maxScale.Y = deltam.Y;
  594. }
  595. if (deltaM.Z > deltam.Z)
  596. {
  597. if (deltam.Z < minScale.Z)
  598. minScale.Z = deltam.Z;
  599. if (deltaM.Z > maxScale.Z)
  600. maxScale.Z = deltaM.Z;
  601. }
  602. else
  603. {
  604. if (deltaM.Z < minScale.Z)
  605. minScale.Z = deltaM.Z;
  606. if (deltam.Z > maxScale.Z)
  607. maxScale.Z = deltam.Z;
  608. }
  609. }
  610. }
  611. // size == the vertice of box with all coords positive
  612. m_grpOOBsize.X = 0.5f*Math.Abs(maxScale.X - minScale.X);
  613. m_grpOOBsize.Y = 0.5f*Math.Abs(maxScale.Y - minScale.Y);
  614. m_grpOOBsize.Z = 0.5f*Math.Abs(maxScale.Z - minScale.Z);
  615. // centroid:
  616. m_grpOOBoffset.X = 0.5f*(maxScale.X + minScale.X);
  617. m_grpOOBoffset.Y = 0.5f*(maxScale.Y + minScale.Y);
  618. m_grpOOBoffset.Z = 0.5f*(maxScale.Z + minScale.Z);
  619. // containing sphere:
  620. m_grpBSphereRadiusSQ = m_grpOOBsize.LengthSquared();
  621. m_ValidgrpOOB = true;
  622. }
  623. public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
  624. {
  625. // We got a request from the inner_scene to raytrace along the Ray hRay
  626. // We're going to check all of the prim in this group for intersection with the ray
  627. // If we get a result, we're going to find the closest result to the origin of the ray
  628. // and send back the intersection information back to the innerscene.
  629. EntityIntersection result = new EntityIntersection();
  630. foreach (SceneObjectPart part in m_partsList)
  631. {
  632. // Temporary commented to stop compiler warning
  633. //Vector3 partPosition =
  634. // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
  635. Quaternion parentrotation = GroupRotation;
  636. // Telling the prim to raytrace.
  637. //EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
  638. EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
  639. // This may need to be updated to the maximum draw distance possible..
  640. // We might (and probably will) be checking for prim creation from other sims
  641. // when the camera crosses the border.
  642. if (m_scene != null)
  643. {
  644. float idist = (m_scene.RegionInfo.RegionSizeX + m_scene.RegionInfo.RegionSizeY)/2;
  645. if (inter.HitTF)
  646. {
  647. // We need to find the closest prim to return to the testcaller along the ray
  648. if (inter.distance < idist)
  649. {
  650. result.HitTF = true;
  651. result.ipoint = inter.ipoint;
  652. result.obj = part;
  653. result.normal = inter.normal;
  654. result.distance = inter.distance;
  655. }
  656. }
  657. }
  658. }
  659. return result;
  660. }
  661. /// <summary>
  662. /// Gets a vector representing the size of the bounding box containing all the prims in the group
  663. /// Treats all prims as rectangular, so no shape (cut etc) is taken into account
  664. /// offsetHeight is the offset in the Z axis from the centre of the bounding box to the centre of the root prim
  665. /// </summary>
  666. /// <returns></returns>
  667. public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY,
  668. out float minZ, out float maxZ)
  669. {
  670. Vector3 pos = m_rootPart.AbsolutePosition;
  671. Quaternion rot = m_rootPart.GetRotationOffset();
  672. // Vector3 size = GroupScale();
  673. Vector3 minScale = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  674. Vector3 maxScale = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  675. //limits in group frame
  676. foreach (SceneObjectPart part in m_partsList)
  677. {
  678. Vector3 partscale = part.Scale*0.5f;
  679. Vector3 partoffset = part.OffsetPosition;
  680. if (part.ParentID != 0) // prims are rotated in group
  681. {
  682. partscale *= part.GetRotationOffset();
  683. partscale.X = Math.Abs(partscale.X);
  684. partscale.Y = Math.Abs(partscale.Y);
  685. partscale.Z = Math.Abs(partscale.Z);
  686. }
  687. Vector3 deltam = partoffset - partscale;
  688. Vector3 deltaM = partoffset + partscale;
  689. if (deltam.X < minScale.X)
  690. minScale.X = deltam.X;
  691. if (deltam.Y < minScale.Y)
  692. minScale.Y = deltam.Y;
  693. if (deltam.Z < minScale.Z)
  694. minScale.Z = deltam.Z;
  695. if (deltaM.X > maxScale.X)
  696. maxScale.X = deltaM.X;
  697. if (deltaM.Y > maxScale.Y)
  698. maxScale.Y = deltaM.Y;
  699. if (deltaM.Z > maxScale.Z)
  700. maxScale.Z = deltaM.Z;
  701. }
  702. Vector3 tmp;
  703. tmp.X = 0.5f*Math.Abs(maxScale.X - minScale.X);
  704. tmp.Y = 0.5f*Math.Abs(maxScale.Y - minScale.Y);
  705. tmp.Z = 0.5f*Math.Abs(maxScale.Z - minScale.Z);
  706. // tmp has half scale
  707. // group rotation
  708. tmp = tmp*rot;
  709. // scale is positive
  710. tmp.X = Math.Abs(tmp.X);
  711. tmp.Y = Math.Abs(tmp.Y);
  712. tmp.Z = Math.Abs(tmp.Z);
  713. // group position
  714. minX = pos.X - tmp.X;
  715. minY = pos.Y - tmp.Y;
  716. minZ = pos.Z - tmp.Z;
  717. maxX = pos.X + tmp.X;
  718. maxY = pos.Y + tmp.Y;
  719. maxZ = pos.Z + tmp.Z;
  720. /*
  721. maxX = -256f;
  722. maxY = -256f;
  723. maxZ = -256f;
  724. minX = 256f;
  725. minY = 256f;
  726. minZ = 8192f;
  727. foreach (SceneObjectPart part in m_partsList)
  728. {
  729. Vector3 worldPos = part.GetWorldPosition();
  730. Vector3 offset = worldPos - AbsolutePosition;
  731. Quaternion worldRot;
  732. if (part.ParentID == 0)
  733. worldRot = part.RotationOffset;
  734. else
  735. worldRot = part.GetWorldRotation();
  736. Vector3 frontTopLeft;
  737. Vector3 frontTopRight;
  738. Vector3 frontBottomLeft;
  739. Vector3 frontBottomRight;
  740. Vector3 backTopLeft;
  741. Vector3 backTopRight;
  742. Vector3 backBottomLeft;
  743. Vector3 backBottomRight;
  744. Vector3 orig = Vector3.Zero;
  745. frontTopLeft.X = orig.X - (part.Scale.X / 2);
  746. frontTopLeft.Y = orig.Y - (part.Scale.Y / 2);
  747. frontTopLeft.Z = orig.Z + (part.Scale.Z / 2);
  748. frontTopRight.X = orig.X - (part.Scale.X / 2);
  749. frontTopRight.Y = orig.Y + (part.Scale.Y / 2);
  750. frontTopRight.Z = orig.Z + (part.Scale.Z / 2);
  751. frontBottomLeft.X = orig.X - (part.Scale.X / 2);
  752. frontBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
  753. frontBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
  754. frontBottomRight.X = orig.X - (part.Scale.X / 2);
  755. frontBottomRight.Y = orig.Y + (part.Scale.Y / 2);
  756. frontBottomRight.Z = orig.Z - (part.Scale.Z / 2);
  757. backTopLeft.X = orig.X + (part.Scale.X / 2);
  758. backTopLeft.Y = orig.Y - (part.Scale.Y / 2);
  759. backTopLeft.Z = orig.Z + (part.Scale.Z / 2);
  760. backTopRight.X = orig.X + (part.Scale.X / 2);
  761. backTopRight.Y = orig.Y + (part.Scale.Y / 2);
  762. backTopRight.Z = orig.Z + (part.Scale.Z / 2);
  763. backBottomLeft.X = orig.X + (part.Scale.X / 2);
  764. backBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
  765. backBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
  766. backBottomRight.X = orig.X + (part.Scale.X / 2);
  767. backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
  768. backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
  769. frontTopLeft = frontTopLeft * worldRot;
  770. frontTopRight = frontTopRight * worldRot;
  771. frontBottomLeft = frontBottomLeft * worldRot;
  772. frontBottomRight = frontBottomRight * worldRot;
  773. backBottomLeft = backBottomLeft * worldRot;
  774. backBottomRight = backBottomRight * worldRot;
  775. backTopLeft = backTopLeft * worldRot;
  776. backTopRight = backTopRight * worldRot;
  777. frontTopLeft += offset;
  778. frontTopRight += offset;
  779. frontBottomLeft += offset;
  780. frontBottomRight += offset;
  781. backBottomLeft += offset;
  782. backBottomRight += offset;
  783. backTopLeft += offset;
  784. backTopRight += offset;
  785. if (frontTopRight.X > maxX)
  786. maxX = frontTopRight.X;
  787. if (frontTopLeft.X > maxX)
  788. maxX = frontTopLeft.X;
  789. if (frontBottomRight.X > maxX)
  790. maxX = frontBottomRight.X;
  791. if (frontBottomLeft.X > maxX)
  792. maxX = frontBottomLeft.X;
  793. if (backTopRight.X > maxX)
  794. maxX = backTopRight.X;
  795. if (backTopLeft.X > maxX)
  796. maxX = backTopLeft.X;
  797. if (backBottomRight.X > maxX)
  798. maxX = backBottomRight.X;
  799. if (backBottomLeft.X > maxX)
  800. maxX = backBottomLeft.X;
  801. if (frontTopRight.X < minX)
  802. minX = frontTopRight.X;
  803. if (frontTopLeft.X < minX)
  804. minX = frontTopLeft.X;
  805. if (frontBottomRight.X < minX)
  806. minX = frontBottomRight.X;
  807. if (frontBottomLeft.X < minX)
  808. minX = frontBottomLeft.X;
  809. if (backTopRight.X < minX)
  810. minX = backTopRight.X;
  811. if (backTopLeft.X < minX)
  812. minX = backTopLeft.X;
  813. if (backBottomRight.X < minX)
  814. minX = backBottomRight.X;
  815. if (backBottomLeft.X < minX)
  816. minX = backBottomLeft.X;
  817. if (frontTopRight.Y > maxY)
  818. maxY = frontTopRight.Y;
  819. if (frontTopLeft.Y > maxY)
  820. maxY = frontTopLeft.Y;
  821. if (frontBottomRight.Y > maxY)
  822. maxY = frontBottomRight.Y;
  823. if (frontBottomLeft.Y > maxY)
  824. maxY = frontBottomLeft.Y;
  825. if (backTopRight.Y > maxY)
  826. maxY = backTopRight.Y;
  827. if (backTopLeft.Y > maxY)
  828. maxY = backTopLeft.Y;
  829. if (backBottomRight.Y > maxY)
  830. maxY = backBottomRight.Y;
  831. if (backBottomLeft.Y > maxY)
  832. maxY = backBottomLeft.Y;
  833. if (backTopRight.Y < minY)
  834. minY = backTopRight.Y;
  835. if (backTopLeft.Y < minY)
  836. minY = backTopLeft.Y;
  837. if (backBottomRight.Y < minY)
  838. minY = backBottomRight.Y;
  839. if (backBottomLeft.Y < minY)
  840. minY = backBottomLeft.Y;
  841. if (backTopRight.Y < minY)
  842. minY = backTopRight.Y;
  843. if (backTopLeft.Y < minY)
  844. minY = backTopLeft.Y;
  845. if (backBottomRight.Y < minY)
  846. minY = backBottomRight.Y;
  847. if (backBottomLeft.Y < minY)
  848. minY = backBottomLeft.Y;
  849. if (frontTopRight.Z > maxZ)
  850. maxZ = frontTopRight.Z;
  851. if (frontTopLeft.Z > maxZ)
  852. maxZ = frontTopLeft.Z;
  853. if (frontBottomRight.Z > maxZ)
  854. maxZ = frontBottomRight.Z;
  855. if (frontBottomLeft.Z > maxZ)
  856. maxZ = frontBottomLeft.Z;
  857. if (backTopRight.Z > maxZ)
  858. maxZ = backTopRight.Z;
  859. if (backTopLeft.Z > maxZ)
  860. maxZ = backTopLeft.Z;
  861. if (backBottomRight.Z > maxZ)
  862. maxZ = backBottomRight.Z;
  863. if (backBottomLeft.Z > maxZ)
  864. maxZ = backBottomLeft.Z;
  865. if (frontTopRight.Z < minZ)
  866. minZ = frontTopRight.Z;
  867. if (frontTopLeft.Z < minZ)
  868. minZ = frontTopLeft.Z;
  869. if (frontBottomRight.Z < minZ)
  870. minZ = frontBottomRight.Z;
  871. if (frontBottomLeft.Z < minZ)
  872. minZ = frontBottomLeft.Z;
  873. if (backTopRight.Z < minZ)
  874. minZ = backTopRight.Z;
  875. if (backTopLeft.Z < minZ)
  876. minZ = backTopLeft.Z;
  877. if (backBottomRight.Z < minZ)
  878. minZ = backBottomRight.Z;
  879. if (backBottomLeft.Z < minZ)
  880. minZ = backBottomLeft.Z;
  881. }
  882. */
  883. }
  884. public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
  885. {
  886. float minX;
  887. float maxX;
  888. float minY;
  889. float maxY;
  890. float minZ;
  891. float maxZ;
  892. GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
  893. Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ);
  894. offsetHeight = 0.5f*(maxZ + minZ);
  895. offsetHeight -= m_rootPart.AbsolutePosition.Z;
  896. /*
  897. offsetHeight = 0;
  898. float lower = (minZ * -1);
  899. if (lower > maxZ)
  900. {
  901. offsetHeight = lower - (boundingBox.Z / 2);
  902. }
  903. else if (maxZ > lower)
  904. {
  905. offsetHeight = maxZ - (boundingBox.Z / 2);
  906. offsetHeight *= -1;
  907. }
  908. */
  909. // MainConsole.Instance.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z);
  910. return boundingBox;
  911. }
  912. #region Adding/Removing children from this group
  913. /// <summary>
  914. /// Clear all children from this group
  915. /// </summary>
  916. public void ClearChildren()
  917. {
  918. lock (m_partsLock)
  919. {
  920. m_parts.Clear();
  921. m_partsList.Clear();
  922. m_ValidgrpOOB = false;
  923. }
  924. }
  925. /// <summary>
  926. /// Add a child to the group, set the parent id's and then set the link number
  927. /// </summary>
  928. /// <param name="child"></param>
  929. /// <param name="linkNum"></param>
  930. /// <returns></returns>
  931. public bool AddChild(ISceneChildEntity child, int linkNum)
  932. {
  933. lock (m_partsLock)
  934. {
  935. if (child is SceneObjectPart)
  936. {
  937. SceneObjectPart part = (SceneObjectPart) child;
  938. //Root part is first
  939. if (m_partsList.Count == 0)
  940. {
  941. m_rootPart = part;
  942. }
  943. //Set the parent prim
  944. part.SetParent(this);
  945. if (m_rootPart.LocalId != 0 && !part.IsRoot)
  946. part.SetParentLocalId(m_rootPart.LocalId);
  947. else
  948. part.SetParentLocalId(0);
  949. //Fix the link num
  950. part.LinkNum = linkNum;
  951. if (!m_parts.ContainsKey(child.UUID))
  952. {
  953. m_parts.Add(child.UUID, part);
  954. m_partsList.Add(part);
  955. m_ValidgrpOOB = false;
  956. }
  957. return true;
  958. }
  959. }
  960. return false;
  961. }
  962. /// <summary>
  963. /// Add this child to the group and set the parent ID's,
  964. /// but do NOT set the link number,
  965. /// the caller wants to deal with it if they call this
  966. /// </summary>
  967. /// <param name="child"></param>
  968. /// <returns></returns>
  969. public bool LinkChild(ISceneChildEntity child)
  970. {
  971. lock (m_partsLock)
  972. {
  973. if (child is SceneObjectPart)
  974. {
  975. SceneObjectPart part = (SceneObjectPart) child;
  976. //Root part is first
  977. if (m_partsList.Count == 0)
  978. {
  979. m_rootPart = part;
  980. }
  981. //Set the parent prim
  982. part.SetParent(this);
  983. part.SetParentLocalId(m_rootPart.LocalId);
  984. if (!m_parts.ContainsKey(child.UUID))
  985. {
  986. m_parts.Add(child.UUID, part);
  987. m_partsList.Add(part);
  988. m_ValidgrpOOB = false;
  989. }
  990. m_partsList.Sort(m_scene.SceneGraph.LinkSetSorter);
  991. return true;
  992. }
  993. }
  994. return false;
  995. }
  996. /// <summary>
  997. /// Remove this child from the group and then update the link numbers so that there is not a hole
  998. /// </summary>
  999. /// <param name="child"></param>
  1000. /// <returns></returns>
  1001. public bool RemoveChild(ISceneChildEntity child)
  1002. {
  1003. lock (m_partsLock)
  1004. {
  1005. if (child is SceneObjectPart)
  1006. {
  1007. SceneObjectPart part = (SceneObjectPart) child;
  1008. m_parts.Remove(part.UUID);
  1009. m_partsList.Remove(part);
  1010. m_ValidgrpOOB = false;
  1011. //Fix the link numbers now
  1012. FixLinkNumbers();
  1013. return true;
  1014. }
  1015. }
  1016. return false;
  1017. }
  1018. /// <summary>
  1019. /// After a prim is removed, fix the link numbers so that they are correct
  1020. /// </summary>
  1021. private void FixLinkNumbers()
  1022. {
  1023. if (m_partsList.Count == 1)
  1024. {
  1025. m_partsList[0].LinkNum = 0;
  1026. return;
  1027. }
  1028. lock (m_partsLock)
  1029. {
  1030. // has prims so starts at 1
  1031. int lastSeenLinkNum = 1;
  1032. m_partsList.Sort(Scene.SceneGraph.LinkSetSorter);
  1033. foreach (SceneObjectPart t in m_partsList)
  1034. {
  1035. //If it isn't the same as the last seen +1, fix it
  1036. if (t != null && t.LinkNum != lastSeenLinkNum)
  1037. t.LinkNum = lastSeenLinkNum;
  1038. //Go onto the next prim
  1039. lastSeenLinkNum++;
  1040. }
  1041. }
  1042. }
  1043. #endregion
  1044. #endregion
  1045. /// <summary>
  1046. /// The position center of the bounding box relative to it's Position
  1047. /// </summary>
  1048. [XmlIgnore]
  1049. public Vector3 OOBoffset
  1050. {
  1051. get
  1052. {
  1053. if (!m_ValidgrpOOB)
  1054. UpdateOOBfromOOBs();
  1055. return m_grpOOBoffset;
  1056. }
  1057. }
  1058. public object ChildrenListLock
  1059. {
  1060. get { return m_partsLock; }
  1061. }
  1062. #region ISceneObject Members
  1063. public event BlankHandler OnFinishedPhysicalRepresentationBuilding;
  1064. public Vector3 LastSignificantPosition
  1065. {
  1066. get { return m_lastSignificantPosition; }
  1067. }
  1068. public UUID LastParcelUUID
  1069. {
  1070. get { return m_lastParcelUUID; }
  1071. set { m_lastParcelUUID = value; }
  1072. }
  1073. /// <summary>
  1074. /// The size of a bounding box oriented as prim, is future will consider cutted prims, meshs etc
  1075. /// </summary>
  1076. [XmlIgnore]
  1077. public Vector3 OOBsize
  1078. {
  1079. get
  1080. {
  1081. if (!m_ValidgrpOOB)
  1082. UpdateOOBfromOOBs();
  1083. return m_grpOOBsize;
  1084. }
  1085. }
  1086. /// <summary>
  1087. /// The square of the radius of a sphere containing the oob
  1088. /// </summary>
  1089. [XmlIgnore]
  1090. public float BSphereRadiusSQ
  1091. {
  1092. get
  1093. {
  1094. if (!m_ValidgrpOOB)
  1095. UpdateOOBfromOOBs();
  1096. return m_grpBSphereRadiusSQ;
  1097. }
  1098. }
  1099. public override bool HasGroupChanged
  1100. {
  1101. get { return m_hasGroupChanged; }
  1102. set
  1103. {
  1104. if (value)
  1105. {
  1106. if (m_scene != null)
  1107. {
  1108. IBackupModule backup = m_scene.RequestModuleInterface<IBackupModule>();
  1109. if (backup != null)
  1110. {
  1111. if (!backup.LoadingPrims) //Do NOT add to backup while still loading prims
  1112. backup.AddPrimBackupTaint(this);
  1113. }
  1114. }
  1115. }
  1116. m_hasGroupChanged = value;
  1117. }
  1118. }
  1119. /// <summary>
  1120. /// Force all prims in the scene object to persist
  1121. /// </summary>
  1122. public void ForcePersistence()
  1123. {
  1124. //Force normal backup
  1125. HasGroupChanged = true;
  1126. ForceInventoryPersistence();
  1127. }
  1128. /// <summary>
  1129. /// Clears all undo states from this group
  1130. /// </summary>
  1131. public void ClearUndoState()
  1132. {
  1133. foreach (SceneObjectPart child in ChildrenList)
  1134. {
  1135. child.ClearUndoState();
  1136. }
  1137. }
  1138. /// <value>
  1139. /// Is this scene object acting as an attachment?
  1140. /// We return false if the group has already been deleted.
  1141. /// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I
  1142. /// presume either all or no parts in a linkset can be part of an attachment (in which
  1143. /// case the value would get proprogated down into all the descendent parts).
  1144. /// </value>
  1145. public bool IsAttachment
  1146. {
  1147. get { return m_rootPart.IsAttachment; }
  1148. }
  1149. //private bool m_isBackedUp = false;
  1150. public byte GetAttachmentPoint()
  1151. {
  1152. return m_rootPart.Shape.State;
  1153. }
  1154. public Vector3 GetAttachmentPos()
  1155. {
  1156. return m_rootPart.SavedAttachedPos;
  1157. }
  1158. public byte GetSavedAttachmentPoint()
  1159. {
  1160. return (byte) m_rootPart.SavedAttachmentPoint;
  1161. }
  1162. public void FinishedSerializingGenericProperties()
  1163. {
  1164. foreach (

Large files files are truncated, but you can click here to view the full file