diff options
author | BlueWall | 2012-10-20 04:32:45 -0400 |
---|---|---|
committer | BlueWall | 2012-10-20 04:32:45 -0400 |
commit | af9cd7d30cc3926242338da2ed66c7cc444c6240 (patch) | |
tree | 80d8eea5b0d6d70deeb65ae6d6736648110f15b4 /OpenSim/Region | |
parent | Add CLICK_ACTION_ZOOM (diff) | |
parent | minor: remove unnecessary bit of method doc from OdePrim.BadMeshAssetCollideB... (diff) | |
download | opensim-SC-af9cd7d30cc3926242338da2ed66c7cc444c6240.zip opensim-SC-af9cd7d30cc3926242338da2ed66c7cc444c6240.tar.gz opensim-SC-af9cd7d30cc3926242338da2ed66c7cc444c6240.tar.bz2 opensim-SC-af9cd7d30cc3926242338da2ed66c7cc444c6240.tar.xz |
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region')
12 files changed, 769 insertions, 456 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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Linq; | ||
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Threading; | 33 | using System.Threading; |
33 | using log4net; | 34 | using 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using log4net; | 32 | using log4net; |
32 | using Mono.Addins; | 33 | using Mono.Addins; |
@@ -36,6 +37,8 @@ using OpenMetaverse.StructuredData; | |||
36 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
37 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
38 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Services.Interfaces; | ||
41 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | ||
39 | 42 | ||
40 | namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups | 43 | namespace 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)] |
429 | public static extern string GetVersion(); | 431 | public 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] |
432 | public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, | 435 | public 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] |
533 | public static extern void DumpBulletStatistics(); | 536 | public 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] |
537 | public static extern void SetDebugLogCallback(DebugLogCallback callback); | 540 | public 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] |
563 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | 566 | public 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] |
568 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | 572 | public 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) | |||
604 | public static extern bool IsNativeShape2(IntPtr shape); | 608 | public static extern bool IsNativeShape2(IntPtr shape); |
605 | 609 | ||
606 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 610 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
611 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
612 | |||
613 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
607 | public static extern IntPtr CreateCompoundShape2(IntPtr sim); | 614 | public 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); |