diff options
author | Melanie | 2013-04-22 22:28:41 +0200 |
---|---|---|
committer | Melanie | 2013-04-22 22:28:41 +0200 |
commit | 671a97ef76f681503b7e2024c6037cb5814e245c (patch) | |
tree | 4d88ad2405f84ffbb3c9226f4c1ccff07b323766 /OpenSim/Region | |
parent | Merge branch 'master' of ssh://3dhosting.de/var/git/careminster (diff) | |
parent | Merge branch 'master' into careminster (diff) | |
download | opensim-SC-671a97ef76f681503b7e2024c6037cb5814e245c.zip opensim-SC-671a97ef76f681503b7e2024c6037cb5814e245c.tar.gz opensim-SC-671a97ef76f681503b7e2024c6037cb5814e245c.tar.bz2 opensim-SC-671a97ef76f681503b7e2024c6037cb5814e245c.tar.xz |
Merge branch 'master' of ssh://3dhosting.de/var/git/careminster
Diffstat (limited to 'OpenSim/Region')
29 files changed, 2135 insertions, 900 deletions
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 7361f50..cd2338d 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs | |||
@@ -821,7 +821,7 @@ namespace OpenSim | |||
821 | 821 | ||
822 | if (foundClientServer) | 822 | if (foundClientServer) |
823 | { | 823 | { |
824 | m_clientServers[clientServerElement].NetworkStop(); | 824 | m_clientServers[clientServerElement].Stop(); |
825 | m_clientServers.RemoveAt(clientServerElement); | 825 | m_clientServers.RemoveAt(clientServerElement); |
826 | } | 826 | } |
827 | } | 827 | } |
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs index 54a441b..bb7e6d0 100644 --- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs +++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs | |||
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack | |||
38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, | 38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, |
39 | AgentCircuitManager authenticateClass); | 39 | AgentCircuitManager authenticateClass); |
40 | 40 | ||
41 | void NetworkStop(); | ||
42 | bool HandlesRegion(Location x); | 41 | bool HandlesRegion(Location x); |
43 | void AddScene(IScene x); | ||
44 | 42 | ||
43 | /// <summary> | ||
44 | /// Add the given scene to be handled by this IClientNetworkServer. | ||
45 | /// </summary> | ||
46 | /// <param name='scene'></param> | ||
47 | void AddScene(IScene scene); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Start sending and receiving data. | ||
51 | /// </summary> | ||
45 | void Start(); | 52 | void Start(); |
53 | |||
54 | /// <summary> | ||
55 | /// Stop sending and receiving data. | ||
56 | /// </summary> | ||
46 | void Stop(); | 57 | void Stop(); |
47 | } | 58 | } |
48 | } | 59 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 4979be8..b7469ae 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -823,12 +823,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
823 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 823 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
824 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 824 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
825 | 825 | ||
826 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | 826 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; |
827 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 827 | handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); |
828 | // use same as MoveAgentIntoRegion (both should be task ) | 828 | handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; |
829 | handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported | ||
830 | |||
829 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 831 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
830 | } | 832 | } |
831 | 833 | ||
834 | |||
832 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 835 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
833 | { | 836 | { |
834 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 837 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index e07ce4c..33ca08c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -62,11 +62,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | 62 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); |
63 | } | 63 | } |
64 | 64 | ||
65 | public void NetworkStop() | ||
66 | { | ||
67 | m_udpServer.Stop(); | ||
68 | } | ||
69 | |||
70 | public void AddScene(IScene scene) | 65 | public void AddScene(IScene scene) |
71 | { | 66 | { |
72 | m_udpServer.AddScene(scene); | 67 | m_udpServer.AddScene(scene); |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 5aad7f0..bbe7446 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | |||
@@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
358 | bool asAttachment) | 358 | bool asAttachment) |
359 | { | 359 | { |
360 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); | 360 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); |
361 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); | 361 | // Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); |
362 | 362 | ||
363 | foreach (SceneObjectGroup objectGroup in objlist) | 363 | foreach (SceneObjectGroup objectGroup in objlist) |
364 | { | 364 | { |
@@ -379,7 +379,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
379 | objectGroup.AbsolutePosition.Z); | 379 | objectGroup.AbsolutePosition.Z); |
380 | 380 | ||
381 | Quaternion inventoryStoredRotation = objectGroup.GroupRotation; | 381 | Quaternion inventoryStoredRotation = objectGroup.GroupRotation; |
382 | originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; | 382 | //originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; |
383 | 383 | ||
384 | // Restore attachment data after trip through the sim | 384 | // Restore attachment data after trip through the sim |
385 | if (objectGroup.RootPart.AttachPoint > 0) | 385 | if (objectGroup.RootPart.AttachPoint > 0) |
@@ -418,9 +418,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
418 | else | 418 | else |
419 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); | 419 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); |
420 | 420 | ||
421 | // Restore the position of each group now that it has been stored to inventory. | 421 | // // Restore the position of each group now that it has been stored to inventory. |
422 | foreach (SceneObjectGroup objectGroup in objlist) | 422 | // foreach (SceneObjectGroup objectGroup in objlist) |
423 | objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; | 423 | // objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; |
424 | 424 | ||
425 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); | 425 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); |
426 | 426 | ||
@@ -866,7 +866,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
866 | return null; | 866 | return null; |
867 | } | 867 | } |
868 | 868 | ||
869 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) | 869 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment)) |
870 | return null; | 870 | return null; |
871 | 871 | ||
872 | for (int i = 0; i < objlist.Count; i++) | 872 | for (int i = 0; i < objlist.Count; i++) |
@@ -965,10 +965,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
965 | /// <param name="item"></param> | 965 | /// <param name="item"></param> |
966 | /// <param name="objlist"></param> | 966 | /// <param name="objlist"></param> |
967 | /// <param name="pos"></param> | 967 | /// <param name="pos"></param> |
968 | /// <param name="veclist"> | ||
969 | /// List of vector position adjustments for a coalesced objects. For ordinary objects | ||
970 | /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist | ||
971 | /// </param> | ||
968 | /// <param name="isAttachment"></param> | 972 | /// <param name="isAttachment"></param> |
969 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> | 973 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> |
970 | private bool DoPreRezWhenFromItem( | 974 | private bool DoPreRezWhenFromItem( |
971 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) | 975 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, |
976 | Vector3 pos, List<Vector3> veclist, bool isAttachment) | ||
972 | { | 977 | { |
973 | UUID fromUserInventoryItemId = UUID.Zero; | 978 | UUID fromUserInventoryItemId = UUID.Zero; |
974 | 979 | ||
@@ -991,28 +996,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
991 | } | 996 | } |
992 | } | 997 | } |
993 | 998 | ||
994 | int primcount = 0; | 999 | for (int i = 0; i < objlist.Count; i++) |
995 | foreach (SceneObjectGroup g in objlist) | ||
996 | primcount += g.PrimCount; | ||
997 | |||
998 | if (!m_Scene.Permissions.CanRezObject( | ||
999 | primcount, remoteClient.AgentId, pos) | ||
1000 | && !isAttachment) | ||
1001 | { | 1000 | { |
1002 | // The client operates in no fail mode. It will | 1001 | SceneObjectGroup g = objlist[i]; |
1003 | // have already removed the item from the folder | 1002 | |
1004 | // if it's no copy. | 1003 | if (!m_Scene.Permissions.CanRezObject( |
1005 | // Put it back if it's not an attachment | 1004 | g.PrimCount, remoteClient.AgentId, pos + veclist[i]) |
1006 | // | 1005 | && !isAttachment) |
1007 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | 1006 | { |
1008 | remoteClient.SendBulkUpdateInventory(item); | 1007 | // The client operates in no fail mode. It will |
1008 | // have already removed the item from the folder | ||
1009 | // if it's no copy. | ||
1010 | // Put it back if it's not an attachment | ||
1011 | // | ||
1012 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | ||
1013 | remoteClient.SendBulkUpdateInventory(item); | ||
1009 | 1014 | ||
1010 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); | 1015 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); |
1011 | remoteClient.SendAlertMessage(string.Format( | 1016 | remoteClient.SendAlertMessage(string.Format( |
1012 | "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", | 1017 | "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", |
1013 | item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); | 1018 | item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name)); |
1014 | 1019 | ||
1015 | return false; | 1020 | return false; |
1021 | } | ||
1016 | } | 1022 | } |
1017 | 1023 | ||
1018 | for (int i = 0; i < objlist.Count; i++) | 1024 | for (int i = 0; i < objlist.Count; i++) |
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 2b13a8b..de8539f 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -412,7 +412,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
412 | //public bool HttpVerboseThrottle = true; // not implemented | 412 | //public bool HttpVerboseThrottle = true; // not implemented |
413 | public List<string> HttpCustomHeaders = null; | 413 | public List<string> HttpCustomHeaders = null; |
414 | public bool HttpPragmaNoCache = true; | 414 | public bool HttpPragmaNoCache = true; |
415 | private Thread httpThread; | ||
416 | 415 | ||
417 | // Request info | 416 | // Request info |
418 | private UUID _itemID; | 417 | private UUID _itemID; |
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 79dd4a0..f8e93e1 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | |||
@@ -1453,6 +1453,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1453 | 1453 | ||
1454 | bool permission = false; | 1454 | bool permission = false; |
1455 | 1455 | ||
1456 | // m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); | ||
1457 | |||
1456 | ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); | 1458 | ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); |
1457 | if (land == null) return false; | 1459 | if (land == null) return false; |
1458 | 1460 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 28fce53..a2510a78 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -5647,12 +5647,12 @@ Environment.Exit(1); | |||
5647 | List<SceneObjectGroup> objects, | 5647 | List<SceneObjectGroup> objects, |
5648 | out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) | 5648 | out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) |
5649 | { | 5649 | { |
5650 | minX = 256; | 5650 | minX = float.MaxValue; |
5651 | maxX = -256; | 5651 | maxX = float.MinValue; |
5652 | minY = 256; | 5652 | minY = float.MaxValue; |
5653 | maxY = -256; | 5653 | maxY = float.MinValue; |
5654 | minZ = 8192; | 5654 | minZ = float.MaxValue; |
5655 | maxZ = -256; | 5655 | maxZ = float.MinValue; |
5656 | 5656 | ||
5657 | List<Vector3> offsets = new List<Vector3>(); | 5657 | List<Vector3> offsets = new List<Vector3>(); |
5658 | 5658 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ec7c3fa..9e644aa 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -5005,6 +5005,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
5005 | oldTex.DefaultTexture = fallbackOldFace; | 5005 | oldTex.DefaultTexture = fallbackOldFace; |
5006 | } | 5006 | } |
5007 | 5007 | ||
5008 | // Materials capable viewers can send a ObjectImage packet | ||
5009 | // when nothing in TE has changed. MaterialID should be updated | ||
5010 | // by the RenderMaterials CAP handler, so updating it here may cause a | ||
5011 | // race condtion. Therefore, if no non-materials TE fields have changed, | ||
5012 | // we should ignore any changes and not update Shape.TextureEntry | ||
5013 | |||
5014 | bool otherFieldsChanged = false; | ||
5015 | |||
5008 | for (int i = 0 ; i < GetNumberOfSides(); i++) | 5016 | for (int i = 0 ; i < GetNumberOfSides(); i++) |
5009 | { | 5017 | { |
5010 | 5018 | ||
@@ -5031,18 +5039,36 @@ namespace OpenSim.Region.Framework.Scenes | |||
5031 | // Max change, skip the rest of testing | 5039 | // Max change, skip the rest of testing |
5032 | if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) | 5040 | if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) |
5033 | break; | 5041 | break; |
5042 | |||
5043 | if (!otherFieldsChanged) | ||
5044 | { | ||
5045 | if (oldFace.Bump != newFace.Bump) otherFieldsChanged = true; | ||
5046 | if (oldFace.Fullbright != newFace.Fullbright) otherFieldsChanged = true; | ||
5047 | if (oldFace.Glow != newFace.Glow) otherFieldsChanged = true; | ||
5048 | if (oldFace.MediaFlags != newFace.MediaFlags) otherFieldsChanged = true; | ||
5049 | if (oldFace.OffsetU != newFace.OffsetU) otherFieldsChanged = true; | ||
5050 | if (oldFace.OffsetV != newFace.OffsetV) otherFieldsChanged = true; | ||
5051 | if (oldFace.RepeatU != newFace.RepeatU) otherFieldsChanged = true; | ||
5052 | if (oldFace.RepeatV != newFace.RepeatV) otherFieldsChanged = true; | ||
5053 | if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true; | ||
5054 | if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true; | ||
5055 | if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true; | ||
5056 | } | ||
5034 | } | 5057 | } |
5035 | 5058 | ||
5036 | m_shape.TextureEntry = newTex.GetBytes(); | 5059 | if (changeFlags != 0 || otherFieldsChanged) |
5037 | if (changeFlags != 0) | 5060 | { |
5038 | TriggerScriptChangedEvent(changeFlags); | 5061 | m_shape.TextureEntry = newTex.GetBytes(); |
5039 | UpdateFlag = UpdateRequired.FULL; | 5062 | if (changeFlags != 0) |
5040 | ParentGroup.HasGroupChanged = true; | 5063 | TriggerScriptChangedEvent(changeFlags); |
5064 | UpdateFlag = UpdateRequired.FULL; | ||
5065 | ParentGroup.HasGroupChanged = true; | ||
5041 | 5066 | ||
5042 | //This is madness.. | 5067 | //This is madness.. |
5043 | //ParentGroup.ScheduleGroupForFullUpdate(); | 5068 | //ParentGroup.ScheduleGroupForFullUpdate(); |
5044 | //This is sparta | 5069 | //This is sparta |
5045 | ScheduleFullUpdate(); | 5070 | ScheduleFullUpdate(); |
5071 | } | ||
5046 | } | 5072 | } |
5047 | 5073 | ||
5048 | 5074 | ||
diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs new file mode 100644 index 0000000..4ab6609 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | |||
@@ -0,0 +1,579 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Security.Cryptography; // for computing md5 hash | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | |||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | |||
46 | using Ionic.Zlib; | ||
47 | |||
48 | // You will need to uncomment these lines if you are adding a region module to some other assembly which does not already | ||
49 | // specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans | ||
50 | // the available DLLs | ||
51 | //[assembly: Addin("MaterialsDemoModule", "1.0")] | ||
52 | //[assembly: AddinDependency("OpenSim", "0.5")] | ||
53 | |||
54 | namespace OpenSim.Region.OptionalModules.MaterialsDemoModule | ||
55 | { | ||
56 | /// <summary> | ||
57 | /// | ||
58 | // # # ## ##### # # # # # #### | ||
59 | // # # # # # # ## # # ## # # # | ||
60 | // # # # # # # # # # # # # # # | ||
61 | // # ## # ###### ##### # # # # # # # # ### | ||
62 | // ## ## # # # # # ## # # ## # # | ||
63 | // # # # # # # # # # # # #### | ||
64 | // | ||
65 | // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! | ||
66 | // | ||
67 | ////////////// WARNING ////////////////////////////////////////////////////////////////// | ||
68 | /// This is an *Experimental* module for developing support for materials-capable viewers | ||
69 | /// This module should NOT be used in a production environment! It may cause data corruption and | ||
70 | /// viewer crashes. It should be only used to evaluate implementations of materials. | ||
71 | /// | ||
72 | /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature | ||
73 | /// of OpenSimulator and is not field proven at the time this module was written. Persistence | ||
74 | /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials | ||
75 | /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means | ||
76 | /// of archiving however the texture resources used by these materials probably will not as they | ||
77 | /// may not be adequately referenced to ensure proper archiving. | ||
78 | /// | ||
79 | /// | ||
80 | /// | ||
81 | /// To enable this module, add this string at the bottom of OpenSim.ini: | ||
82 | /// [MaterialsDemoModule] | ||
83 | /// | ||
84 | /// </summary> | ||
85 | /// | ||
86 | |||
87 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] | ||
88 | public class MaterialsDemoModule : INonSharedRegionModule | ||
89 | { | ||
90 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
91 | |||
92 | public string Name { get { return "MaterialsDemoModule"; } } | ||
93 | |||
94 | public Type ReplaceableInterface { get { return null; } } | ||
95 | |||
96 | private Scene m_scene = null; | ||
97 | private bool m_enabled = false; | ||
98 | |||
99 | public Dictionary<UUID, OSDMap> m_knownMaterials = new Dictionary<UUID, OSDMap>(); | ||
100 | |||
101 | public void Initialise(IConfigSource source) | ||
102 | { | ||
103 | m_enabled = (source.Configs["MaterialsDemoModule"] != null); | ||
104 | if (!m_enabled) | ||
105 | return; | ||
106 | |||
107 | m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); | ||
108 | } | ||
109 | |||
110 | public void Close() | ||
111 | { | ||
112 | if (!m_enabled) | ||
113 | return; | ||
114 | |||
115 | m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); | ||
116 | } | ||
117 | |||
118 | public void AddRegion(Scene scene) | ||
119 | { | ||
120 | if (!m_enabled) | ||
121 | return; | ||
122 | |||
123 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); | ||
124 | m_scene = scene; | ||
125 | m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps); | ||
126 | m_scene.EventManager.OnObjectAddedToScene += new Action<SceneObjectGroup>(EventManager_OnObjectAddedToScene); | ||
127 | } | ||
128 | |||
129 | void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) | ||
130 | { | ||
131 | foreach (var part in obj.Parts) | ||
132 | if (part != null) | ||
133 | GetStoredMaterialsForPart(part); | ||
134 | } | ||
135 | |||
136 | void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) | ||
137 | { | ||
138 | string capsBase = "/CAPS/" + caps.CapsObjectPath; | ||
139 | |||
140 | IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); | ||
141 | caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); | ||
142 | |||
143 | // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET | ||
144 | // and POST handlers, (at least at the time this was originally written), so we first set up a POST | ||
145 | // handler normally and then add a GET handler via MainServer | ||
146 | |||
147 | IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); | ||
148 | MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); | ||
149 | |||
150 | // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well | ||
151 | IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap); | ||
152 | MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); | ||
153 | } | ||
154 | |||
155 | public void RemoveRegion(Scene scene) | ||
156 | { | ||
157 | if (!m_enabled) | ||
158 | return; | ||
159 | |||
160 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); | ||
161 | } | ||
162 | |||
163 | public void RegionLoaded(Scene scene) | ||
164 | { | ||
165 | } | ||
166 | |||
167 | OSDMap GetMaterial(UUID id) | ||
168 | { | ||
169 | OSDMap map = null; | ||
170 | if (m_knownMaterials.ContainsKey(id)) | ||
171 | { | ||
172 | map = new OSDMap(); | ||
173 | map["ID"] = OSD.FromBinary(id.GetBytes()); | ||
174 | map["Material"] = m_knownMaterials[id]; | ||
175 | } | ||
176 | return map; | ||
177 | } | ||
178 | |||
179 | void GetStoredMaterialsForPart(SceneObjectPart part) | ||
180 | { | ||
181 | OSDMap OSMaterials = null; | ||
182 | OSDArray matsArr = null; | ||
183 | |||
184 | if (part.DynAttrs == null) | ||
185 | { | ||
186 | m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); | ||
187 | } | ||
188 | |||
189 | lock (part.DynAttrs) | ||
190 | { | ||
191 | if (part.DynAttrs.ContainsKey("OS:Materials")) | ||
192 | OSMaterials = part.DynAttrs["OS:Materials"]; | ||
193 | if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) | ||
194 | { | ||
195 | |||
196 | OSD osd = OSMaterials["Materials"]; | ||
197 | if (osd is OSDArray) | ||
198 | matsArr = osd as OSDArray; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (OSMaterials == null) | ||
203 | return; | ||
204 | |||
205 | m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); | ||
206 | |||
207 | |||
208 | if (matsArr == null) | ||
209 | { | ||
210 | m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | foreach (OSD elemOsd in matsArr) | ||
215 | { | ||
216 | if (elemOsd != null && elemOsd is OSDMap) | ||
217 | { | ||
218 | |||
219 | OSDMap matMap = elemOsd as OSDMap; | ||
220 | if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) | ||
221 | { | ||
222 | try | ||
223 | { | ||
224 | m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; | ||
225 | } | ||
226 | catch (Exception e) | ||
227 | { | ||
228 | m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material: " + e.ToString()); | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | |||
236 | void StoreMaterialsForPart(SceneObjectPart part) | ||
237 | { | ||
238 | try | ||
239 | { | ||
240 | if (part == null || part.Shape == null) | ||
241 | return; | ||
242 | |||
243 | Dictionary<UUID, OSDMap> mats = new Dictionary<UUID, OSDMap>(); | ||
244 | |||
245 | Primitive.TextureEntry te = part.Shape.Textures; | ||
246 | |||
247 | if (te.DefaultTexture != null) | ||
248 | { | ||
249 | if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) | ||
250 | mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; | ||
251 | } | ||
252 | |||
253 | if (te.FaceTextures != null) | ||
254 | { | ||
255 | foreach (var face in te.FaceTextures) | ||
256 | { | ||
257 | if (face != null) | ||
258 | { | ||
259 | if (m_knownMaterials.ContainsKey(face.MaterialID)) | ||
260 | mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | if (mats.Count == 0) | ||
265 | return; | ||
266 | |||
267 | OSDArray matsArr = new OSDArray(); | ||
268 | foreach (KeyValuePair<UUID, OSDMap> kvp in mats) | ||
269 | { | ||
270 | OSDMap matOsd = new OSDMap(); | ||
271 | matOsd["ID"] = OSD.FromUUID(kvp.Key); | ||
272 | matOsd["Material"] = kvp.Value; | ||
273 | matsArr.Add(matOsd); | ||
274 | } | ||
275 | |||
276 | OSDMap OSMaterials = new OSDMap(); | ||
277 | OSMaterials["Materials"] = matsArr; | ||
278 | |||
279 | lock (part.DynAttrs) | ||
280 | part.DynAttrs["OS:Materials"] = OSMaterials; | ||
281 | } | ||
282 | catch (Exception e) | ||
283 | { | ||
284 | m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart(): " + e.ToString()); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | |||
289 | public string RenderMaterialsPostCap(string request, string path, | ||
290 | string param, IOSHttpRequest httpRequest, | ||
291 | IOSHttpResponse httpResponse) | ||
292 | { | ||
293 | m_log.Debug("[MaterialsDemoModule]: POST cap handler"); | ||
294 | |||
295 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
296 | OSDMap resp = new OSDMap(); | ||
297 | |||
298 | OSDMap materialsFromViewer = null; | ||
299 | |||
300 | OSDArray respArr = new OSDArray(); | ||
301 | |||
302 | if (req.ContainsKey("Zipped")) | ||
303 | { | ||
304 | OSD osd = null; | ||
305 | |||
306 | byte[] inBytes = req["Zipped"].AsBinary(); | ||
307 | |||
308 | try | ||
309 | { | ||
310 | osd = ZDecompressBytesToOsd(inBytes); | ||
311 | |||
312 | if (osd != null) | ||
313 | { | ||
314 | if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries | ||
315 | { | ||
316 | foreach (OSD elem in (OSDArray)osd) | ||
317 | { | ||
318 | |||
319 | try | ||
320 | { | ||
321 | UUID id = new UUID(elem.AsBinary(), 0); | ||
322 | |||
323 | if (m_knownMaterials.ContainsKey(id)) | ||
324 | { | ||
325 | m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); | ||
326 | OSDMap matMap = new OSDMap(); | ||
327 | matMap["ID"] = OSD.FromBinary(id.GetBytes()); | ||
328 | |||
329 | matMap["Material"] = m_knownMaterials[id]; | ||
330 | respArr.Add(matMap); | ||
331 | } | ||
332 | else | ||
333 | m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); | ||
334 | } | ||
335 | catch (Exception e) | ||
336 | { | ||
337 | // report something here? | ||
338 | continue; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | else if (osd is OSDMap) // reqest to assign a material | ||
343 | { | ||
344 | materialsFromViewer = osd as OSDMap; | ||
345 | |||
346 | if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) | ||
347 | { | ||
348 | OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; | ||
349 | if (matsOsd is OSDArray) | ||
350 | { | ||
351 | OSDArray matsArr = matsOsd as OSDArray; | ||
352 | |||
353 | try | ||
354 | { | ||
355 | foreach (OSDMap matsMap in matsArr) | ||
356 | { | ||
357 | m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); | ||
358 | |||
359 | uint matLocalID = 0; | ||
360 | try { matLocalID = matsMap["ID"].AsUInteger(); } | ||
361 | catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } | ||
362 | m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); | ||
363 | |||
364 | |||
365 | OSDMap mat = null; | ||
366 | try { mat = matsMap["Material"] as OSDMap; } | ||
367 | catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } | ||
368 | m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); | ||
369 | |||
370 | UUID id = HashOsd(mat); | ||
371 | m_knownMaterials[id] = mat; | ||
372 | |||
373 | |||
374 | var sop = m_scene.GetSceneObjectPart(matLocalID); | ||
375 | if (sop == null) | ||
376 | m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); | ||
377 | else | ||
378 | { | ||
379 | //var te = sop.Shape.Textures; | ||
380 | var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); | ||
381 | |||
382 | if (te == null) | ||
383 | { | ||
384 | m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | int face = -1; | ||
389 | |||
390 | if (matsMap.ContainsKey("Face")) | ||
391 | { | ||
392 | face = matsMap["Face"].AsInteger(); | ||
393 | if (te.FaceTextures == null) // && face == 0) | ||
394 | { | ||
395 | if (te.DefaultTexture == null) | ||
396 | m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); | ||
397 | else | ||
398 | { | ||
399 | if (te.DefaultTexture.MaterialID == null) | ||
400 | m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); | ||
401 | else | ||
402 | { | ||
403 | te.DefaultTexture.MaterialID = id; | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | if (te.FaceTextures.Length >= face - 1) | ||
410 | { | ||
411 | if (te.FaceTextures[face] == null) | ||
412 | te.DefaultTexture.MaterialID = id; | ||
413 | else | ||
414 | te.FaceTextures[face].MaterialID = id; | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | if (te.DefaultTexture != null) | ||
421 | te.DefaultTexture.MaterialID = id; | ||
422 | } | ||
423 | |||
424 | m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); | ||
425 | |||
426 | //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually | ||
427 | |||
428 | if (sop.ParentGroup != null) | ||
429 | { | ||
430 | sop.Shape.TextureEntry = te.GetBytes(); | ||
431 | sop.TriggerScriptChangedEvent(Changed.TEXTURE); | ||
432 | sop.UpdateFlag = UpdateRequired.FULL; | ||
433 | sop.ParentGroup.HasGroupChanged = true; | ||
434 | |||
435 | sop.ScheduleFullUpdate(); | ||
436 | |||
437 | StoreMaterialsForPart(sop); | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | catch (Exception e) | ||
444 | { | ||
445 | m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | } | ||
453 | catch (Exception e) | ||
454 | { | ||
455 | m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message); | ||
456 | //return ""; | ||
457 | } | ||
458 | m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); | ||
459 | } | ||
460 | |||
461 | |||
462 | resp["Zipped"] = ZCompressOSD(respArr, false); | ||
463 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
464 | |||
465 | //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); | ||
466 | m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); | ||
467 | m_log.Debug("[MaterialsDemoModule]: cap response: " + response); | ||
468 | return response; | ||
469 | } | ||
470 | |||
471 | |||
472 | public string RenderMaterialsGetCap(string request, string path, | ||
473 | string param, IOSHttpRequest httpRequest, | ||
474 | IOSHttpResponse httpResponse) | ||
475 | { | ||
476 | m_log.Debug("[MaterialsDemoModule]: GET cap handler"); | ||
477 | |||
478 | OSDMap resp = new OSDMap(); | ||
479 | |||
480 | |||
481 | int matsCount = 0; | ||
482 | |||
483 | OSDArray allOsd = new OSDArray(); | ||
484 | |||
485 | foreach (KeyValuePair<UUID, OSDMap> kvp in m_knownMaterials) | ||
486 | { | ||
487 | OSDMap matMap = new OSDMap(); | ||
488 | |||
489 | matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); | ||
490 | |||
491 | matMap["Material"] = kvp.Value; | ||
492 | allOsd.Add(matMap); | ||
493 | matsCount++; | ||
494 | } | ||
495 | |||
496 | |||
497 | resp["Zipped"] = ZCompressOSD(allOsd, false); | ||
498 | m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); | ||
499 | |||
500 | return OSDParser.SerializeLLSDXmlString(resp); | ||
501 | } | ||
502 | |||
503 | static string ZippedOsdBytesToString(byte[] bytes) | ||
504 | { | ||
505 | try | ||
506 | { | ||
507 | return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); | ||
508 | } | ||
509 | catch (Exception e) | ||
510 | { | ||
511 | return "ZippedOsdBytesToString caught an exception: " + e.ToString(); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /// <summary> | ||
516 | /// computes a UUID by hashing a OSD object | ||
517 | /// </summary> | ||
518 | /// <param name="osd"></param> | ||
519 | /// <returns></returns> | ||
520 | private static UUID HashOsd(OSD osd) | ||
521 | { | ||
522 | using (var md5 = MD5.Create()) | ||
523 | using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) | ||
524 | return new UUID(md5.ComputeHash(ms), 0); | ||
525 | } | ||
526 | |||
527 | public static OSD ZCompressOSD(OSD inOsd, bool useHeader) | ||
528 | { | ||
529 | OSD osd = null; | ||
530 | |||
531 | using (MemoryStream msSinkCompressed = new MemoryStream()) | ||
532 | { | ||
533 | using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, | ||
534 | Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) | ||
535 | { | ||
536 | CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); | ||
537 | zOut.Close(); | ||
538 | } | ||
539 | |||
540 | msSinkCompressed.Seek(0L, SeekOrigin.Begin); | ||
541 | osd = OSD.FromBinary( msSinkCompressed.ToArray()); | ||
542 | } | ||
543 | |||
544 | return osd; | ||
545 | } | ||
546 | |||
547 | |||
548 | public static OSD ZDecompressBytesToOsd(byte[] input) | ||
549 | { | ||
550 | OSD osd = null; | ||
551 | |||
552 | using (MemoryStream msSinkUnCompressed = new MemoryStream()) | ||
553 | { | ||
554 | using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) | ||
555 | { | ||
556 | CopyStream(new MemoryStream(input), zOut); | ||
557 | zOut.Close(); | ||
558 | } | ||
559 | msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); | ||
560 | osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); | ||
561 | } | ||
562 | |||
563 | return osd; | ||
564 | } | ||
565 | |||
566 | static void CopyStream(System.IO.Stream input, System.IO.Stream output) | ||
567 | { | ||
568 | byte[] buffer = new byte[2048]; | ||
569 | int len; | ||
570 | while ((len = input.Read(buffer, 0, 2048)) > 0) | ||
571 | { | ||
572 | output.Write(buffer, 0, len); | ||
573 | } | ||
574 | |||
575 | output.Flush(); | ||
576 | } | ||
577 | |||
578 | } | ||
579 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs new file mode 100755 index 0000000..8416740 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorAvatarMove : BSActor | ||
40 | { | ||
41 | BSVMotor m_velocityMotor; | ||
42 | |||
43 | public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_velocityMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); | ||
69 | |||
70 | // If the object is physically active, add the hoverer prestep action | ||
71 | if (isActive) | ||
72 | { | ||
73 | ActivateAvatarMove(); | ||
74 | } | ||
75 | else | ||
76 | { | ||
77 | DeactivateAvatarMove(); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
82 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
83 | // Called at taint-time. | ||
84 | // BSActor.RemoveBodyDependencies() | ||
85 | public override void RemoveBodyDependencies() | ||
86 | { | ||
87 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
88 | } | ||
89 | |||
90 | // Usually called when target velocity changes to set the current velocity and the target | ||
91 | // into the movement motor. | ||
92 | public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) | ||
93 | { | ||
94 | m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() | ||
95 | { | ||
96 | if (m_velocityMotor != null) | ||
97 | { | ||
98 | m_velocityMotor.Reset(); | ||
99 | m_velocityMotor.SetTarget(targ); | ||
100 | m_velocityMotor.SetCurrent(vel); | ||
101 | m_velocityMotor.Enabled = true; | ||
102 | } | ||
103 | }); | ||
104 | } | ||
105 | |||
106 | // If a hover motor has not been created, create one and start the hovering. | ||
107 | private void ActivateAvatarMove() | ||
108 | { | ||
109 | if (m_velocityMotor == null) | ||
110 | { | ||
111 | // Infinite decay and timescale values so motor only changes current to target values. | ||
112 | m_velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
113 | 0.2f, // time scale | ||
114 | BSMotor.Infinite, // decay time scale | ||
115 | BSMotor.InfiniteVector, // friction timescale | ||
116 | 1f // efficiency | ||
117 | ); | ||
118 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
119 | SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); | ||
120 | |||
121 | m_physicsScene.BeforeStep += Mover; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | private void DeactivateAvatarMove() | ||
126 | { | ||
127 | if (m_velocityMotor != null) | ||
128 | { | ||
129 | m_physicsScene.BeforeStep -= Mover; | ||
130 | m_velocityMotor = null; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
135 | private void Mover(float timeStep) | ||
136 | { | ||
137 | // Don't do movement while the object is selected. | ||
138 | if (!isActive) | ||
139 | return; | ||
140 | |||
141 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
142 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
143 | |||
144 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
145 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
146 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
147 | // component is not fooled with (thus allowing gravity to do its thing). | ||
148 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
149 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
150 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
151 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
152 | // errors can creap in and the avatar will slowly float off in some direction. | ||
153 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
154 | // from real pushing. | ||
155 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
156 | |||
157 | m_velocityMotor.Step(timeStep); | ||
158 | m_controllingPrim.IsStationary = false; | ||
159 | |||
160 | // If we're not supposed to be moving, make sure things are zero. | ||
161 | if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
162 | { | ||
163 | // The avatar shouldn't be moving | ||
164 | m_velocityMotor.Zero(); | ||
165 | |||
166 | if (m_controllingPrim.IsColliding) | ||
167 | { | ||
168 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
169 | if (!m_controllingPrim.ColliderIsMoving) | ||
170 | { | ||
171 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); | ||
172 | m_controllingPrim.IsStationary = true; | ||
173 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
174 | } | ||
175 | |||
176 | // Standing has more friction on the ground | ||
177 | if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) | ||
178 | { | ||
179 | m_controllingPrim.Friction = BSParam.AvatarStandingFriction; | ||
180 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
181 | } | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | if (m_controllingPrim.Flying) | ||
186 | { | ||
187 | // Flying and not collising and velocity nearly zero. | ||
188 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", | ||
193 | m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | // Supposed to be moving. | ||
198 | OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; | ||
199 | |||
200 | if (m_controllingPrim.Friction != BSParam.AvatarFriction) | ||
201 | { | ||
202 | // Probably starting up walking. Set friction to moving friction. | ||
203 | m_controllingPrim.Friction = BSParam.AvatarFriction; | ||
204 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
205 | } | ||
206 | |||
207 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
208 | // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). | ||
209 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
210 | { | ||
211 | if (m_controllingPrim.RawVelocity.Z < 0) | ||
212 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
213 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
214 | } | ||
215 | |||
216 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
217 | OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; | ||
218 | |||
219 | // Should we check for move force being small and forcing velocity to zero? | ||
220 | |||
221 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
222 | moveForce += WalkUpStairs(); | ||
223 | |||
224 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", | ||
225 | m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); | ||
226 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
231 | // avatar up so it can walk up and over the low objects. | ||
232 | private OMV.Vector3 WalkUpStairs() | ||
233 | { | ||
234 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
235 | |||
236 | // This test is done if moving forward, not flying and is colliding with something. | ||
237 | // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", | ||
238 | // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); | ||
239 | if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) | ||
240 | { | ||
241 | // The range near the character's feet where we will consider stairs | ||
242 | float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; | ||
243 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
244 | |||
245 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is | ||
246 | foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) | ||
247 | { | ||
248 | // Don't care about collisions with the terrain | ||
249 | if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) | ||
250 | { | ||
251 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
252 | // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
253 | // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
254 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
255 | { | ||
256 | // This contact is within the 'near the feet' range. | ||
257 | // The normal should be our contact point to the object so it is pointing away | ||
258 | // thus the difference between our facing orientation and the normal should be small. | ||
259 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; | ||
260 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
261 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
262 | if (diff < BSParam.AvatarStepApproachFactor) | ||
263 | { | ||
264 | // Found the stairs contact point. Push up a little to raise the character. | ||
265 | float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; | ||
266 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
267 | |||
268 | // Also move the avatar up for the new height | ||
269 | OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); | ||
270 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
271 | } | ||
272 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", | ||
273 | m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | } | ||
283 | } | ||
284 | |||
285 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs new file mode 100755 index 0000000..92ace66 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorHover : BSActor | ||
40 | { | ||
41 | private BSFMotor m_hoverMotor; | ||
42 | |||
43 | public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_hoverMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); | ||
69 | |||
70 | // If not active any more, turn me off | ||
71 | if (!m_controllingPrim.HoverActive) | ||
72 | { | ||
73 | SetEnabled(false); | ||
74 | } | ||
75 | |||
76 | // If the object is physically active, add the hoverer prestep action | ||
77 | if (isActive) | ||
78 | { | ||
79 | ActivateHover(); | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | DeactivateHover(); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
88 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
89 | // Called at taint-time. | ||
90 | // BSActor.RemoveBodyDependencies() | ||
91 | public override void RemoveBodyDependencies() | ||
92 | { | ||
93 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
94 | } | ||
95 | |||
96 | // If a hover motor has not been created, create one and start the hovering. | ||
97 | private void ActivateHover() | ||
98 | { | ||
99 | if (m_hoverMotor == null) | ||
100 | { | ||
101 | // Turning the target on | ||
102 | m_hoverMotor = new BSFMotor("BSActorHover", | ||
103 | m_controllingPrim.HoverTau, // timeScale | ||
104 | BSMotor.Infinite, // decay time scale | ||
105 | BSMotor.Infinite, // friction timescale | ||
106 | 1f // efficiency | ||
107 | ); | ||
108 | m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); | ||
109 | m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); | ||
110 | m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
111 | |||
112 | m_physicsScene.BeforeStep += Hoverer; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | private void DeactivateHover() | ||
117 | { | ||
118 | if (m_hoverMotor != null) | ||
119 | { | ||
120 | m_physicsScene.BeforeStep -= Hoverer; | ||
121 | m_hoverMotor = null; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
126 | private void Hoverer(float timeStep) | ||
127 | { | ||
128 | // Don't do hovering while the object is selected. | ||
129 | if (!isActive) | ||
130 | return; | ||
131 | |||
132 | m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); | ||
133 | m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); | ||
134 | float targetHeight = m_hoverMotor.Step(timeStep); | ||
135 | |||
136 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
137 | // Compute the amount of force to push us there. | ||
138 | float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; | ||
139 | // Undo anything the object thinks it's doing at the moment | ||
140 | moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; | ||
141 | |||
142 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
143 | m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", | ||
144 | m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); | ||
145 | } | ||
146 | |||
147 | // Based on current position, determine what we should be hovering at now. | ||
148 | // Must recompute often. What if we walked offa cliff> | ||
149 | private float ComputeCurrentHoverHeight() | ||
150 | { | ||
151 | float ret = m_controllingPrim.HoverHeight; | ||
152 | float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); | ||
153 | |||
154 | switch (m_controllingPrim.HoverType) | ||
155 | { | ||
156 | case PIDHoverType.Ground: | ||
157 | ret = groundHeight + m_controllingPrim.HoverHeight; | ||
158 | break; | ||
159 | case PIDHoverType.GroundAndWater: | ||
160 | float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); | ||
161 | if (groundHeight > waterHeight) | ||
162 | { | ||
163 | ret = groundHeight + m_controllingPrim.HoverHeight; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | ret = waterHeight + m_controllingPrim.HoverHeight; | ||
168 | } | ||
169 | break; | ||
170 | } | ||
171 | return ret; | ||
172 | } | ||
173 | } | ||
174 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index 7219617..09ee32b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs | |||
@@ -36,11 +36,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
36 | { | 36 | { |
37 | public class BSActorLockAxis : BSActor | 37 | public class BSActorLockAxis : BSActor |
38 | { | 38 | { |
39 | bool TryExperimentalLockAxisCode = true; | ||
40 | BSConstraint LockAxisConstraint = null; | 39 | BSConstraint LockAxisConstraint = null; |
41 | 40 | ||
42 | public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) | 41 | public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) |
43 | : base(physicsScene, pObj,actorName) | 42 | : base(physicsScene, pObj, actorName) |
44 | { | 43 | { |
45 | m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); | 44 | m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); |
46 | LockAxisConstraint = null; | 45 | LockAxisConstraint = null; |
@@ -69,18 +68,13 @@ public class BSActorLockAxis : BSActor | |||
69 | // If all the axis are free, we don't need to exist | 68 | // If all the axis are free, we don't need to exist |
70 | if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) | 69 | if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) |
71 | { | 70 | { |
72 | m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,allAxisFree,removing={1}", m_controllingPrim.LocalID, ActorName); | 71 | Enabled = false; |
73 | m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); | ||
74 | return; | ||
75 | } | 72 | } |
73 | |||
76 | // If the object is physically active, add the axis locking constraint | 74 | // If the object is physically active, add the axis locking constraint |
77 | if (Enabled | 75 | if (isActive) |
78 | && m_controllingPrim.IsPhysicallyActive | ||
79 | && TryExperimentalLockAxisCode | ||
80 | && m_controllingPrim.LockedAxis != m_controllingPrim.LockedAxisFree) | ||
81 | { | 76 | { |
82 | if (LockAxisConstraint == null) | 77 | AddAxisLockConstraint(); |
83 | AddAxisLockConstraint(); | ||
84 | } | 78 | } |
85 | else | 79 | else |
86 | { | 80 | { |
@@ -99,7 +93,7 @@ public class BSActorLockAxis : BSActor | |||
99 | // If a constraint is set up, remove it from the physical scene | 93 | // If a constraint is set up, remove it from the physical scene |
100 | RemoveAxisLockConstraint(); | 94 | RemoveAxisLockConstraint(); |
101 | // Schedule a call before the next simulation step to restore the constraint. | 95 | // Schedule a call before the next simulation step to restore the constraint. |
102 | m_physicsScene.PostTaintObject(m_controllingPrim.LockedAxisActorName, m_controllingPrim.LocalID, delegate() | 96 | m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate() |
103 | { | 97 | { |
104 | Refresh(); | 98 | Refresh(); |
105 | }); | 99 | }); |
@@ -108,58 +102,61 @@ public class BSActorLockAxis : BSActor | |||
108 | 102 | ||
109 | private void AddAxisLockConstraint() | 103 | private void AddAxisLockConstraint() |
110 | { | 104 | { |
111 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | 105 | if (LockAxisConstraint == null) |
112 | // the other in the object. | 106 | { |
113 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | 107 | // Lock that axis by creating a 6DOF constraint that has one end in the world and |
114 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | 108 | // the other in the object. |
109 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
110 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
115 | 111 | ||
116 | // Remove any existing axis constraint (just to be sure) | 112 | // Remove any existing axis constraint (just to be sure) |
117 | RemoveAxisLockConstraint(); | 113 | RemoveAxisLockConstraint(); |
118 | 114 | ||
119 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, | 115 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, |
120 | OMV.Vector3.Zero, OMV.Quaternion.Identity, | 116 | OMV.Vector3.Zero, OMV.Quaternion.Identity, |
121 | false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); | 117 | false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); |
122 | LockAxisConstraint = axisConstrainer; | 118 | LockAxisConstraint = axisConstrainer; |
123 | m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); | 119 | m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); |
124 | 120 | ||
125 | // The constraint is tied to the world and oriented to the prim. | 121 | // The constraint is tied to the world and oriented to the prim. |
126 | 122 | ||
127 | // Free to move linearly in the region | 123 | // Free to move linearly in the region |
128 | OMV.Vector3 linearLow = OMV.Vector3.Zero; | 124 | OMV.Vector3 linearLow = OMV.Vector3.Zero; |
129 | OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; | 125 | OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; |
130 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); | 126 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); |
131 | 127 | ||
132 | // Angular with some axis locked | 128 | // Angular with some axis locked |
133 | float fPI = (float)Math.PI; | 129 | float fPI = (float)Math.PI; |
134 | OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); | 130 | OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); |
135 | OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); | 131 | OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); |
136 | if (m_controllingPrim.LockedAxis.X != 1f) | 132 | if (m_controllingPrim.LockedAxis.X != 1f) |
137 | { | 133 | { |
138 | angularLow.X = 0f; | 134 | angularLow.X = 0f; |
139 | angularHigh.X = 0f; | 135 | angularHigh.X = 0f; |
140 | } | 136 | } |
141 | if (m_controllingPrim.LockedAxis.Y != 1f) | 137 | if (m_controllingPrim.LockedAxis.Y != 1f) |
142 | { | 138 | { |
143 | angularLow.Y = 0f; | 139 | angularLow.Y = 0f; |
144 | angularHigh.Y = 0f; | 140 | angularHigh.Y = 0f; |
145 | } | 141 | } |
146 | if (m_controllingPrim.LockedAxis.Z != 1f) | 142 | if (m_controllingPrim.LockedAxis.Z != 1f) |
147 | { | 143 | { |
148 | angularLow.Z = 0f; | 144 | angularLow.Z = 0f; |
149 | angularHigh.Z = 0f; | 145 | angularHigh.Z = 0f; |
150 | } | 146 | } |
151 | if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) | 147 | if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) |
152 | { | 148 | { |
153 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); | 149 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); |
154 | } | 150 | } |
155 | 151 | ||
156 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", | 152 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", |
157 | m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); | 153 | m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); |
158 | 154 | ||
159 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | 155 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. |
160 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | 156 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); |
161 | 157 | ||
162 | axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); | 158 | axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); |
159 | } | ||
163 | } | 160 | } |
164 | 161 | ||
165 | private void RemoveAxisLockConstraint() | 162 | private void RemoveAxisLockConstraint() |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs new file mode 100755 index 0000000..56aacc5 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorMoveToTarget : BSActor | ||
40 | { | ||
41 | private BSVMotor m_targetMotor; | ||
42 | |||
43 | public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_targetMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", | ||
69 | m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, | ||
70 | m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); | ||
71 | |||
72 | // If not active any more... | ||
73 | if (!m_controllingPrim.MoveToTargetActive) | ||
74 | { | ||
75 | Enabled = false; | ||
76 | } | ||
77 | |||
78 | if (isActive) | ||
79 | { | ||
80 | ActivateMoveToTarget(); | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | DeactivateMoveToTarget(); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
89 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
90 | // Called at taint-time. | ||
91 | // BSActor.RemoveBodyDependencies() | ||
92 | public override void RemoveBodyDependencies() | ||
93 | { | ||
94 | // Nothing to do for the moveToTarget since it is all software at pre-step action time. | ||
95 | } | ||
96 | |||
97 | // If a hover motor has not been created, create one and start the hovering. | ||
98 | private void ActivateMoveToTarget() | ||
99 | { | ||
100 | if (m_targetMotor == null) | ||
101 | { | ||
102 | // We're taking over after this. | ||
103 | m_controllingPrim.ZeroMotion(true); | ||
104 | |||
105 | m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate", | ||
106 | m_controllingPrim.MoveToTargetTau, // timeScale | ||
107 | BSMotor.Infinite, // decay time scale | ||
108 | BSMotor.InfiniteVector, // friction timescale | ||
109 | 1f // efficiency | ||
110 | ); | ||
111 | m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
112 | m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); | ||
113 | m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); | ||
114 | |||
115 | m_physicsScene.BeforeStep += Mover; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | private void DeactivateMoveToTarget() | ||
120 | { | ||
121 | if (m_targetMotor != null) | ||
122 | { | ||
123 | m_physicsScene.BeforeStep -= Mover; | ||
124 | m_targetMotor = null; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
129 | private void Mover(float timeStep) | ||
130 | { | ||
131 | // Don't do hovering while the object is selected. | ||
132 | if (!isActive) | ||
133 | return; | ||
134 | |||
135 | OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) | ||
136 | |||
137 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
138 | OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); | ||
139 | |||
140 | // If we are very close to our target, turn off the movement motor. | ||
141 | if (m_targetMotor.ErrorIsZero()) | ||
142 | { | ||
143 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", | ||
144 | m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); | ||
145 | m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; | ||
146 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
147 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | m_controllingPrim.ForcePosition = movePosition; | ||
152 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
153 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
154 | } | ||
155 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); | ||
156 | } | ||
157 | } | ||
158 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs new file mode 100755 index 0000000..3ad138d --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorSetForce : BSActor | ||
40 | { | ||
41 | BSFMotor m_forceMotor; | ||
42 | |||
43 | public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_forceMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); | ||
69 | |||
70 | // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) | ||
71 | if (m_controllingPrim.RawForce == OMV.Vector3.Zero) | ||
72 | { | ||
73 | m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); | ||
74 | Enabled = false; | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | // If the object is physically active, add the hoverer prestep action | ||
79 | if (isActive) | ||
80 | { | ||
81 | ActivateSetForce(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | DeactivateSetForce(); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
90 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
91 | // Called at taint-time. | ||
92 | // BSActor.RemoveBodyDependencies() | ||
93 | public override void RemoveBodyDependencies() | ||
94 | { | ||
95 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
96 | } | ||
97 | |||
98 | // If a hover motor has not been created, create one and start the hovering. | ||
99 | private void ActivateSetForce() | ||
100 | { | ||
101 | if (m_forceMotor == null) | ||
102 | { | ||
103 | // A fake motor that might be used someday | ||
104 | m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f, 1f); | ||
105 | |||
106 | m_physicsScene.BeforeStep += Mover; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | private void DeactivateSetForce() | ||
111 | { | ||
112 | if (m_forceMotor != null) | ||
113 | { | ||
114 | m_physicsScene.BeforeStep -= Mover; | ||
115 | m_forceMotor = null; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
120 | private void Mover(float timeStep) | ||
121 | { | ||
122 | // Don't do force while the object is selected. | ||
123 | if (!isActive) | ||
124 | return; | ||
125 | |||
126 | m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); | ||
127 | if (m_controllingPrim.PhysBody.HasPhysicalBody) | ||
128 | { | ||
129 | m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); | ||
130 | m_controllingPrim.ActivateIfPhysical(false); | ||
131 | } | ||
132 | |||
133 | // TODO: | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs new file mode 100755 index 0000000..7a791ec --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorSetTorque : BSActor | ||
40 | { | ||
41 | BSFMotor m_torqueMotor; | ||
42 | |||
43 | public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_torqueMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); | ||
69 | |||
70 | // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) | ||
71 | if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) | ||
72 | { | ||
73 | m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); | ||
74 | Enabled = false; | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | // If the object is physically active, add the hoverer prestep action | ||
79 | if (isActive) | ||
80 | { | ||
81 | ActivateSetTorque(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | DeactivateSetTorque(); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
90 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
91 | // Called at taint-time. | ||
92 | // BSActor.RemoveBodyDependencies() | ||
93 | public override void RemoveBodyDependencies() | ||
94 | { | ||
95 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
96 | } | ||
97 | |||
98 | // If a hover motor has not been created, create one and start the hovering. | ||
99 | private void ActivateSetTorque() | ||
100 | { | ||
101 | if (m_torqueMotor == null) | ||
102 | { | ||
103 | // A fake motor that might be used someday | ||
104 | m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f, 1f); | ||
105 | |||
106 | m_physicsScene.BeforeStep += Mover; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | private void DeactivateSetTorque() | ||
111 | { | ||
112 | if (m_torqueMotor != null) | ||
113 | { | ||
114 | m_physicsScene.BeforeStep -= Mover; | ||
115 | m_torqueMotor = null; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
120 | private void Mover(float timeStep) | ||
121 | { | ||
122 | // Don't do force while the object is selected. | ||
123 | if (!isActive) | ||
124 | return; | ||
125 | |||
126 | m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); | ||
127 | if (m_controllingPrim.PhysBody.HasPhysicalBody) | ||
128 | { | ||
129 | m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true); | ||
130 | m_controllingPrim.ActivateIfPhysical(false); | ||
131 | } | ||
132 | |||
133 | // TODO: | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index 5a19ba4..12a8817 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | |||
@@ -32,45 +32,72 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
32 | { | 32 | { |
33 | public class BSActorCollection | 33 | public class BSActorCollection |
34 | { | 34 | { |
35 | private BSScene PhysicsScene { get; set; } | 35 | private BSScene m_physicsScene { get; set; } |
36 | private Dictionary<string, BSActor> m_actors; | 36 | private Dictionary<string, BSActor> m_actors; |
37 | 37 | ||
38 | public BSActorCollection(BSScene physicsScene) | 38 | public BSActorCollection(BSScene physicsScene) |
39 | { | 39 | { |
40 | PhysicsScene = physicsScene; | 40 | m_physicsScene = physicsScene; |
41 | m_actors = new Dictionary<string, BSActor>(); | 41 | m_actors = new Dictionary<string, BSActor>(); |
42 | } | 42 | } |
43 | public void Add(string name, BSActor actor) | 43 | public void Add(string name, BSActor actor) |
44 | { | 44 | { |
45 | m_actors[name] = actor; | 45 | lock (m_actors) |
46 | { | ||
47 | if (!m_actors.ContainsKey(name)) | ||
48 | { | ||
49 | m_actors[name] = actor; | ||
50 | } | ||
51 | } | ||
46 | } | 52 | } |
47 | public bool RemoveAndRelease(string name) | 53 | public bool RemoveAndRelease(string name) |
48 | { | 54 | { |
49 | bool ret = false; | 55 | bool ret = false; |
50 | if (m_actors.ContainsKey(name)) | 56 | lock (m_actors) |
51 | { | 57 | { |
52 | BSActor beingRemoved = m_actors[name]; | 58 | if (m_actors.ContainsKey(name)) |
53 | beingRemoved.Dispose(); | 59 | { |
54 | m_actors.Remove(name); | 60 | BSActor beingRemoved = m_actors[name]; |
55 | ret = true; | 61 | m_actors.Remove(name); |
62 | beingRemoved.Dispose(); | ||
63 | ret = true; | ||
64 | } | ||
56 | } | 65 | } |
57 | return ret; | 66 | return ret; |
58 | } | 67 | } |
59 | public void Clear() | 68 | public void Clear() |
60 | { | 69 | { |
61 | Release(); | 70 | lock (m_actors) |
62 | m_actors.Clear(); | 71 | { |
72 | Release(); | ||
73 | m_actors.Clear(); | ||
74 | } | ||
75 | } | ||
76 | public void Dispose() | ||
77 | { | ||
78 | Clear(); | ||
63 | } | 79 | } |
64 | public bool HasActor(string name) | 80 | public bool HasActor(string name) |
65 | { | 81 | { |
66 | return m_actors.ContainsKey(name); | 82 | return m_actors.ContainsKey(name); |
67 | } | 83 | } |
84 | public bool TryGetActor(string actorName, out BSActor theActor) | ||
85 | { | ||
86 | return m_actors.TryGetValue(actorName, out theActor); | ||
87 | } | ||
68 | public void ForEachActor(Action<BSActor> act) | 88 | public void ForEachActor(Action<BSActor> act) |
69 | { | 89 | { |
70 | foreach (KeyValuePair<string, BSActor> kvp in m_actors) | 90 | lock (m_actors) |
71 | act(kvp.Value); | 91 | { |
92 | foreach (KeyValuePair<string, BSActor> kvp in m_actors) | ||
93 | act(kvp.Value); | ||
94 | } | ||
72 | } | 95 | } |
73 | 96 | ||
97 | public void Enable(bool enabl) | ||
98 | { | ||
99 | ForEachActor(a => a.SetEnabled(enabl)); | ||
100 | } | ||
74 | public void Release() | 101 | public void Release() |
75 | { | 102 | { |
76 | ForEachActor(a => a.Dispose()); | 103 | ForEachActor(a => a.Dispose()); |
@@ -98,7 +125,7 @@ public abstract class BSActor | |||
98 | { | 125 | { |
99 | protected BSScene m_physicsScene { get; private set; } | 126 | protected BSScene m_physicsScene { get; private set; } |
100 | protected BSPhysObject m_controllingPrim { get; private set; } | 127 | protected BSPhysObject m_controllingPrim { get; private set; } |
101 | protected bool Enabled { get; set; } | 128 | public virtual bool Enabled { get; set; } |
102 | public string ActorName { get; private set; } | 129 | public string ActorName { get; private set; } |
103 | 130 | ||
104 | public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) | 131 | public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) |
@@ -114,8 +141,10 @@ public abstract class BSActor | |||
114 | { | 141 | { |
115 | get { return Enabled; } | 142 | get { return Enabled; } |
116 | } | 143 | } |
117 | // Turn the actor on an off. | 144 | |
118 | public virtual void Enable(bool setEnabled) | 145 | // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. |
146 | // Anyone else should assign true/false to 'Enabled'. | ||
147 | public void SetEnabled(bool setEnabled) | ||
119 | { | 148 | { |
120 | Enabled = setEnabled; | 149 | Enabled = setEnabled; |
121 | } | 150 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 25be416..a0d58d3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject | |||
46 | private OMV.Vector3 _position; | 46 | private OMV.Vector3 _position; |
47 | private float _mass; | 47 | private float _mass; |
48 | private float _avatarVolume; | 48 | private float _avatarVolume; |
49 | private OMV.Vector3 _force; | ||
50 | private OMV.Vector3 _velocity; | ||
51 | private OMV.Vector3 _torque; | ||
52 | private float _collisionScore; | 49 | private float _collisionScore; |
53 | private OMV.Vector3 _acceleration; | 50 | private OMV.Vector3 _acceleration; |
54 | private OMV.Quaternion _orientation; | 51 | private OMV.Quaternion _orientation; |
@@ -61,17 +58,13 @@ public sealed class BSCharacter : BSPhysObject | |||
61 | private OMV.Vector3 _rotationalVelocity; | 58 | private OMV.Vector3 _rotationalVelocity; |
62 | private bool _kinematic; | 59 | private bool _kinematic; |
63 | private float _buoyancy; | 60 | private float _buoyancy; |
64 | private bool _isStationaryStanding; // true is standing on a stationary object | ||
65 | 61 | ||
66 | private BSVMotor _velocityMotor; | 62 | private BSActorAvatarMove m_moveActor; |
63 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; | ||
67 | 64 | ||
68 | private OMV.Vector3 _PIDTarget; | 65 | private OMV.Vector3 _PIDTarget; |
69 | private bool _usePID; | 66 | private bool _usePID; |
70 | private float _PIDTau; | 67 | private float _PIDTau; |
71 | private bool _useHoverPID; | ||
72 | private float _PIDHoverHeight; | ||
73 | private PIDHoverType _PIDHoverType; | ||
74 | private float _PIDHoverTao; | ||
75 | 68 | ||
76 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | 69 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) |
77 | : base(parent_scene, localID, avName, "BSCharacter") | 70 | : base(parent_scene, localID, avName, "BSCharacter") |
@@ -81,11 +74,10 @@ public sealed class BSCharacter : BSPhysObject | |||
81 | 74 | ||
82 | _flying = isFlying; | 75 | _flying = isFlying; |
83 | _orientation = OMV.Quaternion.Identity; | 76 | _orientation = OMV.Quaternion.Identity; |
84 | _velocity = OMV.Vector3.Zero; | 77 | RawVelocity = OMV.Vector3.Zero; |
85 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 78 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
86 | Friction = BSParam.AvatarStandingFriction; | 79 | Friction = BSParam.AvatarStandingFriction; |
87 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; | 80 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; |
88 | _isStationaryStanding = false; | ||
89 | 81 | ||
90 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | 82 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
91 | // replace with the default values. | 83 | // replace with the default values. |
@@ -99,7 +91,12 @@ public sealed class BSCharacter : BSPhysObject | |||
99 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 91 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
100 | ComputeAvatarVolumeAndMass(); | 92 | ComputeAvatarVolumeAndMass(); |
101 | 93 | ||
102 | SetupMovementMotor(); | 94 | // The avatar's movement is controlled by this motor that speeds up and slows down |
95 | // the avatar seeking to reach the motor's target speed. | ||
96 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
97 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
98 | m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName); | ||
99 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); | ||
103 | 100 | ||
104 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 101 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
105 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 102 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
@@ -139,10 +136,10 @@ public sealed class BSCharacter : BSPhysObject | |||
139 | ForcePosition = _position; | 136 | ForcePosition = _position; |
140 | 137 | ||
141 | // Set the velocity | 138 | // Set the velocity |
142 | _velocityMotor.Reset(); | 139 | if (m_moveActor != null) |
143 | _velocityMotor.SetTarget(_velocity); | 140 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); |
144 | _velocityMotor.SetCurrent(_velocity); | 141 | |
145 | ForceVelocity = _velocity; | 142 | ForceVelocity = RawVelocity; |
146 | 143 | ||
147 | // This will enable or disable the flying buoyancy of the avatar. | 144 | // This will enable or disable the flying buoyancy of the avatar. |
148 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | 145 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |
@@ -163,6 +160,9 @@ public sealed class BSCharacter : BSPhysObject | |||
163 | // Make so capsule does not fall over | 160 | // Make so capsule does not fall over |
164 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | 161 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
165 | 162 | ||
163 | // The avatar mover sets some parameters. | ||
164 | PhysicalActors.Refresh(); | ||
165 | |||
166 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | 166 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
167 | 167 | ||
168 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 168 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); |
@@ -176,162 +176,6 @@ public sealed class BSCharacter : BSPhysObject | |||
176 | PhysBody.ApplyCollisionMask(PhysicsScene); | 176 | PhysBody.ApplyCollisionMask(PhysicsScene); |
177 | } | 177 | } |
178 | 178 | ||
179 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
180 | // the avatar seeking to reach the motor's target speed. | ||
181 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
182 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
183 | private void SetupMovementMotor() | ||
184 | { | ||
185 | // Infinite decay and timescale values so motor only changes current to target values. | ||
186 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
187 | 0.2f, // time scale | ||
188 | BSMotor.Infinite, // decay time scale | ||
189 | BSMotor.InfiniteVector, // friction timescale | ||
190 | 1f // efficiency | ||
191 | ); | ||
192 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
193 | |||
194 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
195 | { | ||
196 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
197 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
198 | |||
199 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
200 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
201 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
202 | // component is not fooled with (thus allowing gravity to do its thing). | ||
203 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
204 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
205 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
206 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
207 | // errors can creap in and the avatar will slowly float off in some direction. | ||
208 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
209 | // from real pushing. | ||
210 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
211 | |||
212 | _velocityMotor.Step(timeStep); | ||
213 | _isStationaryStanding = false; | ||
214 | |||
215 | // If we're not supposed to be moving, make sure things are zero. | ||
216 | if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
217 | { | ||
218 | // The avatar shouldn't be moving | ||
219 | _velocityMotor.Zero(); | ||
220 | |||
221 | if (IsColliding) | ||
222 | { | ||
223 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
224 | if (!ColliderIsMoving) | ||
225 | { | ||
226 | DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID); | ||
227 | _isStationaryStanding = true; | ||
228 | ZeroMotion(true /* inTaintTime */); | ||
229 | } | ||
230 | |||
231 | // Standing has more friction on the ground | ||
232 | if (Friction != BSParam.AvatarStandingFriction) | ||
233 | { | ||
234 | Friction = BSParam.AvatarStandingFriction; | ||
235 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
236 | } | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | if (Flying) | ||
241 | { | ||
242 | // Flying and not collising and velocity nearly zero. | ||
243 | ZeroMotion(true /* inTaintTime */); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | // Supposed to be moving. | ||
252 | OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; | ||
253 | |||
254 | if (Friction != BSParam.AvatarFriction) | ||
255 | { | ||
256 | // Probably starting up walking. Set friction to moving friction. | ||
257 | Friction = BSParam.AvatarFriction; | ||
258 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
259 | } | ||
260 | |||
261 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
262 | // The check for _velocity.Z < 0 makes jumping work (temporary upward force). | ||
263 | if (!Flying && !IsColliding) | ||
264 | { | ||
265 | if (_velocity.Z < 0) | ||
266 | stepVelocity.Z = _velocity.Z; | ||
267 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
268 | } | ||
269 | |||
270 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
271 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; | ||
272 | |||
273 | // Should we check for move force being small and forcing velocity to zero? | ||
274 | |||
275 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
276 | moveForce += WalkUpStairs(); | ||
277 | |||
278 | DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
279 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); | ||
280 | } | ||
281 | }); | ||
282 | } | ||
283 | |||
284 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
285 | // avatar up so it can walk up and over the low objects. | ||
286 | private OMV.Vector3 WalkUpStairs() | ||
287 | { | ||
288 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
289 | |||
290 | // This test is done if moving forward, not flying and is colliding with something. | ||
291 | // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", | ||
292 | // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); | ||
293 | if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) | ||
294 | { | ||
295 | // The range near the character's feet where we will consider stairs | ||
296 | float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; | ||
297 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
298 | |||
299 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is | ||
300 | foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList) | ||
301 | { | ||
302 | // Don't care about collisions with the terrain | ||
303 | if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID) | ||
304 | { | ||
305 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
306 | // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
307 | // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
308 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
309 | { | ||
310 | // This contact is within the 'near the feet' range. | ||
311 | // The normal should be our contact point to the object so it is pointing away | ||
312 | // thus the difference between our facing orientation and the normal should be small. | ||
313 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation; | ||
314 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
315 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
316 | if (diff < BSParam.AvatarStepApproachFactor) | ||
317 | { | ||
318 | // Found the stairs contact point. Push up a little to raise the character. | ||
319 | float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor; | ||
320 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
321 | |||
322 | // Also move the avatar up for the new height | ||
323 | OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); | ||
324 | ForcePosition = RawPosition + displacement; | ||
325 | } | ||
326 | DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", | ||
327 | LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | return ret; | ||
334 | } | ||
335 | 179 | ||
336 | public override void RequestPhysicsterseUpdate() | 180 | public override void RequestPhysicsterseUpdate() |
337 | { | 181 | { |
@@ -403,7 +247,7 @@ public sealed class BSCharacter : BSPhysObject | |||
403 | // Called at taint time! | 247 | // Called at taint time! |
404 | public override void ZeroMotion(bool inTaintTime) | 248 | public override void ZeroMotion(bool inTaintTime) |
405 | { | 249 | { |
406 | _velocity = OMV.Vector3.Zero; | 250 | RawVelocity = OMV.Vector3.Zero; |
407 | _acceleration = OMV.Vector3.Zero; | 251 | _acceleration = OMV.Vector3.Zero; |
408 | _rotationalVelocity = OMV.Vector3.Zero; | 252 | _rotationalVelocity = OMV.Vector3.Zero; |
409 | 253 | ||
@@ -542,15 +386,15 @@ public sealed class BSCharacter : BSPhysObject | |||
542 | } | 386 | } |
543 | 387 | ||
544 | public override OMV.Vector3 Force { | 388 | public override OMV.Vector3 Force { |
545 | get { return _force; } | 389 | get { return RawForce; } |
546 | set { | 390 | set { |
547 | _force = value; | 391 | RawForce = value; |
548 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 392 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
549 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 393 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
550 | { | 394 | { |
551 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 395 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); |
552 | if (PhysBody.HasPhysicalBody) | 396 | if (PhysBody.HasPhysicalBody) |
553 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | 397 | PhysicsScene.PE.SetObjectForce(PhysBody, RawForce); |
554 | }); | 398 | }); |
555 | } | 399 | } |
556 | } | 400 | } |
@@ -573,7 +417,7 @@ public sealed class BSCharacter : BSPhysObject | |||
573 | { | 417 | { |
574 | get | 418 | get |
575 | { | 419 | { |
576 | return m_targetVelocity; | 420 | return base.m_targetVelocity; |
577 | } | 421 | } |
578 | set | 422 | set |
579 | { | 423 | { |
@@ -583,51 +427,39 @@ public sealed class BSCharacter : BSPhysObject | |||
583 | if (_setAlwaysRun) | 427 | if (_setAlwaysRun) |
584 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); | 428 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); |
585 | 429 | ||
586 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | 430 | if (m_moveActor != null) |
587 | { | 431 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); |
588 | _velocityMotor.Reset(); | ||
589 | _velocityMotor.SetTarget(targetVel); | ||
590 | _velocityMotor.SetCurrent(_velocity); | ||
591 | _velocityMotor.Enabled = true; | ||
592 | }); | ||
593 | } | 432 | } |
594 | } | 433 | } |
595 | public override OMV.Vector3 RawVelocity | ||
596 | { | ||
597 | get { return _velocity; } | ||
598 | set { _velocity = value; } | ||
599 | } | ||
600 | // Directly setting velocity means this is what the user really wants now. | 434 | // Directly setting velocity means this is what the user really wants now. |
601 | public override OMV.Vector3 Velocity { | 435 | public override OMV.Vector3 Velocity { |
602 | get { return _velocity; } | 436 | get { return RawVelocity; } |
603 | set { | 437 | set { |
604 | _velocity = value; | 438 | RawVelocity = value; |
605 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 439 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); |
606 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 440 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() |
607 | { | 441 | { |
608 | _velocityMotor.Reset(); | 442 | if (m_moveActor != null) |
609 | _velocityMotor.SetCurrent(_velocity); | 443 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); |
610 | _velocityMotor.SetTarget(_velocity); | ||
611 | _velocityMotor.Enabled = false; | ||
612 | 444 | ||
613 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 445 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity); |
614 | ForceVelocity = _velocity; | 446 | ForceVelocity = RawVelocity; |
615 | }); | 447 | }); |
616 | } | 448 | } |
617 | } | 449 | } |
618 | public override OMV.Vector3 ForceVelocity { | 450 | public override OMV.Vector3 ForceVelocity { |
619 | get { return _velocity; } | 451 | get { return RawVelocity; } |
620 | set { | 452 | set { |
621 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | 453 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
622 | 454 | ||
623 | _velocity = value; | 455 | RawVelocity = value; |
624 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 456 | PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
625 | PhysicsScene.PE.Activate(PhysBody, true); | 457 | PhysicsScene.PE.Activate(PhysBody, true); |
626 | } | 458 | } |
627 | } | 459 | } |
628 | public override OMV.Vector3 Torque { | 460 | public override OMV.Vector3 Torque { |
629 | get { return _torque; } | 461 | get { return RawTorque; } |
630 | set { _torque = value; | 462 | set { RawTorque = value; |
631 | } | 463 | } |
632 | } | 464 | } |
633 | public override float CollisionScore { | 465 | public override float CollisionScore { |
@@ -783,27 +615,6 @@ public sealed class BSCharacter : BSPhysObject | |||
783 | set { _PIDTau = value; } | 615 | set { _PIDTau = value; } |
784 | } | 616 | } |
785 | 617 | ||
786 | // Used for llSetHoverHeight and maybe vehicle height | ||
787 | // Hover Height will override MoveTo target's Z | ||
788 | public override bool PIDHoverActive { | ||
789 | set { _useHoverPID = value; } | ||
790 | } | ||
791 | public override float PIDHoverHeight { | ||
792 | set { _PIDHoverHeight = value; } | ||
793 | } | ||
794 | public override PIDHoverType PIDHoverType { | ||
795 | set { _PIDHoverType = value; } | ||
796 | } | ||
797 | public override float PIDHoverTau { | ||
798 | set { _PIDHoverTao = value; } | ||
799 | } | ||
800 | |||
801 | // For RotLookAt | ||
802 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
803 | public override bool APIDActive { set { return; } } | ||
804 | public override float APIDStrength { set { return; } } | ||
805 | public override float APIDDamping { set { return; } } | ||
806 | |||
807 | public override void AddForce(OMV.Vector3 force, bool pushforce) | 618 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
808 | { | 619 | { |
809 | // Since this force is being applied in only one step, make this a force per second. | 620 | // Since this force is being applied in only one step, make this a force per second. |
@@ -833,7 +644,7 @@ public sealed class BSCharacter : BSPhysObject | |||
833 | } | 644 | } |
834 | } | 645 | } |
835 | 646 | ||
836 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 647 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
837 | } | 648 | } |
838 | public override void SetMomentum(OMV.Vector3 momentum) { | 649 | public override void SetMomentum(OMV.Vector3 momentum) { |
839 | } | 650 | } |
@@ -887,7 +698,7 @@ public sealed class BSCharacter : BSPhysObject | |||
887 | public override void UpdateProperties(EntityProperties entprop) | 698 | public override void UpdateProperties(EntityProperties entprop) |
888 | { | 699 | { |
889 | // Don't change position if standing on a stationary object. | 700 | // Don't change position if standing on a stationary object. |
890 | if (!_isStationaryStanding) | 701 | if (!IsStationary) |
891 | _position = entprop.Position; | 702 | _position = entprop.Position; |
892 | 703 | ||
893 | _orientation = entprop.Rotation; | 704 | _orientation = entprop.Rotation; |
@@ -896,8 +707,8 @@ public sealed class BSCharacter : BSPhysObject | |||
896 | // and will send agent updates to the clients if velocity changes by more than | 707 | // and will send agent updates to the clients if velocity changes by more than |
897 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | 708 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many |
898 | // extra updates. | 709 | // extra updates. |
899 | if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) | 710 | if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) |
900 | _velocity = entprop.Velocity; | 711 | RawVelocity = entprop.Velocity; |
901 | 712 | ||
902 | _acceleration = entprop.Acceleration; | 713 | _acceleration = entprop.Acceleration; |
903 | _rotationalVelocity = entprop.RotationalVelocity; | 714 | _rotationalVelocity = entprop.RotationalVelocity; |
@@ -920,7 +731,7 @@ public sealed class BSCharacter : BSPhysObject | |||
920 | // base.RequestPhysicsterseUpdate(); | 731 | // base.RequestPhysicsterseUpdate(); |
921 | 732 | ||
922 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 733 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
923 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 734 | LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); |
924 | } | 735 | } |
925 | } | 736 | } |
926 | } | 737 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 0fd1f73..612c68b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -1358,6 +1358,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1358 | // If vertical attaction timescale is reasonable | 1358 | // If vertical attaction timescale is reasonable |
1359 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1359 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1360 | { | 1360 | { |
1361 | //Another formula to try got from : | ||
1362 | //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html | ||
1363 | |||
1364 | Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation; | ||
1365 | |||
1366 | // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 | ||
1367 | // since only computing half the distance between the angles. | ||
1368 | float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; | ||
1369 | |||
1370 | // Make a prediction of where the up axis will be when this is applied rather then where it is now as | ||
1371 | // this makes for a smoother adjustment and less fighting between the various forces. | ||
1372 | Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1373 | |||
1374 | // This is only half the distance to the target so it will take 2 seconds to complete the turn. | ||
1375 | Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); | ||
1376 | |||
1377 | // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared | ||
1378 | Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; | ||
1379 | |||
1380 | VehicleRotationalVelocity += vertContributionV; | ||
1381 | |||
1382 | VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", | ||
1383 | ControllingPrim.LocalID, | ||
1384 | VehicleUpAxis, | ||
1385 | predictedUp, | ||
1386 | torqueVector, | ||
1387 | vertContributionV); | ||
1388 | //===================================================================== | ||
1389 | /* | ||
1361 | // Possible solution derived from a discussion at: | 1390 | // Possible solution derived from a discussion at: |
1362 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | 1391 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no |
1363 | 1392 | ||
@@ -1392,6 +1421,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1392 | differenceAngle, | 1421 | differenceAngle, |
1393 | correctionRotation, | 1422 | correctionRotation, |
1394 | vertContributionV); | 1423 | vertContributionV); |
1424 | */ | ||
1395 | 1425 | ||
1396 | // =================================================================== | 1426 | // =================================================================== |
1397 | /* | 1427 | /* |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 385ed9e..06df85e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -86,6 +86,7 @@ public static class BSParam | |||
86 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 86 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes |
87 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | 87 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects |
88 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } | 88 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } |
89 | public static bool ShouldUseBulletHACD { get; set; } | ||
89 | 90 | ||
90 | public static float TerrainImplementation { get; private set; } | 91 | public static float TerrainImplementation { get; private set; } |
91 | public static int TerrainMeshMagnification { get; private set; } | 92 | public static int TerrainMeshMagnification { get; private set; } |
@@ -149,6 +150,15 @@ public static class BSParam | |||
149 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | 150 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } |
150 | public static int CSHullMaxVertices { get; private set; } | 151 | public static int CSHullMaxVertices { get; private set; } |
151 | public static float CSHullMaxSkinWidth { get; private set; } | 152 | public static float CSHullMaxSkinWidth { get; private set; } |
153 | public static float BHullMaxVerticesPerHull { get; private set; } // 100 | ||
154 | public static float BHullMinClusters { get; private set; } // 2 | ||
155 | public static float BHullCompacityWeight { get; private set; } // 0.1 | ||
156 | public static float BHullVolumeWeight { get; private set; } // 0.0 | ||
157 | public static float BHullConcavity { get; private set; } // 100 | ||
158 | public static bool BHullAddExtraDistPoints { get; private set; } // false | ||
159 | public static bool BHullAddNeighboursDistPoints { get; private set; } // false | ||
160 | public static bool BHullAddFacesPoints { get; private set; } // false | ||
161 | public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false | ||
152 | 162 | ||
153 | // Linkset implementation parameters | 163 | // Linkset implementation parameters |
154 | public static float LinksetImplementation { get; private set; } | 164 | public static float LinksetImplementation { get; private set; } |
@@ -325,6 +335,10 @@ public static class BSParam | |||
325 | true, | 335 | true, |
326 | (s) => { return ShouldRemoveZeroWidthTriangles; }, | 336 | (s) => { return ShouldRemoveZeroWidthTriangles; }, |
327 | (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), | 337 | (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), |
338 | new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", | ||
339 | false, | ||
340 | (s) => { return ShouldUseBulletHACD; }, | ||
341 | (s,v) => { ShouldUseBulletHACD = v; } ), | ||
328 | 342 | ||
329 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | 343 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", |
330 | 5, | 344 | 5, |
@@ -663,10 +677,47 @@ public static class BSParam | |||
663 | (s) => { return CSHullMaxVertices; }, | 677 | (s) => { return CSHullMaxVertices; }, |
664 | (s,v) => { CSHullMaxVertices = v; } ), | 678 | (s,v) => { CSHullMaxVertices = v; } ), |
665 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | 679 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", |
666 | 0, | 680 | 0f, |
667 | (s) => { return CSHullMaxSkinWidth; }, | 681 | (s) => { return CSHullMaxSkinWidth; }, |
668 | (s,v) => { CSHullMaxSkinWidth = v; } ), | 682 | (s,v) => { CSHullMaxSkinWidth = v; } ), |
669 | 683 | ||
684 | new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", | ||
685 | 100f, | ||
686 | (s) => { return BHullMaxVerticesPerHull; }, | ||
687 | (s,v) => { BHullMaxVerticesPerHull = v; } ), | ||
688 | new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", | ||
689 | 2f, | ||
690 | (s) => { return BHullMinClusters; }, | ||
691 | (s,v) => { BHullMinClusters = v; } ), | ||
692 | new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", | ||
693 | 2f, | ||
694 | (s) => { return BHullCompacityWeight; }, | ||
695 | (s,v) => { BHullCompacityWeight = v; } ), | ||
696 | new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", | ||
697 | 0.1f, | ||
698 | (s) => { return BHullVolumeWeight; }, | ||
699 | (s,v) => { BHullVolumeWeight = v; } ), | ||
700 | new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", | ||
701 | 100f, | ||
702 | (s) => { return BHullConcavity; }, | ||
703 | (s,v) => { BHullConcavity = v; } ), | ||
704 | new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", | ||
705 | false, | ||
706 | (s) => { return BHullAddExtraDistPoints; }, | ||
707 | (s,v) => { BHullAddExtraDistPoints = v; } ), | ||
708 | new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", | ||
709 | false, | ||
710 | (s) => { return BHullAddNeighboursDistPoints; }, | ||
711 | (s,v) => { BHullAddNeighboursDistPoints = v; } ), | ||
712 | new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", | ||
713 | false, | ||
714 | (s) => { return BHullAddFacesPoints; }, | ||
715 | (s,v) => { BHullAddFacesPoints = v; } ), | ||
716 | new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", | ||
717 | false, | ||
718 | (s) => { return BHullShouldAdjustCollisionMargin; }, | ||
719 | (s,v) => { BHullShouldAdjustCollisionMargin = v; } ), | ||
720 | |||
670 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | 721 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", |
671 | (float)BSLinkset.LinksetImplementation.Compound, | 722 | (float)BSLinkset.LinksetImplementation.Compound, |
672 | (s) => { return LinksetImplementation; }, | 723 | (s) => { return LinksetImplementation; }, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 98ea833..98eb4ca 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -43,7 +43,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
43 | * VariableName: used by the simulator and performs taint operations, etc | 43 | * VariableName: used by the simulator and performs taint operations, etc |
44 | * RawVariableName: direct reference to the BulletSim storage for the variable value | 44 | * RawVariableName: direct reference to the BulletSim storage for the variable value |
45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | 45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. |
46 | * The last two (and certainly the last one) should be referenced only in taint-time. | 46 | * The last one should only be referenced in taint-time. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | /* | 49 | /* |
@@ -84,6 +84,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
84 | // Initialize variables kept in base. | 84 | // Initialize variables kept in base. |
85 | GravModifier = 1.0f; | 85 | GravModifier = 1.0f; |
86 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | 86 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); |
87 | HoverActive = false; | ||
87 | 88 | ||
88 | // We don't have any physical representation yet. | 89 | // We don't have any physical representation yet. |
89 | PhysBody = new BulletBody(localID); | 90 | PhysBody = new BulletBody(localID); |
@@ -110,11 +111,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
110 | // Tell the object to clean up. | 111 | // Tell the object to clean up. |
111 | public virtual void Destroy() | 112 | public virtual void Destroy() |
112 | { | 113 | { |
113 | UnRegisterAllPreStepActions(); | 114 | PhysicalActors.Enable(false); |
114 | UnRegisterAllPostStepActions(); | ||
115 | PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() | 115 | PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() |
116 | { | 116 | { |
117 | PhysicalActors.Release(); | 117 | PhysicalActors.Dispose(); |
118 | }); | 118 | }); |
119 | } | 119 | } |
120 | 120 | ||
@@ -203,15 +203,48 @@ public abstract class BSPhysObject : PhysicsActor | |||
203 | public abstract OMV.Quaternion RawOrientation { get; set; } | 203 | public abstract OMV.Quaternion RawOrientation { get; set; } |
204 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 204 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
205 | 205 | ||
206 | public abstract OMV.Vector3 RawVelocity { get; set; } | 206 | public OMV.Vector3 RawVelocity { get; set; } |
207 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 207 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
208 | 208 | ||
209 | public OMV.Vector3 RawForce { get; set; } | ||
210 | public OMV.Vector3 RawTorque { get; set; } | ||
211 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) | ||
212 | { | ||
213 | AddAngularForce(force, pushforce, false); | ||
214 | } | ||
215 | public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); | ||
216 | |||
209 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 217 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
210 | 218 | ||
211 | public abstract float ForceBuoyancy { get; set; } | 219 | public abstract float ForceBuoyancy { get; set; } |
212 | 220 | ||
213 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | 221 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } |
214 | 222 | ||
223 | public override bool PIDActive { set { MoveToTargetActive = value; } } | ||
224 | public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } | ||
225 | public override float PIDTau { set { MoveToTargetTau = value; } } | ||
226 | |||
227 | public bool MoveToTargetActive { get; set; } | ||
228 | public OMV.Vector3 MoveToTargetTarget { get; set; } | ||
229 | public float MoveToTargetTau { get; set; } | ||
230 | |||
231 | // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z | ||
232 | public override bool PIDHoverActive { set { HoverActive = value; } } | ||
233 | public override float PIDHoverHeight { set { HoverHeight = value; } } | ||
234 | public override PIDHoverType PIDHoverType { set { HoverType = value; } } | ||
235 | public override float PIDHoverTau { set { HoverTau = value; } } | ||
236 | |||
237 | public bool HoverActive { get; set; } | ||
238 | public float HoverHeight { get; set; } | ||
239 | public PIDHoverType HoverType { get; set; } | ||
240 | public float HoverTau { get; set; } | ||
241 | |||
242 | // For RotLookAt | ||
243 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
244 | public override bool APIDActive { set { return; } } | ||
245 | public override float APIDStrength { set { return; } } | ||
246 | public override float APIDDamping { set { return; } } | ||
247 | |||
215 | // The current velocity forward | 248 | // The current velocity forward |
216 | public virtual float ForwardSpeed | 249 | public virtual float ForwardSpeed |
217 | { | 250 | { |
@@ -237,7 +270,51 @@ public abstract class BSPhysObject : PhysicsActor | |||
237 | 270 | ||
238 | public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. | 271 | public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. |
239 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free | 272 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free |
240 | public readonly String LockedAxisActorName = "BSPrim.LockedAxis"; | 273 | |
274 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
275 | // they need waking up when parameters are changed. | ||
276 | // Called in taint-time!! | ||
277 | public void ActivateIfPhysical(bool forceIt) | ||
278 | { | ||
279 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
280 | PhysicsScene.PE.Activate(PhysBody, forceIt); | ||
281 | } | ||
282 | |||
283 | // 'actors' act on the physical object to change or constrain its motion. These can range from | ||
284 | // hovering to complex vehicle motion. | ||
285 | // May be called at non-taint time as this just adds the actor to the action list and the real | ||
286 | // work is done during the simulation step. | ||
287 | // Note that, if the actor is already in the list and we are disabling same, the actor is just left | ||
288 | // in the list disabled. | ||
289 | public delegate BSActor CreateActor(); | ||
290 | public void EnableActor(bool enableActor, string actorName, CreateActor creator) | ||
291 | { | ||
292 | lock (PhysicalActors) | ||
293 | { | ||
294 | BSActor theActor; | ||
295 | if (PhysicalActors.TryGetActor(actorName, out theActor)) | ||
296 | { | ||
297 | // The actor already exists so just turn it on or off | ||
298 | DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); | ||
299 | theActor.Enabled = enableActor; | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | // The actor does not exist. If it should, create it. | ||
304 | if (enableActor) | ||
305 | { | ||
306 | DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); | ||
307 | theActor = creator(); | ||
308 | PhysicalActors.Add(actorName, theActor); | ||
309 | theActor.Enabled = true; | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | } | ||
241 | 318 | ||
242 | #region Collisions | 319 | #region Collisions |
243 | 320 | ||
@@ -255,7 +332,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
255 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 332 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
256 | // On a collision, check the collider and remember if the last collider was moving | 333 | // On a collision, check the collider and remember if the last collider was moving |
257 | // Used to modify the standing of avatars (avatars on stationary things stand still) | 334 | // Used to modify the standing of avatars (avatars on stationary things stand still) |
258 | protected bool ColliderIsMoving; | 335 | public bool ColliderIsMoving; |
336 | // Used by BSCharacter to manage standing (and not slipping) | ||
337 | public bool IsStationary; | ||
259 | 338 | ||
260 | // Count of collisions for this object | 339 | // Count of collisions for this object |
261 | protected long CollisionAccumulation { get; set; } | 340 | protected long CollisionAccumulation { get; set; } |
@@ -293,7 +372,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
293 | protected CollisionEventUpdate CollisionCollection; | 372 | protected CollisionEventUpdate CollisionCollection; |
294 | // Remember collisions from last tick for fancy collision based actions | 373 | // Remember collisions from last tick for fancy collision based actions |
295 | // (like a BSCharacter walking up stairs). | 374 | // (like a BSCharacter walking up stairs). |
296 | protected CollisionEventUpdate CollisionsLastTick; | 375 | public CollisionEventUpdate CollisionsLastTick; |
297 | 376 | ||
298 | // The simulation step is telling this object about a collision. | 377 | // The simulation step is telling this object about a collision. |
299 | // Return 'true' if a collision was processed and should be sent up. | 378 | // Return 'true' if a collision was processed and should be sent up. |
@@ -424,104 +503,6 @@ public abstract class BSPhysObject : PhysicsActor | |||
424 | 503 | ||
425 | public BSActorCollection PhysicalActors; | 504 | public BSActorCollection PhysicalActors; |
426 | 505 | ||
427 | // There are some actions that must be performed for a physical object before each simulation step. | ||
428 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
429 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
430 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
431 | private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
432 | private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>(); | ||
433 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
434 | { | ||
435 | string identifier = op + "-" + id.ToString(); | ||
436 | |||
437 | lock (RegisteredPrestepActions) | ||
438 | { | ||
439 | // Clean out any existing action | ||
440 | UnRegisterPreStepAction(op, id); | ||
441 | RegisteredPrestepActions[identifier] = actn; | ||
442 | PhysicsScene.BeforeStep += actn; | ||
443 | } | ||
444 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
445 | } | ||
446 | |||
447 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
448 | // Returns 'true' if an action was actually removed | ||
449 | protected bool UnRegisterPreStepAction(string op, uint id) | ||
450 | { | ||
451 | string identifier = op + "-" + id.ToString(); | ||
452 | bool removed = false; | ||
453 | lock (RegisteredPrestepActions) | ||
454 | { | ||
455 | if (RegisteredPrestepActions.ContainsKey(identifier)) | ||
456 | { | ||
457 | PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier]; | ||
458 | RegisteredPrestepActions.Remove(identifier); | ||
459 | removed = true; | ||
460 | } | ||
461 | } | ||
462 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
463 | return removed; | ||
464 | } | ||
465 | |||
466 | protected void UnRegisterAllPreStepActions() | ||
467 | { | ||
468 | lock (RegisteredPrestepActions) | ||
469 | { | ||
470 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions) | ||
471 | { | ||
472 | PhysicsScene.BeforeStep -= kvp.Value; | ||
473 | } | ||
474 | RegisteredPrestepActions.Clear(); | ||
475 | } | ||
476 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
477 | } | ||
478 | |||
479 | protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn) | ||
480 | { | ||
481 | string identifier = op + "-" + id.ToString(); | ||
482 | |||
483 | lock (RegisteredPoststepActions) | ||
484 | { | ||
485 | // Clean out any existing action | ||
486 | UnRegisterPostStepAction(op, id); | ||
487 | RegisteredPoststepActions[identifier] = actn; | ||
488 | PhysicsScene.AfterStep += actn; | ||
489 | } | ||
490 | DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); | ||
491 | } | ||
492 | |||
493 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
494 | // Returns 'true' if an action was actually removed. | ||
495 | protected bool UnRegisterPostStepAction(string op, uint id) | ||
496 | { | ||
497 | string identifier = op + "-" + id.ToString(); | ||
498 | bool removed = false; | ||
499 | lock (RegisteredPoststepActions) | ||
500 | { | ||
501 | if (RegisteredPoststepActions.ContainsKey(identifier)) | ||
502 | { | ||
503 | PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier]; | ||
504 | RegisteredPoststepActions.Remove(identifier); | ||
505 | removed = true; | ||
506 | } | ||
507 | } | ||
508 | DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
509 | return removed; | ||
510 | } | ||
511 | |||
512 | protected void UnRegisterAllPostStepActions() | ||
513 | { | ||
514 | lock (RegisteredPoststepActions) | ||
515 | { | ||
516 | foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions) | ||
517 | { | ||
518 | PhysicsScene.AfterStep -= kvp.Value; | ||
519 | } | ||
520 | RegisteredPoststepActions.Clear(); | ||
521 | } | ||
522 | DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); | ||
523 | } | ||
524 | |||
525 | // When an update to the physical properties happens, this event is fired to let | 506 | // When an update to the physical properties happens, this event is fired to let |
526 | // different actors to modify the update before it is passed around | 507 | // different actors to modify the update before it is passed around |
527 | public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); | 508 | public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); |
@@ -533,46 +514,6 @@ public abstract class BSPhysObject : PhysicsActor | |||
533 | actions(ref entprop); | 514 | actions(ref entprop); |
534 | } | 515 | } |
535 | 516 | ||
536 | private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>(); | ||
537 | public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn) | ||
538 | { | ||
539 | lock (RegisteredPreUpdatePropertyActions) | ||
540 | { | ||
541 | // Clean out any existing action | ||
542 | UnRegisterPreUpdatePropertyAction(identifier); | ||
543 | RegisteredPreUpdatePropertyActions[identifier] = actn; | ||
544 | OnPreUpdateProperty += actn; | ||
545 | } | ||
546 | DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier); | ||
547 | } | ||
548 | public bool UnRegisterPreUpdatePropertyAction(string identifier) | ||
549 | { | ||
550 | bool removed = false; | ||
551 | lock (RegisteredPreUpdatePropertyActions) | ||
552 | { | ||
553 | if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier)) | ||
554 | { | ||
555 | OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier]; | ||
556 | RegisteredPreUpdatePropertyActions.Remove(identifier); | ||
557 | removed = true; | ||
558 | } | ||
559 | } | ||
560 | DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed); | ||
561 | return removed; | ||
562 | } | ||
563 | public void UnRegisterAllPreUpdatePropertyActions() | ||
564 | { | ||
565 | lock (RegisteredPreUpdatePropertyActions) | ||
566 | { | ||
567 | foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions) | ||
568 | { | ||
569 | OnPreUpdateProperty -= kvp.Value; | ||
570 | } | ||
571 | RegisteredPreUpdatePropertyActions.Clear(); | ||
572 | } | ||
573 | DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID); | ||
574 | } | ||
575 | |||
576 | #endregion // Per Simulation Step actions | 517 | #endregion // Per Simulation Step actions |
577 | 518 | ||
578 | // High performance detailed logging routine used by the physical objects. | 519 | // High performance detailed logging routine used by the physical objects. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e56276a..3423d2e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject | |||
55 | private OMV.Vector3 _position; | 55 | private OMV.Vector3 _position; |
56 | 56 | ||
57 | private float _mass; // the mass of this object | 57 | private float _mass; // the mass of this object |
58 | private OMV.Vector3 _force; | ||
59 | private OMV.Vector3 _velocity; | ||
60 | private OMV.Vector3 _torque; | ||
61 | private OMV.Vector3 _acceleration; | 58 | private OMV.Vector3 _acceleration; |
62 | private OMV.Quaternion _orientation; | 59 | private OMV.Quaternion _orientation; |
63 | private int _physicsActorType; | 60 | private int _physicsActorType; |
@@ -73,16 +70,13 @@ public class BSPrim : BSPhysObject | |||
73 | private int CrossingFailures { get; set; } | 70 | private int CrossingFailures { get; set; } |
74 | 71 | ||
75 | public BSDynamics VehicleActor; | 72 | public BSDynamics VehicleActor; |
76 | public string VehicleActorName = "BasicVehicle"; | 73 | public const string VehicleActorName = "BasicVehicle"; |
77 | 74 | ||
78 | private BSVMotor _targetMotor; | 75 | public const string HoverActorName = "HoverActor"; |
79 | private OMV.Vector3 _PIDTarget; | 76 | public const String LockedAxisActorName = "BSPrim.LockedAxis"; |
80 | private float _PIDTau; | 77 | public const string MoveToTargetActorName = "MoveToTargetActor"; |
81 | 78 | public const string SetForceActorName = "SetForceActor"; | |
82 | private BSFMotor _hoverMotor; | 79 | public const string SetTorqueActorName = "SetTorqueActor"; |
83 | private float _PIDHoverHeight; | ||
84 | private PIDHoverType _PIDHoverType; | ||
85 | private float _PIDHoverTau; | ||
86 | 80 | ||
87 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 81 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
88 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 82 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -95,12 +89,13 @@ public class BSPrim : BSPhysObject | |||
95 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). | 89 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
96 | _orientation = rotation; | 90 | _orientation = rotation; |
97 | _buoyancy = 0f; | 91 | _buoyancy = 0f; |
98 | _velocity = OMV.Vector3.Zero; | 92 | RawVelocity = OMV.Vector3.Zero; |
99 | _rotationalVelocity = OMV.Vector3.Zero; | 93 | _rotationalVelocity = OMV.Vector3.Zero; |
100 | BaseShape = pbs; | 94 | BaseShape = pbs; |
101 | _isPhysical = pisPhysical; | 95 | _isPhysical = pisPhysical; |
102 | _isVolumeDetect = false; | 96 | _isVolumeDetect = false; |
103 | 97 | ||
98 | // We keep a handle to the vehicle actor so we can set vehicle parameters later. | ||
104 | VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); | 99 | VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); |
105 | PhysicalActors.Add(VehicleActorName, VehicleActor); | 100 | PhysicalActors.Add(VehicleActorName, VehicleActor); |
106 | 101 | ||
@@ -233,7 +228,7 @@ public class BSPrim : BSPhysObject | |||
233 | // Called at taint time! | 228 | // Called at taint time! |
234 | public override void ZeroMotion(bool inTaintTime) | 229 | public override void ZeroMotion(bool inTaintTime) |
235 | { | 230 | { |
236 | _velocity = OMV.Vector3.Zero; | 231 | RawVelocity = OMV.Vector3.Zero; |
237 | _acceleration = OMV.Vector3.Zero; | 232 | _acceleration = OMV.Vector3.Zero; |
238 | _rotationalVelocity = OMV.Vector3.Zero; | 233 | _rotationalVelocity = OMV.Vector3.Zero; |
239 | 234 | ||
@@ -270,19 +265,17 @@ public class BSPrim : BSPhysObject | |||
270 | if (axis.Z != 1) locking.Z = 0f; | 265 | if (axis.Z != 1) locking.Z = 0f; |
271 | LockedAxis = locking; | 266 | LockedAxis = locking; |
272 | 267 | ||
273 | if (LockedAxis != LockedAxisFree) | 268 | EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate() |
274 | { | 269 | { |
275 | PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() | 270 | return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName); |
276 | { | 271 | }); |
277 | // If there is not already an axis locker, make one | 272 | |
278 | if (!PhysicalActors.HasActor(LockedAxisActorName)) | 273 | // Update parameters so the new actor's Refresh() action is called at the right time. |
279 | { | 274 | PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() |
280 | DetailLog("{0},BSPrim.LockAngularMotion,taint,registeringLockAxisActor", LocalID); | 275 | { |
281 | PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName)); | 276 | UpdatePhysicalParameters(); |
282 | } | 277 | }); |
283 | UpdatePhysicalParameters(); | 278 | |
284 | }); | ||
285 | } | ||
286 | return; | 279 | return; |
287 | } | 280 | } |
288 | 281 | ||
@@ -407,9 +400,9 @@ public class BSPrim : BSPhysObject | |||
407 | ZeroMotion(inTaintTime); | 400 | ZeroMotion(inTaintTime); |
408 | ret = true; | 401 | ret = true; |
409 | } | 402 | } |
410 | if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) | 403 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity) |
411 | { | 404 | { |
412 | _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); | 405 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); |
413 | ret = true; | 406 | ret = true; |
414 | } | 407 | } |
415 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | 408 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) |
@@ -506,48 +499,25 @@ public class BSPrim : BSPhysObject | |||
506 | } | 499 | } |
507 | 500 | ||
508 | public override OMV.Vector3 Force { | 501 | public override OMV.Vector3 Force { |
509 | get { return _force; } | 502 | get { return RawForce; } |
510 | set { | 503 | set { |
511 | _force = value; | 504 | RawForce = value; |
512 | if (_force != OMV.Vector3.Zero) | 505 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() |
513 | { | 506 | { |
514 | // If the force is non-zero, it must be reapplied each tick because | 507 | return new BSActorSetForce(PhysicsScene, this, SetForceActorName); |
515 | // Bullet clears the forces applied last frame. | 508 | }); |
516 | RegisterPreStepAction("BSPrim.setForce", LocalID, | ||
517 | delegate(float timeStep) | ||
518 | { | ||
519 | if (!IsPhysicallyActive || _force == OMV.Vector3.Zero) | ||
520 | { | ||
521 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
522 | return; | ||
523 | } | ||
524 | |||
525 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
526 | if (PhysBody.HasPhysicalBody) | ||
527 | { | ||
528 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | ||
529 | ActivateIfPhysical(false); | ||
530 | } | ||
531 | } | ||
532 | ); | ||
533 | } | ||
534 | else | ||
535 | { | ||
536 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
537 | } | ||
538 | } | 509 | } |
539 | } | 510 | } |
540 | 511 | ||
541 | public override int VehicleType { | 512 | public override int VehicleType { |
542 | get { | 513 | get { |
543 | return (int)VehicleActor.Type; // if we are a vehicle, return that type | 514 | return (int)VehicleActor.Type; |
544 | } | 515 | } |
545 | set { | 516 | set { |
546 | Vehicle type = (Vehicle)value; | 517 | Vehicle type = (Vehicle)value; |
547 | 518 | ||
548 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 519 | PhysicsScene.TaintedObject("setVehicleType", delegate() |
549 | { | 520 | { |
550 | // Done at taint time so we're sure the physics engine is not using the variables | ||
551 | // Vehicle code changes the parameters for this vehicle type. | 521 | // Vehicle code changes the parameters for this vehicle type. |
552 | VehicleActor.ProcessTypeChange(type); | 522 | VehicleActor.ProcessTypeChange(type); |
553 | ActivateIfPhysical(false); | 523 | ActivateIfPhysical(false); |
@@ -670,63 +640,40 @@ public class BSPrim : BSPhysObject | |||
670 | } | 640 | } |
671 | } | 641 | } |
672 | } | 642 | } |
673 | public override OMV.Vector3 RawVelocity | ||
674 | { | ||
675 | get { return _velocity; } | ||
676 | set { _velocity = value; } | ||
677 | } | ||
678 | public override OMV.Vector3 Velocity { | 643 | public override OMV.Vector3 Velocity { |
679 | get { return _velocity; } | 644 | get { return RawVelocity; } |
680 | set { | 645 | set { |
681 | _velocity = value; | 646 | RawVelocity = value; |
682 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 647 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
683 | { | 648 | { |
684 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 649 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); |
685 | ForceVelocity = _velocity; | 650 | ForceVelocity = RawVelocity; |
686 | }); | 651 | }); |
687 | } | 652 | } |
688 | } | 653 | } |
689 | public override OMV.Vector3 ForceVelocity { | 654 | public override OMV.Vector3 ForceVelocity { |
690 | get { return _velocity; } | 655 | get { return RawVelocity; } |
691 | set { | 656 | set { |
692 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | 657 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
693 | 658 | ||
694 | _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); | 659 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); |
695 | if (PhysBody.HasPhysicalBody) | 660 | if (PhysBody.HasPhysicalBody) |
696 | { | 661 | { |
697 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); | 662 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); |
698 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 663 | PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
699 | ActivateIfPhysical(false); | 664 | ActivateIfPhysical(false); |
700 | } | 665 | } |
701 | } | 666 | } |
702 | } | 667 | } |
703 | public override OMV.Vector3 Torque { | 668 | public override OMV.Vector3 Torque { |
704 | get { return _torque; } | 669 | get { return RawTorque; } |
705 | set { | 670 | set { |
706 | _torque = value; | 671 | RawTorque = value; |
707 | if (_torque != OMV.Vector3.Zero) | 672 | EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() |
708 | { | ||
709 | // If the torque is non-zero, it must be reapplied each tick because | ||
710 | // Bullet clears the forces applied last frame. | ||
711 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||
712 | delegate(float timeStep) | ||
713 | { | ||
714 | if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero) | ||
715 | { | ||
716 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
717 | return; | ||
718 | } | ||
719 | |||
720 | if (PhysBody.HasPhysicalBody) | ||
721 | AddAngularForce(_torque, false, true); | ||
722 | } | ||
723 | ); | ||
724 | } | ||
725 | else | ||
726 | { | 673 | { |
727 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | 674 | return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName); |
728 | } | 675 | }); |
729 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 676 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); |
730 | } | 677 | } |
731 | } | 678 | } |
732 | public override OMV.Vector3 Acceleration { | 679 | public override OMV.Vector3 Acceleration { |
@@ -839,7 +786,6 @@ public class BSPrim : BSPhysObject | |||
839 | MakeDynamic(IsStatic); | 786 | MakeDynamic(IsStatic); |
840 | 787 | ||
841 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | 788 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
842 | VehicleActor.Refresh(); | ||
843 | PhysicalActors.Refresh(); | 789 | PhysicalActors.Refresh(); |
844 | 790 | ||
845 | // Arrange for collision events if the simulator wants them | 791 | // Arrange for collision events if the simulator wants them |
@@ -909,7 +855,7 @@ public class BSPrim : BSPhysObject | |||
909 | 855 | ||
910 | // For good measure, make sure the transform is set through to the motion state | 856 | // For good measure, make sure the transform is set through to the motion state |
911 | ForcePosition = _position; | 857 | ForcePosition = _position; |
912 | ForceVelocity = _velocity; | 858 | ForceVelocity = RawVelocity; |
913 | ForceRotationalVelocity = _rotationalVelocity; | 859 | ForceRotationalVelocity = _rotationalVelocity; |
914 | 860 | ||
915 | // A dynamic object has mass | 861 | // A dynamic object has mass |
@@ -966,15 +912,6 @@ public class BSPrim : BSPhysObject | |||
966 | } | 912 | } |
967 | } | 913 | } |
968 | 914 | ||
969 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
970 | // they need waking up when parameters are changed. | ||
971 | // Called in taint-time!! | ||
972 | private void ActivateIfPhysical(bool forceIt) | ||
973 | { | ||
974 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
975 | PhysicsScene.PE.Activate(PhysBody, forceIt); | ||
976 | } | ||
977 | |||
978 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 915 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
979 | private void EnableCollisions(bool wantsCollisionEvents) | 916 | private void EnableCollisions(bool wantsCollisionEvents) |
980 | { | 917 | { |
@@ -1096,78 +1033,13 @@ public class BSPrim : BSPhysObject | |||
1096 | } | 1033 | } |
1097 | } | 1034 | } |
1098 | 1035 | ||
1099 | // Used for MoveTo | ||
1100 | public override OMV.Vector3 PIDTarget { | ||
1101 | set | ||
1102 | { | ||
1103 | // TODO: add a sanity check -- don't move more than a region or something like that. | ||
1104 | _PIDTarget = value; | ||
1105 | } | ||
1106 | } | ||
1107 | public override float PIDTau { | ||
1108 | set { _PIDTau = value; } | ||
1109 | } | ||
1110 | public override bool PIDActive { | 1036 | public override bool PIDActive { |
1111 | set { | 1037 | set { |
1112 | if (value) | 1038 | base.MoveToTargetActive = value; |
1039 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() | ||
1113 | { | 1040 | { |
1114 | // We're taking over after this. | 1041 | return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName); |
1115 | ZeroMotion(true); | 1042 | }); |
1116 | |||
1117 | _targetMotor = new BSVMotor("BSPrim.PIDTarget", | ||
1118 | _PIDTau, // timeScale | ||
1119 | BSMotor.Infinite, // decay time scale | ||
1120 | BSMotor.InfiniteVector, // friction timescale | ||
1121 | 1f // efficiency | ||
1122 | ); | ||
1123 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1124 | _targetMotor.SetTarget(_PIDTarget); | ||
1125 | _targetMotor.SetCurrent(RawPosition); | ||
1126 | /* | ||
1127 | _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget"); | ||
1128 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1129 | |||
1130 | _targetMotor.SetTarget(_PIDTarget); | ||
1131 | _targetMotor.SetCurrent(RawPosition); | ||
1132 | _targetMotor.TimeScale = _PIDTau; | ||
1133 | _targetMotor.Efficiency = 1f; | ||
1134 | */ | ||
1135 | |||
1136 | RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep) | ||
1137 | { | ||
1138 | if (!IsPhysicallyActive) | ||
1139 | { | ||
1140 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1141 | return; | ||
1142 | } | ||
1143 | |||
1144 | OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) | ||
1145 | |||
1146 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
1147 | OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep); | ||
1148 | |||
1149 | // If we are very close to our target, turn off the movement motor. | ||
1150 | if (_targetMotor.ErrorIsZero()) | ||
1151 | { | ||
1152 | DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", | ||
1153 | LocalID, movePosition, RawPosition, Mass); | ||
1154 | ForcePosition = _targetMotor.TargetValue; | ||
1155 | _targetMotor.Enabled = false; | ||
1156 | } | ||
1157 | else | ||
1158 | { | ||
1159 | _position = movePosition; | ||
1160 | PositionSanityCheck(true /* intaintTime */); | ||
1161 | ForcePosition = _position; | ||
1162 | } | ||
1163 | DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition); | ||
1164 | }); | ||
1165 | } | ||
1166 | else | ||
1167 | { | ||
1168 | // Stop any targetting | ||
1169 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1170 | } | ||
1171 | } | 1043 | } |
1172 | } | 1044 | } |
1173 | 1045 | ||
@@ -1175,88 +1047,14 @@ public class BSPrim : BSPhysObject | |||
1175 | // Hover Height will override MoveTo target's Z | 1047 | // Hover Height will override MoveTo target's Z |
1176 | public override bool PIDHoverActive { | 1048 | public override bool PIDHoverActive { |
1177 | set { | 1049 | set { |
1178 | if (value) | 1050 | base.HoverActive = value; |
1051 | EnableActor(HoverActive, HoverActorName, delegate() | ||
1179 | { | 1052 | { |
1180 | // Turning the target on | 1053 | return new BSActorHover(PhysicsScene, this, HoverActorName); |
1181 | _hoverMotor = new BSFMotor("BSPrim.Hover", | 1054 | }); |
1182 | _PIDHoverTau, // timeScale | ||
1183 | BSMotor.Infinite, // decay time scale | ||
1184 | BSMotor.Infinite, // friction timescale | ||
1185 | 1f // efficiency | ||
1186 | ); | ||
1187 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1188 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1189 | _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1190 | |||
1191 | RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep) | ||
1192 | { | ||
1193 | // Don't do hovering while the object is selected. | ||
1194 | if (!IsPhysicallyActive) | ||
1195 | return; | ||
1196 | |||
1197 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1198 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1199 | float targetHeight = _hoverMotor.Step(timeStep); | ||
1200 | |||
1201 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
1202 | // Compute the amount of force to push us there. | ||
1203 | float moveForce = (targetHeight - RawPosition.Z) * Mass; | ||
1204 | // Undo anything the object thinks it's doing at the moment | ||
1205 | moveForce = -RawVelocity.Z * Mass; | ||
1206 | |||
1207 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
1208 | DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass); | ||
1209 | }); | ||
1210 | } | ||
1211 | else | ||
1212 | { | ||
1213 | UnRegisterPreStepAction("BSPrim.Hover", LocalID); | ||
1214 | } | ||
1215 | } | ||
1216 | } | ||
1217 | public override float PIDHoverHeight { | ||
1218 | set { _PIDHoverHeight = value; } | ||
1219 | } | ||
1220 | public override PIDHoverType PIDHoverType { | ||
1221 | set { _PIDHoverType = value; } | ||
1222 | } | ||
1223 | public override float PIDHoverTau { | ||
1224 | set { _PIDHoverTau = value; } | ||
1225 | } | ||
1226 | // Based on current position, determine what we should be hovering at now. | ||
1227 | // Must recompute often. What if we walked offa cliff> | ||
1228 | private float ComputeCurrentPIDHoverHeight() | ||
1229 | { | ||
1230 | float ret = _PIDHoverHeight; | ||
1231 | float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
1232 | |||
1233 | switch (_PIDHoverType) | ||
1234 | { | ||
1235 | case PIDHoverType.Ground: | ||
1236 | ret = groundHeight + _PIDHoverHeight; | ||
1237 | break; | ||
1238 | case PIDHoverType.GroundAndWater: | ||
1239 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
1240 | if (groundHeight > waterHeight) | ||
1241 | { | ||
1242 | ret = groundHeight + _PIDHoverHeight; | ||
1243 | } | ||
1244 | else | ||
1245 | { | ||
1246 | ret = waterHeight + _PIDHoverHeight; | ||
1247 | } | ||
1248 | break; | ||
1249 | } | 1055 | } |
1250 | return ret; | ||
1251 | } | 1056 | } |
1252 | 1057 | ||
1253 | |||
1254 | // For RotLookAt | ||
1255 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
1256 | public override bool APIDActive { set { return; } } | ||
1257 | public override float APIDStrength { set { return; } } | ||
1258 | public override float APIDDamping { set { return; } } | ||
1259 | |||
1260 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 1058 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
1261 | // Per documentation, max force is limited. | 1059 | // Per documentation, max force is limited. |
1262 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 1060 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
@@ -1324,10 +1122,8 @@ public class BSPrim : BSPhysObject | |||
1324 | } | 1122 | } |
1325 | } | 1123 | } |
1326 | 1124 | ||
1327 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1125 | // BSPhysObject.AddAngularForce() |
1328 | AddAngularForce(force, pushforce, false); | 1126 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
1329 | } | ||
1330 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1331 | { | 1127 | { |
1332 | if (force.IsFinite()) | 1128 | if (force.IsFinite()) |
1333 | { | 1129 | { |
@@ -1661,7 +1457,7 @@ public class BSPrim : BSPhysObject | |||
1661 | { | 1457 | { |
1662 | // Create the correct physical representation for this type of object. | 1458 | // Create the correct physical representation for this type of object. |
1663 | // Updates base.PhysBody and base.PhysShape with the new information. | 1459 | // Updates base.PhysBody and base.PhysShape with the new information. |
1664 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1460 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. |
1665 | PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1461 | PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1666 | { | 1462 | { |
1667 | // Called if the current prim body is about to be destroyed. | 1463 | // Called if the current prim body is about to be destroyed. |
@@ -1675,9 +1471,9 @@ public class BSPrim : BSPhysObject | |||
1675 | return; | 1471 | return; |
1676 | } | 1472 | } |
1677 | 1473 | ||
1474 | // Called at taint-time | ||
1678 | protected virtual void RemoveBodyDependencies() | 1475 | protected virtual void RemoveBodyDependencies() |
1679 | { | 1476 | { |
1680 | VehicleActor.RemoveBodyDependencies(); | ||
1681 | PhysicalActors.RemoveBodyDependencies(); | 1477 | PhysicalActors.RemoveBodyDependencies(); |
1682 | } | 1478 | } |
1683 | 1479 | ||
@@ -1685,6 +1481,7 @@ public class BSPrim : BSPhysObject | |||
1685 | // the world that things have changed. | 1481 | // the world that things have changed. |
1686 | public override void UpdateProperties(EntityProperties entprop) | 1482 | public override void UpdateProperties(EntityProperties entprop) |
1687 | { | 1483 | { |
1484 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. | ||
1688 | TriggerPreUpdatePropertyAction(ref entprop); | 1485 | TriggerPreUpdatePropertyAction(ref entprop); |
1689 | 1486 | ||
1690 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG | 1487 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
@@ -1694,8 +1491,8 @@ public class BSPrim : BSPhysObject | |||
1694 | _orientation = entprop.Rotation; | 1491 | _orientation = entprop.Rotation; |
1695 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be | 1492 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
1696 | // very sensitive to velocity changes. | 1493 | // very sensitive to velocity changes. |
1697 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) | 1494 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) |
1698 | _velocity = entprop.Velocity; | 1495 | RawVelocity = entprop.Velocity; |
1699 | _acceleration = entprop.Acceleration; | 1496 | _acceleration = entprop.Acceleration; |
1700 | _rotationalVelocity = entprop.RotationalVelocity; | 1497 | _rotationalVelocity = entprop.RotationalVelocity; |
1701 | 1498 | ||
@@ -1705,7 +1502,7 @@ public class BSPrim : BSPhysObject | |||
1705 | if (PositionSanityCheck(true /* inTaintTime */ )) | 1502 | if (PositionSanityCheck(true /* inTaintTime */ )) |
1706 | { | 1503 | { |
1707 | entprop.Position = _position; | 1504 | entprop.Position = _position; |
1708 | entprop.Velocity = _velocity; | 1505 | entprop.Velocity = RawVelocity; |
1709 | entprop.RotationalVelocity = _rotationalVelocity; | 1506 | entprop.RotationalVelocity = _rotationalVelocity; |
1710 | entprop.Acceleration = _acceleration; | 1507 | entprop.Acceleration = _acceleration; |
1711 | } | 1508 | } |
@@ -1717,16 +1514,8 @@ public class BSPrim : BSPhysObject | |||
1717 | LastEntityProperties = CurrentEntityProperties; | 1514 | LastEntityProperties = CurrentEntityProperties; |
1718 | CurrentEntityProperties = entprop; | 1515 | CurrentEntityProperties = entprop; |
1719 | 1516 | ||
1517 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. | ||
1720 | base.RequestPhysicsterseUpdate(); | 1518 | base.RequestPhysicsterseUpdate(); |
1721 | /* | ||
1722 | else | ||
1723 | { | ||
1724 | // For debugging, report the movement of children | ||
1725 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1726 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
1727 | entprop.Acceleration, entprop.RotationalVelocity); | ||
1728 | } | ||
1729 | */ | ||
1730 | } | 1519 | } |
1731 | } | 1520 | } |
1732 | } | 1521 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index d65d407..28242d4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | |||
@@ -163,6 +163,15 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
163 | // TODO: this will have to change when linksets are articulated. | 163 | // TODO: this will have to change when linksets are articulated. |
164 | base.UpdateProperties(entprop); | 164 | base.UpdateProperties(entprop); |
165 | } | 165 | } |
166 | /* | ||
167 | else | ||
168 | { | ||
169 | // For debugging, report the movement of children | ||
170 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
171 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
172 | entprop.Acceleration, entprop.RotationalVelocity); | ||
173 | } | ||
174 | */ | ||
166 | // The linkset might like to know about changing locations | 175 | // The linkset might like to know about changing locations |
167 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | 176 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
168 | } | 177 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 9818b05..8e05b58 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -316,6 +316,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
316 | break; | 316 | break; |
317 | case "bulletxna": | 317 | case "bulletxna": |
318 | ret = new BSAPIXNA(engineName, this); | 318 | ret = new BSAPIXNA(engineName, this); |
319 | BSParam.ShouldUseBulletHACD = false; | ||
319 | break; | 320 | break; |
320 | } | 321 | } |
321 | 322 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 220fbbc..76860e4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -722,7 +722,7 @@ public sealed class BSShapeCollection : IDisposable | |||
722 | // Remove usage of the previous shape. | 722 | // Remove usage of the previous shape. |
723 | DereferenceShape(prim.PhysShape, shapeCallback); | 723 | DereferenceShape(prim.PhysShape, shapeCallback); |
724 | 724 | ||
725 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | 725 | newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod); |
726 | // It might not have been created if we're waiting for an asset. | 726 | // It might not have been created if we're waiting for an asset. |
727 | newShape = VerifyMeshCreated(newShape, prim); | 727 | newShape = VerifyMeshCreated(newShape, prim); |
728 | 728 | ||
@@ -733,7 +733,7 @@ public sealed class BSShapeCollection : IDisposable | |||
733 | } | 733 | } |
734 | 734 | ||
735 | List<ConvexResult> m_hulls; | 735 | List<ConvexResult> m_hulls; |
736 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 736 | private BulletShape CreatePhysicalHull(BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
737 | { | 737 | { |
738 | 738 | ||
739 | BulletShape newShape = new BulletShape(); | 739 | BulletShape newShape = new BulletShape(); |
@@ -747,116 +747,153 @@ public sealed class BSShapeCollection : IDisposable | |||
747 | } | 747 | } |
748 | else | 748 | else |
749 | { | 749 | { |
750 | // Build a new hull in the physical world. | 750 | if (BSParam.ShouldUseBulletHACD) |
751 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | ||
752 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); | ||
753 | if (meshData != null) | ||
754 | { | 751 | { |
755 | 752 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); | |
756 | int[] indices = meshData.getIndexListAsInt(); | 753 | MeshDesc meshDesc; |
757 | List<OMV.Vector3> vertices = meshData.getVertexList(); | 754 | if (!Meshes.TryGetValue(newHullKey, out meshDesc)) |
758 | |||
759 | //format conversion from IMesh format to DecompDesc format | ||
760 | List<int> convIndices = new List<int>(); | ||
761 | List<float3> convVertices = new List<float3>(); | ||
762 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
763 | { | 755 | { |
764 | convIndices.Add(indices[ii]); | 756 | // That's odd because the mesh should have been created before the hull |
757 | // but, since it doesn't exist, create it. | ||
758 | newShape = CreatePhysicalMesh(prim, newHullKey, prim.BaseShape, prim.Size, lod); | ||
759 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,noMeshBuiltNew,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
760 | |||
761 | if (newShape.HasPhysicalShape) | ||
762 | { | ||
763 | ReferenceShape(newShape); | ||
764 | Meshes.TryGetValue(newHullKey, out meshDesc); | ||
765 | } | ||
765 | } | 766 | } |
766 | foreach (OMV.Vector3 vv in vertices) | 767 | if (meshDesc.shape.HasPhysicalShape) |
767 | { | 768 | { |
768 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | 769 | HACDParams parms; |
770 | parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; | ||
771 | parms.minClusters = BSParam.BHullMinClusters; | ||
772 | parms.compacityWeight = BSParam.BHullCompacityWeight; | ||
773 | parms.volumeWeight = BSParam.BHullVolumeWeight; | ||
774 | parms.concavity = BSParam.BHullConcavity; | ||
775 | parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); | ||
776 | parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); | ||
777 | parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); | ||
778 | parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); | ||
779 | |||
780 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); | ||
781 | newShape = PhysicsScene.PE.BuildHullShapeFromMesh(PhysicsScene.World, meshDesc.shape, parms); | ||
782 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
769 | } | 783 | } |
770 | 784 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | |
771 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | 785 | } |
772 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | 786 | if (!newShape.HasPhysicalShape) |
787 | { | ||
788 | // Build a new hull in the physical world. | ||
789 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | ||
790 | IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false); | ||
791 | if (meshData != null) | ||
773 | { | 792 | { |
774 | // Simple primitive shapes we know are convex so they are better implemented with | 793 | int[] indices = meshData.getIndexListAsInt(); |
775 | // fewer hulls. | 794 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
776 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | 795 | |
777 | if (PrimHasNoCuts(pbs)) | 796 | //format conversion from IMesh format to DecompDesc format |
797 | List<int> convIndices = new List<int>(); | ||
798 | List<float3> convVertices = new List<float3>(); | ||
799 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
778 | { | 800 | { |
779 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | 801 | convIndices.Add(indices[ii]); |
802 | } | ||
803 | foreach (OMV.Vector3 vv in vertices) | ||
804 | { | ||
805 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
780 | } | 806 | } |
781 | } | ||
782 | 807 | ||
783 | // setup and do convex hull conversion | 808 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; |
784 | m_hulls = new List<ConvexResult>(); | 809 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) |
785 | DecompDesc dcomp = new DecompDesc(); | 810 | { |
786 | dcomp.mIndices = convIndices; | 811 | // Simple primitive shapes we know are convex so they are better implemented with |
787 | dcomp.mVertices = convVertices; | 812 | // fewer hulls. |
788 | dcomp.mDepth = maxDepthSplit; | 813 | // Check for simple shape (prim without cuts) and reduce split parameter if so. |
789 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | 814 | if (PrimHasNoCuts(pbs)) |
790 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | 815 | { |
791 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | 816 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; |
792 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | 817 | } |
793 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | 818 | } |
794 | // create the hull into the _hulls variable | ||
795 | convexBuilder.process(dcomp); | ||
796 | |||
797 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
798 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
799 | |||
800 | // Convert the vertices and indices for passing to unmanaged. | ||
801 | // The hull information is passed as a large floating point array. | ||
802 | // The format is: | ||
803 | // convHulls[0] = number of hulls | ||
804 | // convHulls[1] = number of vertices in first hull | ||
805 | // convHulls[2] = hull centroid X coordinate | ||
806 | // convHulls[3] = hull centroid Y coordinate | ||
807 | // convHulls[4] = hull centroid Z coordinate | ||
808 | // convHulls[5] = first hull vertex X | ||
809 | // convHulls[6] = first hull vertex Y | ||
810 | // convHulls[7] = first hull vertex Z | ||
811 | // convHulls[8] = second hull vertex X | ||
812 | // ... | ||
813 | // convHulls[n] = number of vertices in second hull | ||
814 | // convHulls[n+1] = second hull centroid X coordinate | ||
815 | // ... | ||
816 | // | ||
817 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
818 | // data structures that do not need to be converted in order to pass to Bullet. | ||
819 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
820 | int hullCount = m_hulls.Count; | ||
821 | int totalVertices = 1; // include one for the count of the hulls | ||
822 | foreach (ConvexResult cr in m_hulls) | ||
823 | { | ||
824 | totalVertices += 4; // add four for the vertex count and centroid | ||
825 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
826 | } | ||
827 | float[] convHulls = new float[totalVertices]; | ||
828 | 819 | ||
829 | convHulls[0] = (float)hullCount; | 820 | // setup and do convex hull conversion |
830 | int jj = 1; | 821 | m_hulls = new List<ConvexResult>(); |
831 | foreach (ConvexResult cr in m_hulls) | 822 | DecompDesc dcomp = new DecompDesc(); |
832 | { | 823 | dcomp.mIndices = convIndices; |
833 | // copy vertices for index access | 824 | dcomp.mVertices = convVertices; |
834 | float3[] verts = new float3[cr.HullVertices.Count]; | 825 | dcomp.mDepth = maxDepthSplit; |
835 | int kk = 0; | 826 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; |
836 | foreach (float3 ff in cr.HullVertices) | 827 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; |
828 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
829 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
830 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
831 | // create the hull into the _hulls variable | ||
832 | convexBuilder.process(dcomp); | ||
833 | |||
834 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
835 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
836 | |||
837 | // Convert the vertices and indices for passing to unmanaged. | ||
838 | // The hull information is passed as a large floating point array. | ||
839 | // The format is: | ||
840 | // convHulls[0] = number of hulls | ||
841 | // convHulls[1] = number of vertices in first hull | ||
842 | // convHulls[2] = hull centroid X coordinate | ||
843 | // convHulls[3] = hull centroid Y coordinate | ||
844 | // convHulls[4] = hull centroid Z coordinate | ||
845 | // convHulls[5] = first hull vertex X | ||
846 | // convHulls[6] = first hull vertex Y | ||
847 | // convHulls[7] = first hull vertex Z | ||
848 | // convHulls[8] = second hull vertex X | ||
849 | // ... | ||
850 | // convHulls[n] = number of vertices in second hull | ||
851 | // convHulls[n+1] = second hull centroid X coordinate | ||
852 | // ... | ||
853 | // | ||
854 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
855 | // data structures that do not need to be converted in order to pass to Bullet. | ||
856 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
857 | int hullCount = m_hulls.Count; | ||
858 | int totalVertices = 1; // include one for the count of the hulls | ||
859 | foreach (ConvexResult cr in m_hulls) | ||
837 | { | 860 | { |
838 | verts[kk++] = ff; | 861 | totalVertices += 4; // add four for the vertex count and centroid |
862 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
839 | } | 863 | } |
864 | float[] convHulls = new float[totalVertices]; | ||
840 | 865 | ||
841 | // add to the array one hull's worth of data | 866 | convHulls[0] = (float)hullCount; |
842 | convHulls[jj++] = cr.HullIndices.Count; | 867 | int jj = 1; |
843 | convHulls[jj++] = 0f; // centroid x,y,z | 868 | foreach (ConvexResult cr in m_hulls) |
844 | convHulls[jj++] = 0f; | ||
845 | convHulls[jj++] = 0f; | ||
846 | foreach (int ind in cr.HullIndices) | ||
847 | { | 869 | { |
848 | convHulls[jj++] = verts[ind].x; | 870 | // copy vertices for index access |
849 | convHulls[jj++] = verts[ind].y; | 871 | float3[] verts = new float3[cr.HullVertices.Count]; |
850 | convHulls[jj++] = verts[ind].z; | 872 | int kk = 0; |
873 | foreach (float3 ff in cr.HullVertices) | ||
874 | { | ||
875 | verts[kk++] = ff; | ||
876 | } | ||
877 | |||
878 | // add to the array one hull's worth of data | ||
879 | convHulls[jj++] = cr.HullIndices.Count; | ||
880 | convHulls[jj++] = 0f; // centroid x,y,z | ||
881 | convHulls[jj++] = 0f; | ||
882 | convHulls[jj++] = 0f; | ||
883 | foreach (int ind in cr.HullIndices) | ||
884 | { | ||
885 | convHulls[jj++] = verts[ind].x; | ||
886 | convHulls[jj++] = verts[ind].y; | ||
887 | convHulls[jj++] = verts[ind].z; | ||
888 | } | ||
851 | } | 889 | } |
890 | // create the hull data structure in Bullet | ||
891 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); | ||
852 | } | 892 | } |
853 | // create the hull data structure in Bullet | ||
854 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); | ||
855 | } | 893 | } |
894 | newShape.shapeKey = newHullKey; | ||
856 | } | 895 | } |
857 | 896 | ||
858 | newShape.shapeKey = newHullKey; | ||
859 | |||
860 | return newShape; | 897 | return newShape; |
861 | } | 898 | } |
862 | 899 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index cd15850..5240ad8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -213,13 +213,13 @@ public sealed class BSTerrainManager : IDisposable | |||
213 | }); | 213 | }); |
214 | } | 214 | } |
215 | 215 | ||
216 | // Another region is calling this region passing a terrain. | 216 | // Another region is calling this region and passing a terrain. |
217 | // A region that is not the mega-region root will pass its terrain to the root region so the root region | 217 | // A region that is not the mega-region root will pass its terrain to the root region so the root region |
218 | // physics engine will have all the terrains. | 218 | // physics engine will have all the terrains. |
219 | private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | 219 | private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
220 | { | 220 | { |
221 | // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. | 221 | // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. |
222 | PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + m_worldOffset.ToString(), 0, delegate() | 222 | PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() |
223 | { | 223 | { |
224 | UpdateTerrain(id, heightMap, minCoords, maxCoords); | 224 | UpdateTerrain(id, heightMap, minCoords, maxCoords); |
225 | }); | 225 | }); |
@@ -306,7 +306,7 @@ public sealed class BSTerrainManager : IDisposable | |||
306 | newTerrainID = ++m_terrainCount; | 306 | newTerrainID = ++m_terrainCount; |
307 | 307 | ||
308 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", | 308 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
309 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 309 | BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); |
310 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 310 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
311 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 311 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
312 | 312 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 8a15abe..a0131c7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -6,7 +6,6 @@ Enable vehicle border crossings (at least as poorly as ODE) | |||
6 | Terrain skirts | 6 | Terrain skirts |
7 | Avatar created in previous region and not new region when crossing border | 7 | Avatar created in previous region and not new region when crossing border |
8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | 8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) |
9 | Lock axis | ||
10 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. | 9 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. |
11 | Not sure if it is because standing on it. Done with large prim linksets. | 10 | Not sure if it is because standing on it. Done with large prim linksets. |
12 | Linkset child rotations. | 11 | Linkset child rotations. |
@@ -344,3 +343,5 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | |||
344 | Verify that angular motion specified around Z moves in the vehicle coordinates. | 343 | Verify that angular motion specified around Z moves in the vehicle coordinates. |
345 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. | 344 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. |
346 | Nebadon vehicles turning funny in arena (DONE) | 345 | Nebadon vehicles turning funny in arena (DONE) |
346 | Lock axis (DONE 20130401) | ||
347 | |||
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs index b4abc1d..4bf2a82 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | ||
31 | using log4net; | ||
30 | using OpenMetaverse; | 32 | using OpenMetaverse; |
31 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
32 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
@@ -34,10 +36,10 @@ using OpenSim.Region.CoreModules.World.Land; | |||
34 | 36 | ||
35 | namespace OpenSim.Region.RegionCombinerModule | 37 | namespace OpenSim.Region.RegionCombinerModule |
36 | { | 38 | { |
37 | public class RegionCombinerLargeLandChannel : ILandChannel | 39 | public class RegionCombinerLargeLandChannel : ILandChannel |
38 | { | 40 | { |
39 | // private static readonly ILog m_log = | 41 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
40 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | |
41 | private RegionData RegData; | 43 | private RegionData RegData; |
42 | private ILandChannel RootRegionLandChannel; | 44 | private ILandChannel RootRegionLandChannel; |
43 | private readonly List<RegionData> RegionConnections; | 45 | private readonly List<RegionData> RegionConnections; |
@@ -75,40 +77,51 @@ public class RegionCombinerLargeLandChannel : ILandChannel | |||
75 | 77 | ||
76 | public ILandObject GetLandObject(int x, int y) | 78 | public ILandObject GetLandObject(int x, int y) |
77 | { | 79 | { |
78 | //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); | 80 | return GetLandObject((float)x, (float)y); |
79 | 81 | ||
80 | if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) | 82 | // m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); |
81 | { | 83 | // |
82 | return RootRegionLandChannel.GetLandObject(x, y); | 84 | // if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) |
83 | } | 85 | // { |
84 | else | 86 | // return RootRegionLandChannel.GetLandObject(x, y); |
85 | { | 87 | // } |
86 | int offsetX = (x / (int)Constants.RegionSize); | 88 | // else |
87 | int offsetY = (y / (int)Constants.RegionSize); | 89 | // { |
88 | offsetX *= (int)Constants.RegionSize; | 90 | // int offsetX = (x / (int)Constants.RegionSize); |
89 | offsetY *= (int)Constants.RegionSize; | 91 | // int offsetY = (y / (int)Constants.RegionSize); |
90 | 92 | // offsetX *= (int)Constants.RegionSize; | |
91 | foreach (RegionData regionData in RegionConnections) | 93 | // offsetY *= (int)Constants.RegionSize; |
92 | { | 94 | // |
93 | if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) | 95 | // foreach (RegionData regionData in RegionConnections) |
94 | { | 96 | // { |
95 | return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); | 97 | // if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) |
96 | } | 98 | // { |
97 | } | 99 | // m_log.DebugFormat( |
98 | ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); | 100 | // "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}", |
99 | obj.LandData.Name = "NO LAND"; | 101 | // regionData.RegionScene.Name, offsetX, offsetY); |
100 | return obj; | 102 | // |
101 | } | 103 | // return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); |
104 | // } | ||
105 | // } | ||
106 | // //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); | ||
107 | // //obj.LandData.Name = "NO LAND"; | ||
108 | // //return obj; | ||
109 | // } | ||
110 | // | ||
111 | // m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y); | ||
112 | // | ||
113 | // return null; | ||
102 | } | 114 | } |
103 | 115 | ||
104 | public ILandObject GetLandObject(int localID) | 116 | public ILandObject GetLandObject(int localID) |
105 | { | 117 | { |
118 | // XXX: Possibly should be looking in every land channel, not just the root. | ||
106 | return RootRegionLandChannel.GetLandObject(localID); | 119 | return RootRegionLandChannel.GetLandObject(localID); |
107 | } | 120 | } |
108 | 121 | ||
109 | public ILandObject GetLandObject(float x, float y) | 122 | public ILandObject GetLandObject(float x, float y) |
110 | { | 123 | { |
111 | //m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); | 124 | // m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); |
112 | 125 | ||
113 | if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) | 126 | if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) |
114 | { | 127 | { |
@@ -125,14 +138,22 @@ public class RegionCombinerLargeLandChannel : ILandChannel | |||
125 | { | 138 | { |
126 | if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) | 139 | if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) |
127 | { | 140 | { |
141 | // m_log.DebugFormat( | ||
142 | // "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}", | ||
143 | // regionData.RegionScene.Name, offsetX, offsetY); | ||
144 | |||
128 | return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); | 145 | return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); |
129 | } | 146 | } |
130 | } | 147 | } |
131 | 148 | ||
132 | ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); | 149 | // ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); |
133 | obj.LandData.Name = "NO LAND"; | 150 | // obj.LandData.Name = "NO LAND"; |
134 | return obj; | 151 | // return obj; |
135 | } | 152 | } |
153 | |||
154 | // m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y); | ||
155 | |||
156 | return null; | ||
136 | } | 157 | } |
137 | 158 | ||
138 | public bool IsForcefulBansAllowed() | 159 | public bool IsForcefulBansAllowed() |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 26850c4..fa238aa 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -528,8 +528,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
528 | { | 528 | { |
529 | File.Delete(savedState); | 529 | File.Delete(savedState); |
530 | } | 530 | } |
531 | catch(Exception) | 531 | catch (Exception e) |
532 | { | 532 | { |
533 | m_log.Warn( | ||
534 | string.Format( | ||
535 | "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ", | ||
536 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name), | ||
537 | e); | ||
533 | } | 538 | } |
534 | } | 539 | } |
535 | 540 | ||