aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs53
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs84
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs29
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs218
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs38
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs162
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs150
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs444
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs13
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs26
-rw-r--r--OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs4
-rw-r--r--OpenSim/Services/HypergridService/HGFriendsService.cs2
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs2
-rw-r--r--OpenSim/Services/Interfaces/IPresenceService.cs38
16 files changed, 810 insertions, 461 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 11db18a..f1903c3 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Linq;
31using System.Reflection; 32using System.Reflection;
32using System.Threading; 33using System.Threading;
33using log4net; 34using log4net;
@@ -495,42 +496,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
495 496
496 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) 497 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
497 { 498 {
498 foreach (FriendInfo friend in friendList) 499 List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend);
500 List<string> remoteFriendStringIds = new List<string>();
501 foreach (string friendStringId in friendStringIds)
499 { 502 {
500 UUID friendID; 503 UUID friendUuid;
501 if (UUID.TryParse(friend.Friend, out friendID)) 504 if (UUID.TryParse(friendStringId, out friendUuid))
502 { 505 {
503 // Try local 506 if (LocalStatusNotification(userID, friendUuid, online))
504 if (LocalStatusNotification(userID, friendID, online))
505 continue; 507 continue;
506 508
507 // The friend is not here [as root]. Let's forward. 509 remoteFriendStringIds.Add(friendStringId);
508 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
509 if (friendSessions != null && friendSessions.Length > 0)
510 {
511 PresenceInfo friendSession = null;
512 foreach (PresenceInfo pinfo in friendSessions)
513 {
514 if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad
515 {
516 friendSession = pinfo;
517 break;
518 }
519 }
520
521 if (friendSession != null)
522 {
523 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
524 //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
525 m_FriendsSimConnector.StatusNotify(region, userID, friendID, online);
526 }
527 }
528
529 // Friend is not online. Ignore.
530 } 510 }
531 else 511 else
532 { 512 {
533 m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend); 513 m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friendStringId);
514 }
515 }
516
517 // We do this regrouping so that we can efficiently send a single request rather than one for each
518 // friend in what may be a very large friends list.
519 PresenceInfo[] friendSessions = PresenceService.GetAgents(remoteFriendStringIds.ToArray());
520
521 foreach (PresenceInfo friendSession in friendSessions)
522 {
523 // let's guard against sessions-gone-bad
524 if (friendSession.RegionID != UUID.Zero)
525 {
526 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
527 //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
528 m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online);
534 } 529 }
535 } 530 }
536 } 531 }
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index 28cd09f..e238d01 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -66,9 +66,9 @@ namespace OpenSim.Region.Framework.Scenes
66// /// </summary> 66// /// </summary>
67// private bool m_waitingForObjectAsset; 67// private bool m_waitingForObjectAsset;
68 68
69 public UuidGatherer(IAssetService assetCache) 69 public UuidGatherer(IAssetService assetService)
70 { 70 {
71 m_assetService = assetCache; 71 m_assetService = assetService;
72 } 72 }
73 73
74 /// <summary> 74 /// <summary>
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
index 10b83e6..1528330 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Reflection; 31using System.Reflection;
31using log4net; 32using log4net;
32using Mono.Addins; 33using Mono.Addins;
@@ -36,6 +37,8 @@ using OpenMetaverse.StructuredData;
36using OpenSim.Framework; 37using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
39 42
40namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups 43namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
41{ 44{
@@ -45,6 +48,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 49
47 private List<Scene> m_sceneList = new List<Scene>(); 50 private List<Scene> m_sceneList = new List<Scene>();
51 private IPresenceService m_presenceService;
48 52
49 private IMessageTransferModule m_msgTransferModule = null; 53 private IMessageTransferModule m_msgTransferModule = null;
50 54
@@ -54,6 +58,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
54 private bool m_groupMessagingEnabled = false; 58 private bool m_groupMessagingEnabled = false;
55 private bool m_debugEnabled = true; 59 private bool m_debugEnabled = true;
56 60
61 /// <summary>
62 /// If enabled, module only tries to send group IMs to online users by querying cached presence information.
63 /// </summary>
64 private bool m_messageOnlineAgentsOnly;
65
66 /// <summary>
67 /// Cache for online users.
68 /// </summary>
69 /// <remarks>
70 /// Group ID is key, presence information for online members is value.
71 /// Will only be non-null if m_messageOnlineAgentsOnly = true
72 /// We cache here so that group messages don't constantly have to re-request the online user list to avoid
73 /// attempted expensive sending of messages to offline users.
74 /// The tradeoff is that a user that comes online will not receive messages consistently from all other users
75 /// until caches have updated.
76 /// Therefore, we set the cache expiry to just 20 seconds.
77 /// </remarks>
78 private ExpiringCache<UUID, PresenceInfo[]> m_usersOnlineCache;
79
80 private int m_usersOnlineCacheExpirySeconds = 20;
81
57 #region IRegionModuleBase Members 82 #region IRegionModuleBase Members
58 83
59 public void Initialise(IConfigSource config) 84 public void Initialise(IConfigSource config)
@@ -83,10 +108,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
83 return; 108 return;
84 } 109 }
85 110
111 m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false);
112
113 if (m_messageOnlineAgentsOnly)
114 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
115
86 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true); 116 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true);
87 } 117 }
88 118
89 m_log.Info("[GROUPS-MESSAGING]: GroupsMessagingModule starting up"); 119 m_log.InfoFormat(
120 "[GROUPS-MESSAGING]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}",
121 m_messageOnlineAgentsOnly, m_debugEnabled);
90 } 122 }
91 123
92 public void AddRegion(Scene scene) 124 public void AddRegion(Scene scene)
@@ -126,6 +158,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
126 return; 158 return;
127 } 159 }
128 160
161 if (m_presenceService == null)
162 m_presenceService = scene.PresenceService;
129 163
130 m_sceneList.Add(scene); 164 m_sceneList.Add(scene);
131 165
@@ -207,12 +241,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
207 public void SendMessageToGroup(GridInstantMessage im, UUID groupID) 241 public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
208 { 242 {
209 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID); 243 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID);
210 244 int groupMembersCount = groupMembers.Count;
211 if (m_debugEnabled) 245
212 m_log.DebugFormat( 246 if (m_messageOnlineAgentsOnly)
213 "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members", 247 {
214 groupID, groupMembers.Count); 248 string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray();
215 249
250 // We cache in order not to overwhlem the presence service on large grids with many groups. This does
251 // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed.
252 // (assuming this is the same across all grid simulators).
253 PresenceInfo[] onlineAgents;
254 if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents))
255 {
256 onlineAgents = m_presenceService.GetAgents(t1);
257 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
258 }
259
260 HashSet<string> onlineAgentsUuidSet = new HashSet<string>();
261 Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID));
262
263 groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
264
265 // if (m_debugEnabled)
266// m_log.DebugFormat(
267// "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members, {2} online",
268// groupID, groupMembersCount, groupMembers.Count());
269 }
270 else
271 {
272 if (m_debugEnabled)
273 m_log.DebugFormat(
274 "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members",
275 groupID, groupMembers.Count);
276 }
277
278 int requestStartTick = Environment.TickCount;
279
216 foreach (GroupMembersData member in groupMembers) 280 foreach (GroupMembersData member in groupMembers)
217 { 281 {
218 if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID)) 282 if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID))
@@ -254,6 +318,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
254 ProcessMessageFromGroupSession(msg); 318 ProcessMessageFromGroupSession(msg);
255 } 319 }
256 } 320 }
321
322 // Temporary for assessing how long it still takes to send messages to large online groups.
323 if (m_messageOnlineAgentsOnly)
324 m_log.DebugFormat(
325 "[GROUPS-MESSAGING]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms",
326 groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick);
257 } 327 }
258 328
259 #region SimGridEventHandlers 329 #region SimGridEventHandlers
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
index e669f4c..b9b4413 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
@@ -123,7 +123,36 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
123 public void AddRegion(Scene scene) 123 public void AddRegion(Scene scene)
124 { 124 {
125 if (m_groupsEnabled) 125 if (m_groupsEnabled)
126 {
126 scene.RegisterModuleInterface<IGroupsModule>(this); 127 scene.RegisterModuleInterface<IGroupsModule>(this);
128 scene.AddCommand(
129 "debug",
130 this,
131 "debug groups verbose",
132 "debug groups verbose <true|false>",
133 "This setting turns on very verbose groups debugging",
134 HandleDebugGroupsVerbose);
135 }
136 }
137
138 private void HandleDebugGroupsVerbose(object modules, string[] args)
139 {
140 if (args.Length < 4)
141 {
142 MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
143 return;
144 }
145
146 bool verbose = false;
147 if (!bool.TryParse(args[3], out verbose))
148 {
149 MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
150 return;
151 }
152
153 m_debugEnabled = verbose;
154
155 MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
127 } 156 }
128 157
129 public void RegionLoaded(Scene scene) 158 public void RegionLoaded(Scene scene)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 2e6b2da..623ac8f 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -41,8 +41,6 @@ public class BSCharacter : BSPhysObject
41 41
42 // private bool _stopped; 42 // private bool _stopped;
43 private OMV.Vector3 _size; 43 private OMV.Vector3 _size;
44 private OMV.Vector3 _scale;
45 private PrimitiveBaseShape _pbs;
46 private bool _grabbed; 44 private bool _grabbed;
47 private bool _selected; 45 private bool _selected;
48 private OMV.Vector3 _position; 46 private OMV.Vector3 _position;
@@ -67,6 +65,10 @@ public class BSCharacter : BSPhysObject
67 private bool _kinematic; 65 private bool _kinematic;
68 private float _buoyancy; 66 private float _buoyancy;
69 67
68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71
70 private OMV.Vector3 _PIDTarget; 72 private OMV.Vector3 _PIDTarget;
71 private bool _usePID; 73 private bool _usePID;
72 private float _PIDTau; 74 private float _PIDTau;
@@ -84,14 +86,18 @@ public class BSCharacter : BSPhysObject
84 _flying = isFlying; 86 _flying = isFlying;
85 _orientation = OMV.Quaternion.Identity; 87 _orientation = OMV.Quaternion.Identity;
86 _velocity = OMV.Vector3.Zero; 88 _velocity = OMV.Vector3.Zero;
89 _appliedVelocity = OMV.Vector3.Zero;
87 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
92 _avatarDensity = PhysicsScene.Params.avatarDensity;
88 93
89 // The dimensions of the avatar capsule are kept in the scale. 94 // The dimensions of the avatar capsule are kept in the scale.
90 // Physics creates a unit capsule which is scaled by the physics engine. 95 // Physics creates a unit capsule which is scaled by the physics engine.
91 ComputeAvatarScale(_size); 96 ComputeAvatarScale(_size);
92 _avatarDensity = PhysicsScene.Params.avatarDensity; 97 // set _avatarVolume and _mass based on capsule size, _density and Scale
93 // set _avatarVolume and _mass based on capsule size, _density and _scale
94 ComputeAvatarVolumeAndMass(); 98 ComputeAvatarVolumeAndMass();
99 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
100 LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
95 101
96 ShapeData shapeData = new ShapeData(); 102 ShapeData shapeData = new ShapeData();
97 shapeData.ID = LocalID; 103 shapeData.ID = LocalID;
@@ -99,28 +105,22 @@ public class BSCharacter : BSPhysObject
99 shapeData.Position = _position; 105 shapeData.Position = _position;
100 shapeData.Rotation = _orientation; 106 shapeData.Rotation = _orientation;
101 shapeData.Velocity = _velocity; 107 shapeData.Velocity = _velocity;
102 shapeData.Scale = _scale; 108 shapeData.Size = Scale;
109 shapeData.Scale = Scale;
103 shapeData.Mass = _mass; 110 shapeData.Mass = _mass;
104 shapeData.Buoyancy = _buoyancy; 111 shapeData.Buoyancy = _buoyancy;
105 shapeData.Static = ShapeData.numericFalse; 112 shapeData.Static = ShapeData.numericFalse;
106 shapeData.Friction = PhysicsScene.Params.avatarFriction; 113 shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
107 shapeData.Restitution = PhysicsScene.Params.avatarRestitution; 114 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
108 115
109 // do actual create at taint time 116 // do actual create at taint time
110 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 117 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
111 { 118 {
112 DetailLog("{0},BSCharacter.create,taint", LocalID); 119 DetailLog("{0},BSCharacter.create,taint", LocalID);
113 BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData); 120 // New body and shape into BSBody and BSShape
121 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
114 122
115 // Set the buoyancy for flying. This will be refactored when all the settings happen in C#. 123 SetPhysicalProperties();
116 // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
117 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
118
119 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
120
121 // This works here because CreateObject has already put the character into the physical world.
122 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
123 (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
124 }); 124 });
125 return; 125 return;
126 } 126 }
@@ -131,53 +131,85 @@ public class BSCharacter : BSPhysObject
131 DetailLog("{0},BSCharacter.Destroy", LocalID); 131 DetailLog("{0},BSCharacter.Destroy", LocalID);
132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
133 { 133 {
134 BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID); 134 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
135 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
135 }); 136 });
136 } 137 }
137 138
139 private void SetPhysicalProperties()
140 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
142
143 ZeroMotion();
144 ForcePosition = _position;
145 // Set the velocity and compute the proper friction
146 ForceVelocity = _velocity;
147 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
148 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
149 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
150 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
151 {
152 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
153 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
154 }
155
156 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
157 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
158
159 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
160
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
162
163 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
165
166 // Do this after the object has been added to the world
167 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
168 (uint)CollisionFilterGroups.AvatarFilter,
169 (uint)CollisionFilterGroups.AvatarMask);
170 }
171
138 public override void RequestPhysicsterseUpdate() 172 public override void RequestPhysicsterseUpdate()
139 { 173 {
140 base.RequestPhysicsterseUpdate(); 174 base.RequestPhysicsterseUpdate();
141 } 175 }
142 // No one calls this method so I don't know what it could possibly mean 176 // No one calls this method so I don't know what it could possibly mean
143 public override bool Stopped { 177 public override bool Stopped { get { return false; } }
144 get { return false; }
145 }
146 public override OMV.Vector3 Size { 178 public override OMV.Vector3 Size {
147 get 179 get
148 { 180 {
149 // Avatar capsule size is kept in the scale parameter. 181 // Avatar capsule size is kept in the scale parameter.
150 return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 182 return _size;
151 } 183 }
152 184
153 set { 185 set {
154 // When an avatar's size is set, only the height is changed 186 // When an avatar's size is set, only the height is changed.
155 // and that really only depends on the radius.
156 _size = value; 187 _size = value;
157 ComputeAvatarScale(_size); 188 ComputeAvatarScale(_size);
158
159 // TODO: something has to be done with the avatar's vertical position
160
161 ComputeAvatarVolumeAndMass(); 189 ComputeAvatarVolumeAndMass();
190 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
191 LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
162 192
163 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 193 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
164 { 194 {
165 BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true); 195 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
196 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
197 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
166 }); 198 });
167 199
168 } 200 }
169 } 201 }
170 public override PrimitiveBaseShape Shape { 202 public override OMV.Vector3 Scale { get; set; }
171 set { _pbs = value; 203 public override PrimitiveBaseShape Shape
172 } 204 {
205 set { BaseShape = value; }
173 } 206 }
207
174 public override bool Grabbed { 208 public override bool Grabbed {
175 set { _grabbed = value; 209 set { _grabbed = value; }
176 }
177 } 210 }
178 public override bool Selected { 211 public override bool Selected {
179 set { _selected = value; 212 set { _selected = value; }
180 }
181 } 213 }
182 public override void CrossingFailure() { return; } 214 public override void CrossingFailure() { return; }
183 public override void link(PhysicsActor obj) { return; } 215 public override void link(PhysicsActor obj) { return; }
@@ -204,7 +236,7 @@ public class BSCharacter : BSPhysObject
204 236
205 public override OMV.Vector3 Position { 237 public override OMV.Vector3 Position {
206 get { 238 get {
207 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); 239 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
208 return _position; 240 return _position;
209 } 241 }
210 set { 242 set {
@@ -214,7 +246,7 @@ public class BSCharacter : BSPhysObject
214 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 246 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
215 { 247 {
216 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 248 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
217 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 249 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
218 }); 250 });
219 } 251 }
220 } 252 }
@@ -263,7 +295,7 @@ public class BSCharacter : BSPhysObject
263 // A version of the sanity check that also makes sure a new position value is 295 // A version of the sanity check that also makes sure a new position value is
264 // pushed back to the physics engine. This routine would be used by anyone 296 // pushed back to the physics engine. This routine would be used by anyone
265 // who is not already pushing the value. 297 // who is not already pushing the value.
266 private bool PositionSanityCheck2(bool inTaintTime) 298 private bool PositionSanityCheck(bool inTaintTime)
267 { 299 {
268 bool ret = false; 300 bool ret = false;
269 if (PositionSanityCheck()) 301 if (PositionSanityCheck())
@@ -273,7 +305,7 @@ public class BSCharacter : BSPhysObject
273 BSScene.TaintCallback sanityOperation = delegate() 305 BSScene.TaintCallback sanityOperation = delegate()
274 { 306 {
275 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 307 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 308 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
277 }; 309 };
278 if (inTaintTime) 310 if (inTaintTime)
279 sanityOperation(); 311 sanityOperation();
@@ -284,11 +316,7 @@ public class BSCharacter : BSPhysObject
284 return ret; 316 return ret;
285 } 317 }
286 318
287 public override float Mass { 319 public override float Mass { get { return _mass; } }
288 get {
289 return _mass;
290 }
291 }
292 320
293 // used when we only want this prim's mass and not the linkset thing 321 // used when we only want this prim's mass and not the linkset thing
294 public override float MassRaw { get {return _mass; } } 322 public override float MassRaw { get {return _mass; } }
@@ -301,15 +329,13 @@ public class BSCharacter : BSPhysObject
301 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 329 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
302 { 330 {
303 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 331 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
304 BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force); 332 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
305 }); 333 });
306 } 334 }
307 } 335 }
308 336
309 public override int VehicleType { 337 // Avatars don't do vehicles
310 get { return 0; } 338 public override int VehicleType { get { return 0; } set { return; } }
311 set { return; }
312 }
313 public override void VehicleFloatParam(int param, float value) { } 339 public override void VehicleFloatParam(int param, float value) { }
314 public override void VehicleVectorParam(int param, OMV.Vector3 value) {} 340 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
315 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } 341 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
@@ -328,15 +354,37 @@ public class BSCharacter : BSPhysObject
328 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 354 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
329 { 355 {
330 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 356 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
331 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity); 357 ForceVelocity = _velocity;
332 }); 358 });
333 } 359 }
334 } 360 }
335 public override OMV.Vector3 ForceVelocity { 361 public override OMV.Vector3 ForceVelocity {
336 get { return _velocity; } 362 get { return _velocity; }
337 set { 363 set {
364 // Depending on whether the avatar is moving or not, change the friction
365 // to keep the avatar from slipping around
366 if (_velocity.Length() == 0)
367 {
368 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
369 {
370 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
371 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
372 }
373 }
374 else
375 {
376 if (_currentFriction != PhysicsScene.Params.avatarFriction)
377 {
378 _currentFriction = PhysicsScene.Params.avatarFriction;
379 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
380 }
381 }
338 _velocity = value; 382 _velocity = value;
339 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity); 383 // Remember the set velocity so we can suppress the reduction by friction, ...
384 _appliedVelocity = value;
385
386 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
387 BulletSimAPI.Activate2(BSBody.ptr, true);
340 } 388 }
341 } 389 }
342 public override OMV.Vector3 Torque { 390 public override OMV.Vector3 Torque {
@@ -360,8 +408,8 @@ public class BSCharacter : BSPhysObject
360 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 408 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
361 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 409 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
362 { 410 {
363 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); 411 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
364 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 412 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
365 }); 413 });
366 } 414 }
367 } 415 }
@@ -389,12 +437,18 @@ public class BSCharacter : BSPhysObject
389 set { _isPhysical = value; 437 set { _isPhysical = value;
390 } 438 }
391 } 439 }
440 public override bool IsSolid {
441 get { return true; }
442 }
443 public override bool IsStatic {
444 get { return false; }
445 }
392 public override bool Flying { 446 public override bool Flying {
393 get { return _flying; } 447 get { return _flying; }
394 set { 448 set {
395 _flying = value; 449 _flying = value;
396 // simulate flying by changing the effect of gravity 450 // simulate flying by changing the effect of gravity
397 this.Buoyancy = ComputeBuoyancyFromFlying(_flying); 451 Buoyancy = ComputeBuoyancyFromFlying(_flying);
398 } 452 }
399 } 453 }
400 // Flying is implimented by changing the avatar's buoyancy. 454 // Flying is implimented by changing the avatar's buoyancy.
@@ -454,10 +508,19 @@ public class BSCharacter : BSPhysObject
454 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 508 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
455 { 509 {
456 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 510 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
457 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy); 511 ForceBuoyancy = _buoyancy;
458 }); 512 });
459 } 513 }
460 } 514 }
515 public override float ForceBuoyancy {
516 get { return _buoyancy; }
517 set { _buoyancy = value;
518 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
519 // Buoyancy is faked by changing the gravity applied to the object
520 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
521 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
522 }
523 }
461 524
462 // Used for MoveTo 525 // Used for MoveTo
463 public override OMV.Vector3 PIDTarget { 526 public override OMV.Vector3 PIDTarget {
@@ -518,27 +581,32 @@ public class BSCharacter : BSPhysObject
518 581
519 private void ComputeAvatarScale(OMV.Vector3 size) 582 private void ComputeAvatarScale(OMV.Vector3 size)
520 { 583 {
521 _scale.X = PhysicsScene.Params.avatarCapsuleRadius; 584 // The 'size' given by the simulator is the mid-point of the avatar
522 _scale.Y = PhysicsScene.Params.avatarCapsuleRadius; 585 // and X and Y are unspecified.
523 586
524 // The 1.15 came from ODE but it seems to cause the avatar to float off the ground 587 OMV.Vector3 newScale = OMV.Vector3.Zero;
525 // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 588 newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
526 _scale.Z = (_size.Z) - (_scale.X + _scale.Y); 589 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
590
591 // From the total height, remote the capsule half spheres that are at each end
592 newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
593 // newScale.Z = (size.Z * 2f);
594 Scale = newScale;
527 } 595 }
528 596
529 // set _avatarVolume and _mass based on capsule size, _density and _scale 597 // set _avatarVolume and _mass based on capsule size, _density and Scale
530 private void ComputeAvatarVolumeAndMass() 598 private void ComputeAvatarVolumeAndMass()
531 { 599 {
532 _avatarVolume = (float)( 600 _avatarVolume = (float)(
533 Math.PI 601 Math.PI
534 * _scale.X 602 * Scale.X
535 * _scale.Y // the area of capsule cylinder 603 * Scale.Y // the area of capsule cylinder
536 * _scale.Z // times height of capsule cylinder 604 * Scale.Z // times height of capsule cylinder
537 + 1.33333333f 605 + 1.33333333f
538 * Math.PI 606 * Math.PI
539 * _scale.X 607 * Scale.X
540 * Math.Min(_scale.X, _scale.Y) 608 * Math.Min(Scale.X, Scale.Y)
541 * _scale.Y // plus the volume of the capsule end caps 609 * Scale.Y // plus the volume of the capsule end caps
542 ); 610 );
543 _mass = _avatarDensity * _avatarVolume; 611 _mass = _avatarDensity * _avatarVolume;
544 } 612 }
@@ -553,7 +621,23 @@ public class BSCharacter : BSPhysObject
553 _acceleration = entprop.Acceleration; 621 _acceleration = entprop.Acceleration;
554 _rotationalVelocity = entprop.RotationalVelocity; 622 _rotationalVelocity = entprop.RotationalVelocity;
555 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 623 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
556 PositionSanityCheck2(true); 624 PositionSanityCheck(true);
625
626 // remember the current and last set values
627 LastEntityProperties = CurrentEntityProperties;
628 CurrentEntityProperties = entprop;
629
630 if (entprop.Velocity != LastEntityProperties.Velocity)
631 {
632 // Changes in the velocity are suppressed in avatars.
633 // That's just the way they are defined.
634 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
635 _velocity = avVel;
636 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
637 }
638
639 // Tell the linkset about this
640 Linkset.UpdateProperties(this);
557 641
558 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 642 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
559 // base.RequestPhysicsterseUpdate(); 643 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index cae599c..ead6a08 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -47,6 +47,7 @@ public abstract class BSPhysObject : PhysicsActor
47 TypeName = typeName; 47 TypeName = typeName;
48 48
49 Linkset = new BSLinkset(PhysicsScene, this); 49 Linkset = new BSLinkset(PhysicsScene, this);
50 LastAssetBuildFailed = false;
50 51
51 CollisionCollection = new CollisionEventUpdate(); 52 CollisionCollection = new CollisionEventUpdate();
52 SubscribedEventsMs = 0; 53 SubscribedEventsMs = 0;
@@ -69,6 +70,23 @@ public abstract class BSPhysObject : PhysicsActor
69 // Reference to the physical shape (btCollisionShape) of this object 70 // Reference to the physical shape (btCollisionShape) of this object
70 public BulletShape BSShape; 71 public BulletShape BSShape;
71 72
73 // 'true' if the mesh's underlying asset failed to build.
74 // This will keep us from looping after the first time the build failed.
75 public bool LastAssetBuildFailed { get; set; }
76
77 // The objects base shape information. Null if not a prim type shape.
78 public PrimitiveBaseShape BaseShape { get; protected set; }
79
80 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences
82 // between the current update and the previous values.
83 public EntityProperties CurrentEntityProperties { get; set; }
84 public EntityProperties LastEntityProperties { get; set; }
85
86 public abstract OMV.Vector3 Scale { get; set; }
87 public abstract bool IsSolid { get; }
88 public abstract bool IsStatic { get; }
89
72 // Stop all physical motion. 90 // Stop all physical motion.
73 public abstract void ZeroMotion(); 91 public abstract void ZeroMotion();
74 92
@@ -89,6 +107,10 @@ public abstract class BSPhysObject : PhysicsActor
89 107
90 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 108 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
91 109
110 public abstract float ForceBuoyancy { get; set; }
111
112 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
113
92 #region Collisions 114 #region Collisions
93 115
94 // Requested number of milliseconds between collision events. Zero means disabled. 116 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -129,30 +151,28 @@ public abstract class BSPhysObject : PhysicsActor
129 // if someone has subscribed for collision events.... 151 // if someone has subscribed for collision events....
130 if (SubscribedEvents()) { 152 if (SubscribedEvents()) {
131 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 153 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
132 // DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 154 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
133 // LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); 155 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
134 156
135 ret = true; 157 ret = true;
136 } 158 }
137 return ret; 159 return ret;
138 } 160 }
139 161
140 // Routine to send the collected collisions into the simulator. 162 // Send the collected collisions into the simulator.
141 // Also handles removal of this from the collection of objects with collisions if
142 // there are no collisions from this object. Mechanism is create one last
143 // collision event to make collision_end work.
144 // Called at taint time from within the Step() function thus no locking problems 163 // Called at taint time from within the Step() function thus no locking problems
145 // with CollisionCollection and ObjectsWithNoMoreCollisions. 164 // with CollisionCollection and ObjectsWithNoMoreCollisions.
146 // Return 'true' if there were some actual collisions passed up 165 // Return 'true' if there were some actual collisions passed up
147 public virtual bool SendCollisions() 166 public virtual bool SendCollisions()
148 { 167 {
149 bool ret = true; 168 bool ret = true;
169 // If the 'no collision' call, force it to happen right now so quick collision_end
170 bool force = CollisionCollection.Count == 0;
150 171
151 // throttle the collisions to the number of milliseconds specified in the subscription 172 // throttle the collisions to the number of milliseconds specified in the subscription
152 int nowTime = PhysicsScene.SimulationNowTime; 173 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
153 if (nowTime >= NextCollisionOkTime)
154 { 174 {
155 NextCollisionOkTime = nowTime + SubscribedEventsMs; 175 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
156 176
157 // We are called if we previously had collisions. If there are no collisions 177 // We are called if we previously had collisions. If there are no collisions
158 // this time, send up one last empty event so OpenSim can sense collision end. 178 // this time, send up one last empty event so OpenSim can sense collision end.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 6a4365c..aeeb4dd 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -46,12 +46,10 @@ public sealed class BSPrim : BSPhysObject
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private static readonly string LogHeader = "[BULLETS PRIM]"; 47 private static readonly string LogHeader = "[BULLETS PRIM]";
48 48
49 private PrimitiveBaseShape _pbs; 49 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
50 50 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
51 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
52 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
53 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 51 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
54 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer 52 // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
55 53
56 private bool _grabbed; 54 private bool _grabbed;
57 private bool _isSelected; 55 private bool _isSelected;
@@ -98,12 +96,12 @@ public sealed class BSPrim : BSPhysObject
98 _physicsActorType = (int)ActorTypes.Prim; 96 _physicsActorType = (int)ActorTypes.Prim;
99 _position = pos; 97 _position = pos;
100 _size = size; 98 _size = size;
101 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 99 Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
102 _orientation = rotation; 100 _orientation = rotation;
103 _buoyancy = 1f; 101 _buoyancy = 1f;
104 _velocity = OMV.Vector3.Zero; 102 _velocity = OMV.Vector3.Zero;
105 _rotationalVelocity = OMV.Vector3.Zero; 103 _rotationalVelocity = OMV.Vector3.Zero;
106 _pbs = pbs; 104 BaseShape = pbs;
107 _isPhysical = pisPhysical; 105 _isPhysical = pisPhysical;
108 _isVolumeDetect = false; 106 _isVolumeDetect = false;
109 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 107 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
@@ -160,33 +158,32 @@ public sealed class BSPrim : BSPhysObject
160 get { return _size; } 158 get { return _size; }
161 set { 159 set {
162 _size = value; 160 _size = value;
163 PhysicsScene.TaintedObject("BSPrim.setSize", delegate() 161 ForceBodyShapeRebuild(false);
164 {
165 _mass = CalculateMass(); // changing size changes the mass
166 // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
167 // scale and margins are set.
168 CreateGeomAndObject(true);
169 // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
170 });
171 } 162 }
172 } 163 }
173 // Scale is what we set in the physics engine. It is different than 'size' in that 164 // Scale is what we set in the physics engine. It is different than 'size' in that
174 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. 165 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
175 public OMV.Vector3 Scale 166 public override OMV.Vector3 Scale { get; set; }
176 { 167
177 get { return _scale; }
178 set { _scale = value; }
179 }
180 public override PrimitiveBaseShape Shape { 168 public override PrimitiveBaseShape Shape {
181 set { 169 set {
182 _pbs = value; 170 BaseShape = value;
183 PhysicsScene.TaintedObject("BSPrim.setShape", delegate() 171 ForceBodyShapeRebuild(false);
184 {
185 _mass = CalculateMass(); // changing the shape changes the mass
186 CreateGeomAndObject(true);
187 });
188 } 172 }
189 } 173 }
174 public override bool ForceBodyShapeRebuild(bool inTaintTime)
175 {
176 BSScene.TaintCallback rebuildOperation = delegate()
177 {
178 _mass = CalculateMass(); // changing the shape changes the mass
179 CreateGeomAndObject(true);
180 };
181 if (inTaintTime)
182 rebuildOperation();
183 else
184 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
185 return true;
186 }
190 public override bool Grabbed { 187 public override bool Grabbed {
191 set { _grabbed = value; 188 set { _grabbed = value;
192 } 189 }
@@ -325,9 +322,9 @@ public sealed class BSPrim : BSPhysObject
325 } 322 }
326 323
327 // A version of the sanity check that also makes sure a new position value is 324 // A version of the sanity check that also makes sure a new position value is
328 // pushed back to the physics engine. This routine would be used by anyone 325 // pushed to the physics engine. This routine would be used by anyone
329 // who is not already pushing the value. 326 // who is not already pushing the value.
330 private bool PositionSanityCheck2(bool inTaintTime) 327 private bool PositionSanityCheck(bool inTaintTime)
331 { 328 {
332 bool ret = false; 329 bool ret = false;
333 if (PositionSanityCheck()) 330 if (PositionSanityCheck())
@@ -337,7 +334,7 @@ public sealed class BSPrim : BSPhysObject
337 BSScene.TaintCallback sanityOperation = delegate() 334 BSScene.TaintCallback sanityOperation = delegate()
338 { 335 {
339 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 336 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
340 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 337 ForcePosition = _position;
341 }; 338 };
342 if (inTaintTime) 339 if (inTaintTime)
343 sanityOperation(); 340 sanityOperation();
@@ -547,13 +544,13 @@ public sealed class BSPrim : BSPhysObject
547 } 544 }
548 545
549 // An object is static (does not move) if selected or not physical 546 // An object is static (does not move) if selected or not physical
550 private bool IsStatic 547 public override bool IsStatic
551 { 548 {
552 get { return _isSelected || !IsPhysical; } 549 get { return _isSelected || !IsPhysical; }
553 } 550 }
554 551
555 // An object is solid if it's not phantom and if it's not doing VolumeDetect 552 // An object is solid if it's not phantom and if it's not doing VolumeDetect
556 public bool IsSolid 553 public override bool IsSolid
557 { 554 {
558 get { return !IsPhantom && !_isVolumeDetect; } 555 get { return !IsPhantom && !_isVolumeDetect; }
559 } 556 }
@@ -631,6 +628,12 @@ public sealed class BSPrim : BSPhysObject
631 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); 628 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
632 // There is no inertia in a static object 629 // There is no inertia in a static object
633 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); 630 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
631 // Set collision detection parameters
632 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
633 {
634 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
635 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
636 }
634 // There can be special things needed for implementing linksets 637 // There can be special things needed for implementing linksets
635 Linkset.MakeStatic(this); 638 Linkset.MakeStatic(this);
636 // The activation state is 'disabled' so Bullet will not try to act on it. 639 // The activation state is 'disabled' so Bullet will not try to act on it.
@@ -662,6 +665,13 @@ public sealed class BSPrim : BSPhysObject
662 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); 665 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
663 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); 666 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
664 667
668 // Set collision detection parameters
669 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
670 {
671 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
672 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
673 }
674
665 // Various values for simulation limits 675 // Various values for simulation limits
666 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 676 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
667 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); 677 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
@@ -813,13 +823,20 @@ public sealed class BSPrim : BSPhysObject
813 _buoyancy = value; 823 _buoyancy = value;
814 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 824 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
815 { 825 {
816 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 826 ForceBuoyancy = _buoyancy;
817 // Buoyancy is faked by changing the gravity applied to the object
818 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
819 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
820 }); 827 });
821 } 828 }
822 } 829 }
830 public override float ForceBuoyancy {
831 get { return _buoyancy; }
832 set {
833 _buoyancy = value;
834 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
835 // Buoyancy is faked by changing the gravity applied to the object
836 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
837 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
838 }
839 }
823 840
824 // Used for MoveTo 841 // Used for MoveTo
825 public override OMV.Vector3 PIDTarget { 842 public override OMV.Vector3 PIDTarget {
@@ -907,19 +924,19 @@ public sealed class BSPrim : BSPhysObject
907 float tmp; 924 float tmp;
908 925
909 float returnMass = 0; 926 float returnMass = 0;
910 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 927 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
911 float hollowVolume = hollowAmount * hollowAmount; 928 float hollowVolume = hollowAmount * hollowAmount;
912 929
913 switch (_pbs.ProfileShape) 930 switch (BaseShape.ProfileShape)
914 { 931 {
915 case ProfileShape.Square: 932 case ProfileShape.Square:
916 // default box 933 // default box
917 934
918 if (_pbs.PathCurve == (byte)Extrusion.Straight) 935 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
919 { 936 {
920 if (hollowAmount > 0.0) 937 if (hollowAmount > 0.0)
921 { 938 {
922 switch (_pbs.HollowShape) 939 switch (BaseShape.HollowShape)
923 { 940 {
924 case HollowShape.Square: 941 case HollowShape.Square:
925 case HollowShape.Same: 942 case HollowShape.Same:
@@ -943,19 +960,19 @@ public sealed class BSPrim : BSPhysObject
943 } 960 }
944 } 961 }
945 962
946 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 963 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
947 { 964 {
948 //a tube 965 //a tube
949 966
950 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 967 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
951 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 968 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
952 volume -= volume*tmp*tmp; 969 volume -= volume*tmp*tmp;
953 970
954 if (hollowAmount > 0.0) 971 if (hollowAmount > 0.0)
955 { 972 {
956 hollowVolume *= hollowAmount; 973 hollowVolume *= hollowAmount;
957 974
958 switch (_pbs.HollowShape) 975 switch (BaseShape.HollowShape)
959 { 976 {
960 case HollowShape.Square: 977 case HollowShape.Square:
961 case HollowShape.Same: 978 case HollowShape.Same:
@@ -980,13 +997,13 @@ public sealed class BSPrim : BSPhysObject
980 997
981 case ProfileShape.Circle: 998 case ProfileShape.Circle:
982 999
983 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1000 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
984 { 1001 {
985 volume *= 0.78539816339f; // elipse base 1002 volume *= 0.78539816339f; // elipse base
986 1003
987 if (hollowAmount > 0.0) 1004 if (hollowAmount > 0.0)
988 { 1005 {
989 switch (_pbs.HollowShape) 1006 switch (BaseShape.HollowShape)
990 { 1007 {
991 case HollowShape.Same: 1008 case HollowShape.Same:
992 case HollowShape.Circle: 1009 case HollowShape.Circle:
@@ -1008,10 +1025,10 @@ public sealed class BSPrim : BSPhysObject
1008 } 1025 }
1009 } 1026 }
1010 1027
1011 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1028 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1012 { 1029 {
1013 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 1030 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1014 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1031 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1015 volume *= (1.0f - tmp * tmp); 1032 volume *= (1.0f - tmp * tmp);
1016 1033
1017 if (hollowAmount > 0.0) 1034 if (hollowAmount > 0.0)
@@ -1020,7 +1037,7 @@ public sealed class BSPrim : BSPhysObject
1020 // calculate the hollow volume by it's shape compared to the prim shape 1037 // calculate the hollow volume by it's shape compared to the prim shape
1021 hollowVolume *= hollowAmount; 1038 hollowVolume *= hollowAmount;
1022 1039
1023 switch (_pbs.HollowShape) 1040 switch (BaseShape.HollowShape)
1024 { 1041 {
1025 case HollowShape.Same: 1042 case HollowShape.Same:
1026 case HollowShape.Circle: 1043 case HollowShape.Circle:
@@ -1044,7 +1061,7 @@ public sealed class BSPrim : BSPhysObject
1044 break; 1061 break;
1045 1062
1046 case ProfileShape.HalfCircle: 1063 case ProfileShape.HalfCircle:
1047 if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1064 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1048 { 1065 {
1049 volume *= 0.52359877559829887307710723054658f; 1066 volume *= 0.52359877559829887307710723054658f;
1050 } 1067 }
@@ -1052,7 +1069,7 @@ public sealed class BSPrim : BSPhysObject
1052 1069
1053 case ProfileShape.EquilateralTriangle: 1070 case ProfileShape.EquilateralTriangle:
1054 1071
1055 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1072 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1056 { 1073 {
1057 volume *= 0.32475953f; 1074 volume *= 0.32475953f;
1058 1075
@@ -1060,7 +1077,7 @@ public sealed class BSPrim : BSPhysObject
1060 { 1077 {
1061 1078
1062 // calculate the hollow volume by it's shape compared to the prim shape 1079 // calculate the hollow volume by it's shape compared to the prim shape
1063 switch (_pbs.HollowShape) 1080 switch (BaseShape.HollowShape)
1064 { 1081 {
1065 case HollowShape.Same: 1082 case HollowShape.Same:
1066 case HollowShape.Triangle: 1083 case HollowShape.Triangle:
@@ -1085,11 +1102,11 @@ public sealed class BSPrim : BSPhysObject
1085 volume *= (1.0f - hollowVolume); 1102 volume *= (1.0f - hollowVolume);
1086 } 1103 }
1087 } 1104 }
1088 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1105 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1089 { 1106 {
1090 volume *= 0.32475953f; 1107 volume *= 0.32475953f;
1091 volume *= 0.01f * (float)(200 - _pbs.PathScaleX); 1108 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1092 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1109 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1093 volume *= (1.0f - tmp * tmp); 1110 volume *= (1.0f - tmp * tmp);
1094 1111
1095 if (hollowAmount > 0.0) 1112 if (hollowAmount > 0.0)
@@ -1097,7 +1114,7 @@ public sealed class BSPrim : BSPhysObject
1097 1114
1098 hollowVolume *= hollowAmount; 1115 hollowVolume *= hollowAmount;
1099 1116
1100 switch (_pbs.HollowShape) 1117 switch (BaseShape.HollowShape)
1101 { 1118 {
1102 case HollowShape.Same: 1119 case HollowShape.Same:
1103 case HollowShape.Triangle: 1120 case HollowShape.Triangle:
@@ -1137,26 +1154,26 @@ public sealed class BSPrim : BSPhysObject
1137 float profileBegin; 1154 float profileBegin;
1138 float profileEnd; 1155 float profileEnd;
1139 1156
1140 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) 1157 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1141 { 1158 {
1142 taperX1 = _pbs.PathScaleX * 0.01f; 1159 taperX1 = BaseShape.PathScaleX * 0.01f;
1143 if (taperX1 > 1.0f) 1160 if (taperX1 > 1.0f)
1144 taperX1 = 2.0f - taperX1; 1161 taperX1 = 2.0f - taperX1;
1145 taperX = 1.0f - taperX1; 1162 taperX = 1.0f - taperX1;
1146 1163
1147 taperY1 = _pbs.PathScaleY * 0.01f; 1164 taperY1 = BaseShape.PathScaleY * 0.01f;
1148 if (taperY1 > 1.0f) 1165 if (taperY1 > 1.0f)
1149 taperY1 = 2.0f - taperY1; 1166 taperY1 = 2.0f - taperY1;
1150 taperY = 1.0f - taperY1; 1167 taperY = 1.0f - taperY1;
1151 } 1168 }
1152 else 1169 else
1153 { 1170 {
1154 taperX = _pbs.PathTaperX * 0.01f; 1171 taperX = BaseShape.PathTaperX * 0.01f;
1155 if (taperX < 0.0f) 1172 if (taperX < 0.0f)
1156 taperX = -taperX; 1173 taperX = -taperX;
1157 taperX1 = 1.0f - taperX; 1174 taperX1 = 1.0f - taperX;
1158 1175
1159 taperY = _pbs.PathTaperY * 0.01f; 1176 taperY = BaseShape.PathTaperY * 0.01f;
1160 if (taperY < 0.0f) 1177 if (taperY < 0.0f)
1161 taperY = -taperY; 1178 taperY = -taperY;
1162 taperY1 = 1.0f - taperY; 1179 taperY1 = 1.0f - taperY;
@@ -1166,13 +1183,13 @@ public sealed class BSPrim : BSPhysObject
1166 1183
1167 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); 1184 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1168 1185
1169 pathBegin = (float)_pbs.PathBegin * 2.0e-5f; 1186 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1170 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; 1187 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1171 volume *= (pathEnd - pathBegin); 1188 volume *= (pathEnd - pathBegin);
1172 1189
1173 // this is crude aproximation 1190 // this is crude aproximation
1174 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; 1191 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1175 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; 1192 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1176 volume *= (profileEnd - profileBegin); 1193 volume *= (profileEnd - profileBegin);
1177 1194
1178 returnMass = _density * volume; 1195 returnMass = _density * volume;
@@ -1207,7 +1224,8 @@ public sealed class BSPrim : BSPhysObject
1207 shape.Position = _position; 1224 shape.Position = _position;
1208 shape.Rotation = _orientation; 1225 shape.Rotation = _orientation;
1209 shape.Velocity = _velocity; 1226 shape.Velocity = _velocity;
1210 shape.Scale = _scale; 1227 shape.Size = _size;
1228 shape.Scale = Scale;
1211 shape.Mass = _isPhysical ? _mass : 0f; 1229 shape.Mass = _isPhysical ? _mass : 0f;
1212 shape.Buoyancy = _buoyancy; 1230 shape.Buoyancy = _buoyancy;
1213 shape.HullKey = 0; 1231 shape.HullKey = 0;
@@ -1217,7 +1235,6 @@ public sealed class BSPrim : BSPhysObject
1217 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; 1235 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1218 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1236 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1219 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue; 1237 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1220 shape.Size = _size;
1221 } 1238 }
1222 // Rebuild the geometry and object. 1239 // Rebuild the geometry and object.
1223 // This is called when the shape changes so we need to recreate the mesh/hull. 1240 // This is called when the shape changes so we need to recreate the mesh/hull.
@@ -1234,7 +1251,7 @@ public sealed class BSPrim : BSPhysObject
1234 // Create the correct physical representation for this type of object. 1251 // Create the correct physical representation for this type of object.
1235 // Updates BSBody and BSShape with the new information. 1252 // Updates BSBody and BSShape with the new information.
1236 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1253 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1237 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs, 1254 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
1238 null, delegate(BulletBody dBody) 1255 null, delegate(BulletBody dBody)
1239 { 1256 {
1240 // Called if the current prim body is about to be destroyed. 1257 // Called if the current prim body is about to be destroyed.
@@ -1328,9 +1345,11 @@ public sealed class BSPrim : BSPhysObject
1328 _acceleration = entprop.Acceleration; 1345 _acceleration = entprop.Acceleration;
1329 _rotationalVelocity = entprop.RotationalVelocity; 1346 _rotationalVelocity = entprop.RotationalVelocity;
1330 1347
1331 PositionSanityCheck2(true); 1348 // remember the current and last set values
1349 LastEntityProperties = CurrentEntityProperties;
1350 CurrentEntityProperties = entprop;
1332 1351
1333 Linkset.UpdateProperties(this); 1352 PositionSanityCheck(true);
1334 1353
1335 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1354 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1336 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1355 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
@@ -1348,6 +1367,9 @@ public sealed class BSPrim : BSPhysObject
1348 entprop.Acceleration, entprop.RotationalVelocity); 1367 entprop.Acceleration, entprop.RotationalVelocity);
1349 } 1368 }
1350 */ 1369 */
1370 // The linkset implimentation might want to know about this.
1371
1372 Linkset.UpdateProperties(this);
1351 } 1373 }
1352} 1374}
1353} 1375}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 2c3c481..6621d39 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -256,14 +256,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
257 257
258 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 258 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
259 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 259 World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
260 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 260 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
261 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), 261 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
262 m_DebugLogCallbackHandle); 262 m_DebugLogCallbackHandle));
263
264 // Initialization to support the transition to a new API which puts most of the logic
265 // into the C# code so it is easier to modify and add to.
266 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
267 263
268 Constraints = new BSConstraintCollection(World); 264 Constraints = new BSConstraintCollection(World);
269 265
@@ -360,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
360 } 356 }
361 357
362 // Anything left in the unmanaged code should be cleaned out 358 // Anything left in the unmanaged code should be cleaned out
363 BulletSimAPI.Shutdown(WorldID); 359 BulletSimAPI.Shutdown2(World.ptr);
364 360
365 // Not logging any more 361 // Not logging any more
366 PhysicsLogging.Close(); 362 PhysicsLogging.Close();
@@ -498,7 +494,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
498 { 494 {
499 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 495 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
500 496
501 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 497 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
502 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 498 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
503 499
504 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 500 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
@@ -536,26 +532,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters
536 } 532 }
537 } 533 }
538 534
539 // This is a kludge to get avatar movement updates.
540 // the simulator expects collisions for avatars even if there are have been no collisions. This updates
541 // avatar animations and stuff.
542 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
543 foreach (BSPhysObject bsp in m_avatars)
544 bsp.SendCollisions();
545
546 // The above SendCollision's batch up the collisions on the objects. 535 // The above SendCollision's batch up the collisions on the objects.
547 // Now push the collisions into the simulator. 536 // Now push the collisions into the simulator.
548 if (ObjectsWithCollisions.Count > 0) 537 if (ObjectsWithCollisions.Count > 0)
549 { 538 {
550 foreach (BSPhysObject bsp in ObjectsWithCollisions) 539 foreach (BSPhysObject bsp in ObjectsWithCollisions)
551 if (!m_avatars.Contains(bsp)) // don't call avatars twice 540 if (!bsp.SendCollisions())
552 if (!bsp.SendCollisions()) 541 {
553 { 542 // If the object is done colliding, see that it's removed from the colliding list
554 // If the object is done colliding, see that it's removed from the colliding list 543 ObjectsWithNoMoreCollisions.Add(bsp);
555 ObjectsWithNoMoreCollisions.Add(bsp); 544 }
556 }
557 } 545 }
558 546
547 // This is a kludge to get avatar movement updates.
548 // The simulator expects collisions for avatars even if there are have been no collisions.
549 // The event updates avatar animations and stuff.
550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
551 foreach (BSPhysObject bsp in m_avatars)
552 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
553 bsp.SendCollisions();
554
559 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 555 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
560 // Not done above because it is inside an iteration of ObjectWithCollisions. 556 // Not done above because it is inside an iteration of ObjectWithCollisions.
561 if (ObjectsWithNoMoreCollisions.Count > 0) 557 if (ObjectsWithNoMoreCollisions.Count > 0)
@@ -579,11 +575,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
579 } 575 }
580 } 576 }
581 577
578 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
579 // Only enable this in a limited test world with few objects.
580 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
581
582 // The physics engine returns the number of milliseconds it simulated this call. 582 // The physics engine returns the number of milliseconds it simulated this call.
583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
584 // We multiply by 45 to give a recognizable running rate (45 or less). 584 // We multiply by 55 to give a recognizable running rate (55 or less).
585 return numSubSteps * m_fixedTimeStep * 1000 * 45; 585 return numSubSteps * m_fixedTimeStep * 1000 * 55;
586 // return timeStep * 1000 * 45; 586 // return timeStep * 1000 * 55;
587 } 587 }
588 588
589 // Something has collided 589 // Something has collided
@@ -800,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
800 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 800 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
801 delegate float ParamGet(BSScene scene); 801 delegate float ParamGet(BSScene scene);
802 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); 802 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
803 delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
803 804
804 private struct ParameterDefn 805 private struct ParameterDefn
805 { 806 {
@@ -809,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
809 public ParamUser userParam; // get the value from the configuration file 810 public ParamUser userParam; // get the value from the configuration file
810 public ParamGet getter; // return the current value stored for this parameter 811 public ParamGet getter; // return the current value stored for this parameter
811 public ParamSet setter; // set the current value for this parameter 812 public ParamSet setter; // set the current value for this parameter
813 public SetOnObject onObject; // set the value on an object in the physical domain
812 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) 814 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
813 { 815 {
814 name = n; 816 name = n;
@@ -817,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
817 userParam = u; 819 userParam = u;
818 getter = g; 820 getter = g;
819 setter = s; 821 setter = s;
822 onObject = null;
823 }
824 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
825 {
826 name = n;
827 desc = d;
828 defaultValue = v;
829 userParam = u;
830 getter = g;
831 setter = s;
832 onObject = o;
820 } 833 }
821 } 834 }
822 835
@@ -838,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
838 // 851 //
839 // The single letter parameters for the delegates are: 852 // The single letter parameters for the delegates are:
840 // s = BSScene 853 // s = BSScene
854 // o = BSPhysObject
841 // p = string parameter name 855 // p = string parameter name
842 // l = localID of referenced object 856 // l = localID of referenced object
843 // v = float value 857 // v = float value
@@ -947,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters
947 -9.80665f, 961 -9.80665f,
948 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, 962 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
949 (s) => { return s.m_params[0].gravity; }, 963 (s) => { return s.m_params[0].gravity; },
950 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), 964 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
965 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
951 966
952 967
953 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", 968 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
954 0f, 969 0f,
955 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 970 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
956 (s) => { return s.m_params[0].linearDamping; }, 971 (s) => { return s.m_params[0].linearDamping; },
957 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ), 972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
973 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
958 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 974 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
959 0f, 975 0f,
960 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 976 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
961 (s) => { return s.m_params[0].angularDamping; }, 977 (s) => { return s.m_params[0].angularDamping; },
962 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ), 978 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
979 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
963 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 980 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
964 0.2f, 981 0.2f,
965 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 982 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
966 (s) => { return s.m_params[0].deactivationTime; }, 983 (s) => { return s.m_params[0].deactivationTime; },
967 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ), 984 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
985 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ),
968 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 986 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
969 0.8f, 987 0.8f,
970 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 988 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].linearSleepingThreshold; }, 989 (s) => { return s.m_params[0].linearSleepingThreshold; },
972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 990 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
991 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
973 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 992 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
974 1.0f, 993 1.0f,
975 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 994 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
976 (s) => { return s.m_params[0].angularSleepingThreshold; }, 995 (s) => { return s.m_params[0].angularSleepingThreshold; },
977 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 996 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
997 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
978 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 998 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
979 0f, // set to zero to disable 999 0f, // set to zero to disable
980 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 1000 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
981 (s) => { return s.m_params[0].ccdMotionThreshold; }, 1001 (s) => { return s.m_params[0].ccdMotionThreshold; },
982 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 1002 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1003 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ),
983 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 1004 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
984 0f, 1005 0f,
985 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 1006 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
986 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 1007 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
987 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 1008 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1009 (s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ),
988 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
989 0.1f, 1011 0.1f,
990 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
991 (s) => { return s.m_params[0].contactProcessingThreshold; }, 1013 (s) => { return s.m_params[0].contactProcessingThreshold; },
992 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 1014 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1015 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ),
993 1016
994 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1017 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
995 0.5f, 1018 0.5f,
996 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1019 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
997 (s) => { return s.m_params[0].terrainFriction; }, 1020 (s) => { return s.m_params[0].terrainFriction; },
998 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), 1021 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
999 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , 1022 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
1000 0.8f, 1023 0.8f,
1001 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, 1024 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
1002 (s) => { return s.m_params[0].terrainHitFraction; }, 1025 (s) => { return s.m_params[0].terrainHitFraction; },
1003 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), 1026 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
1004 new ParameterDefn("TerrainRestitution", "Bouncyness" , 1027 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
1005 0f, 1028 0f,
1006 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1029 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1007 (s) => { return s.m_params[0].terrainRestitution; }, 1030 (s) => { return s.m_params[0].terrainRestitution; },
1008 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 1031 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1009 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1032 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1010 0.2f, 1033 0.2f,
1011 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1034 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1012 (s) => { return s.m_params[0].avatarFriction; }, 1035 (s) => { return s.m_params[0].avatarFriction; },
1013 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1036 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1037 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1038 10f,
1039 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1040 (s) => { return s.m_params[0].avatarStandingFriction; },
1041 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
1014 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 1042 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1015 60f, 1043 60f,
1016 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 1044 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
@@ -1227,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1227 return ret; 1255 return ret;
1228 } 1256 }
1229 1257
1230 // check to see if we are updating a parameter for a particular or all of the prims
1231 protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
1232 {
1233 List<uint> operateOn;
1234 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1235 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1236 }
1237
1238 // update all the localIDs specified 1258 // update all the localIDs specified
1239 // If the local ID is APPLY_TO_NONE, just change the default value 1259 // If the local ID is APPLY_TO_NONE, just change the default value
1240 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1260 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1241 // If the localID is a specific object, apply the parameter change to only that object 1261 // If the localID is a specific object, apply the parameter change to only that object
1242 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) 1262 protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
1243 { 1263 {
1264 List<uint> objectIDs = new List<uint>();
1244 switch (localID) 1265 switch (localID)
1245 { 1266 {
1246 case PhysParameterEntry.APPLY_TO_NONE: 1267 case PhysParameterEntry.APPLY_TO_NONE:
1247 defaultLoc = val; // setting only the default value 1268 defaultLoc = val; // setting only the default value
1269 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1270 objectIDs.Add(TERRAIN_ID);
1271 TaintedUpdateParameter(parm, objectIDs, val);
1248 break; 1272 break;
1249 case PhysParameterEntry.APPLY_TO_ALL: 1273 case PhysParameterEntry.APPLY_TO_ALL:
1250 defaultLoc = val; // setting ALL also sets the default value 1274 defaultLoc = val; // setting ALL also sets the default value
1251 List<uint> objectIDs = lIDs; 1275 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1252 string xparm = parm.ToLower(); 1276 TaintedUpdateParameter(parm, objectIDs, val);
1253 float xval = val;
1254 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1255 foreach (uint lID in objectIDs)
1256 {
1257 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1258 }
1259 });
1260 break; 1277 break;
1261 default: 1278 default:
1262 // setting only one localID 1279 // setting only one localID
1263 TaintedUpdateParameter(parm, localID, val); 1280 objectIDs.Add(localID);
1281 TaintedUpdateParameter(parm, objectIDs, val);
1264 break; 1282 break;
1265 } 1283 }
1266 } 1284 }
1267 1285
1268 // schedule the actual updating of the paramter to when the phys engine is not busy 1286 // schedule the actual updating of the paramter to when the phys engine is not busy
1269 protected void TaintedUpdateParameter(string parm, uint localID, float val) 1287 protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
1270 { 1288 {
1271 uint xlocalID = localID;
1272 string xparm = parm.ToLower();
1273 float xval = val; 1289 float xval = val;
1274 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1290 List<uint> xlIDs = lIDs;
1275 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval); 1291 string xparm = parm;
1292 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1293 ParameterDefn thisParam;
1294 if (TryGetParameter(xparm, out thisParam))
1295 {
1296 if (thisParam.onObject != null)
1297 {
1298 foreach (uint lID in xlIDs)
1299 {
1300 BSPhysObject theObject = null;
1301 PhysObjects.TryGetValue(lID, out theObject);
1302 thisParam.onObject(this, theObject, xval);
1303 }
1304 }
1305 }
1276 }); 1306 });
1277 } 1307 }
1278 1308
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d189f1d..d3ba273 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable
51 } 51 }
52 52
53 // Description of a hull. 53 // Description of a hull.
54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects 54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
55 private struct HullDesc 55 private struct HullDesc
56 { 56 {
57 public IntPtr ptr; 57 public IntPtr ptr;
@@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable
59 public DateTime lastReferenced; 59 public DateTime lastReferenced;
60 } 60 }
61 61
62 private struct BodyDesc 62 // The sharable set of meshes and hulls. Indexed by their shape hash.
63 {
64 public IntPtr ptr;
65 // Bodies are only used once so reference count is always either one or zero
66 public int referenceCount;
67 public DateTime lastReferenced;
68 }
69
70 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 63 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
71 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 64 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73 65
74 public BSShapeCollection(BSScene physScene) 66 public BSShapeCollection(BSScene physScene)
75 { 67 {
@@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable
92 // First checks the shape and updates that if necessary then makes 84 // First checks the shape and updates that if necessary then makes
93 // sure the body is of the right type. 85 // sure the body is of the right type.
94 // Return 'true' if either the body or the shape changed. 86 // Return 'true' if either the body or the shape changed.
87 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
88 // the current shape or body is destroyed. This allows the caller to remove any
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed.
95 // Called at taint-time!! 91 // Called at taint-time!!
96 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, 92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
97 ShapeData shapeData, PrimitiveBaseShape pbs, 93 ShapeData shapeData, PrimitiveBaseShape pbs,
98 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
99 { 95 {
@@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable
103 lock (m_collectionActivityLock) 99 lock (m_collectionActivityLock)
104 { 100 {
105 // Do we have the correct geometry for this type of object? 101 // Do we have the correct geometry for this type of object?
106 // Updates prim.BSShape with information/pointers to requested shape 102 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape.
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); 104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
108 // If we had to select a new shape geometry for the object, 105 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it. 106 // rebuild the body around it.
@@ -120,40 +117,24 @@ public class BSShapeCollection : IDisposable
120 117
121 // Track another user of a body 118 // Track another user of a body
122 // We presume the caller has allocated the body. 119 // We presume the caller has allocated the body.
123 // Bodies only have one user so the reference count is either 1 or 0. 120 // Bodies only have one user so the body is just put into the world if not already there.
124 public void ReferenceBody(BulletBody body, bool inTaintTime) 121 public void ReferenceBody(BulletBody body, bool inTaintTime)
125 { 122 {
126 lock (m_collectionActivityLock) 123 lock (m_collectionActivityLock)
127 { 124 {
128 BodyDesc bodyDesc; 125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
129 if (Bodies.TryGetValue(body.ID, out bodyDesc)) 126 BSScene.TaintCallback createOperation = delegate()
130 { 127 {
131 bodyDesc.referenceCount++; 128 if (!BulletSimAPI.IsInWorld2(body.ptr))
132 DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
133 }
134 else
135 {
136 // New entry
137 bodyDesc.ptr = body.ptr;
138 bodyDesc.referenceCount = 1;
139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
140 body.ID, body, bodyDesc.referenceCount);
141 BSScene.TaintCallback createOperation = delegate()
142 { 129 {
143 if (!BulletSimAPI.IsInWorld2(body.ptr)) 130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
144 { 131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
145 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 132 }
146 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", 133 };
147 body.ID, body); 134 if (inTaintTime)
148 } 135 createOperation();
149 }; 136 else
150 if (inTaintTime) 137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
151 createOperation();
152 else
153 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
154 }
155 bodyDesc.lastReferenced = System.DateTime.Now;
156 Bodies[body.ID] = bodyDesc;
157 } 138 }
158 } 139 }
159 140
@@ -166,43 +147,25 @@ public class BSShapeCollection : IDisposable
166 147
167 lock (m_collectionActivityLock) 148 lock (m_collectionActivityLock)
168 { 149 {
169 BodyDesc bodyDesc; 150 BSScene.TaintCallback removeOperation = delegate()
170 if (Bodies.TryGetValue(body.ID, out bodyDesc))
171 { 151 {
172 bodyDesc.referenceCount--; 152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
173 bodyDesc.lastReferenced = System.DateTime.Now; 153 body.ID, body.ptr.ToString("X"), inTaintTime);
174 Bodies[body.ID] = bodyDesc; 154 // If the caller needs to know the old body is going away, pass the event up.
175 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); 155 if (bodyCallback != null) bodyCallback(body);
176 156
177 // If body is no longer being used, free it -- bodies can never be shared. 157 // It may have already been removed from the world in which case the next is a NOOP.
178 if (bodyDesc.referenceCount == 0) 158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
179 { 159
180 Bodies.Remove(body.ID); 160 // Zero any reference to the shape so it is not freed when the body is deleted.
181 BSScene.TaintCallback removeOperation = delegate() 161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
182 { 162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
183 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", 163 };
184 body.ID, body.ptr.ToString("X"), inTaintTime); 164 // If already in taint-time, do the operations now. Otherwise queue for later.
185 // If the caller needs to know the old body is going away, pass the event up. 165 if (inTaintTime)
186 if (bodyCallback != null) bodyCallback(body); 166 removeOperation();
187
188 // It may have already been removed from the world in which case the next is a NOOP.
189 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
190
191 // Zero any reference to the shape so it is not freed when the body is deleted.
192 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
193 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
194 };
195 // If already in taint-time, do the operations now. Otherwise queue for later.
196 if (inTaintTime)
197 removeOperation();
198 else
199 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
200 }
201 }
202 else 167 else
203 { 168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
204 DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
205 }
206 } 169 }
207 } 170 }
208 171
@@ -271,7 +234,6 @@ public class BSShapeCollection : IDisposable
271 } 234 }
272 235
273 // Release the usage of a shape. 236 // Release the usage of a shape.
274 // The collisionObject is released since it is a copy of the real collision shape.
275 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
276 { 238 {
277 if (shape.ptr == IntPtr.Zero) 239 if (shape.ptr == IntPtr.Zero)
@@ -279,26 +241,32 @@ public class BSShapeCollection : IDisposable
279 241
280 BSScene.TaintCallback dereferenceOperation = delegate() 242 BSScene.TaintCallback dereferenceOperation = delegate()
281 { 243 {
282 switch (shape.type) 244 if (shape.ptr != IntPtr.Zero)
283 { 245 {
284 case ShapeData.PhysicsShapeType.SHAPE_HULL: 246 if (shape.isNativeShape)
285 DereferenceHull(shape, shapeCallback); 247 {
286 break;
287 case ShapeData.PhysicsShapeType.SHAPE_MESH:
288 DereferenceMesh(shape, shapeCallback);
289 break;
290 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
291 break;
292 default:
293 // Native shapes are not tracked and are released immediately 248 // Native shapes are not tracked and are released immediately
294 if (shape.ptr != IntPtr.Zero & shape.isNativeShape) 249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
253 }
254 else
255 {
256 switch (shape.type)
295 { 257 {
296 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 258 case ShapeData.PhysicsShapeType.SHAPE_HULL:
297 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 259 DereferenceHull(shape, shapeCallback);
298 if (shapeCallback != null) shapeCallback(shape); 260 break;
299 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 261 case ShapeData.PhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback);
263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
265 break;
266 default:
267 break;
300 } 268 }
301 break; 269 }
302 } 270 }
303 }; 271 };
304 if (inTaintTime) 272 if (inTaintTime)
@@ -351,19 +319,31 @@ public class BSShapeCollection : IDisposable
351 319
352 // Create the geometry information in Bullet for later use. 320 // Create the geometry information in Bullet for later use.
353 // The objects needs a hull if it's physical otherwise a mesh is enough. 321 // The objects needs a hull if it's physical otherwise a mesh is enough.
354 // No locking here because this is done when we know physics is not simulating. 322 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
355 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. 323 // shared geometries will be used. If the parameters of the existing shape are the same
324 // as this request, the shape is not rebuilt.
325 // Info in prim.BSShape is updated to the new shape.
356 // Returns 'true' if the geometry was rebuilt. 326 // Returns 'true' if the geometry was rebuilt.
357 // Called at taint-time! 327 // Called at taint-time!
358 private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, 328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
359 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) 329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
360 { 330 {
361 bool ret = false; 331 bool ret = false;
362 bool haveShape = false; 332 bool haveShape = false;
363 bool nativeShapePossible = true; 333 bool nativeShapePossible = true;
364 334
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 {
337 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
341 haveShape = true;
342 }
365 // If the prim attributes are simple, this could be a simple Bullet native shape 343 // If the prim attributes are simple, this could be a simple Bullet native shape
366 if (nativeShapePossible 344 if (!haveShape
345 && pbs != null
346 && nativeShapePossible
367 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 347 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
368 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 348 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
369 && pbs.ProfileHollow == 0 349 && pbs.ProfileHollow == 0
@@ -406,7 +386,7 @@ public class BSShapeCollection : IDisposable
406 // If a simple shape is not happening, create a mesh and possibly a hull. 386 // If a simple shape is not happening, create a mesh and possibly a hull.
407 // Note that if it's a native shape, the check for physical/non-physical is not 387 // Note that if it's a native shape, the check for physical/non-physical is not
408 // made. Native shapes are best used in either case. 388 // made. Native shapes are best used in either case.
409 if (!haveShape) 389 if (!haveShape && pbs != null)
410 { 390 {
411 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 391 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
412 { 392 {
@@ -425,12 +405,12 @@ public class BSShapeCollection : IDisposable
425 return ret; 405 return ret;
426 } 406 }
427 407
428 // Creates a native shape and assignes it to prim.BSShape 408 // Creates a native shape and assignes it to prim.BSShape.
429 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData, 409 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
410 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
430 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 411 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
431 ShapeDestructionCallback shapeCallback) 412 ShapeDestructionCallback shapeCallback)
432 { 413 {
433 BulletShape newShape;
434 414
435 shapeData.Type = shapeType; 415 shapeData.Type = shapeType;
436 // Bullet native objects are scaled by the Bullet engine so pass the size in 416 // Bullet native objects are scaled by the Bullet engine so pass the size in
@@ -440,23 +420,42 @@ public class BSShapeCollection : IDisposable
440 // release any previous shape 420 // release any previous shape
441 DereferenceShape(prim.BSShape, true, shapeCallback); 421 DereferenceShape(prim.BSShape, true, shapeCallback);
442 422
443 // Native shapes are always built independently. 423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
444 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
445 newShape.shapeKey = (System.UInt64)shapeKey;
446 newShape.isNativeShape = true;
447 424
448 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. 425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
449 // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape); 426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale);
450 428
451 prim.BSShape = newShape; 429 prim.BSShape = newShape;
452 return true; 430 return true;
453 } 431 }
454 432
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
435 {
436 BulletShape newShape;
437
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
439 {
440 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
442 shapeType);
443 }
444 else
445 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
447 }
448 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true;
450
451 return newShape;
452 }
453
455 // Builds a mesh shape in the physical world and updates prim.BSShape. 454 // Builds a mesh shape in the physical world and updates prim.BSShape.
456 // Dereferences previous shape in BSShape and adds a reference for this new shape. 455 // Dereferences previous shape in BSShape and adds a reference for this new shape.
457 // Returns 'true' of a mesh was actually built. Otherwise . 456 // Returns 'true' of a mesh was actually built. Otherwise .
458 // Called at taint-time! 457 // Called at taint-time!
459 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, 458 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
460 ShapeDestructionCallback shapeCallback) 459 ShapeDestructionCallback shapeCallback)
461 { 460 {
462 BulletShape newShape = new BulletShape(IntPtr.Zero); 461 BulletShape newShape = new BulletShape(IntPtr.Zero);
@@ -475,6 +474,8 @@ public class BSShapeCollection : IDisposable
475 DereferenceShape(prim.BSShape, true, shapeCallback); 474 DereferenceShape(prim.BSShape, true, shapeCallback);
476 475
477 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); 476 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
477 // Take evasive action if the mesh was not constructed.
478 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
478 479
479 ReferenceShape(newShape); 480 ReferenceShape(newShape);
480 481
@@ -488,7 +489,7 @@ public class BSShapeCollection : IDisposable
488 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 489 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
489 { 490 {
490 IMesh meshData = null; 491 IMesh meshData = null;
491 IntPtr meshPtr; 492 IntPtr meshPtr = IntPtr.Zero;
492 MeshDesc meshDesc; 493 MeshDesc meshDesc;
493 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 494 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
494 { 495 {
@@ -500,23 +501,26 @@ public class BSShapeCollection : IDisposable
500 // Pass false for physicalness as this creates some sort of bounding box which we don't need 501 // Pass false for physicalness as this creates some sort of bounding box which we don't need
501 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 502 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
502 503
503 int[] indices = meshData.getIndexListAsInt(); 504 if (meshData != null)
504 List<OMV.Vector3> vertices = meshData.getVertexList();
505
506 float[] verticesAsFloats = new float[vertices.Count * 3];
507 int vi = 0;
508 foreach (OMV.Vector3 vv in vertices)
509 { 505 {
510 verticesAsFloats[vi++] = vv.X; 506 int[] indices = meshData.getIndexListAsInt();
511 verticesAsFloats[vi++] = vv.Y; 507 List<OMV.Vector3> vertices = meshData.getVertexList();
512 verticesAsFloats[vi++] = vv.Z;
513 }
514 508
515 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 509 float[] verticesAsFloats = new float[vertices.Count * 3];
516 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 510 int vi = 0;
511 foreach (OMV.Vector3 vv in vertices)
512 {
513 verticesAsFloats[vi++] = vv.X;
514 verticesAsFloats[vi++] = vv.Y;
515 verticesAsFloats[vi++] = vv.Z;
516 }
517 517
518 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 518 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
519 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 519 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
520
521 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
522 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
523 }
520 } 524 }
521 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 525 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
522 newShape.shapeKey = newMeshKey; 526 newShape.shapeKey = newMeshKey;
@@ -526,7 +530,7 @@ public class BSShapeCollection : IDisposable
526 530
527 // See that hull shape exists in the physical world and update prim.BSShape. 531 // See that hull shape exists in the physical world and update prim.BSShape.
528 // We could be creating the hull because scale changed or whatever. 532 // We could be creating the hull because scale changed or whatever.
529 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, 533 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
530 ShapeDestructionCallback shapeCallback) 534 ShapeDestructionCallback shapeCallback)
531 { 535 {
532 BulletShape newShape; 536 BulletShape newShape;
@@ -545,6 +549,7 @@ public class BSShapeCollection : IDisposable
545 DereferenceShape(prim.BSShape, true, shapeCallback); 549 DereferenceShape(prim.BSShape, true, shapeCallback);
546 550
547 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 551 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
552 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
548 553
549 ReferenceShape(newShape); 554 ReferenceShape(newShape);
550 555
@@ -558,7 +563,7 @@ public class BSShapeCollection : IDisposable
558 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 563 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
559 { 564 {
560 565
561 IntPtr hullPtr; 566 IntPtr hullPtr = IntPtr.Zero;
562 HullDesc hullDesc; 567 HullDesc hullDesc;
563 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 568 if (Hulls.TryGetValue(newHullKey, out hullDesc))
564 { 569 {
@@ -570,86 +575,89 @@ public class BSShapeCollection : IDisposable
570 // Build a new hull in the physical world 575 // Build a new hull in the physical world
571 // Pass false for physicalness as this creates some sort of bounding box which we don't need 576 // Pass false for physicalness as this creates some sort of bounding box which we don't need
572 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 577 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
573 578 if (meshData != null)
574 int[] indices = meshData.getIndexListAsInt();
575 List<OMV.Vector3> vertices = meshData.getVertexList();
576
577 //format conversion from IMesh format to DecompDesc format
578 List<int> convIndices = new List<int>();
579 List<float3> convVertices = new List<float3>();
580 for (int ii = 0; ii < indices.GetLength(0); ii++)
581 { 579 {
582 convIndices.Add(indices[ii]);
583 }
584 foreach (OMV.Vector3 vv in vertices)
585 {
586 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
587 }
588 580
589 // setup and do convex hull conversion 581 int[] indices = meshData.getIndexListAsInt();
590 m_hulls = new List<ConvexResult>(); 582 List<OMV.Vector3> vertices = meshData.getVertexList();
591 DecompDesc dcomp = new DecompDesc();
592 dcomp.mIndices = convIndices;
593 dcomp.mVertices = convVertices;
594 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
595 // create the hull into the _hulls variable
596 convexBuilder.process(dcomp);
597
598 // Convert the vertices and indices for passing to unmanaged.
599 // The hull information is passed as a large floating point array.
600 // The format is:
601 // convHulls[0] = number of hulls
602 // convHulls[1] = number of vertices in first hull
603 // convHulls[2] = hull centroid X coordinate
604 // convHulls[3] = hull centroid Y coordinate
605 // convHulls[4] = hull centroid Z coordinate
606 // convHulls[5] = first hull vertex X
607 // convHulls[6] = first hull vertex Y
608 // convHulls[7] = first hull vertex Z
609 // convHulls[8] = second hull vertex X
610 // ...
611 // convHulls[n] = number of vertices in second hull
612 // convHulls[n+1] = second hull centroid X coordinate
613 // ...
614 //
615 // TODO: is is very inefficient. Someday change the convex hull generator to return
616 // data structures that do not need to be converted in order to pass to Bullet.
617 // And maybe put the values directly into pinned memory rather than marshaling.
618 int hullCount = m_hulls.Count;
619 int totalVertices = 1; // include one for the count of the hulls
620 foreach (ConvexResult cr in m_hulls)
621 {
622 totalVertices += 4; // add four for the vertex count and centroid
623 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
624 }
625 float[] convHulls = new float[totalVertices];
626 583
627 convHulls[0] = (float)hullCount; 584 //format conversion from IMesh format to DecompDesc format
628 int jj = 1; 585 List<int> convIndices = new List<int>();
629 foreach (ConvexResult cr in m_hulls) 586 List<float3> convVertices = new List<float3>();
630 { 587 for (int ii = 0; ii < indices.GetLength(0); ii++)
631 // copy vertices for index access 588 {
632 float3[] verts = new float3[cr.HullVertices.Count]; 589 convIndices.Add(indices[ii]);
633 int kk = 0; 590 }
634 foreach (float3 ff in cr.HullVertices) 591 foreach (OMV.Vector3 vv in vertices)
635 { 592 {
636 verts[kk++] = ff; 593 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
637 } 594 }
638 595
639 // add to the array one hull's worth of data 596 // setup and do convex hull conversion
640 convHulls[jj++] = cr.HullIndices.Count; 597 m_hulls = new List<ConvexResult>();
641 convHulls[jj++] = 0f; // centroid x,y,z 598 DecompDesc dcomp = new DecompDesc();
642 convHulls[jj++] = 0f; 599 dcomp.mIndices = convIndices;
643 convHulls[jj++] = 0f; 600 dcomp.mVertices = convVertices;
644 foreach (int ind in cr.HullIndices) 601 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
602 // create the hull into the _hulls variable
603 convexBuilder.process(dcomp);
604
605 // Convert the vertices and indices for passing to unmanaged.
606 // The hull information is passed as a large floating point array.
607 // The format is:
608 // convHulls[0] = number of hulls
609 // convHulls[1] = number of vertices in first hull
610 // convHulls[2] = hull centroid X coordinate
611 // convHulls[3] = hull centroid Y coordinate
612 // convHulls[4] = hull centroid Z coordinate
613 // convHulls[5] = first hull vertex X
614 // convHulls[6] = first hull vertex Y
615 // convHulls[7] = first hull vertex Z
616 // convHulls[8] = second hull vertex X
617 // ...
618 // convHulls[n] = number of vertices in second hull
619 // convHulls[n+1] = second hull centroid X coordinate
620 // ...
621 //
622 // TODO: is is very inefficient. Someday change the convex hull generator to return
623 // data structures that do not need to be converted in order to pass to Bullet.
624 // And maybe put the values directly into pinned memory rather than marshaling.
625 int hullCount = m_hulls.Count;
626 int totalVertices = 1; // include one for the count of the hulls
627 foreach (ConvexResult cr in m_hulls)
645 { 628 {
646 convHulls[jj++] = verts[ind].x; 629 totalVertices += 4; // add four for the vertex count and centroid
647 convHulls[jj++] = verts[ind].y; 630 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
648 convHulls[jj++] = verts[ind].z;
649 } 631 }
632 float[] convHulls = new float[totalVertices];
633
634 convHulls[0] = (float)hullCount;
635 int jj = 1;
636 foreach (ConvexResult cr in m_hulls)
637 {
638 // copy vertices for index access
639 float3[] verts = new float3[cr.HullVertices.Count];
640 int kk = 0;
641 foreach (float3 ff in cr.HullVertices)
642 {
643 verts[kk++] = ff;
644 }
645
646 // add to the array one hull's worth of data
647 convHulls[jj++] = cr.HullIndices.Count;
648 convHulls[jj++] = 0f; // centroid x,y,z
649 convHulls[jj++] = 0f;
650 convHulls[jj++] = 0f;
651 foreach (int ind in cr.HullIndices)
652 {
653 convHulls[jj++] = verts[ind].x;
654 convHulls[jj++] = verts[ind].y;
655 convHulls[jj++] = verts[ind].z;
656 }
657 }
658 // create the hull data structure in Bullet
659 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
650 } 660 }
651 // create the hull data structure in Bullet
652 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
653 } 661 }
654 662
655 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 663 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
@@ -690,11 +698,55 @@ public class BSShapeCollection : IDisposable
690 return ComputeShapeKey(shapeData, pbs, out lod); 698 return ComputeShapeKey(shapeData, pbs, out lod);
691 } 699 }
692 700
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
702 {
703 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero)
705 return newShape;
706
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
711 {
712 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim;
714 Util.FireAndForget(delegate
715 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
717 if (assetProvider != null)
718 {
719 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
720 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
721 {
722 if (!yprim.BaseShape.SculptEntry)
723 return;
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return;
726
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length];
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object.
731 yprim.ForceBodyShapeRebuild(false);
732
733 });
734 }
735 });
736 }
737
738 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
741
742 return fillinShape;
743 }
744
693 // Create a body object in Bullet. 745 // Create a body object in Bullet.
694 // Updates prim.BSBody with the information about the new body if one is created. 746 // Updates prim.BSBody with the information about the new body if one is created.
695 // Returns 'true' if an object was actually created. 747 // Returns 'true' if an object was actually created.
696 // Called at taint-time. 748 // Called at taint-time.
697 private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, 749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
698 ShapeData shapeData, BodyDestructionCallback bodyCallback) 750 ShapeData shapeData, BodyDestructionCallback bodyCallback)
699 { 751 {
700 bool ret = false; 752 bool ret = false;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index caf411e..4106534 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -114,6 +114,7 @@ public class BSTerrainManager
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity)); 115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); 116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 // Ground plane does not move 118 // Ground plane does not move
118 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 119 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
119 // Everything collides with the ground plane. 120 // Everything collides with the ground plane.
@@ -334,7 +335,8 @@ public class BSTerrainManager
334 335
335 // Make sure the new shape is processed. 336 // Make sure the new shape is processed.
336 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); 337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
339 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
338 340
339 m_terrainModified = true; 341 m_terrainModified = true;
340 }; 342 };
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 276111c..5ffd591 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -223,6 +223,7 @@ public struct ShapeData
223 KEY_SPHERE = 2, 223 KEY_SPHERE = 2,
224 KEY_CONE = 3, 224 KEY_CONE = 3,
225 KEY_CYLINDER = 4, 225 KEY_CYLINDER = 4,
226 KEY_CAPSULE = 5,
226 } 227 }
227} 228}
228[StructLayout(LayoutKind.Sequential)] 229[StructLayout(LayoutKind.Sequential)]
@@ -282,6 +283,7 @@ public struct ConfigurationParameters
282 public float terrainHitFraction; 283 public float terrainHitFraction;
283 public float terrainRestitution; 284 public float terrainRestitution;
284 public float avatarFriction; 285 public float avatarFriction;
286 public float avatarStandingFriction;
285 public float avatarDensity; 287 public float avatarDensity;
286 public float avatarRestitution; 288 public float avatarRestitution;
287 public float avatarCapsuleRadius; 289 public float avatarCapsuleRadius;
@@ -388,7 +390,7 @@ public enum CollisionFilterGroups : uint
388 VolumeDetectMask = ~BSensorTrigger, 390 VolumeDetectMask = ~BSensorTrigger,
389 TerrainFilter = BTerrainFilter, 391 TerrainFilter = BTerrainFilter,
390 TerrainMask = BAllFilter & ~BStaticFilter, 392 TerrainMask = BAllFilter & ~BStaticFilter,
391 GroundPlaneFilter = BAllFilter, 393 GroundPlaneFilter = BGroundPlaneFilter,
392 GroundPlaneMask = BAllFilter 394 GroundPlaneMask = BAllFilter
393 395
394}; 396};
@@ -428,6 +430,7 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg
428[return: MarshalAs(UnmanagedType.LPStr)] 430[return: MarshalAs(UnmanagedType.LPStr)]
429public static extern string GetVersion(); 431public static extern string GetVersion();
430 432
433/* Remove the linkage to the old api methods
431[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
432public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 435public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
433 int maxCollisions, IntPtr collisionArray, 436 int maxCollisions, IntPtr collisionArray,
@@ -531,7 +534,7 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
531// =============================================================================== 534// ===============================================================================
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern void DumpBulletStatistics(); 536public static extern void DumpBulletStatistics();
534 537*/
535// Log a debug message 538// Log a debug message
536[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
537public static extern void SetDebugLogCallback(DebugLogCallback callback); 540public static extern void SetDebugLogCallback(DebugLogCallback callback);
@@ -562,7 +565,8 @@ public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
562[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
563public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 566public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
564 int maxCollisions, IntPtr collisionArray, 567 int maxCollisions, IntPtr collisionArray,
565 int maxUpdates, IntPtr updateArray); 568 int maxUpdates, IntPtr updateArray,
569 DebugLogCallback logRoutine);
566 570
567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 571[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
568public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 572public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
@@ -604,6 +608,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
604public static extern bool IsNativeShape2(IntPtr shape); 608public static extern bool IsNativeShape2(IntPtr shape);
605 609
606[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
611public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
612
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
607public static extern IntPtr CreateCompoundShape2(IntPtr sim); 614public static extern IntPtr CreateCompoundShape2(IntPtr sim);
608 615
609[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index 5a1fdf9..2548648 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -67,6 +67,14 @@ namespace OpenSim.Region.Physics.OdePlugin
67 private int m_expectedCollisionContacts = 0; 67 private int m_expectedCollisionContacts = 0;
68 68
69 /// <summary> 69 /// <summary>
70 /// Gets collide bits so that we can still perform land collisions if a mesh fails to load.
71 /// </summary>
72 private int BadMeshAssetCollideBits
73 {
74 get { return m_isphysical ? (int)CollisionCategories.Land : 0; }
75 }
76
77 /// <summary>
70 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. 78 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
71 /// </summary> 79 /// </summary>
72 public override bool IsPhysical 80 public override bool IsPhysical
@@ -344,11 +352,10 @@ namespace OpenSim.Region.Physics.OdePlugin
344 if (m_assetFailed) 352 if (m_assetFailed)
345 { 353 {
346 d.GeomSetCategoryBits(prim_geom, 0); 354 d.GeomSetCategoryBits(prim_geom, 0);
347 d.GeomSetCollideBits(prim_geom, BadAssetColideBits()); 355 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
348 } 356 }
349 else 357 else
350 { 358 {
351
352 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 359 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
353 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 360 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
354 } 361 }
@@ -418,7 +425,7 @@ namespace OpenSim.Region.Physics.OdePlugin
418 if (m_assetFailed) 425 if (m_assetFailed)
419 { 426 {
420 d.GeomSetCategoryBits(prim_geom, 0); 427 d.GeomSetCategoryBits(prim_geom, 0);
421 d.GeomSetCollideBits(prim_geom, BadAssetColideBits()); 428 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
422 } 429 }
423 else 430 else
424 { 431 {
@@ -851,11 +858,6 @@ namespace OpenSim.Region.Physics.OdePlugin
851 858
852 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>(); 859 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
853 860
854 public int BadAssetColideBits()
855 {
856 return (m_isphysical ? (int)CollisionCategories.Land : 0);
857 }
858
859 private void setMesh(OdeScene parent_scene, IMesh mesh) 861 private void setMesh(OdeScene parent_scene, IMesh mesh)
860 { 862 {
861// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh); 863// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh);
@@ -1137,7 +1139,7 @@ Console.WriteLine("ZProcessTaints for " + Name);
1137 if (prm.m_assetFailed) 1139 if (prm.m_assetFailed)
1138 { 1140 {
1139 d.GeomSetCategoryBits(prm.prim_geom, 0); 1141 d.GeomSetCategoryBits(prm.prim_geom, 0);
1140 d.GeomSetCollideBits(prm.prim_geom, prm.BadAssetColideBits()); 1142 d.GeomSetCollideBits(prm.prim_geom, prm.BadMeshAssetCollideBits);
1141 } 1143 }
1142 else 1144 else
1143 { 1145 {
@@ -1191,7 +1193,7 @@ Console.WriteLine("ZProcessTaints for " + Name);
1191 if (m_assetFailed) 1193 if (m_assetFailed)
1192 { 1194 {
1193 d.GeomSetCategoryBits(prim_geom, 0); 1195 d.GeomSetCategoryBits(prim_geom, 0);
1194 d.GeomSetCollideBits(prim_geom, BadAssetColideBits()); 1196 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1195 } 1197 }
1196 else 1198 else
1197 { 1199 {
@@ -1393,7 +1395,7 @@ Console.WriteLine("ZProcessTaints for " + Name);
1393 if (m_assetFailed) 1395 if (m_assetFailed)
1394 { 1396 {
1395 d.GeomSetCategoryBits(prim_geom, 0); 1397 d.GeomSetCategoryBits(prim_geom, 0);
1396 d.GeomSetCollideBits(prim_geom, BadAssetColideBits()); 1398 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1397 } 1399 }
1398 else 1400 else
1399 { 1401 {
@@ -2137,7 +2139,7 @@ Console.WriteLine(" JointCreateFixed");
2137 } 2139 }
2138 2140
2139 if (m_assetFailed) 2141 if (m_assetFailed)
2140 d.GeomSetCollideBits(prim_geom, BadAssetColideBits()); 2142 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
2141 else 2143 else
2142 2144
2143 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 2145 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
index e235733..6d5ce4b 100644
--- a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
+++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
@@ -128,7 +128,7 @@ namespace OpenSim.Services.Connectors.Friends
128 return Call(region, sendData); 128 return Call(region, sendData);
129 } 129 }
130 130
131 public bool StatusNotify(GridRegion region, UUID userID, UUID friendID, bool online) 131 public bool StatusNotify(GridRegion region, UUID userID, string friendID, bool online)
132 { 132 {
133 Dictionary<string, object> sendData = new Dictionary<string, object>(); 133 Dictionary<string, object> sendData = new Dictionary<string, object>();
134 //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); 134 //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
@@ -136,7 +136,7 @@ namespace OpenSim.Services.Connectors.Friends
136 sendData["METHOD"] = "status"; 136 sendData["METHOD"] = "status";
137 137
138 sendData["FromID"] = userID.ToString(); 138 sendData["FromID"] = userID.ToString();
139 sendData["ToID"] = friendID.ToString(); 139 sendData["ToID"] = friendID;
140 sendData["Online"] = online.ToString(); 140 sendData["Online"] = online.ToString();
141 141
142 return Call(region, sendData); 142 return Call(region, sendData);
diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs
index 98423d7..a8bcfb2 100644
--- a/OpenSim/Services/HypergridService/HGFriendsService.cs
+++ b/OpenSim/Services/HypergridService/HGFriendsService.cs
@@ -397,7 +397,7 @@ namespace OpenSim.Services.HypergridService
397 if (region != null) 397 if (region != null)
398 { 398 {
399 m_log.DebugFormat("[HGFRIENDS SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline")); 399 m_log.DebugFormat("[HGFRIENDS SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
400 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online); 400 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID.ToString(), online);
401 } 401 }
402 } 402 }
403 } 403 }
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
index a6fc731..a26a922 100644
--- a/OpenSim/Services/HypergridService/UserAgentService.cs
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -504,7 +504,7 @@ namespace OpenSim.Services.HypergridService
504 if (region != null) 504 if (region != null)
505 { 505 {
506 m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline")); 506 m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
507 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online); 507 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID.ToString(), online);
508 } 508 }
509 } 509 }
510 } 510 }
diff --git a/OpenSim/Services/Interfaces/IPresenceService.cs b/OpenSim/Services/Interfaces/IPresenceService.cs
index 8d583ff..90f9842 100644
--- a/OpenSim/Services/Interfaces/IPresenceService.cs
+++ b/OpenSim/Services/Interfaces/IPresenceService.cs
@@ -61,13 +61,49 @@ namespace OpenSim.Services.Interfaces
61 61
62 public interface IPresenceService 62 public interface IPresenceService
63 { 63 {
64 /// <summary>
65 /// Store session information.
66 /// </summary>
67 /// <returns>/returns>
68 /// <param name='userID'></param>
69 /// <param name='sessionID'></param>
70 /// <param name='secureSessionID'></param>
64 bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID); 71 bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID);
72
73 /// <summary>
74 /// Remove session information.
75 /// </summary>
76 /// <returns></returns>
77 /// <param name='sessionID'></param>
65 bool LogoutAgent(UUID sessionID); 78 bool LogoutAgent(UUID sessionID);
79
80 /// <summary>
81 /// Remove session information for all agents in the given region.
82 /// </summary>
83 /// <returns></returns>
84 /// <param name='regionID'></param>
66 bool LogoutRegionAgents(UUID regionID); 85 bool LogoutRegionAgents(UUID regionID);
67 86
87 /// <summary>
88 /// Update data for an existing session.
89 /// </summary>
90 /// <returns></returns>
91 /// <param name='sessionID'></param>
92 /// <param name='regionID'></param>
68 bool ReportAgent(UUID sessionID, UUID regionID); 93 bool ReportAgent(UUID sessionID, UUID regionID);
69 94
95 /// <summary>
96 /// Get session information for a given session ID.
97 /// </summary>
98 /// <returns></returns>
99 /// <param name='sessionID'></param>
70 PresenceInfo GetAgent(UUID sessionID); 100 PresenceInfo GetAgent(UUID sessionID);
101
102 /// <summary>
103 /// Get session information for a collection of users.
104 /// </summary>
105 /// <returns>Session information for the users.</returns>
106 /// <param name='userIDs'></param>
71 PresenceInfo[] GetAgents(string[] userIDs); 107 PresenceInfo[] GetAgents(string[] userIDs);
72 } 108 }
73} 109} \ No newline at end of file