Merge branch 'master' into careminster
Conflicts: CONTRIBUTORS.txt OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.csavinationmerge
commit
71dd55a1ce
|
@ -1,4 +1,4 @@
|
||||||
<<<>>>>The following people have contributed to OpenSim (Thank you
|
<<<>>>>The following people have contributed to OpenSim (Thank you
|
||||||
for your effort!)
|
for your effort!)
|
||||||
|
|
||||||
= Current OpenSim Developers (in very rough order of appearance) =
|
= Current OpenSim Developers (in very rough order of appearance) =
|
||||||
|
|
|
@ -696,7 +696,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||||
|
|
||||||
region.ExternalHostName = (string) requestData["external_address"];
|
region.ExternalHostName = (string) requestData["external_address"];
|
||||||
|
|
||||||
bool persist = Convert.ToBoolean((string) requestData["persist"]);
|
bool persist = Convert.ToBoolean(requestData["persist"]);
|
||||||
if (persist)
|
if (persist)
|
||||||
{
|
{
|
||||||
// default place for region configuration files is in the
|
// default place for region configuration files is in the
|
||||||
|
@ -1105,8 +1105,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||||
string lastName = (string) requestData["user_lastname"];
|
string lastName = (string) requestData["user_lastname"];
|
||||||
string password = (string) requestData["user_password"];
|
string password = (string) requestData["user_password"];
|
||||||
|
|
||||||
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
|
uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
|
||||||
uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
|
uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
|
||||||
|
|
||||||
string email = ""; // empty string for email
|
string email = ""; // empty string for email
|
||||||
if (requestData.Contains("user_email"))
|
if (requestData.Contains("user_email"))
|
||||||
|
@ -1303,9 +1303,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||||
|
|
||||||
if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
|
if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
|
||||||
if (requestData.ContainsKey("start_region_x"))
|
if (requestData.ContainsKey("start_region_x"))
|
||||||
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
|
regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
|
||||||
if (requestData.ContainsKey("start_region_y"))
|
if (requestData.ContainsKey("start_region_y"))
|
||||||
regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
|
regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
|
||||||
|
|
||||||
// if (requestData.ContainsKey("start_lookat_x"))
|
// if (requestData.ContainsKey("start_lookat_x"))
|
||||||
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
|
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
|
||||||
|
|
|
@ -19,9 +19,6 @@ CREATE TABLE `GridUser` (
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
:VERSION 2 # --------------------------
|
:VERSION 2 # --------------------------
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
ALTER TABLE `GridUser` ADD COLUMN TOS CHAR(36);
|
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
|
@ -728,14 +728,14 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
const int sampleLength = 80;
|
const int sampleLength = 80;
|
||||||
char[] sampleChars = new char[sampleLength];
|
char[] sampleChars = new char[sampleLength];
|
||||||
reader.Read(sampleChars, 0, sampleLength);
|
reader.Read(sampleChars, 0, sampleLength);
|
||||||
output = string.Format("[BASE HTTP SERVER]: {0}...", new string(sampleChars).Replace("\n", @"\n"));
|
output = new string(sampleChars);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output = string.Format("[BASE HTTP SERVER]: {0}", reader.ReadToEnd());
|
output = reader.ReadToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.Debug(output);
|
m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,9 +177,9 @@ namespace OpenSim.Framework.Servers
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDebug < 0 || newDebug > 5)
|
if (newDebug < 0 || newDebug > 6)
|
||||||
{
|
{
|
||||||
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..5", newDebug);
|
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..6", newDebug);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,6 +285,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
|
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
|
||||||
|
{
|
||||||
|
if (!Enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp))
|
||||||
|
{
|
||||||
|
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
|
||||||
{
|
{
|
||||||
lock (sp.AttachmentsSyncLock)
|
lock (sp.AttachmentsSyncLock)
|
||||||
{
|
{
|
||||||
|
@ -862,7 +876,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
// This will throw if the attachment fails
|
// This will throw if the attachment fails
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
AttachObject(sp, objatt, attachmentPt, false, false, false);
|
AttachObjectInternal(sp, objatt, attachmentPt, false, false, false);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,6 +64,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
|
private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
|
||||||
// private OSChatMessage m_osChatMessageReceived;
|
// private OSChatMessage m_osChatMessageReceived;
|
||||||
|
|
||||||
|
// Used to test whether the operations have fired the attach event. Must be reset after each test.
|
||||||
|
private int m_numberOfAttachEventsFired;
|
||||||
|
|
||||||
[TestFixtureSetUp]
|
[TestFixtureSetUp]
|
||||||
public void FixtureInit()
|
public void FixtureInit()
|
||||||
{
|
{
|
||||||
|
@ -99,6 +102,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
|
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
|
||||||
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
|
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
|
||||||
|
|
||||||
|
scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++;
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +186,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
// TestHelpers.EnableLogging();
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
|
|
||||||
Scene scene = CreateTestScene();
|
Scene scene = CreateTestScene();
|
||||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||||
|
@ -189,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
|
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
|
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
|
||||||
|
|
||||||
// Check status on scene presence
|
// Check status on scene presence
|
||||||
|
@ -216,7 +224,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||||
|
|
||||||
// TestHelpers.DisableLogging();
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -228,6 +237,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
// TestHelpers.EnableLogging();
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
|
|
||||||
Scene scene = CreateTestScene();
|
Scene scene = CreateTestScene();
|
||||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||||
|
@ -247,6 +258,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
Assert.That(sp.HasAttachments(), Is.False);
|
Assert.That(sp.HasAttachments(), Is.False);
|
||||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -261,6 +275,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||||
|
|
||||||
|
@ -280,6 +295,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||||
|
|
||||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -338,6 +356,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
ISceneEntity so
|
ISceneEntity so
|
||||||
= scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
= scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
|
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
|
||||||
|
|
||||||
// Check scene presence status
|
// Check scene presence status
|
||||||
|
@ -353,6 +373,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
// Check object in scene
|
// Check object in scene
|
||||||
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
|
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
|
||||||
|
|
||||||
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -369,6 +392,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
SceneObjectGroup so
|
SceneObjectGroup so
|
||||||
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
|
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
|
||||||
|
|
||||||
// Check status on scene presence
|
// Check status on scene presence
|
||||||
|
@ -380,6 +405,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
|
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
|
||||||
|
|
||||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -461,10 +489,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
|
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
scene.IncomingCloseAgent(presence.UUID, false);
|
scene.IncomingCloseAgent(presence.UUID, false);
|
||||||
|
|
||||||
// Check that we can't retrieve this attachment from the scene.
|
// Check that we can't retrieve this attachment from the scene.
|
||||||
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
|
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
|
||||||
|
|
||||||
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -480,6 +512,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
|
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
|
||||||
acd.Appearance = new AvatarAppearance();
|
acd.Appearance = new AvatarAppearance();
|
||||||
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
|
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
|
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
|
||||||
|
|
||||||
Assert.That(presence.HasAttachments(), Is.True);
|
Assert.That(presence.HasAttachments(), Is.True);
|
||||||
|
@ -502,6 +536,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||||
|
|
||||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// Check events. We expect OnAttach to fire on login.
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -522,10 +559,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
Vector3 newPosition = new Vector3(1, 2, 4);
|
Vector3 newPosition = new Vector3(1, 2, 4);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
|
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
|
||||||
|
|
||||||
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
|
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
|
||||||
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
|
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
|
||||||
|
|
||||||
|
// Check events
|
||||||
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -574,6 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
Vector3 teleportPosition = new Vector3(10, 11, 12);
|
Vector3 teleportPosition = new Vector3(10, 11, 12);
|
||||||
Vector3 teleportLookAt = new Vector3(20, 21, 22);
|
Vector3 teleportLookAt = new Vector3(20, 21, 22);
|
||||||
|
|
||||||
|
m_numberOfAttachEventsFired = 0;
|
||||||
sceneA.RequestTeleportLocation(
|
sceneA.RequestTeleportLocation(
|
||||||
beforeTeleportSp.ControllingClient,
|
beforeTeleportSp.ControllingClient,
|
||||||
sceneB.RegionInfo.RegionHandle,
|
sceneB.RegionInfo.RegionHandle,
|
||||||
|
@ -616,29 +658,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
|
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
|
||||||
|
|
||||||
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
||||||
}
|
|
||||||
|
|
||||||
// I'm commenting this test because scene setup NEEDS InventoryService to
|
// Check events
|
||||||
// be non-null
|
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||||
//[Test]
|
}
|
||||||
// public void T032_CrossAttachments()
|
|
||||||
// {
|
|
||||||
// TestHelpers.InMethod();
|
|
||||||
//
|
|
||||||
// ScenePresence presence = scene.GetScenePresence(agent1);
|
|
||||||
// ScenePresence presence2 = scene2.GetScenePresence(agent1);
|
|
||||||
// presence2.AddAttachment(sog1);
|
|
||||||
// presence2.AddAttachment(sog2);
|
|
||||||
//
|
|
||||||
// ISharedRegionModule serialiser = new SerialiserModule();
|
|
||||||
// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser);
|
|
||||||
// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser);
|
|
||||||
//
|
|
||||||
// Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross");
|
|
||||||
//
|
|
||||||
// //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful");
|
|
||||||
// Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted");
|
|
||||||
// Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,14 +112,19 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||||
public void GetDrawStringSize(string text, string fontName, int fontSize,
|
public void GetDrawStringSize(string text, string fontName, int fontSize,
|
||||||
out double xSize, out double ySize)
|
out double xSize, out double ySize)
|
||||||
{
|
{
|
||||||
using (Font myFont = new Font(fontName, fontSize))
|
lock (this)
|
||||||
{
|
{
|
||||||
SizeF stringSize = new SizeF();
|
using (Font myFont = new Font(fontName, fontSize))
|
||||||
lock (m_graph)
|
|
||||||
{
|
{
|
||||||
stringSize = m_graph.MeasureString(text, myFont);
|
SizeF stringSize = new SizeF();
|
||||||
xSize = stringSize.Width;
|
|
||||||
ySize = stringSize.Height;
|
// XXX: This lock may be unnecessary.
|
||||||
|
lock (m_graph)
|
||||||
|
{
|
||||||
|
stringSize = m_graph.MeasureString(text, myFont);
|
||||||
|
xSize = stringSize.Width;
|
||||||
|
ySize = stringSize.Height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
public class BS6DofConstraint : BSConstraint
|
public class BS6DofConstraint : BSConstraint
|
||||||
{
|
{
|
||||||
|
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
|
||||||
|
|
||||||
|
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
|
||||||
|
|
||||||
// Create a btGeneric6DofConstraint
|
// Create a btGeneric6DofConstraint
|
||||||
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
||||||
Vector3 frame1, Quaternion frame1rot,
|
Vector3 frame1, Quaternion frame1rot,
|
||||||
|
@ -44,11 +48,14 @@ public class BS6DofConstraint : BSConstraint
|
||||||
m_body1 = obj1;
|
m_body1 = obj1;
|
||||||
m_body2 = obj2;
|
m_body2 = obj2;
|
||||||
m_constraint = new BulletConstraint(
|
m_constraint = new BulletConstraint(
|
||||||
BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
|
BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
|
||||||
frame1, frame1rot,
|
frame1, frame1rot,
|
||||||
frame2, frame2rot,
|
frame2, frame2rot,
|
||||||
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
|
world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
|
||||||
|
BSScene.DetailLogZero, world.worldID,
|
||||||
|
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
||||||
|
@ -58,11 +65,36 @@ public class BS6DofConstraint : BSConstraint
|
||||||
m_world = world;
|
m_world = world;
|
||||||
m_body1 = obj1;
|
m_body1 = obj1;
|
||||||
m_body2 = obj2;
|
m_body2 = obj2;
|
||||||
m_constraint = new BulletConstraint(
|
if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
|
||||||
BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
|
{
|
||||||
joinPoint,
|
world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
|
||||||
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
BSScene.DetailLogZero, world.worldID,
|
||||||
m_enabled = true;
|
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
||||||
|
world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
|
||||||
|
"[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
|
||||||
|
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_constraint = new BulletConstraint(
|
||||||
|
BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
|
||||||
|
joinPoint,
|
||||||
|
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
|
world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
|
||||||
|
BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
|
||||||
|
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
|
||||||
|
if (m_constraint.ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
|
||||||
|
LogHeader, obj1.ID, obj2.ID);
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
|
public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
|
||||||
|
@ -70,7 +102,7 @@ public class BS6DofConstraint : BSConstraint
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot);
|
BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -81,9 +113,9 @@ public class BS6DofConstraint : BSConstraint
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
|
BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
|
||||||
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
|
BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
|
||||||
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
|
BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -94,7 +126,7 @@ public class BS6DofConstraint : BSConstraint
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
|
float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
|
ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +135,7 @@ public class BS6DofConstraint : BSConstraint
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
|
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
|
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +143,7 @@ public class BS6DofConstraint : BSConstraint
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold);
|
ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenMetaverse;
|
using OMV = OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Physics.Manager;
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
@ -39,48 +39,35 @@ public class BSCharacter : BSPhysObject
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
private static readonly string LogHeader = "[BULLETS CHAR]";
|
private static readonly string LogHeader = "[BULLETS CHAR]";
|
||||||
|
|
||||||
public BSScene Scene { get; private set; }
|
|
||||||
private String _avName;
|
|
||||||
// private bool _stopped;
|
// private bool _stopped;
|
||||||
private Vector3 _size;
|
private OMV.Vector3 _size;
|
||||||
private Vector3 _scale;
|
private OMV.Vector3 _scale;
|
||||||
private PrimitiveBaseShape _pbs;
|
private PrimitiveBaseShape _pbs;
|
||||||
private uint _localID = 0;
|
|
||||||
private bool _grabbed;
|
private bool _grabbed;
|
||||||
private bool _selected;
|
private bool _selected;
|
||||||
private Vector3 _position;
|
private OMV.Vector3 _position;
|
||||||
private float _mass;
|
private float _mass;
|
||||||
public float _density;
|
private float _avatarDensity;
|
||||||
public float _avatarVolume;
|
private float _avatarVolume;
|
||||||
private Vector3 _force;
|
private OMV.Vector3 _force;
|
||||||
private Vector3 _velocity;
|
private OMV.Vector3 _velocity;
|
||||||
private Vector3 _torque;
|
private OMV.Vector3 _torque;
|
||||||
private float _collisionScore;
|
private float _collisionScore;
|
||||||
private Vector3 _acceleration;
|
private OMV.Vector3 _acceleration;
|
||||||
private Quaternion _orientation;
|
private OMV.Quaternion _orientation;
|
||||||
private int _physicsActorType;
|
private int _physicsActorType;
|
||||||
private bool _isPhysical;
|
private bool _isPhysical;
|
||||||
private bool _flying;
|
private bool _flying;
|
||||||
private bool _setAlwaysRun;
|
private bool _setAlwaysRun;
|
||||||
private bool _throttleUpdates;
|
private bool _throttleUpdates;
|
||||||
private bool _isColliding;
|
private bool _isColliding;
|
||||||
private long _collidingStep;
|
|
||||||
private bool _collidingGround;
|
|
||||||
private long _collidingGroundStep;
|
|
||||||
private bool _collidingObj;
|
private bool _collidingObj;
|
||||||
private bool _floatOnWater;
|
private bool _floatOnWater;
|
||||||
private Vector3 _rotationalVelocity;
|
private OMV.Vector3 _rotationalVelocity;
|
||||||
private bool _kinematic;
|
private bool _kinematic;
|
||||||
private float _buoyancy;
|
private float _buoyancy;
|
||||||
|
|
||||||
public override BulletBody BSBody { get; set; }
|
private OMV.Vector3 _PIDTarget;
|
||||||
public override BulletShape BSShape { get; set; }
|
|
||||||
public override BSLinkset Linkset { get; set; }
|
|
||||||
|
|
||||||
private int _subscribedEventsMs = 0;
|
|
||||||
private int _nextCollisionOkTime = 0;
|
|
||||||
|
|
||||||
private Vector3 _PIDTarget;
|
|
||||||
private bool _usePID;
|
private bool _usePID;
|
||||||
private float _PIDTau;
|
private float _PIDTau;
|
||||||
private bool _useHoverPID;
|
private bool _useHoverPID;
|
||||||
|
@ -88,28 +75,26 @@ public class BSCharacter : BSPhysObject
|
||||||
private PIDHoverType _PIDHoverType;
|
private PIDHoverType _PIDHoverType;
|
||||||
private float _PIDHoverTao;
|
private float _PIDHoverTao;
|
||||||
|
|
||||||
public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
|
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
||||||
{
|
{
|
||||||
_localID = localID;
|
base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
|
||||||
_avName = avName;
|
|
||||||
Scene = parent_scene;
|
|
||||||
_physicsActorType = (int)ActorTypes.Agent;
|
_physicsActorType = (int)ActorTypes.Agent;
|
||||||
_position = pos;
|
_position = pos;
|
||||||
_size = size;
|
_size = size;
|
||||||
_flying = isFlying;
|
_flying = isFlying;
|
||||||
_orientation = Quaternion.Identity;
|
_orientation = OMV.Quaternion.Identity;
|
||||||
_velocity = Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||||
|
|
||||||
// The dimensions of the avatar capsule are kept in the scale.
|
// The dimensions of the avatar capsule are kept in the scale.
|
||||||
// Physics creates a unit capsule which is scaled by the physics engine.
|
// Physics creates a unit capsule which is scaled by the physics engine.
|
||||||
_scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z);
|
ComputeAvatarScale(_size);
|
||||||
_density = Scene.Params.avatarDensity;
|
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||||
ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
|
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
||||||
|
ComputeAvatarVolumeAndMass();
|
||||||
Linkset = new BSLinkset(Scene, this);
|
|
||||||
|
|
||||||
ShapeData shapeData = new ShapeData();
|
ShapeData shapeData = new ShapeData();
|
||||||
shapeData.ID = _localID;
|
shapeData.ID = LocalID;
|
||||||
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
|
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
|
||||||
shapeData.Position = _position;
|
shapeData.Position = _position;
|
||||||
shapeData.Rotation = _orientation;
|
shapeData.Rotation = _orientation;
|
||||||
|
@ -118,21 +103,25 @@ public class BSCharacter : BSPhysObject
|
||||||
shapeData.Mass = _mass;
|
shapeData.Mass = _mass;
|
||||||
shapeData.Buoyancy = _buoyancy;
|
shapeData.Buoyancy = _buoyancy;
|
||||||
shapeData.Static = ShapeData.numericFalse;
|
shapeData.Static = ShapeData.numericFalse;
|
||||||
shapeData.Friction = Scene.Params.avatarFriction;
|
shapeData.Friction = PhysicsScene.Params.avatarFriction;
|
||||||
shapeData.Restitution = Scene.Params.avatarRestitution;
|
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
|
||||||
|
|
||||||
// do actual create at taint time
|
// do actual create at taint time
|
||||||
Scene.TaintedObject("BSCharacter.create", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.create", _localID);
|
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
||||||
BulletSimAPI.CreateObject(Scene.WorldID, shapeData);
|
BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
|
||||||
|
|
||||||
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#
|
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
|
||||||
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
|
// If not set at creation, the avatar will stop flying when created after crossing a region boundry.
|
||||||
|
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
|
||||||
|
|
||||||
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(Scene.World.Ptr, LocalID));
|
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
|
||||||
|
|
||||||
|
// This works here because CreateObject has already put the character into the physical world.
|
||||||
|
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
|
||||||
|
(uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +129,9 @@ public class BSCharacter : BSPhysObject
|
||||||
public override void Destroy()
|
public override void Destroy()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||||
Scene.TaintedObject("BSCharacter.destroy", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
||||||
{
|
{
|
||||||
BulletSimAPI.DestroyObject(Scene.WorldID, _localID);
|
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,26 +143,26 @@ public class BSCharacter : BSPhysObject
|
||||||
public override bool Stopped {
|
public override bool Stopped {
|
||||||
get { return false; }
|
get { return false; }
|
||||||
}
|
}
|
||||||
public override Vector3 Size {
|
public override OMV.Vector3 Size {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// Avatar capsule size is kept in the scale parameter.
|
// Avatar capsule size is kept in the scale parameter.
|
||||||
return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
|
return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
// When an avatar's size is set, only the height is changed
|
// When an avatar's size is set, only the height is changed
|
||||||
// and that really only depends on the radius.
|
// and that really only depends on the radius.
|
||||||
_size = value;
|
_size = value;
|
||||||
_scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
|
ComputeAvatarScale(_size);
|
||||||
|
|
||||||
// TODO: something has to be done with the avatar's vertical position
|
// TODO: something has to be done with the avatar's vertical position
|
||||||
|
|
||||||
ComputeAvatarVolumeAndMass();
|
ComputeAvatarVolumeAndMass();
|
||||||
|
|
||||||
Scene.TaintedObject("BSCharacter.setSize", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetObjectScaleMass(Scene.WorldID, LocalID, _scale, _mass, true);
|
BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -182,11 +171,6 @@ public class BSCharacter : BSPhysObject
|
||||||
set { _pbs = value;
|
set { _pbs = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override uint LocalID {
|
|
||||||
set { _localID = value;
|
|
||||||
}
|
|
||||||
get { return _localID; }
|
|
||||||
}
|
|
||||||
public override bool Grabbed {
|
public override bool Grabbed {
|
||||||
set { _grabbed = value;
|
set { _grabbed = value;
|
||||||
}
|
}
|
||||||
|
@ -198,9 +182,27 @@ public class BSCharacter : BSPhysObject
|
||||||
public override void CrossingFailure() { return; }
|
public override void CrossingFailure() { return; }
|
||||||
public override void link(PhysicsActor obj) { return; }
|
public override void link(PhysicsActor obj) { return; }
|
||||||
public override void delink() { return; }
|
public override void delink() { return; }
|
||||||
public override void LockAngularMotion(Vector3 axis) { return; }
|
|
||||||
|
|
||||||
public override Vector3 Position {
|
// Set motion values to zero.
|
||||||
|
// Do it to the properties so the values get set in the physics engine.
|
||||||
|
// Push the setting of the values to the viewer.
|
||||||
|
// Called at taint time!
|
||||||
|
public override void ZeroMotion()
|
||||||
|
{
|
||||||
|
_velocity = OMV.Vector3.Zero;
|
||||||
|
_acceleration = OMV.Vector3.Zero;
|
||||||
|
_rotationalVelocity = OMV.Vector3.Zero;
|
||||||
|
|
||||||
|
// Zero some other properties directly into the physics engine
|
||||||
|
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
|
||||||
|
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
|
||||||
|
BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||||
|
BulletSimAPI.ClearForces2(BSBody.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LockAngularMotion(OMV.Vector3 axis) { return; }
|
||||||
|
|
||||||
|
public override OMV.Vector3 Position {
|
||||||
get {
|
get {
|
||||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
||||||
return _position;
|
return _position;
|
||||||
|
@ -209,10 +211,10 @@ public class BSCharacter : BSPhysObject
|
||||||
_position = value;
|
_position = value;
|
||||||
PositionSanityCheck();
|
PositionSanityCheck();
|
||||||
|
|
||||||
Scene.TaintedObject("BSCharacter.setPosition", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||||
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
|
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +227,7 @@ public class BSCharacter : BSPhysObject
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// If below the ground, move the avatar up
|
// If below the ground, move the avatar up
|
||||||
float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position);
|
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
|
||||||
if (Position.Z < terrainHeight)
|
if (Position.Z < terrainHeight)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
||||||
|
@ -247,10 +249,10 @@ public class BSCharacter : BSPhysObject
|
||||||
{
|
{
|
||||||
// The new position value must be pushed into the physics engine but we can't
|
// The new position value must be pushed into the physics engine but we can't
|
||||||
// just assign to "Position" because of potential call loops.
|
// just assign to "Position" because of potential call loops.
|
||||||
Scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||||
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
|
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||||
});
|
});
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -266,15 +268,15 @@ public class BSCharacter : BSPhysObject
|
||||||
// used when we only want this prim's mass and not the linkset thing
|
// used when we only want this prim's mass and not the linkset thing
|
||||||
public override float MassRaw { get {return _mass; } }
|
public override float MassRaw { get {return _mass; } }
|
||||||
|
|
||||||
public override Vector3 Force {
|
public override OMV.Vector3 Force {
|
||||||
get { return _force; }
|
get { return _force; }
|
||||||
set {
|
set {
|
||||||
_force = value;
|
_force = value;
|
||||||
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
|
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
|
||||||
Scene.TaintedObject("BSCharacter.SetForce", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
||||||
BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force);
|
BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,28 +286,28 @@ public class BSCharacter : BSPhysObject
|
||||||
set { return; }
|
set { return; }
|
||||||
}
|
}
|
||||||
public override void VehicleFloatParam(int param, float value) { }
|
public override void VehicleFloatParam(int param, float value) { }
|
||||||
public override void VehicleVectorParam(int param, Vector3 value) {}
|
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
||||||
public override void VehicleRotationParam(int param, Quaternion rotation) { }
|
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
||||||
public override void VehicleFlags(int param, bool remove) { }
|
public override void VehicleFlags(int param, bool remove) { }
|
||||||
|
|
||||||
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
|
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
|
||||||
public override void SetVolumeDetect(int param) { return; }
|
public override void SetVolumeDetect(int param) { return; }
|
||||||
|
|
||||||
public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
|
public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
|
||||||
public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
|
public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
|
||||||
public override Vector3 Velocity {
|
public override OMV.Vector3 Velocity {
|
||||||
get { return _velocity; }
|
get { return _velocity; }
|
||||||
set {
|
set {
|
||||||
_velocity = value;
|
_velocity = value;
|
||||||
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
|
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
|
||||||
Scene.TaintedObject("BSCharacter.setVelocity", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
||||||
BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity);
|
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override Vector3 Torque {
|
public override OMV.Vector3 Torque {
|
||||||
get { return _torque; }
|
get { return _torque; }
|
||||||
set { _torque = value;
|
set { _torque = value;
|
||||||
}
|
}
|
||||||
|
@ -315,19 +317,19 @@ public class BSCharacter : BSPhysObject
|
||||||
set { _collisionScore = value;
|
set { _collisionScore = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override Vector3 Acceleration {
|
public override OMV.Vector3 Acceleration {
|
||||||
get { return _acceleration; }
|
get { return _acceleration; }
|
||||||
set { _acceleration = value; }
|
set { _acceleration = value; }
|
||||||
}
|
}
|
||||||
public override Quaternion Orientation {
|
public override OMV.Quaternion Orientation {
|
||||||
get { return _orientation; }
|
get { return _orientation; }
|
||||||
set {
|
set {
|
||||||
_orientation = value;
|
_orientation = value;
|
||||||
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
|
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
|
||||||
Scene.TaintedObject("BSCharacter.setOrientation", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
||||||
{
|
{
|
||||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
||||||
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
|
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,12 +366,12 @@ public class BSCharacter : BSPhysObject
|
||||||
set { _throttleUpdates = value; }
|
set { _throttleUpdates = value; }
|
||||||
}
|
}
|
||||||
public override bool IsColliding {
|
public override bool IsColliding {
|
||||||
get { return (_collidingStep == Scene.SimulationStep); }
|
get { return (CollidingStep == PhysicsScene.SimulationStep); }
|
||||||
set { _isColliding = value; }
|
set { _isColliding = value; }
|
||||||
}
|
}
|
||||||
public override bool CollidingGround {
|
public override bool CollidingGround {
|
||||||
get { return (_collidingGroundStep == Scene.SimulationStep); }
|
get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
|
||||||
set { _collidingGround = value; }
|
set { CollidingGround = value; }
|
||||||
}
|
}
|
||||||
public override bool CollidingObj {
|
public override bool CollidingObj {
|
||||||
get { return _collidingObj; }
|
get { return _collidingObj; }
|
||||||
|
@ -378,7 +380,7 @@ public class BSCharacter : BSPhysObject
|
||||||
public override bool FloatOnWater {
|
public override bool FloatOnWater {
|
||||||
set { _floatOnWater = value; }
|
set { _floatOnWater = value; }
|
||||||
}
|
}
|
||||||
public override Vector3 RotationalVelocity {
|
public override OMV.Vector3 RotationalVelocity {
|
||||||
get { return _rotationalVelocity; }
|
get { return _rotationalVelocity; }
|
||||||
set { _rotationalVelocity = value; }
|
set { _rotationalVelocity = value; }
|
||||||
}
|
}
|
||||||
|
@ -390,16 +392,16 @@ public class BSCharacter : BSPhysObject
|
||||||
public override float Buoyancy {
|
public override float Buoyancy {
|
||||||
get { return _buoyancy; }
|
get { return _buoyancy; }
|
||||||
set { _buoyancy = value;
|
set { _buoyancy = value;
|
||||||
Scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||||
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
|
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for MoveTo
|
// Used for MoveTo
|
||||||
public override Vector3 PIDTarget {
|
public override OMV.Vector3 PIDTarget {
|
||||||
set { _PIDTarget = value; }
|
set { _PIDTarget = value; }
|
||||||
}
|
}
|
||||||
public override bool PIDActive {
|
public override bool PIDActive {
|
||||||
|
@ -425,22 +427,22 @@ public class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// For RotLookAt
|
// For RotLookAt
|
||||||
public override Quaternion APIDTarget { set { return; } }
|
public override OMV.Quaternion APIDTarget { set { return; } }
|
||||||
public override bool APIDActive { set { return; } }
|
public override bool APIDActive { set { return; } }
|
||||||
public override float APIDStrength { set { return; } }
|
public override float APIDStrength { set { return; } }
|
||||||
public override float APIDDamping { set { return; } }
|
public override float APIDDamping { set { return; } }
|
||||||
|
|
||||||
public override void AddForce(Vector3 force, bool pushforce) {
|
public override void AddForce(OMV.Vector3 force, bool pushforce) {
|
||||||
if (force.IsFinite())
|
if (force.IsFinite())
|
||||||
{
|
{
|
||||||
_force.X += force.X;
|
_force.X += force.X;
|
||||||
_force.Y += force.Y;
|
_force.Y += force.Y;
|
||||||
_force.Z += force.Z;
|
_force.Z += force.Z;
|
||||||
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
|
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
|
||||||
Scene.TaintedObject("BSCharacter.AddForce", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
|
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
|
||||||
BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force);
|
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -450,42 +452,19 @@ public class BSCharacter : BSPhysObject
|
||||||
//m_lastUpdateSent = false;
|
//m_lastUpdateSent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddAngularForce(Vector3 force, bool pushforce) {
|
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
|
||||||
}
|
}
|
||||||
public override void SetMomentum(Vector3 momentum) {
|
public override void SetMomentum(OMV.Vector3 momentum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn on collision events at a rate no faster than one every the given milliseconds
|
private void ComputeAvatarScale(OMV.Vector3 size)
|
||||||
public override void SubscribeEvents(int ms) {
|
|
||||||
_subscribedEventsMs = ms;
|
|
||||||
if (ms > 0)
|
|
||||||
{
|
|
||||||
// make sure first collision happens
|
|
||||||
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
|
|
||||||
|
|
||||||
Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate()
|
|
||||||
{
|
|
||||||
BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ZeroMotion()
|
|
||||||
{
|
{
|
||||||
return;
|
_scale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||||
}
|
_scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
||||||
|
|
||||||
// Stop collision events
|
// The 1.15 came from ODE but it seems to cause the avatar to float off the ground
|
||||||
public override void UnSubscribeEvents() {
|
// _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
|
||||||
_subscribedEventsMs = 0;
|
_scale.Z = (_size.Z) - (_scale.X + _scale.Y);
|
||||||
Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
|
|
||||||
{
|
|
||||||
BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Return 'true' if someone has subscribed to events
|
|
||||||
public override bool SubscribedEvents() {
|
|
||||||
return (_subscribedEventsMs > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
||||||
|
@ -502,7 +481,7 @@ public class BSCharacter : BSPhysObject
|
||||||
* Math.Min(_scale.X, _scale.Y)
|
* Math.Min(_scale.X, _scale.Y)
|
||||||
* _scale.Y // plus the volume of the capsule end caps
|
* _scale.Y // plus the volume of the capsule end caps
|
||||||
);
|
);
|
||||||
_mass = _density * _avatarVolume;
|
_mass = _avatarDensity * _avatarVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The physics engine says that properties have updated. Update same and inform
|
// The physics engine says that properties have updated. Update same and inform
|
||||||
|
@ -520,67 +499,9 @@ public class BSCharacter : BSPhysObject
|
||||||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||||
PositionSanityCheck2();
|
PositionSanityCheck2();
|
||||||
|
|
||||||
float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
|
float heightHere = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
|
||||||
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
|
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
|
||||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
|
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by the scene when a collision with this object is reported
|
|
||||||
// The collision, if it should be reported to the character, is placed in a collection
|
|
||||||
// that will later be sent to the simulator when SendCollisions() is called.
|
|
||||||
CollisionEventUpdate collisionCollection = null;
|
|
||||||
public override bool Collide(uint collidingWith, BSPhysObject collidee, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
// The following makes IsColliding() and IsCollidingGround() work
|
|
||||||
_collidingStep = Scene.SimulationStep;
|
|
||||||
if (collidingWith <= Scene.TerrainManager.HighestTerrainID)
|
|
||||||
{
|
|
||||||
_collidingGroundStep = Scene.SimulationStep;
|
|
||||||
}
|
|
||||||
// DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
|
|
||||||
|
|
||||||
// throttle collisions to the rate specified in the subscription
|
|
||||||
if (SubscribedEvents()) {
|
|
||||||
int nowTime = Scene.SimulationNowTime;
|
|
||||||
if (nowTime >= _nextCollisionOkTime) {
|
|
||||||
_nextCollisionOkTime = nowTime + _subscribedEventsMs;
|
|
||||||
|
|
||||||
if (collisionCollection == null)
|
|
||||||
collisionCollection = new CollisionEventUpdate();
|
|
||||||
collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SendCollisions()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if (collisionCollection != null && collisionCollection.Count > 0)
|
|
||||||
{
|
|
||||||
base.SendCollisionUpdate(collisionCollection);
|
|
||||||
collisionCollection = null;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Kludge to make a collision call even if there are no collisions.
|
|
||||||
// This causes the avatar animation to get updated.
|
|
||||||
if (collisionCollection == null)
|
|
||||||
collisionCollection = new CollisionEventUpdate();
|
|
||||||
base.SendCollisionUpdate(collisionCollection);
|
|
||||||
// If there were any collisions in the collection, make sure we don't use the
|
|
||||||
// same instance next time.
|
|
||||||
if (collisionCollection.Count > 0)
|
|
||||||
collisionCollection = null;
|
|
||||||
// End kludge
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke the detailed logger and output something if it's enabled.
|
|
||||||
private void DetailLog(string msg, params Object[] args)
|
|
||||||
{
|
|
||||||
Scene.PhysicsLogging.Write(msg, args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,20 +49,23 @@ public abstract class BSConstraint : IDisposable
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
{
|
{
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
|
bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
|
||||||
m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
|
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
|
||||||
m_constraint.Ptr = System.IntPtr.Zero;
|
m_constraint.ptr = System.IntPtr.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BulletBody Body1 { get { return m_body1; } }
|
public BulletBody Body1 { get { return m_body1; } }
|
||||||
public BulletBody Body2 { get { return m_body2; } }
|
public BulletBody Body2 { get { return m_body2; } }
|
||||||
|
public BulletConstraint Constraint { get { return m_constraint; } }
|
||||||
|
public abstract ConstraintType Type { get; }
|
||||||
|
|
||||||
|
|
||||||
public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
|
public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high);
|
ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +73,7 @@ public abstract class BSConstraint : IDisposable
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high);
|
ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ public abstract class BSConstraint : IDisposable
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.Ptr, cnt);
|
BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable
|
||||||
if (m_enabled)
|
if (m_enabled)
|
||||||
{
|
{
|
||||||
// Recompute the internal transforms
|
// Recompute the internal transforms
|
||||||
BulletSimAPI.CalculateTransforms2(m_constraint.Ptr);
|
BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -110,11 +113,11 @@ public abstract class BSConstraint : IDisposable
|
||||||
// Setting an object's mass to zero (making it static like when it's selected)
|
// Setting an object's mass to zero (making it static like when it's selected)
|
||||||
// automatically disables the constraints.
|
// automatically disables the constraints.
|
||||||
// If the link is enabled, be sure to set the constraint itself to enabled.
|
// If the link is enabled, be sure to set the constraint itself to enabled.
|
||||||
BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true));
|
BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
|
m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -54,18 +54,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public class BSDynamics
|
public class BSDynamics
|
||||||
{
|
{
|
||||||
private int frcount = 0; // Used to limit dynamics debug output to
|
private BSScene PhysicsScene { get; set; }
|
||||||
// every 100th frame
|
// the prim this dynamic controller belongs to
|
||||||
|
private BSPrim Prim { get; set; }
|
||||||
private BSScene m_physicsScene;
|
|
||||||
private BSPrim m_prim; // the prim this dynamic controller belongs to
|
|
||||||
|
|
||||||
// Vehicle properties
|
// Vehicle properties
|
||||||
private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
|
public Vehicle Type { get; set; }
|
||||||
public Vehicle Type
|
|
||||||
{
|
|
||||||
get { return m_type; }
|
|
||||||
}
|
|
||||||
// private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
|
// private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
|
||||||
private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
|
private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
|
||||||
// HOVER_TERRAIN_ONLY
|
// HOVER_TERRAIN_ONLY
|
||||||
|
@ -126,14 +121,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
public BSDynamics(BSScene myScene, BSPrim myPrim)
|
public BSDynamics(BSScene myScene, BSPrim myPrim)
|
||||||
{
|
{
|
||||||
m_physicsScene = myScene;
|
PhysicsScene = myScene;
|
||||||
m_prim = myPrim;
|
Prim = myPrim;
|
||||||
m_type = Vehicle.TYPE_NONE;
|
Type = Vehicle.TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return 'true' if this vehicle is doing vehicle things
|
||||||
|
public bool IsActive
|
||||||
|
{
|
||||||
|
get { return Type != Vehicle.TYPE_NONE; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
|
internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
|
||||||
{
|
{
|
||||||
VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
|
VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
|
||||||
switch (pParam)
|
switch (pParam)
|
||||||
{
|
{
|
||||||
case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
|
case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
|
||||||
|
@ -232,7 +233,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
|
internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
|
||||||
{
|
{
|
||||||
VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
|
VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
|
||||||
switch (pParam)
|
switch (pParam)
|
||||||
{
|
{
|
||||||
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
|
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
|
||||||
|
@ -267,7 +268,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
|
internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
|
||||||
{
|
{
|
||||||
VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
|
VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
|
||||||
switch (pParam)
|
switch (pParam)
|
||||||
{
|
{
|
||||||
case Vehicle.REFERENCE_FRAME:
|
case Vehicle.REFERENCE_FRAME:
|
||||||
|
@ -281,7 +282,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
internal void ProcessVehicleFlags(int pParam, bool remove)
|
internal void ProcessVehicleFlags(int pParam, bool remove)
|
||||||
{
|
{
|
||||||
VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove);
|
VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
|
||||||
VehicleFlag parm = (VehicleFlag)pParam;
|
VehicleFlag parm = (VehicleFlag)pParam;
|
||||||
if (remove)
|
if (remove)
|
||||||
{
|
{
|
||||||
|
@ -301,9 +302,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
internal void ProcessTypeChange(Vehicle pType)
|
internal void ProcessTypeChange(Vehicle pType)
|
||||||
{
|
{
|
||||||
VDetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType);
|
VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
|
||||||
// Set Defaults For Type
|
// Set Defaults For Type
|
||||||
m_type = pType;
|
Type = pType;
|
||||||
switch (pType)
|
switch (pType)
|
||||||
{
|
{
|
||||||
case Vehicle.TYPE_NONE:
|
case Vehicle.TYPE_NONE:
|
||||||
|
@ -465,26 +466,37 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
}//end SetDefaultsForType
|
}//end SetDefaultsForType
|
||||||
|
|
||||||
|
// Some of the properties of this prim may have changed.
|
||||||
|
// Do any updating needed for a vehicle
|
||||||
|
public void Refresh()
|
||||||
|
{
|
||||||
|
if (Type == Vehicle.TYPE_NONE) return;
|
||||||
|
|
||||||
|
// Set the prim's inertia to zero. The vehicle code handles that and this
|
||||||
|
// removes the torque action introduced by Bullet.
|
||||||
|
Vector3 inertia = Vector3.Zero;
|
||||||
|
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
|
||||||
|
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
// One step of the vehicle properties for the next 'pTimestep' seconds.
|
// One step of the vehicle properties for the next 'pTimestep' seconds.
|
||||||
internal void Step(float pTimestep)
|
internal void Step(float pTimestep)
|
||||||
{
|
{
|
||||||
if (m_type == Vehicle.TYPE_NONE) return;
|
if (!IsActive) return;
|
||||||
|
|
||||||
frcount++; // used to limit debug comment output
|
|
||||||
if (frcount > 100)
|
|
||||||
frcount = 0;
|
|
||||||
|
|
||||||
MoveLinear(pTimestep);
|
MoveLinear(pTimestep);
|
||||||
MoveAngular(pTimestep);
|
MoveAngular(pTimestep);
|
||||||
LimitRotation(pTimestep);
|
LimitRotation(pTimestep);
|
||||||
|
|
||||||
// remember the position so next step we can limit absolute movement effects
|
// remember the position so next step we can limit absolute movement effects
|
||||||
m_lastPositionVector = m_prim.Position;
|
m_lastPositionVector = Prim.Position;
|
||||||
|
|
||||||
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
|
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
|
||||||
m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity);
|
Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity);
|
||||||
}// end Step
|
}// end Step
|
||||||
|
|
||||||
|
// Apply the effect of the linear motor.
|
||||||
|
// Also does hover and float.
|
||||||
private void MoveLinear(float pTimestep)
|
private void MoveLinear(float pTimestep)
|
||||||
{
|
{
|
||||||
// m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
|
// m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
|
||||||
|
@ -520,18 +532,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_linearMotorDirection *= keepfraction;
|
m_linearMotorDirection *= keepfraction;
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
|
VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
|
||||||
m_prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
|
Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if what remains of direction is very small, zero it.
|
// if what remains of direction is very small, zero it.
|
||||||
m_linearMotorDirection = Vector3.Zero;
|
m_linearMotorDirection = Vector3.Zero;
|
||||||
m_lastLinearVelocityVector = Vector3.Zero;
|
m_lastLinearVelocityVector = Vector3.Zero;
|
||||||
VDetailLog("{0},MoveLinear,zeroed", m_prim.LocalID);
|
VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert requested object velocity to object relative vector
|
// convert requested object velocity to object relative vector
|
||||||
Quaternion rotq = m_prim.Orientation;
|
Quaternion rotq = Prim.Orientation;
|
||||||
m_newVelocity = m_lastLinearVelocityVector * rotq;
|
m_newVelocity = m_lastLinearVelocityVector * rotq;
|
||||||
|
|
||||||
// Add the various forces into m_dir which will be our new direction vector (velocity)
|
// Add the various forces into m_dir which will be our new direction vector (velocity)
|
||||||
|
@ -539,7 +551,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// add Gravity and Buoyancy
|
// add Gravity and Buoyancy
|
||||||
// There is some gravity, make a gravity force vector that is applied after object velocity.
|
// There is some gravity, make a gravity force vector that is applied after object velocity.
|
||||||
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
|
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
|
||||||
Vector3 grav = m_prim.Scene.DefaultGravity * (m_prim.Mass * (1f - m_VehicleBuoyancy));
|
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RA: Not sure why one would do this
|
* RA: Not sure why one would do this
|
||||||
|
@ -548,11 +560,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
|
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Vector3 pos = m_prim.Position;
|
Vector3 pos = Prim.Position;
|
||||||
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
|
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
|
||||||
|
|
||||||
// If below the terrain, move us above the ground a little.
|
// If below the terrain, move us above the ground a little.
|
||||||
float terrainHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos);
|
float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
|
||||||
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
|
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
|
||||||
// Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
|
// Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
|
||||||
// Vector3 rotatedSize = m_prim.Size * m_prim.Orientation;
|
// Vector3 rotatedSize = m_prim.Size * m_prim.Orientation;
|
||||||
|
@ -560,8 +572,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
if (pos.Z < terrainHeight)
|
if (pos.Z < terrainHeight)
|
||||||
{
|
{
|
||||||
pos.Z = terrainHeight + 2;
|
pos.Z = terrainHeight + 2;
|
||||||
m_prim.Position = pos;
|
Prim.Position = pos;
|
||||||
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", m_prim.LocalID, terrainHeight, pos);
|
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if hovering
|
// Check if hovering
|
||||||
|
@ -570,7 +582,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// We should hover, get the target height
|
// We should hover, get the target height
|
||||||
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
|
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
|
||||||
{
|
{
|
||||||
m_VhoverTargetHeight = m_prim.Scene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
|
m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
|
||||||
}
|
}
|
||||||
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
|
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
|
||||||
{
|
{
|
||||||
|
@ -590,7 +602,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
|
if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
|
||||||
{
|
{
|
||||||
m_prim.Position = pos;
|
Prim.Position = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -608,7 +620,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
|
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 posChange = pos - m_lastPositionVector;
|
Vector3 posChange = pos - m_lastPositionVector;
|
||||||
|
@ -642,9 +654,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
m_prim.Position = pos;
|
Prim.Position = pos;
|
||||||
VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
|
VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
|
||||||
m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
|
Prim.LocalID, m_BlockingEndPoint, posChange, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +676,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
float postemp = (pos.Z - terrainHeight);
|
float postemp = (pos.Z - terrainHeight);
|
||||||
if (postemp > 2.5f)
|
if (postemp > 2.5f)
|
||||||
grav.Z = (float)(grav.Z * 1.037125);
|
grav.Z = (float)(grav.Z * 1.037125);
|
||||||
VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
|
VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav);
|
||||||
}
|
}
|
||||||
if ((m_flags & (VehicleFlag.NO_X)) != 0)
|
if ((m_flags & (VehicleFlag.NO_X)) != 0)
|
||||||
m_newVelocity.X = 0;
|
m_newVelocity.X = 0;
|
||||||
|
@ -674,7 +686,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_newVelocity.Z = 0;
|
m_newVelocity.Z = 0;
|
||||||
|
|
||||||
// Apply velocity
|
// Apply velocity
|
||||||
m_prim.Velocity = m_newVelocity;
|
Prim.Velocity = m_newVelocity;
|
||||||
// apply gravity force
|
// apply gravity force
|
||||||
// Why is this set here? The physics engine already does gravity.
|
// Why is this set here? The physics engine already does gravity.
|
||||||
// m_prim.AddForce(grav, false);
|
// m_prim.AddForce(grav, false);
|
||||||
|
@ -684,10 +696,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_lastLinearVelocityVector *= keepFraction;
|
m_lastLinearVelocityVector *= keepFraction;
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
|
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
|
||||||
m_prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
|
Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
|
||||||
|
|
||||||
} // end MoveLinear()
|
} // end MoveLinear()
|
||||||
|
|
||||||
|
// Apply the effect of the angular motor.
|
||||||
private void MoveAngular(float pTimestep)
|
private void MoveAngular(float pTimestep)
|
||||||
{
|
{
|
||||||
// m_angularMotorDirection // angular velocity requested by LSL motor
|
// m_angularMotorDirection // angular velocity requested by LSL motor
|
||||||
|
@ -699,7 +712,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// m_lastAngularVelocity // what was last applied to body
|
// m_lastAngularVelocity // what was last applied to body
|
||||||
|
|
||||||
// Get what the body is doing, this includes 'external' influences
|
// Get what the body is doing, this includes 'external' influences
|
||||||
Vector3 angularVelocity = m_prim.RotationalVelocity;
|
Vector3 angularVelocity = Prim.RotationalVelocity;
|
||||||
|
|
||||||
if (m_angularMotorApply > 0)
|
if (m_angularMotorApply > 0)
|
||||||
{
|
{
|
||||||
|
@ -716,7 +729,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
|
m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
|
||||||
|
|
||||||
VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}",
|
VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}",
|
||||||
m_prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
|
Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
|
||||||
|
|
||||||
// This is done so that if script request rate is less than phys frame rate the expected
|
// This is done so that if script request rate is less than phys frame rate the expected
|
||||||
// velocity may still be acheived.
|
// velocity may still be acheived.
|
||||||
|
@ -737,7 +750,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
|
float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
|
||||||
// get present body rotation
|
// get present body rotation
|
||||||
Quaternion rotq = m_prim.Orientation;
|
Quaternion rotq = Prim.Orientation;
|
||||||
// make a vector pointing up
|
// make a vector pointing up
|
||||||
Vector3 verterr = Vector3.Zero;
|
Vector3 verterr = Vector3.Zero;
|
||||||
verterr.Z = 1.0f;
|
verterr.Z = 1.0f;
|
||||||
|
@ -767,7 +780,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
vertattr.Y += bounce * angularVelocity.Y;
|
vertattr.Y += bounce * angularVelocity.Y;
|
||||||
|
|
||||||
VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
|
VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
|
||||||
m_prim.LocalID, verterr, bounce, vertattr);
|
Prim.LocalID, verterr, bounce, vertattr);
|
||||||
|
|
||||||
} // else vertical attractor is off
|
} // else vertical attractor is off
|
||||||
|
|
||||||
|
@ -784,13 +797,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
m_lastAngularVelocity.X = 0;
|
m_lastAngularVelocity.X = 0;
|
||||||
m_lastAngularVelocity.Y = 0;
|
m_lastAngularVelocity.Y = 0;
|
||||||
VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
|
VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
|
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
|
||||||
{
|
{
|
||||||
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
|
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
|
||||||
VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
|
VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply friction
|
// apply friction
|
||||||
|
@ -798,14 +811,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
|
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
|
||||||
|
|
||||||
// Apply to the body
|
// Apply to the body
|
||||||
m_prim.RotationalVelocity = m_lastAngularVelocity;
|
Prim.RotationalVelocity = m_lastAngularVelocity;
|
||||||
|
|
||||||
VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity);
|
VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
|
||||||
} //end MoveAngular
|
} //end MoveAngular
|
||||||
|
|
||||||
internal void LimitRotation(float timestep)
|
internal void LimitRotation(float timestep)
|
||||||
{
|
{
|
||||||
Quaternion rotq = m_prim.Orientation;
|
Quaternion rotq = Prim.Orientation;
|
||||||
Quaternion m_rot = rotq;
|
Quaternion m_rot = rotq;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (m_RollreferenceFrame != Quaternion.Identity)
|
if (m_RollreferenceFrame != Quaternion.Identity)
|
||||||
|
@ -840,8 +853,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
m_prim.Orientation = m_rot;
|
Prim.Orientation = m_rot;
|
||||||
VDetailLog("{0},LimitRotation,done,orig={1},new={2}", m_prim.LocalID, rotq, m_rot);
|
VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -849,8 +862,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// Invoke the detailed logger and output something if it's enabled.
|
// Invoke the detailed logger and output something if it's enabled.
|
||||||
private void VDetailLog(string msg, params Object[] args)
|
private void VDetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
if (m_prim.Scene.VehicleLoggingEnabled)
|
if (Prim.PhysicsScene.VehicleLoggingEnabled)
|
||||||
m_prim.Scene.PhysicsLogging.Write(msg, args);
|
Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
*
|
*
|
||||||
|
@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
class BSHingeConstraint : BSConstraint
|
class BSHingeConstraint : BSConstraint
|
||||||
{
|
{
|
||||||
|
public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
|
||||||
|
|
||||||
public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
|
||||||
Vector3 pivotInA, Vector3 pivotInB,
|
Vector3 pivotInA, Vector3 pivotInB,
|
||||||
Vector3 axisInA, Vector3 axisInB,
|
Vector3 axisInA, Vector3 axisInB,
|
||||||
|
@ -43,7 +45,7 @@ class BSHingeConstraint : BSConstraint
|
||||||
m_body1 = obj1;
|
m_body1 = obj1;
|
||||||
m_body2 = obj2;
|
m_body2 = obj2;
|
||||||
m_constraint = new BulletConstraint(
|
m_constraint = new BulletConstraint(
|
||||||
BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
|
BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
|
||||||
pivotInA, pivotInB,
|
pivotInA, pivotInB,
|
||||||
axisInA, axisInB,
|
axisInA, axisInB,
|
||||||
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
|
||||||
|
|
|
@ -36,17 +36,24 @@ public class BSLinkset
|
||||||
{
|
{
|
||||||
private static string LogHeader = "[BULLETSIM LINKSET]";
|
private static string LogHeader = "[BULLETSIM LINKSET]";
|
||||||
|
|
||||||
private BSPhysObject m_linksetRoot;
|
public BSPhysObject LinksetRoot { get; protected set; }
|
||||||
public BSPhysObject LinksetRoot { get { return m_linksetRoot; } }
|
|
||||||
|
|
||||||
private BSScene m_physicsScene;
|
public BSScene PhysicsScene { get; private set; }
|
||||||
public BSScene PhysicsScene { get { return m_physicsScene; } }
|
|
||||||
|
|
||||||
static int m_nextLinksetID = 1;
|
static int m_nextLinksetID = 1;
|
||||||
public int LinksetID { get; private set; }
|
public int LinksetID { get; private set; }
|
||||||
|
|
||||||
// The children under the root in this linkset
|
// The children under the root in this linkset.
|
||||||
|
// There are two lists of children: the current children at runtime
|
||||||
|
// and the children at taint-time. For instance, if you delink a
|
||||||
|
// child from the linkset, the child is removed from m_children
|
||||||
|
// but the constraint won't be removed until taint time.
|
||||||
|
// Two lists lets this track the 'current' children and
|
||||||
|
// the physical 'taint' children separately.
|
||||||
|
// After taint processing and before the simulation step, these
|
||||||
|
// two lists must be the same.
|
||||||
private List<BSPhysObject> m_children;
|
private List<BSPhysObject> m_children;
|
||||||
|
private List<BSPhysObject> m_taintChildren;
|
||||||
|
|
||||||
// We lock the diddling of linkset classes to prevent any badness.
|
// We lock the diddling of linkset classes to prevent any badness.
|
||||||
// This locks the modification of the instances of this class. Changes
|
// This locks the modification of the instances of this class. Changes
|
||||||
|
@ -79,22 +86,26 @@ public class BSLinkset
|
||||||
// A simple linkset of one (no children)
|
// A simple linkset of one (no children)
|
||||||
LinksetID = m_nextLinksetID++;
|
LinksetID = m_nextLinksetID++;
|
||||||
// We create LOTS of linksets.
|
// We create LOTS of linksets.
|
||||||
if (m_nextLinksetID < 0)
|
if (m_nextLinksetID <= 0)
|
||||||
m_nextLinksetID = 1;
|
m_nextLinksetID = 1;
|
||||||
m_physicsScene = scene;
|
PhysicsScene = scene;
|
||||||
m_linksetRoot = parent;
|
LinksetRoot = parent;
|
||||||
m_children = new List<BSPhysObject>();
|
m_children = new List<BSPhysObject>();
|
||||||
|
m_taintChildren = new List<BSPhysObject>();
|
||||||
m_mass = parent.MassRaw;
|
m_mass = parent.MassRaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link to a linkset where the child knows the parent.
|
// Link to a linkset where the child knows the parent.
|
||||||
// Parent changing should not happen so do some sanity checking.
|
// Parent changing should not happen so do some sanity checking.
|
||||||
// We return the parent's linkset so the child can track its membership.
|
// We return the parent's linkset so the child can track its membership.
|
||||||
|
// Called at runtime.
|
||||||
public BSLinkset AddMeToLinkset(BSPhysObject child)
|
public BSLinkset AddMeToLinkset(BSPhysObject child)
|
||||||
{
|
{
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
AddChildToLinkset(child);
|
// Don't add the root to its own linkset
|
||||||
|
if (!IsRoot(child))
|
||||||
|
AddChildToLinkset(child);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -102,26 +113,18 @@ public class BSLinkset
|
||||||
// Remove a child from a linkset.
|
// Remove a child from a linkset.
|
||||||
// Returns a new linkset for the child which is a linkset of one (just the
|
// Returns a new linkset for the child which is a linkset of one (just the
|
||||||
// orphened child).
|
// orphened child).
|
||||||
|
// Called at runtime.
|
||||||
public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
|
public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
|
||||||
{
|
{
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
if (IsRoot(child))
|
if (IsRoot(child))
|
||||||
{
|
{
|
||||||
// if root of linkset, take the linkset apart
|
// Cannot remove the root from a linkset.
|
||||||
while (m_children.Count > 0)
|
return this;
|
||||||
{
|
|
||||||
// Note that we don't do a foreach because the remove routine
|
|
||||||
// takes it out of the list.
|
|
||||||
RemoveChildFromOtherLinkset(m_children[0]);
|
|
||||||
}
|
|
||||||
m_children.Clear(); // just to make sure
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Just removing a child from an existing linkset
|
|
||||||
RemoveChildFromLinkset(child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoveChildFromLinkset(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The child is down to a linkset of just itself
|
// The child is down to a linkset of just itself
|
||||||
|
@ -131,7 +134,7 @@ public class BSLinkset
|
||||||
// Return 'true' if the passed object is the root object of this linkset
|
// Return 'true' if the passed object is the root object of this linkset
|
||||||
public bool IsRoot(BSPhysObject requestor)
|
public bool IsRoot(BSPhysObject requestor)
|
||||||
{
|
{
|
||||||
return (requestor.LocalID == m_linksetRoot.LocalID);
|
return (requestor.LocalID == LinksetRoot.LocalID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int NumberOfChildren { get { return m_children.Count; } }
|
public int NumberOfChildren { get { return m_children.Count; } }
|
||||||
|
@ -157,51 +160,6 @@ public class BSLinkset
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float ComputeLinksetMass()
|
|
||||||
{
|
|
||||||
float mass = m_linksetRoot.MassRaw;
|
|
||||||
foreach (BSPhysObject bp in m_children)
|
|
||||||
{
|
|
||||||
mass += bp.MassRaw;
|
|
||||||
}
|
|
||||||
return mass;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OMV.Vector3 ComputeLinksetCenterOfMass()
|
|
||||||
{
|
|
||||||
OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
|
|
||||||
float totalMass = m_linksetRoot.MassRaw;
|
|
||||||
|
|
||||||
lock (m_linksetActivityLock)
|
|
||||||
{
|
|
||||||
foreach (BSPhysObject bp in m_children)
|
|
||||||
{
|
|
||||||
com += bp.Position * bp.MassRaw;
|
|
||||||
totalMass += bp.MassRaw;
|
|
||||||
}
|
|
||||||
if (totalMass != 0f)
|
|
||||||
com /= totalMass;
|
|
||||||
}
|
|
||||||
|
|
||||||
return com;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OMV.Vector3 ComputeLinksetGeometricCenter()
|
|
||||||
{
|
|
||||||
OMV.Vector3 com = m_linksetRoot.Position;
|
|
||||||
|
|
||||||
lock (m_linksetActivityLock)
|
|
||||||
{
|
|
||||||
foreach (BSPhysObject bp in m_children)
|
|
||||||
{
|
|
||||||
com += bp.Position * bp.MassRaw;
|
|
||||||
}
|
|
||||||
com /= (m_children.Count + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return com;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The object is going dynamic (physical). Do any setup necessary
|
// The object is going dynamic (physical). Do any setup necessary
|
||||||
// for a dynamic linkset.
|
// for a dynamic linkset.
|
||||||
// Only the state of the passed object can be modified. The rest of the linkset
|
// Only the state of the passed object can be modified. The rest of the linkset
|
||||||
|
@ -210,8 +168,8 @@ public class BSLinkset
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public bool MakeDynamic(BSPhysObject child)
|
public bool MakeDynamic(BSPhysObject child)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
// What is done for each object in BSPrim is what we want.
|
||||||
return ret;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object is going static (non-physical). Do any setup necessary
|
// The object is going static (non-physical). Do any setup necessary
|
||||||
|
@ -226,6 +184,7 @@ public class BSLinkset
|
||||||
|
|
||||||
// When physical properties are changed the linkset needs to recalculate
|
// When physical properties are changed the linkset needs to recalculate
|
||||||
// its internal properties.
|
// its internal properties.
|
||||||
|
// Called at runtime.
|
||||||
public void Refresh(BSPhysObject requestor)
|
public void Refresh(BSPhysObject requestor)
|
||||||
{
|
{
|
||||||
// If there are no children, there can't be any constraints to recompute
|
// If there are no children, there can't be any constraints to recompute
|
||||||
|
@ -242,58 +201,125 @@ public class BSLinkset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call each of the constraints that make up this linkset and recompute the
|
// Routine used when rebuilding the body of the root of the linkset
|
||||||
// various transforms and variables. Used when objects are added or removed
|
// Destroy all the constraints have have been made to root.
|
||||||
// from a linkset to make sure the constraints know about the new mass and
|
// This is called when the root body is changing.
|
||||||
// geometry.
|
// Returns 'true' of something eas actually removed and would need restoring
|
||||||
// Must only be called at taint time!!
|
// Called at taint-time!!
|
||||||
private void RecomputeLinksetConstraintVariables()
|
public bool RemoveBodyDependencies(BSPrim child)
|
||||||
{
|
{
|
||||||
float linksetMass = LinksetMass;
|
bool ret = false;
|
||||||
|
|
||||||
lock (m_linksetActivityLock)
|
lock (m_linksetActivityLock)
|
||||||
{
|
{
|
||||||
bool somethingMissing = false;
|
if (IsRoot(child))
|
||||||
foreach (BSPhysObject child in m_children)
|
|
||||||
{
|
{
|
||||||
BSConstraint constrain;
|
// If the one with the dependency is root, must undo all children
|
||||||
if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
|
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
|
||||||
|
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
|
||||||
|
foreach (BSPhysObject bpo in m_taintChildren)
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
|
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
|
||||||
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
|
ret = true;
|
||||||
constrain.RecomputeConstraintVariables(linksetMass);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Non-fatal error that happens when children are being added to the linkset but
|
|
||||||
// their constraints have not been created yet.
|
|
||||||
// Caused by the fact that m_children is built at run time but building constraints
|
|
||||||
// happens at taint time.
|
|
||||||
somethingMissing = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values
|
|
||||||
if (!somethingMissing)
|
|
||||||
{
|
{
|
||||||
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
|
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
|
||||||
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
|
child.LocalID,
|
||||||
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity);
|
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
|
||||||
foreach (BSPhysObject child in m_children)
|
child.LocalID, child.BSBody.ptr.ToString("X"));
|
||||||
|
// Remove the dependency on the body of this one
|
||||||
|
if (m_taintChildren.Contains(child))
|
||||||
{
|
{
|
||||||
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity);
|
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
|
||||||
|
ret = true;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// The root prim takes on the weight of the whole linkset
|
|
||||||
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(LinksetRoot.BSShape.Ptr, linksetMass);
|
|
||||||
BulletSimAPI.SetMassProps2(LinksetRoot.BSBody.Ptr, linksetMass, inertia);
|
|
||||||
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
|
|
||||||
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity);
|
|
||||||
BulletSimAPI.UpdateInertiaTensor2(LinksetRoot.BSBody.Ptr);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Routine used when rebuilding the body of the root of the linkset
|
||||||
|
// This is called after RemoveAllLinksToRoot() to restore all the constraints.
|
||||||
|
// This is called when the root body has been changed.
|
||||||
|
// Called at taint-time!!
|
||||||
|
public void RestoreBodyDependencies(BSPrim child)
|
||||||
|
{
|
||||||
|
lock (m_linksetActivityLock)
|
||||||
|
{
|
||||||
|
if (IsRoot(child))
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
|
||||||
|
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
|
||||||
|
foreach (BSPhysObject bpo in m_taintChildren)
|
||||||
|
{
|
||||||
|
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
|
||||||
|
LinksetRoot.LocalID,
|
||||||
|
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
|
||||||
|
child.LocalID, child.BSBody.ptr.ToString("X"));
|
||||||
|
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// Below this point is internal magic
|
||||||
|
|
||||||
|
private float ComputeLinksetMass()
|
||||||
|
{
|
||||||
|
float mass;
|
||||||
|
lock (m_linksetActivityLock)
|
||||||
|
{
|
||||||
|
mass = LinksetRoot.MassRaw;
|
||||||
|
foreach (BSPhysObject bp in m_taintChildren)
|
||||||
|
{
|
||||||
|
mass += bp.MassRaw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OMV.Vector3 ComputeLinksetCenterOfMass()
|
||||||
|
{
|
||||||
|
OMV.Vector3 com;
|
||||||
|
lock (m_linksetActivityLock)
|
||||||
|
{
|
||||||
|
com = LinksetRoot.Position * LinksetRoot.MassRaw;
|
||||||
|
float totalMass = LinksetRoot.MassRaw;
|
||||||
|
|
||||||
|
foreach (BSPhysObject bp in m_taintChildren)
|
||||||
|
{
|
||||||
|
com += bp.Position * bp.MassRaw;
|
||||||
|
totalMass += bp.MassRaw;
|
||||||
|
}
|
||||||
|
if (totalMass != 0f)
|
||||||
|
com /= totalMass;
|
||||||
|
}
|
||||||
|
|
||||||
|
return com;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OMV.Vector3 ComputeLinksetGeometricCenter()
|
||||||
|
{
|
||||||
|
OMV.Vector3 com;
|
||||||
|
lock (m_linksetActivityLock)
|
||||||
|
{
|
||||||
|
com = LinksetRoot.Position;
|
||||||
|
|
||||||
|
foreach (BSPhysObject bp in m_taintChildren)
|
||||||
|
{
|
||||||
|
com += bp.Position * bp.MassRaw;
|
||||||
|
}
|
||||||
|
com /= (m_taintChildren.Count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return com;
|
||||||
}
|
}
|
||||||
|
|
||||||
// I am the root of a linkset and a new child is being added
|
// I am the root of a linkset and a new child is being added
|
||||||
|
@ -304,12 +330,22 @@ public class BSLinkset
|
||||||
{
|
{
|
||||||
m_children.Add(child);
|
m_children.Add(child);
|
||||||
|
|
||||||
BSPhysObject rootx = LinksetRoot; // capture the root as of now
|
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
|
||||||
|
BulletBody rootBodyx = LinksetRoot.BSBody;
|
||||||
BSPhysObject childx = child;
|
BSPhysObject childx = child;
|
||||||
m_physicsScene.TaintedObject("AddChildToLinkset", delegate()
|
BulletBody childBodyx = child.BSBody;
|
||||||
|
|
||||||
|
DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
|
||||||
|
rootx.LocalID,
|
||||||
|
rootx.LocalID, rootBodyx.ptr.ToString("X"),
|
||||||
|
childx.LocalID, childBodyx.ptr.ToString("X"));
|
||||||
|
|
||||||
|
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
|
DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
|
||||||
PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child
|
// build the physical binding between me and the child
|
||||||
|
m_taintChildren.Add(childx);
|
||||||
|
PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -319,10 +355,10 @@ public class BSLinkset
|
||||||
// This is not being called by the child so we have to make sure the child doesn't think
|
// This is not being called by the child so we have to make sure the child doesn't think
|
||||||
// it's still connected to the linkset.
|
// it's still connected to the linkset.
|
||||||
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
|
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
|
||||||
// has to be updated also (like pointer to prim's parent).
|
// also has to be updated (like pointer to prim's parent).
|
||||||
private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
|
private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
|
||||||
{
|
{
|
||||||
pchild.Linkset = new BSLinkset(m_physicsScene, pchild);
|
pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
|
||||||
RemoveChildFromLinkset(pchild);
|
RemoveChildFromLinkset(pchild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,13 +368,22 @@ public class BSLinkset
|
||||||
{
|
{
|
||||||
if (m_children.Remove(child))
|
if (m_children.Remove(child))
|
||||||
{
|
{
|
||||||
BSPhysObject rootx = LinksetRoot; // capture the root as of now
|
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
|
||||||
|
BulletBody rootBodyx = LinksetRoot.BSBody;
|
||||||
BSPhysObject childx = child;
|
BSPhysObject childx = child;
|
||||||
m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
|
BulletBody childBodyx = child.BSBody;
|
||||||
{
|
|
||||||
DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
|
|
||||||
|
|
||||||
PhysicallyUnlinkAChildFromRoot(rootx, childx);
|
DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
|
||||||
|
childx.LocalID,
|
||||||
|
rootx.LocalID, rootBodyx.ptr.ToString("X"),
|
||||||
|
childx.LocalID, childBodyx.ptr.ToString("X"));
|
||||||
|
|
||||||
|
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
|
||||||
|
{
|
||||||
|
if (m_taintChildren.Contains(childx))
|
||||||
|
m_taintChildren.Remove(childx);
|
||||||
|
|
||||||
|
PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
|
||||||
RecomputeLinksetConstraintVariables();
|
RecomputeLinksetConstraintVariables();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -353,7 +398,8 @@ public class BSLinkset
|
||||||
|
|
||||||
// Create a constraint between me (root of linkset) and the passed prim (the child).
|
// Create a constraint between me (root of linkset) and the passed prim (the child).
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
|
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
|
||||||
|
BSPhysObject childPrim, BulletBody childBody)
|
||||||
{
|
{
|
||||||
// Zero motion for children so they don't interpolate
|
// Zero motion for children so they don't interpolate
|
||||||
childPrim.ZeroMotion();
|
childPrim.ZeroMotion();
|
||||||
|
@ -365,18 +411,36 @@ public class BSLinkset
|
||||||
// real world coordinate of midpoint between the two objects
|
// real world coordinate of midpoint between the two objects
|
||||||
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
|
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
|
||||||
|
|
||||||
|
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
|
||||||
|
rootPrim.LocalID,
|
||||||
|
rootPrim.LocalID, rootBody.ptr.ToString("X"),
|
||||||
|
childPrim.LocalID, childBody.ptr.ToString("X"),
|
||||||
|
rootPrim.Position, childPrim.Position, midPoint);
|
||||||
|
|
||||||
// create a constraint that allows no freedom of movement between the two objects
|
// create a constraint that allows no freedom of movement between the two objects
|
||||||
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
||||||
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}",
|
|
||||||
rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint);
|
// There is great subtlty in these paramters. Notice the check for a ptr of zero.
|
||||||
|
// We pass the BulletBody structure into the taint in order to capture the pointer
|
||||||
|
// of the body at the time of constraint creation. This doesn't work for the very first
|
||||||
|
// construction because there is no body yet. The body
|
||||||
|
// is constructed later at taint time. Thus we use the body address at time of the
|
||||||
|
// taint creation but, if it is zero, use what's in the prim at the moment.
|
||||||
|
// There is a possible race condition since shape can change without a taint call
|
||||||
|
// (like changing to a mesh that is already constructed). The fix for that would be
|
||||||
|
// to only change BSShape at taint time thus syncronizing these operations at
|
||||||
|
// the cost of efficiency and lag.
|
||||||
BS6DofConstraint constrain = new BS6DofConstraint(
|
BS6DofConstraint constrain = new BS6DofConstraint(
|
||||||
m_physicsScene.World, rootPrim.BSBody, childPrim.BSBody,
|
PhysicsScene.World,
|
||||||
|
rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
|
||||||
|
childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
|
||||||
midPoint,
|
midPoint,
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
|
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
|
||||||
* Using the midpoint is easier since it lets the Bullet code use the transforms
|
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
|
||||||
* of the objects.
|
* of the objects.
|
||||||
* Code left as a warning to future programmers.
|
* Code left as a warning to future programmers.
|
||||||
// ==================================================================================
|
// ==================================================================================
|
||||||
|
@ -408,7 +472,7 @@ public class BSLinkset
|
||||||
// ==================================================================================
|
// ==================================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
m_physicsScene.Constraints.AddConstraint(constrain);
|
PhysicsScene.Constraints.AddConstraint(constrain);
|
||||||
|
|
||||||
// zero linear and angular limits makes the objects unable to move in relation to each other
|
// zero linear and angular limits makes the objects unable to move in relation to each other
|
||||||
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||||
|
@ -429,31 +493,79 @@ public class BSLinkset
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove linkage between myself and a particular child
|
// Remove linkage between myself and a particular child
|
||||||
|
// The root and child bodies are passed in because we need to remove the constraint between
|
||||||
|
// the bodies that were at unlink time.
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
|
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
|
||||||
|
BSPhysObject childPrim, BulletBody childBody)
|
||||||
{
|
{
|
||||||
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
|
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
|
||||||
|
rootPrim.LocalID,
|
||||||
|
rootPrim.LocalID, rootBody.ptr.ToString("X"),
|
||||||
|
childPrim.LocalID, childBody.ptr.ToString("X"));
|
||||||
|
|
||||||
// Find the constraint for this link and get rid of it from the overall collection and from my list
|
// Find the constraint for this link and get rid of it from the overall collection and from my list
|
||||||
m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody);
|
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
|
||||||
|
|
||||||
// Make the child refresh its location
|
// Make the child refresh its location
|
||||||
BulletSimAPI.PushUpdate2(childPrim.BSBody.Ptr);
|
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove linkage between myself and any possible children I might have
|
/*
|
||||||
|
// Remove linkage between myself and any possible children I might have.
|
||||||
// Called at taint time!
|
// Called at taint time!
|
||||||
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
|
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
|
||||||
{
|
{
|
||||||
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
|
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
|
||||||
|
|
||||||
m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
|
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Call each of the constraints that make up this linkset and recompute the
|
||||||
|
// various transforms and variables. Used when objects are added or removed
|
||||||
|
// from a linkset to make sure the constraints know about the new mass and
|
||||||
|
// geometry.
|
||||||
|
// Must only be called at taint time!!
|
||||||
|
private void RecomputeLinksetConstraintVariables()
|
||||||
|
{
|
||||||
|
float linksetMass = LinksetMass;
|
||||||
|
foreach (BSPhysObject child in m_taintChildren)
|
||||||
|
{
|
||||||
|
BSConstraint constrain;
|
||||||
|
if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
|
||||||
|
{
|
||||||
|
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
|
||||||
|
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
|
||||||
|
constrain.RecomputeConstraintVariables(linksetMass);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Non-fatal error that happens when children are being added to the linkset but
|
||||||
|
// their constraints have not been created yet.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values
|
||||||
|
if (m_children.Count == m_taintChildren.Count)
|
||||||
|
{
|
||||||
|
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
|
||||||
|
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
|
||||||
|
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
|
||||||
|
foreach (BSPhysObject child in m_taintChildren)
|
||||||
|
{
|
||||||
|
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Invoke the detailed logger and output something if it's enabled.
|
// Invoke the detailed logger and output something if it's enabled.
|
||||||
private void DetailLog(string msg, params Object[] args)
|
private void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
m_physicsScene.PhysicsLogging.Write(msg, args);
|
PhysicsScene.PhysicsLogging.Write(msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
*
|
*
|
||||||
|
@ -39,26 +39,171 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// unless the difference is significant.
|
// unless the difference is significant.
|
||||||
public abstract class BSPhysObject : PhysicsActor
|
public abstract class BSPhysObject : PhysicsActor
|
||||||
{
|
{
|
||||||
public abstract BSLinkset Linkset { get; set; }
|
protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
|
||||||
|
{
|
||||||
|
PhysicsScene = parentScene;
|
||||||
|
LocalID = localID;
|
||||||
|
PhysObjectName = name;
|
||||||
|
TypeName = typeName;
|
||||||
|
|
||||||
public abstract bool Collide(uint collidingWith, BSPhysObject collidee,
|
Linkset = new BSLinkset(PhysicsScene, this);
|
||||||
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
|
|
||||||
public abstract void SendCollisions();
|
|
||||||
|
|
||||||
// Return the object mass without calculating it or side effects
|
CollisionCollection = new CollisionEventUpdate();
|
||||||
|
SubscribedEventsMs = 0;
|
||||||
|
CollidingStep = 0;
|
||||||
|
CollidingGroundStep = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BSScene PhysicsScene { get; protected set; }
|
||||||
|
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
|
||||||
|
public string PhysObjectName { get; protected set; }
|
||||||
|
public string TypeName { get; protected set; }
|
||||||
|
|
||||||
|
public BSLinkset Linkset { get; set; }
|
||||||
|
|
||||||
|
// Return the object mass without calculating it or having side effects
|
||||||
public abstract float MassRaw { get; }
|
public abstract float MassRaw { get; }
|
||||||
|
|
||||||
// Reference to the physical body (btCollisionObject) of this object
|
// Reference to the physical body (btCollisionObject) of this object
|
||||||
public abstract BulletBody BSBody { get; set; }
|
public BulletBody BSBody;
|
||||||
// Reference to the physical shape (btCollisionShape) of this object
|
// Reference to the physical shape (btCollisionShape) of this object
|
||||||
public abstract BulletShape BSShape { get; set; }
|
public BulletShape BSShape;
|
||||||
|
|
||||||
|
// Stop all physical motion.
|
||||||
public abstract void ZeroMotion();
|
public abstract void ZeroMotion();
|
||||||
|
|
||||||
|
// Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
|
||||||
public virtual void StepVehicle(float timeStep) { }
|
public virtual void StepVehicle(float timeStep) { }
|
||||||
|
|
||||||
|
// Update the physical location and motion of the object. Called with data from Bullet.
|
||||||
public abstract void UpdateProperties(EntityProperties entprop);
|
public abstract void UpdateProperties(EntityProperties entprop);
|
||||||
|
|
||||||
|
// Tell the object to clean up.
|
||||||
public abstract void Destroy();
|
public abstract void Destroy();
|
||||||
|
|
||||||
|
#region Collisions
|
||||||
|
|
||||||
|
// Requested number of milliseconds between collision events. Zero means disabled.
|
||||||
|
protected int SubscribedEventsMs { get; set; }
|
||||||
|
// Given subscription, the time that a collision may be passed up
|
||||||
|
protected int NextCollisionOkTime { get; set; }
|
||||||
|
// The simulation step that last had a collision
|
||||||
|
protected long CollidingStep { get; set; }
|
||||||
|
// The simulation step that last had a collision with the ground
|
||||||
|
protected long CollidingGroundStep { get; set; }
|
||||||
|
// The collision flags we think are set in Bullet
|
||||||
|
protected CollisionFlags CurrentCollisionFlags { get; set; }
|
||||||
|
|
||||||
|
// The collisions that have been collected this tick
|
||||||
|
protected CollisionEventUpdate CollisionCollection;
|
||||||
|
|
||||||
|
// The simulation step is telling this object about a collision.
|
||||||
|
// Return 'true' if a collision was processed and should be sent up.
|
||||||
|
// Called at taint time from within the Step() function
|
||||||
|
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
|
||||||
|
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
// The following lines make IsColliding() and IsCollidingGround() work
|
||||||
|
CollidingStep = PhysicsScene.SimulationStep;
|
||||||
|
if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
|
||||||
|
{
|
||||||
|
CollidingGroundStep = PhysicsScene.SimulationStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prims in the same linkset cannot collide with each other
|
||||||
|
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if someone has subscribed for collision events....
|
||||||
|
if (SubscribedEvents()) {
|
||||||
|
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||||
|
// DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||||
|
// LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Routine to send the collected collisions into the simulator.
|
||||||
|
// Also handles removal of this from the collection of objects with collisions if
|
||||||
|
// there are no collisions from this object. Mechanism is create one last
|
||||||
|
// collision event to make collision_end work.
|
||||||
|
// Called at taint time from within the Step() function thus no locking problems
|
||||||
|
// with CollisionCollection and ObjectsWithNoMoreCollisions.
|
||||||
|
// Return 'true' if there were some actual collisions passed up
|
||||||
|
public virtual bool SendCollisions()
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
// throttle the collisions to the number of milliseconds specified in the subscription
|
||||||
|
int nowTime = PhysicsScene.SimulationNowTime;
|
||||||
|
if (nowTime >= NextCollisionOkTime)
|
||||||
|
{
|
||||||
|
NextCollisionOkTime = nowTime + SubscribedEventsMs;
|
||||||
|
|
||||||
|
// We are called if we previously had collisions. If there are no collisions
|
||||||
|
// this time, send up one last empty event so OpenSim can sense collision end.
|
||||||
|
if (CollisionCollection.Count == 0)
|
||||||
|
{
|
||||||
|
// If I have no collisions this time, remove me from the list of objects with collisions.
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
|
||||||
|
base.SendCollisionUpdate(CollisionCollection);
|
||||||
|
|
||||||
|
// The collisionCollection structure is passed around in the simulator.
|
||||||
|
// Make sure we don't have a handle to that one and that a new one is used for next time.
|
||||||
|
CollisionCollection = new CollisionEventUpdate();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe for collision events.
|
||||||
|
// Parameter is the millisecond rate the caller wishes collision events to occur.
|
||||||
|
public override void SubscribeEvents(int ms) {
|
||||||
|
// DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
|
||||||
|
SubscribedEventsMs = ms;
|
||||||
|
if (ms > 0)
|
||||||
|
{
|
||||||
|
// make sure first collision happens
|
||||||
|
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
|
||||||
|
|
||||||
|
PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
|
||||||
|
{
|
||||||
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Subscribing for zero or less is the same as unsubscribing
|
||||||
|
UnSubscribeEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void UnSubscribeEvents() {
|
||||||
|
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
|
||||||
|
SubscribedEventsMs = 0;
|
||||||
|
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
|
||||||
|
{
|
||||||
|
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Return 'true' if the simulator wants collision events
|
||||||
|
public override bool SubscribedEvents() {
|
||||||
|
return (SubscribedEventsMs > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // Collisions
|
||||||
|
|
||||||
|
// High performance detailed logging routine used by the physical objects.
|
||||||
|
protected void DetailLog(string msg, params Object[] args)
|
||||||
|
{
|
||||||
|
PhysicsScene.PhysicsLogging.Write(msg, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,20 +39,20 @@ using log4net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
|
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
|
||||||
// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
|
// Move all logic out of the C++ code and into the C# code for easier future modifications.
|
||||||
// Test sculpties
|
// Test sculpties (verified that they don't work)
|
||||||
// Compute physics FPS reasonably
|
// Compute physics FPS reasonably
|
||||||
// Based on material, set density and friction
|
// Based on material, set density and friction
|
||||||
// More efficient memory usage when passing hull information from BSPrim to BulletSim
|
// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
|
||||||
// Move all logic out of the C++ code and into the C# code for easier future modifications.
|
|
||||||
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
|
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
|
||||||
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
|
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
|
||||||
// At the moment, physical and phantom causes object to drop through the terrain
|
// At the moment, physical and phantom causes object to drop through the terrain
|
||||||
// Physical phantom objects and related typing (collision options )
|
// Physical phantom objects and related typing (collision options )
|
||||||
// Use collision masks for collision with terrain and phantom objects
|
|
||||||
// Check out llVolumeDetect. Must do something for that.
|
// Check out llVolumeDetect. Must do something for that.
|
||||||
|
// Use collision masks for collision with terrain and phantom objects
|
||||||
|
// More efficient memory usage when passing hull information from BSPrim to BulletSim
|
||||||
// Should prim.link() and prim.delink() membership checking happen at taint time?
|
// Should prim.link() and prim.delink() membership checking happen at taint time?
|
||||||
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
|
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
|
||||||
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
|
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
|
||||||
// Implement LockAngularMotion
|
// Implement LockAngularMotion
|
||||||
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
|
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
|
||||||
|
@ -73,12 +73,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
public string BulletSimVersion = "?";
|
public string BulletSimVersion = "?";
|
||||||
|
|
||||||
public Dictionary<uint, BSPhysObject> PhysObjects = new Dictionary<uint, BSPhysObject>();
|
public Dictionary<uint, BSPhysObject> PhysObjects;
|
||||||
|
public BSShapeCollection Shapes;
|
||||||
|
|
||||||
private HashSet<BSPhysObject> m_objectsWithCollisions = new HashSet<BSPhysObject>();
|
// Keeping track of the objects with collisions so we can report begin and end of a collision
|
||||||
// Following is a kludge and can be removed when avatar animation updating is
|
public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
|
||||||
// moved to a better place.
|
public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
|
||||||
private HashSet<BSPhysObject> m_avatarsWithCollisions = new HashSet<BSPhysObject>();
|
// Keep track of all the avatars so we can send them a collision event
|
||||||
|
// every tick so OpenSim will update its animation.
|
||||||
|
private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
|
||||||
|
|
||||||
// List of all the objects that have vehicle properties and should be called
|
// List of all the objects that have vehicle properties and should be called
|
||||||
// to update each physics step.
|
// to update each physics step.
|
||||||
|
@ -202,6 +205,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
||||||
{
|
{
|
||||||
|
mesher = meshmerizer;
|
||||||
|
_taintedObjects = new List<TaintCallbackEntry>();
|
||||||
|
PhysObjects = new Dictionary<uint, BSPhysObject>();
|
||||||
|
Shapes = new BSShapeCollection(this);
|
||||||
|
|
||||||
// Allocate pinned memory to pass parameters.
|
// Allocate pinned memory to pass parameters.
|
||||||
m_params = new ConfigurationParameters[1];
|
m_params = new ConfigurationParameters[1];
|
||||||
m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
|
m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
|
||||||
|
@ -215,12 +223,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
|
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
|
||||||
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
|
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
|
||||||
|
|
||||||
mesher = meshmerizer;
|
|
||||||
_taintedObjects = new List<TaintCallbackEntry>();
|
|
||||||
|
|
||||||
// Enable very detailed logging.
|
// Enable very detailed logging.
|
||||||
// By creating an empty logger when not logging, the log message invocation code
|
// By creating an empty logger when not logging, the log message invocation code
|
||||||
// can be left in and every call doesn't have to check for null.
|
// can be left in and every call doesn't have to check for null.
|
||||||
if (m_physicsLoggingEnabled)
|
if (m_physicsLoggingEnabled)
|
||||||
{
|
{
|
||||||
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
|
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
|
||||||
|
@ -251,7 +256,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// a child in a mega-region.
|
// a child in a mega-region.
|
||||||
// Turns out that Bullet really doesn't care about the extents of the simulated
|
// Turns out that Bullet really doesn't care about the extents of the simulated
|
||||||
// area. It tracks active objects no matter where they are.
|
// area. It tracks active objects no matter where they are.
|
||||||
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
|
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||||
|
|
||||||
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
|
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
|
||||||
WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
|
WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
|
||||||
|
@ -351,6 +356,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
Constraints = null;
|
Constraints = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Shapes != null)
|
||||||
|
{
|
||||||
|
Shapes.Dispose();
|
||||||
|
Shapes = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Anything left in the unmanaged code should be cleaned out
|
// Anything left in the unmanaged code should be cleaned out
|
||||||
BulletSimAPI.Shutdown(WorldID);
|
BulletSimAPI.Shutdown(WorldID);
|
||||||
|
|
||||||
|
@ -379,7 +390,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// TODO: Remove kludge someday.
|
// TODO: Remove kludge someday.
|
||||||
// We must generate a collision for avatars whether they collide or not.
|
// We must generate a collision for avatars whether they collide or not.
|
||||||
// This is required by OpenSim to update avatar animations, etc.
|
// This is required by OpenSim to update avatar animations, etc.
|
||||||
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor);
|
lock (m_avatars) m_avatars.Add(actor);
|
||||||
|
|
||||||
return actor;
|
return actor;
|
||||||
}
|
}
|
||||||
|
@ -397,7 +408,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
{
|
{
|
||||||
lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
|
lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
|
||||||
// Remove kludge someday
|
// Remove kludge someday
|
||||||
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Remove(bsactor);
|
lock (m_avatars) m_avatars.Remove(bsactor);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -464,6 +475,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
int collidersCount = 0;
|
int collidersCount = 0;
|
||||||
IntPtr collidersPtr;
|
IntPtr collidersPtr;
|
||||||
|
|
||||||
|
int beforeTime = 0;
|
||||||
|
int simTime = 0;
|
||||||
|
|
||||||
// prevent simulation until we've been initialized
|
// prevent simulation until we've been initialized
|
||||||
if (!m_initialized) return 5.0f;
|
if (!m_initialized) return 5.0f;
|
||||||
|
|
||||||
|
@ -481,10 +495,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
int numSubSteps = 0;
|
int numSubSteps = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
||||||
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
|
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
|
||||||
DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}",
|
|
||||||
DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
|
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
|
||||||
|
DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
|
||||||
|
DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -502,12 +520,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// Get a value for 'now' so all the collision and update routines don't have to get their own
|
// Get a value for 'now' so all the collision and update routines don't have to get their own
|
||||||
SimulationNowTime = Util.EnvironmentTickCount();
|
SimulationNowTime = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
// This is a kludge to get avatar movement updates.
|
|
||||||
// ODE sends collisions for avatars even if there are have been no collisions. This updates
|
|
||||||
// avatar animations and stuff.
|
|
||||||
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
|
|
||||||
m_objectsWithCollisions = new HashSet<BSPhysObject>(m_avatarsWithCollisions);
|
|
||||||
|
|
||||||
// If there were collisions, process them by sending the event to the prim.
|
// If there were collisions, process them by sending the event to the prim.
|
||||||
// Collisions must be processed before updates.
|
// Collisions must be processed before updates.
|
||||||
if (collidersCount > 0)
|
if (collidersCount > 0)
|
||||||
|
@ -523,11 +535,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a kludge to get avatar movement updates.
|
||||||
|
// ODE sends collisions for avatars even if there are have been no collisions. This updates
|
||||||
|
// avatar animations and stuff.
|
||||||
|
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
|
||||||
|
foreach (BSPhysObject bsp in m_avatars)
|
||||||
|
bsp.SendCollisions();
|
||||||
|
|
||||||
// The above SendCollision's batch up the collisions on the objects.
|
// The above SendCollision's batch up the collisions on the objects.
|
||||||
// Now push the collisions into the simulator.
|
// Now push the collisions into the simulator.
|
||||||
foreach (BSPhysObject bsp in m_objectsWithCollisions)
|
if (ObjectsWithCollisions.Count > 0)
|
||||||
bsp.SendCollisions();
|
{
|
||||||
m_objectsWithCollisions.Clear();
|
foreach (BSPhysObject bsp in ObjectsWithCollisions)
|
||||||
|
if (!m_avatars.Contains(bsp)) // don't call avatars twice
|
||||||
|
if (!bsp.SendCollisions())
|
||||||
|
{
|
||||||
|
// If the object is done colliding, see that it's removed from the colliding list
|
||||||
|
ObjectsWithNoMoreCollisions.Add(bsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
|
||||||
|
// This can't be done by SendCollisions because it is inside an iteration of ObjectWithCollisions.
|
||||||
|
if (ObjectsWithNoMoreCollisions.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
|
||||||
|
ObjectsWithCollisions.Remove(po);
|
||||||
|
ObjectsWithNoMoreCollisions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
|
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
|
||||||
if (updatedEntityCount > 0)
|
if (updatedEntityCount > 0)
|
||||||
|
@ -555,7 +590,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// The physics engine returns the number of milliseconds it simulated this call.
|
// The physics engine returns the number of milliseconds it simulated this call.
|
||||||
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
||||||
// Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
|
// Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
|
||||||
return numSubSteps * m_fixedTimeStep;
|
return numSubSteps * m_fixedTimeStep * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something has collided
|
// Something has collided
|
||||||
|
@ -570,20 +605,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
if (!PhysObjects.TryGetValue(localID, out collider))
|
if (!PhysObjects.TryGetValue(localID, out collider))
|
||||||
{
|
{
|
||||||
// If the object that is colliding cannot be found, just ignore the collision.
|
// If the object that is colliding cannot be found, just ignore the collision.
|
||||||
|
DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The terrain is not in the physical object list so 'collidee'
|
// The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
|
||||||
// can be null when Collide() is called.
|
|
||||||
BSPhysObject collidee = null;
|
BSPhysObject collidee = null;
|
||||||
PhysObjects.TryGetValue(collidingWith, out collidee);
|
PhysObjects.TryGetValue(collidingWith, out collidee);
|
||||||
|
|
||||||
// DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
|
DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
|
||||||
|
|
||||||
if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
|
if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
|
||||||
{
|
{
|
||||||
// If a collision was posted, remember to send it to the simulator
|
// If a collision was posted, remember to send it to the simulator
|
||||||
m_objectsWithCollisions.Add(collider);
|
ObjectsWithCollisions.Add(collider);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -998,7 +1033,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
|
(s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
|
||||||
(s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
|
(s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
|
||||||
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
|
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
|
||||||
ConfigurationParameters.numericFalse,
|
ConfigurationParameters.numericTrue,
|
||||||
(s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
(s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||||
(s) => { return s.m_params[0].shouldSplitSimulationIslands; },
|
(s) => { return s.m_params[0].shouldSplitSimulationIslands; },
|
||||||
(s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
|
(s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
|
||||||
|
|
|
@ -0,0 +1,735 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyrightD
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using OMV = OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
using OpenSim.Region.Physics.ConvexDecompositionDotNet;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public class BSShapeCollection : IDisposable
|
||||||
|
{
|
||||||
|
private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
|
||||||
|
|
||||||
|
protected BSScene PhysicsScene { get; set; }
|
||||||
|
|
||||||
|
private Object m_collectionActivityLock = new Object();
|
||||||
|
|
||||||
|
// Description of a Mesh
|
||||||
|
private struct MeshDesc
|
||||||
|
{
|
||||||
|
public IntPtr ptr;
|
||||||
|
public int referenceCount;
|
||||||
|
public DateTime lastReferenced;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description of a hull.
|
||||||
|
// Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects
|
||||||
|
private struct HullDesc
|
||||||
|
{
|
||||||
|
public IntPtr ptr;
|
||||||
|
public int referenceCount;
|
||||||
|
public DateTime lastReferenced;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct BodyDesc
|
||||||
|
{
|
||||||
|
public IntPtr ptr;
|
||||||
|
// Bodies are only used once so reference count is always either one or zero
|
||||||
|
public int referenceCount;
|
||||||
|
public DateTime lastReferenced;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
|
||||||
|
private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
|
||||||
|
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
|
||||||
|
|
||||||
|
public BSShapeCollection(BSScene physScene)
|
||||||
|
{
|
||||||
|
PhysicsScene = physScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// TODO!!!!!!!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks called just before either the body or shape is destroyed.
|
||||||
|
// Mostly used for changing bodies out from under Linksets.
|
||||||
|
// Useful for other cases where parameters need saving.
|
||||||
|
// Passing 'null' says no callback.
|
||||||
|
public delegate void ShapeDestructionCallback(BulletShape shape);
|
||||||
|
public delegate void BodyDestructionCallback(BulletBody body);
|
||||||
|
|
||||||
|
// Called to update/change the body and shape for an object.
|
||||||
|
// First checks the shape and updates that if necessary then makes
|
||||||
|
// sure the body is of the right type.
|
||||||
|
// Return 'true' if either the body or the shape changed.
|
||||||
|
// Called at taint-time!!
|
||||||
|
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
|
||||||
|
ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||||
|
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
// This lock could probably be pushed down lower but building shouldn't take long
|
||||||
|
lock (m_collectionActivityLock)
|
||||||
|
{
|
||||||
|
// Do we have the correct geometry for this type of object?
|
||||||
|
// Updates prim.BSShape with information/pointers to requested shape
|
||||||
|
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
|
||||||
|
// If we had to select a new shape geometry for the object,
|
||||||
|
// rebuild the body around it.
|
||||||
|
// Updates prim.BSBody with information/pointers to requested body
|
||||||
|
bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData, bodyCallback);
|
||||||
|
ret = newGeom || newBody;
|
||||||
|
}
|
||||||
|
DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
|
||||||
|
prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track another user of a body
|
||||||
|
// We presume the caller has allocated the body.
|
||||||
|
// Bodies only have one user so the reference count is either 1 or 0.
|
||||||
|
public void ReferenceBody(BulletBody body, bool atTaintTime)
|
||||||
|
{
|
||||||
|
lock (m_collectionActivityLock)
|
||||||
|
{
|
||||||
|
BodyDesc bodyDesc;
|
||||||
|
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
||||||
|
{
|
||||||
|
bodyDesc.referenceCount++;
|
||||||
|
DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// New entry
|
||||||
|
bodyDesc.ptr = body.ptr;
|
||||||
|
bodyDesc.referenceCount = 1;
|
||||||
|
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
|
||||||
|
}
|
||||||
|
bodyDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Bodies[body.ID] = bodyDesc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the usage of a body.
|
||||||
|
// Called when releasing use of a BSBody. BSShape is handled separately.
|
||||||
|
public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
|
||||||
|
{
|
||||||
|
if (body.ptr == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (m_collectionActivityLock)
|
||||||
|
{
|
||||||
|
BodyDesc bodyDesc;
|
||||||
|
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
||||||
|
{
|
||||||
|
bodyDesc.referenceCount--;
|
||||||
|
bodyDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Bodies[body.ID] = bodyDesc;
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
|
||||||
|
|
||||||
|
// If body is no longer being used, free it -- bodies are never shared.
|
||||||
|
if (bodyDesc.referenceCount == 0)
|
||||||
|
{
|
||||||
|
Bodies.Remove(body.ID);
|
||||||
|
BSScene.TaintCallback removeOperation = delegate()
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
|
||||||
|
body.ID, body.ptr.ToString("X"));
|
||||||
|
// If the caller needs to know, pass the event up.
|
||||||
|
if (bodyCallback != null) bodyCallback(body);
|
||||||
|
|
||||||
|
// Zero any reference to the shape so it is not freed when the body is deleted.
|
||||||
|
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
|
||||||
|
// It may have already been removed from the world in which case the next is a NOOP.
|
||||||
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||||
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
|
||||||
|
};
|
||||||
|
// If already in taint-time, do the operations now. Otherwise queue for later.
|
||||||
|
if (inTaintTime)
|
||||||
|
removeOperation();
|
||||||
|
else
|
||||||
|
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the datastructures and use count for a shape.
|
||||||
|
// When creating a hull, this is called first to reference the mesh
|
||||||
|
// and then again to reference the hull.
|
||||||
|
// Meshes and hulls for the same shape have the same hash key.
|
||||||
|
// NOTE that native shapes are not added to the mesh list or removed.
|
||||||
|
// Returns 'true' if this is the initial reference to the shape. Otherwise reused.
|
||||||
|
private bool ReferenceShape(BulletShape shape)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
switch (shape.type)
|
||||||
|
{
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||||
|
MeshDesc meshDesc;
|
||||||
|
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
|
||||||
|
{
|
||||||
|
// There is an existing instance of this mesh.
|
||||||
|
meshDesc.referenceCount++;
|
||||||
|
DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
|
||||||
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is a new reference to a mesh
|
||||||
|
meshDesc.ptr = shape.ptr;
|
||||||
|
// We keep a reference to the underlying IMesh data so a hull can be built
|
||||||
|
meshDesc.referenceCount = 1;
|
||||||
|
DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
|
||||||
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||||
|
HullDesc hullDesc;
|
||||||
|
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
|
||||||
|
{
|
||||||
|
// There is an existing instance of this hull.
|
||||||
|
hullDesc.referenceCount++;
|
||||||
|
DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
|
||||||
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is a new reference to a hull
|
||||||
|
hullDesc.ptr = shape.ptr;
|
||||||
|
hullDesc.referenceCount = 1;
|
||||||
|
DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
|
||||||
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Native shapes are not tracked and they don't go into any list
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the usage of a shape.
|
||||||
|
// The collisionObject is released since it is a copy of the real collision shape.
|
||||||
|
public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
if (shape.ptr == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BSScene.TaintCallback dereferenceOperation = delegate()
|
||||||
|
{
|
||||||
|
switch (shape.type)
|
||||||
|
{
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||||
|
DereferenceHull(shape, shapeCallback);
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||||
|
DereferenceMesh(shape, shapeCallback);
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Native shapes are not tracked and are released immediately
|
||||||
|
if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||||
|
BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime);
|
||||||
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
|
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (atTaintTime)
|
||||||
|
{
|
||||||
|
lock (m_collectionActivityLock)
|
||||||
|
{
|
||||||
|
dereferenceOperation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count down the reference count for a mesh shape
|
||||||
|
// Called at taint-time.
|
||||||
|
private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
MeshDesc meshDesc;
|
||||||
|
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
|
||||||
|
{
|
||||||
|
meshDesc.referenceCount--;
|
||||||
|
// TODO: release the Bullet storage
|
||||||
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
|
||||||
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count down the reference count for a hull shape
|
||||||
|
// Called at taint-time.
|
||||||
|
private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
HullDesc hullDesc;
|
||||||
|
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
|
||||||
|
{
|
||||||
|
hullDesc.referenceCount--;
|
||||||
|
// TODO: release the Bullet storage (aging old entries?)
|
||||||
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
|
||||||
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the geometry information in Bullet for later use.
|
||||||
|
// The objects needs a hull if it's physical otherwise a mesh is enough.
|
||||||
|
// No locking here because this is done when we know physics is not simulating.
|
||||||
|
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
|
||||||
|
// Returns 'true' if the geometry was rebuilt.
|
||||||
|
// Called at taint-time!
|
||||||
|
private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
|
||||||
|
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
bool haveShape = false;
|
||||||
|
bool nativeShapePossible = true;
|
||||||
|
|
||||||
|
// If the prim attributes are simple, this could be a simple Bullet native shape
|
||||||
|
if (nativeShapePossible
|
||||||
|
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|
||||||
|
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||||
|
&& pbs.ProfileHollow == 0
|
||||||
|
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
|
||||||
|
&& pbs.PathBegin == 0 && pbs.PathEnd == 0
|
||||||
|
&& pbs.PathTaperX == 0 && pbs.PathTaperY == 0
|
||||||
|
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
|
||||||
|
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
|
||||||
|
{
|
||||||
|
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
|
{
|
||||||
|
haveShape = true;
|
||||||
|
if (forceRebuild
|
||||||
|
|| prim.Scale != shapeData.Size
|
||||||
|
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
|
||||||
|
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
|
||||||
|
prim.LocalID, forceRebuild, prim.BSShape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
haveShape = true;
|
||||||
|
if (forceRebuild
|
||||||
|
|| prim.Scale != shapeData.Size
|
||||||
|
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
|
||||||
|
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
|
||||||
|
prim.LocalID, forceRebuild, prim.BSShape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If a simple shape is not happening, create a mesh and possibly a hull.
|
||||||
|
// Note that if it's a native shape, the check for physical/non-physical is not
|
||||||
|
// made. Native shapes are best used in either case.
|
||||||
|
if (!haveShape)
|
||||||
|
{
|
||||||
|
if (prim.IsPhysical)
|
||||||
|
{
|
||||||
|
// Update prim.BSShape to reference a hull of this shape.
|
||||||
|
ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
||||||
|
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
||||||
|
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a native shape and assignes it to prim.BSShape
|
||||||
|
private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
|
||||||
|
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||||
|
ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
BulletShape newShape;
|
||||||
|
|
||||||
|
shapeData.Type = shapeType;
|
||||||
|
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||||
|
prim.Scale = shapeData.Size;
|
||||||
|
shapeData.Scale = shapeData.Size;
|
||||||
|
|
||||||
|
// release any previous shape
|
||||||
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
|
// Native shapes are always built independently.
|
||||||
|
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||||
|
newShape.shapeKey = (ulong)shapeKey;
|
||||||
|
newShape.isNativeShape = true;
|
||||||
|
|
||||||
|
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
|
||||||
|
// DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
|
||||||
|
|
||||||
|
prim.BSShape = newShape;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Builds a mesh shape in the physical world and updates prim.BSShape.
|
||||||
|
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
||||||
|
// Returns 'true' of a mesh was actually built. Otherwise .
|
||||||
|
// Called at taint-time!
|
||||||
|
private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||||
|
ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||||
|
|
||||||
|
float lod;
|
||||||
|
ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
|
||||||
|
|
||||||
|
// if this new shape is the same as last time, don't recreate the mesh
|
||||||
|
if (prim.BSShape.shapeKey == newMeshKey) return false;
|
||||||
|
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
|
||||||
|
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
|
||||||
|
|
||||||
|
// Since we're recreating new, get rid of the reference to the previous shape
|
||||||
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
|
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
|
||||||
|
|
||||||
|
ReferenceShape(newShape);
|
||||||
|
|
||||||
|
// meshes are already scaled by the meshmerizer
|
||||||
|
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
|
||||||
|
prim.BSShape = newShape;
|
||||||
|
|
||||||
|
return true; // 'true' means a new shape has been added to this prim
|
||||||
|
}
|
||||||
|
|
||||||
|
private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||||
|
{
|
||||||
|
IMesh meshData = null;
|
||||||
|
IntPtr meshPtr;
|
||||||
|
MeshDesc meshDesc;
|
||||||
|
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
||||||
|
{
|
||||||
|
// If the mesh has already been built just use it.
|
||||||
|
meshPtr = meshDesc.ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||||
|
meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||||
|
|
||||||
|
int[] indices = meshData.getIndexListAsInt();
|
||||||
|
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||||
|
|
||||||
|
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||||
|
int vi = 0;
|
||||||
|
foreach (OMV.Vector3 vv in vertices)
|
||||||
|
{
|
||||||
|
verticesAsFloats[vi++] = vv.X;
|
||||||
|
verticesAsFloats[vi++] = vv.Y;
|
||||||
|
verticesAsFloats[vi++] = vv.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
||||||
|
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||||
|
|
||||||
|
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||||
|
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||||
|
}
|
||||||
|
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
||||||
|
newShape.shapeKey = newMeshKey;
|
||||||
|
|
||||||
|
return newShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See that hull shape exists in the physical world and update prim.BSShape.
|
||||||
|
// We could be creating the hull because scale changed or whatever.
|
||||||
|
private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||||
|
ShapeDestructionCallback shapeCallback)
|
||||||
|
{
|
||||||
|
BulletShape newShape;
|
||||||
|
|
||||||
|
float lod;
|
||||||
|
ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
|
||||||
|
|
||||||
|
// if the hull hasn't changed, don't rebuild it
|
||||||
|
if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
|
||||||
|
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
|
||||||
|
|
||||||
|
// Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
|
||||||
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
|
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
|
||||||
|
|
||||||
|
ReferenceShape(newShape);
|
||||||
|
|
||||||
|
// hulls are already scaled by the meshmerizer
|
||||||
|
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
|
||||||
|
prim.BSShape = newShape;
|
||||||
|
return true; // 'true' means a new shape has been added to this prim
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ConvexResult> m_hulls;
|
||||||
|
private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||||
|
{
|
||||||
|
|
||||||
|
IntPtr hullPtr;
|
||||||
|
HullDesc hullDesc;
|
||||||
|
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||||
|
{
|
||||||
|
// If the hull shape already is created, just use it.
|
||||||
|
hullPtr = hullDesc.ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Build a new hull in the physical world
|
||||||
|
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||||
|
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||||
|
|
||||||
|
int[] indices = meshData.getIndexListAsInt();
|
||||||
|
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||||
|
|
||||||
|
//format conversion from IMesh format to DecompDesc format
|
||||||
|
List<int> convIndices = new List<int>();
|
||||||
|
List<float3> convVertices = new List<float3>();
|
||||||
|
for (int ii = 0; ii < indices.GetLength(0); ii++)
|
||||||
|
{
|
||||||
|
convIndices.Add(indices[ii]);
|
||||||
|
}
|
||||||
|
foreach (OMV.Vector3 vv in vertices)
|
||||||
|
{
|
||||||
|
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup and do convex hull conversion
|
||||||
|
m_hulls = new List<ConvexResult>();
|
||||||
|
DecompDesc dcomp = new DecompDesc();
|
||||||
|
dcomp.mIndices = convIndices;
|
||||||
|
dcomp.mVertices = convVertices;
|
||||||
|
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
||||||
|
// create the hull into the _hulls variable
|
||||||
|
convexBuilder.process(dcomp);
|
||||||
|
|
||||||
|
// Convert the vertices and indices for passing to unmanaged.
|
||||||
|
// The hull information is passed as a large floating point array.
|
||||||
|
// The format is:
|
||||||
|
// convHulls[0] = number of hulls
|
||||||
|
// convHulls[1] = number of vertices in first hull
|
||||||
|
// convHulls[2] = hull centroid X coordinate
|
||||||
|
// convHulls[3] = hull centroid Y coordinate
|
||||||
|
// convHulls[4] = hull centroid Z coordinate
|
||||||
|
// convHulls[5] = first hull vertex X
|
||||||
|
// convHulls[6] = first hull vertex Y
|
||||||
|
// convHulls[7] = first hull vertex Z
|
||||||
|
// convHulls[8] = second hull vertex X
|
||||||
|
// ...
|
||||||
|
// convHulls[n] = number of vertices in second hull
|
||||||
|
// convHulls[n+1] = second hull centroid X coordinate
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// TODO: is is very inefficient. Someday change the convex hull generator to return
|
||||||
|
// data structures that do not need to be converted in order to pass to Bullet.
|
||||||
|
// And maybe put the values directly into pinned memory rather than marshaling.
|
||||||
|
int hullCount = m_hulls.Count;
|
||||||
|
int totalVertices = 1; // include one for the count of the hulls
|
||||||
|
foreach (ConvexResult cr in m_hulls)
|
||||||
|
{
|
||||||
|
totalVertices += 4; // add four for the vertex count and centroid
|
||||||
|
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
|
||||||
|
}
|
||||||
|
float[] convHulls = new float[totalVertices];
|
||||||
|
|
||||||
|
convHulls[0] = (float)hullCount;
|
||||||
|
int jj = 1;
|
||||||
|
foreach (ConvexResult cr in m_hulls)
|
||||||
|
{
|
||||||
|
// copy vertices for index access
|
||||||
|
float3[] verts = new float3[cr.HullVertices.Count];
|
||||||
|
int kk = 0;
|
||||||
|
foreach (float3 ff in cr.HullVertices)
|
||||||
|
{
|
||||||
|
verts[kk++] = ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to the array one hull's worth of data
|
||||||
|
convHulls[jj++] = cr.HullIndices.Count;
|
||||||
|
convHulls[jj++] = 0f; // centroid x,y,z
|
||||||
|
convHulls[jj++] = 0f;
|
||||||
|
convHulls[jj++] = 0f;
|
||||||
|
foreach (int ind in cr.HullIndices)
|
||||||
|
{
|
||||||
|
convHulls[jj++] = verts[ind].x;
|
||||||
|
convHulls[jj++] = verts[ind].y;
|
||||||
|
convHulls[jj++] = verts[ind].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create the hull data structure in Bullet
|
||||||
|
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||||
|
}
|
||||||
|
|
||||||
|
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
||||||
|
newShape.shapeKey = newHullKey;
|
||||||
|
|
||||||
|
return newShape; // 'true' means a new shape has been added to this prim
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback from convex hull creater with a newly created hull.
|
||||||
|
// Just add it to our collection of hulls for this shape.
|
||||||
|
private void HullReturn(ConvexResult result)
|
||||||
|
{
|
||||||
|
m_hulls.Add(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a hash of all the shape parameters to be used as a key
|
||||||
|
// for this particular shape.
|
||||||
|
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
|
||||||
|
{
|
||||||
|
// level of detail based on size and type of the object
|
||||||
|
float lod = PhysicsScene.MeshLOD;
|
||||||
|
if (pbs.SculptEntry)
|
||||||
|
lod = PhysicsScene.SculptLOD;
|
||||||
|
|
||||||
|
float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
|
||||||
|
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
|
||||||
|
lod = PhysicsScene.MeshMegaPrimLOD;
|
||||||
|
|
||||||
|
retLod = lod;
|
||||||
|
return (ulong)pbs.GetMeshKey(shapeData.Size, lod);
|
||||||
|
}
|
||||||
|
// For those who don't want the LOD
|
||||||
|
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||||
|
{
|
||||||
|
float lod;
|
||||||
|
return ComputeShapeKey(shapeData, pbs, out lod);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a body object in Bullet.
|
||||||
|
// Updates prim.BSBody with the information about the new body if one is created.
|
||||||
|
// Returns 'true' if an object was actually created.
|
||||||
|
// Called at taint-time.
|
||||||
|
private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
|
||||||
|
ShapeData shapeData, BodyDestructionCallback bodyCallback)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
// the mesh, hull or native shape must have already been created in Bullet
|
||||||
|
bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
|
||||||
|
|
||||||
|
// If there is an existing body, verify it's of an acceptable type.
|
||||||
|
// If not a solid object, body is a GhostObject. Otherwise a RigidBody.
|
||||||
|
if (!mustRebuild)
|
||||||
|
{
|
||||||
|
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
|
||||||
|
if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
|
||||||
|
|| !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
|
||||||
|
{
|
||||||
|
// If the collisionObject is not the correct type for solidness, rebuild what's there
|
||||||
|
mustRebuild = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mustRebuild || forceRebuild)
|
||||||
|
{
|
||||||
|
DereferenceBody(prim.BSBody, true, bodyCallback);
|
||||||
|
|
||||||
|
BulletBody aBody;
|
||||||
|
IntPtr bodyPtr = IntPtr.Zero;
|
||||||
|
if (prim.IsSolid)
|
||||||
|
{
|
||||||
|
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
|
||||||
|
shapeData.ID, shapeData.Position, shapeData.Rotation);
|
||||||
|
// DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
|
||||||
|
shapeData.ID, shapeData.Position, shapeData.Rotation);
|
||||||
|
// DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
||||||
|
}
|
||||||
|
aBody = new BulletBody(shapeData.ID, bodyPtr);
|
||||||
|
|
||||||
|
ReferenceBody(aBody, true);
|
||||||
|
|
||||||
|
prim.BSBody = aBody;
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetailLog(string msg, params Object[] args)
|
||||||
|
{
|
||||||
|
PhysicsScene.PhysicsLogging.Write(msg, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,10 +57,10 @@ public class BSTerrainManager
|
||||||
public const float TERRAIN_COLLISION_MARGIN = 0.0f;
|
public const float TERRAIN_COLLISION_MARGIN = 0.0f;
|
||||||
|
|
||||||
// Until the whole simulator is changed to pass us the region size, we rely on constants.
|
// Until the whole simulator is changed to pass us the region size, we rely on constants.
|
||||||
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, 0f);
|
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||||
|
|
||||||
// The scene that I am part of
|
// The scene that I am part of
|
||||||
private BSScene m_physicsScene;
|
private BSScene PhysicsScene { get; set; }
|
||||||
|
|
||||||
// The ground plane created to keep thing from falling to infinity.
|
// The ground plane created to keep thing from falling to infinity.
|
||||||
private BulletBody m_groundPlane;
|
private BulletBody m_groundPlane;
|
||||||
|
@ -84,18 +84,18 @@ public class BSTerrainManager
|
||||||
// If the parent region (region 0), this is the extent of the combined regions
|
// If the parent region (region 0), this is the extent of the combined regions
|
||||||
// relative to the origin of region zero
|
// relative to the origin of region zero
|
||||||
private Vector3 m_worldMax;
|
private Vector3 m_worldMax;
|
||||||
private PhysicsScene m_parentScene;
|
private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
|
||||||
|
|
||||||
public BSTerrainManager(BSScene physicsScene)
|
public BSTerrainManager(BSScene physicsScene)
|
||||||
{
|
{
|
||||||
m_physicsScene = physicsScene;
|
PhysicsScene = physicsScene;
|
||||||
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
|
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
|
||||||
m_terrainModified = false;
|
m_terrainModified = false;
|
||||||
|
|
||||||
// Assume one region of default size
|
// Assume one region of default size
|
||||||
m_worldOffset = Vector3.Zero;
|
m_worldOffset = Vector3.Zero;
|
||||||
m_worldMax = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, 4096f);
|
m_worldMax = new Vector3(DefaultRegionSize);
|
||||||
m_parentScene = null;
|
MegaRegionParentPhysicsScene = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the initial instance of terrain and the underlying ground plane.
|
// Create the initial instance of terrain and the underlying ground plane.
|
||||||
|
@ -107,10 +107,16 @@ public class BSTerrainManager
|
||||||
public void CreateInitialGroundPlaneAndTerrain()
|
public void CreateInitialGroundPlaneAndTerrain()
|
||||||
{
|
{
|
||||||
// The ground plane is here to catch things that are trying to drop to negative infinity
|
// The ground plane is here to catch things that are trying to drop to negative infinity
|
||||||
BulletShape groundPlaneShape = new BulletShape(BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN));
|
BulletShape groundPlaneShape = new BulletShape(
|
||||||
|
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
|
||||||
|
ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
|
||||||
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
|
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
|
||||||
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.Ptr, Vector3.Zero, Quaternion.Identity));
|
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
||||||
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
|
Vector3.Zero, Quaternion.Identity));
|
||||||
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||||
|
// Everything collides with the ground plane.
|
||||||
|
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
|
||||||
|
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
|
||||||
|
|
||||||
Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
|
Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
|
||||||
Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
|
Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
|
||||||
|
@ -126,13 +132,13 @@ public class BSTerrainManager
|
||||||
// Release all the terrain structures we might have allocated
|
// Release all the terrain structures we might have allocated
|
||||||
public void ReleaseGroundPlaneAndTerrain()
|
public void ReleaseGroundPlaneAndTerrain()
|
||||||
{
|
{
|
||||||
if (m_groundPlane.Ptr != IntPtr.Zero)
|
if (m_groundPlane.ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr))
|
if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
|
||||||
{
|
{
|
||||||
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||||
}
|
}
|
||||||
m_groundPlane.Ptr = IntPtr.Zero;
|
m_groundPlane.ptr = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseTerrain();
|
ReleaseTerrain();
|
||||||
|
@ -143,9 +149,9 @@ public class BSTerrainManager
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
|
foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
|
||||||
{
|
{
|
||||||
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr))
|
if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
|
||||||
{
|
{
|
||||||
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr);
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
|
||||||
BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
|
BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,19 +161,19 @@ public class BSTerrainManager
|
||||||
// The simulator wants to set a new heightmap for the terrain.
|
// The simulator wants to set a new heightmap for the terrain.
|
||||||
public void SetTerrain(float[] heightMap) {
|
public void SetTerrain(float[] heightMap) {
|
||||||
float[] localHeightMap = heightMap;
|
float[] localHeightMap = heightMap;
|
||||||
m_physicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
|
PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
|
||||||
{
|
{
|
||||||
if (m_worldOffset != Vector3.Zero && m_parentScene != null)
|
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
|
||||||
{
|
{
|
||||||
// If a child of a mega-region, we shouldn't have any terrain allocated for us
|
// If a child of a mega-region, we shouldn't have any terrain allocated for us
|
||||||
ReleaseGroundPlaneAndTerrain();
|
ReleaseGroundPlaneAndTerrain();
|
||||||
// If doing the mega-prim stuff and we are the child of the zero region,
|
// If doing the mega-prim stuff and we are the child of the zero region,
|
||||||
// the terrain is added to our parent
|
// the terrain is added to our parent
|
||||||
if (m_parentScene is BSScene)
|
if (MegaRegionParentPhysicsScene is BSScene)
|
||||||
{
|
{
|
||||||
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
|
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
|
||||||
BSScene.DetailLogZero, m_worldOffset, m_worldMax);
|
BSScene.DetailLogZero, m_worldOffset, m_worldMax);
|
||||||
((BSScene)m_parentScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
|
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
|
||||||
localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +182,8 @@ public class BSTerrainManager
|
||||||
// If not doing the mega-prim thing, just change the terrain
|
// If not doing the mega-prim thing, just change the terrain
|
||||||
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
|
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
|
||||||
|
|
||||||
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
|
||||||
|
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -194,10 +201,10 @@ public class BSTerrainManager
|
||||||
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
|
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
|
||||||
// calling this routine from initialization or taint-time routines) or whether to delay
|
// calling this routine from initialization or taint-time routines) or whether to delay
|
||||||
// all the unmanaged activities to taint-time.
|
// all the unmanaged activities to taint-time.
|
||||||
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool doNow)
|
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},doNow={3}",
|
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
|
||||||
BSScene.DetailLogZero, minCoords, maxCoords, doNow);
|
BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);
|
||||||
|
|
||||||
float minZ = float.MaxValue;
|
float minZ = float.MaxValue;
|
||||||
float maxZ = float.MinValue;
|
float maxZ = float.MinValue;
|
||||||
|
@ -232,7 +239,7 @@ public class BSTerrainManager
|
||||||
|
|
||||||
BSScene.TaintCallback rebuildOperation = delegate()
|
BSScene.TaintCallback rebuildOperation = delegate()
|
||||||
{
|
{
|
||||||
if (m_parentScene != null)
|
if (MegaRegionParentPhysicsScene != null)
|
||||||
{
|
{
|
||||||
// It's possible that Combine() was called after this code was queued.
|
// It's possible that Combine() was called after this code was queued.
|
||||||
// If we are a child of combined regions, we don't create any terrain for us.
|
// If we are a child of combined regions, we don't create any terrain for us.
|
||||||
|
@ -245,17 +252,17 @@ public class BSTerrainManager
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapInfo.terrainBody.Ptr != IntPtr.Zero)
|
if (mapInfo.terrainBody.ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
// Updating an existing terrain.
|
// Updating an existing terrain.
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
|
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
|
||||||
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
|
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
|
||||||
|
|
||||||
// Remove from the dynamics world because we're going to mangle this object
|
// Remove from the dynamics world because we're going to mangle this object
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
||||||
|
|
||||||
// Get rid of the old terrain
|
// Get rid of the old terrain
|
||||||
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
||||||
BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
|
BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
|
||||||
mapInfo.Ptr = IntPtr.Zero;
|
mapInfo.Ptr = IntPtr.Zero;
|
||||||
|
|
||||||
|
@ -286,7 +293,7 @@ public class BSTerrainManager
|
||||||
BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
|
BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
|
||||||
|
|
||||||
mapInfo.ID = id;
|
mapInfo.ID = id;
|
||||||
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.ID,
|
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
|
||||||
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
|
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
|
||||||
|
|
||||||
// The terrain object initial position is at the center of the object
|
// The terrain object initial position is at the center of the object
|
||||||
|
@ -296,43 +303,49 @@ public class BSTerrainManager
|
||||||
centerPos.Z = minZ + ((maxZ - minZ) / 2f);
|
centerPos.Z = minZ + ((maxZ - minZ) / 2f);
|
||||||
|
|
||||||
// Create the terrain shape from the mapInfo
|
// Create the terrain shape from the mapInfo
|
||||||
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
|
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
|
||||||
|
ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
|
||||||
|
|
||||||
mapInfo.terrainBody = new BulletBody(mapInfo.ID,
|
mapInfo.terrainBody = new BulletBody(mapInfo.ID,
|
||||||
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.Ptr,
|
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
|
||||||
centerPos, Quaternion.Identity));
|
id, centerPos, Quaternion.Identity));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the entry is in the heightmap table
|
// Make sure the entry is in the heightmap table
|
||||||
m_heightMaps[terrainRegionBase] = mapInfo;
|
m_heightMaps[terrainRegionBase] = mapInfo;
|
||||||
|
|
||||||
// Set current terrain attributes
|
// Set current terrain attributes
|
||||||
BulletSimAPI.SetFriction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
|
BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
|
||||||
BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
|
BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
|
||||||
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainRestitution);
|
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
|
||||||
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
|
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
|
||||||
|
|
||||||
BulletSimAPI.SetMassProps2(mapInfo.terrainBody.Ptr, 0f, Vector3.Zero);
|
BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
|
||||||
BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.Ptr);
|
BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
|
||||||
|
|
||||||
// Return the new terrain to the world of physical objects
|
// Return the new terrain to the world of physical objects
|
||||||
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
||||||
|
|
||||||
// redo its bounding box now that it is in the world
|
// redo its bounding box now that it is in the world
|
||||||
BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
|
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
||||||
|
|
||||||
|
BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
|
||||||
|
(uint)CollisionFilterGroups.TerrainFilter,
|
||||||
|
(uint)CollisionFilterGroups.TerrainMask);
|
||||||
|
|
||||||
// Make sure the new shape is processed.
|
// Make sure the new shape is processed.
|
||||||
BulletSimAPI.Activate2(mapInfo.terrainBody.Ptr, true);
|
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
||||||
|
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
|
|
||||||
m_terrainModified = true;
|
m_terrainModified = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// There is the option to do the changes now (we're already in 'taint time'), or
|
// There is the option to do the changes now (we're already in 'taint time'), or
|
||||||
// to do the Bullet operations later.
|
// to do the Bullet operations later.
|
||||||
if (doNow)
|
if (atTaintTime)
|
||||||
rebuildOperation();
|
rebuildOperation();
|
||||||
else
|
else
|
||||||
m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
|
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -357,7 +370,7 @@ public class BSTerrainManager
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
|
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
|
||||||
// Create a new mapInfo that will be filled with the new info
|
// Create a new mapInfo that will be filled with the new info
|
||||||
mapInfo = new BulletHeightMapInfo(id, heightMapX,
|
mapInfo = new BulletHeightMapInfo(id, heightMapX,
|
||||||
BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, newTerrainID,
|
BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
|
||||||
minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
|
minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
|
||||||
// Put the unfilled heightmap info into the collection of same
|
// Put the unfilled heightmap info into the collection of same
|
||||||
m_heightMaps.Add(terrainRegionBase, mapInfo);
|
m_heightMaps.Add(terrainRegionBase, mapInfo);
|
||||||
|
@ -368,10 +381,10 @@ public class BSTerrainManager
|
||||||
};
|
};
|
||||||
|
|
||||||
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
|
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
|
||||||
if (doNow)
|
if (atTaintTime)
|
||||||
createOperation();
|
createOperation();
|
||||||
else
|
else
|
||||||
m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
|
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +432,7 @@ public class BSTerrainManager
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
||||||
m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
|
PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
|
||||||
LogHeader, terrainBaseXY, regionX, regionY);
|
LogHeader, terrainBaseXY, regionX, regionY);
|
||||||
ret = HEIGHT_GETHEIGHT_RET;
|
ret = HEIGHT_GETHEIGHT_RET;
|
||||||
}
|
}
|
||||||
|
@ -428,8 +441,8 @@ public class BSTerrainManager
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
|
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
|
||||||
LogHeader, m_physicsScene.RegionName, tX, tY);
|
LogHeader, PhysicsScene.RegionName, tX, tY);
|
||||||
}
|
}
|
||||||
m_terrainModified = false;
|
m_terrainModified = false;
|
||||||
lastHeight = ret;
|
lastHeight = ret;
|
||||||
|
@ -453,7 +466,7 @@ public class BSTerrainManager
|
||||||
{
|
{
|
||||||
m_worldOffset = offset;
|
m_worldOffset = offset;
|
||||||
m_worldMax = extents;
|
m_worldMax = extents;
|
||||||
m_parentScene = pScene;
|
MegaRegionParentPhysicsScene = pScene;
|
||||||
if (pScene != null)
|
if (pScene != null)
|
||||||
{
|
{
|
||||||
// We are a child.
|
// We are a child.
|
||||||
|
@ -474,7 +487,7 @@ public class BSTerrainManager
|
||||||
|
|
||||||
private void DetailLog(string msg, params Object[] args)
|
private void DetailLog(string msg, params Object[] args)
|
||||||
{
|
{
|
||||||
m_physicsScene.PhysicsLogging.Write(msg, args);
|
PhysicsScene.PhysicsLogging.Write(msg, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,35 +38,112 @@ namespace OpenSim.Region.Physics.BulletSPlugin {
|
||||||
// The physics engine controller class created at initialization
|
// The physics engine controller class created at initialization
|
||||||
public struct BulletSim
|
public struct BulletSim
|
||||||
{
|
{
|
||||||
public BulletSim(uint worldId, BSScene bss, IntPtr xx) { worldID = worldId; scene = bss; Ptr = xx; }
|
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
|
||||||
|
{
|
||||||
|
ptr = xx;
|
||||||
|
worldID = worldId;
|
||||||
|
physicsScene = bss;
|
||||||
|
}
|
||||||
|
public IntPtr ptr;
|
||||||
public uint worldID;
|
public uint worldID;
|
||||||
// The scene is only in here so very low level routines have a handle to print debug/error messages
|
// The scene is only in here so very low level routines have a handle to print debug/error messages
|
||||||
public BSScene scene;
|
public BSScene physicsScene;
|
||||||
public IntPtr Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct BulletShape
|
|
||||||
{
|
|
||||||
public BulletShape(IntPtr xx) { Ptr = xx; }
|
|
||||||
public IntPtr Ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// An allocated Bullet btRigidBody
|
// An allocated Bullet btRigidBody
|
||||||
public struct BulletBody
|
public struct BulletBody
|
||||||
{
|
{
|
||||||
public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
|
public BulletBody(uint id, IntPtr xx)
|
||||||
public IntPtr Ptr;
|
{
|
||||||
|
ID = id;
|
||||||
|
ptr = xx;
|
||||||
|
collisionFilter = 0;
|
||||||
|
collisionMask = 0;
|
||||||
|
}
|
||||||
|
public IntPtr ptr;
|
||||||
public uint ID;
|
public uint ID;
|
||||||
|
public CollisionFilterGroups collisionFilter;
|
||||||
|
public CollisionFilterGroups collisionMask;
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder buff = new StringBuilder();
|
||||||
|
buff.Append("<id=");
|
||||||
|
buff.Append(ID.ToString());
|
||||||
|
buff.Append(",p=");
|
||||||
|
buff.Append(ptr.ToString("X"));
|
||||||
|
if (collisionFilter != 0 && collisionMask != 0)
|
||||||
|
{
|
||||||
|
buff.Append(",f=");
|
||||||
|
buff.Append(collisionFilter.ToString("X"));
|
||||||
|
buff.Append(",m=");
|
||||||
|
buff.Append(collisionMask.ToString("X"));
|
||||||
|
}
|
||||||
|
buff.Append(">");
|
||||||
|
return buff.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct BulletShape
|
||||||
|
{
|
||||||
|
public BulletShape(IntPtr xx)
|
||||||
|
{
|
||||||
|
ptr = xx;
|
||||||
|
type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
|
shapeKey = 0;
|
||||||
|
isNativeShape = false;
|
||||||
|
}
|
||||||
|
public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
|
||||||
|
{
|
||||||
|
ptr = xx;
|
||||||
|
type = typ;
|
||||||
|
shapeKey = 0;
|
||||||
|
isNativeShape = false;
|
||||||
|
}
|
||||||
|
public IntPtr ptr;
|
||||||
|
public ShapeData.PhysicsShapeType type;
|
||||||
|
public ulong shapeKey;
|
||||||
|
public bool isNativeShape;
|
||||||
|
// Hulls have an underlying mesh. A pointer to it is hidden here.
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder buff = new StringBuilder();
|
||||||
|
buff.Append("<p=");
|
||||||
|
buff.Append(ptr.ToString("X"));
|
||||||
|
buff.Append(",s=");
|
||||||
|
buff.Append(type.ToString());
|
||||||
|
buff.Append(",k=");
|
||||||
|
buff.Append(shapeKey.ToString("X"));
|
||||||
|
buff.Append(",n=");
|
||||||
|
buff.Append(isNativeShape.ToString());
|
||||||
|
buff.Append(">");
|
||||||
|
return buff.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constraint type values as defined by Bullet
|
||||||
|
public enum ConstraintType : int
|
||||||
|
{
|
||||||
|
POINT2POINT_CONSTRAINT_TYPE = 3,
|
||||||
|
HINGE_CONSTRAINT_TYPE,
|
||||||
|
CONETWIST_CONSTRAINT_TYPE,
|
||||||
|
D6_CONSTRAINT_TYPE,
|
||||||
|
SLIDER_CONSTRAINT_TYPE,
|
||||||
|
CONTACT_CONSTRAINT_TYPE,
|
||||||
|
D6_SPRING_CONSTRAINT_TYPE,
|
||||||
|
MAX_CONSTRAINT_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
// An allocated Bullet btConstraint
|
// An allocated Bullet btConstraint
|
||||||
public struct BulletConstraint
|
public struct BulletConstraint
|
||||||
{
|
{
|
||||||
public BulletConstraint(IntPtr xx) { Ptr = xx; }
|
public BulletConstraint(IntPtr xx)
|
||||||
public IntPtr Ptr;
|
{
|
||||||
|
ptr = xx;
|
||||||
|
}
|
||||||
|
public IntPtr ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// An allocated HeightMapThing which hold various heightmap info
|
// An allocated HeightMapThing which holds various heightmap info.
|
||||||
// Made a class rather than a struct so there would be only one
|
// Made a class rather than a struct so there would be only one
|
||||||
// instance of this and C# will pass around pointers rather
|
// instance of this and C# will pass around pointers rather
|
||||||
// than making copies.
|
// than making copies.
|
||||||
|
@ -114,7 +191,9 @@ public struct ShapeData
|
||||||
SHAPE_CYLINDER = 4,
|
SHAPE_CYLINDER = 4,
|
||||||
SHAPE_SPHERE = 5,
|
SHAPE_SPHERE = 5,
|
||||||
SHAPE_MESH = 6,
|
SHAPE_MESH = 6,
|
||||||
SHAPE_HULL = 7
|
SHAPE_HULL = 7,
|
||||||
|
SHAPE_GROUNDPLANE = 8,
|
||||||
|
SHAPE_TERRAIN = 9,
|
||||||
};
|
};
|
||||||
public uint ID;
|
public uint ID;
|
||||||
public PhysicsShapeType Type;
|
public PhysicsShapeType Type;
|
||||||
|
@ -130,10 +209,21 @@ public struct ShapeData
|
||||||
public float Restitution;
|
public float Restitution;
|
||||||
public float Collidable; // true of things bump into this
|
public float Collidable; // true of things bump into this
|
||||||
public float Static; // true if a static object. Otherwise gravity, etc.
|
public float Static; // true if a static object. Otherwise gravity, etc.
|
||||||
|
public float Solid; // true if object cannot be passed through
|
||||||
|
public Vector3 Size;
|
||||||
|
|
||||||
// note that bools are passed as floats since bool size changes by language and architecture
|
// note that bools are passed as floats since bool size changes by language and architecture
|
||||||
public const float numericTrue = 1f;
|
public const float numericTrue = 1f;
|
||||||
public const float numericFalse = 0f;
|
public const float numericFalse = 0f;
|
||||||
|
|
||||||
|
// The native shapes have predefined shape hash keys
|
||||||
|
public enum FixedShapeKey : ulong
|
||||||
|
{
|
||||||
|
KEY_BOX = 1,
|
||||||
|
KEY_SPHERE = 2,
|
||||||
|
KEY_CONE = 3,
|
||||||
|
KEY_CYLINDER = 4,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SweepHit
|
public struct SweepHit
|
||||||
|
@ -227,7 +317,17 @@ public enum ActivationState : uint
|
||||||
ISLAND_SLEEPING,
|
ISLAND_SLEEPING,
|
||||||
WANTS_DEACTIVATION,
|
WANTS_DEACTIVATION,
|
||||||
DISABLE_DEACTIVATION,
|
DISABLE_DEACTIVATION,
|
||||||
DISABLE_SIMULATION
|
DISABLE_SIMULATION,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CollisionObjectTypes : int
|
||||||
|
{
|
||||||
|
CO_COLLISION_OBJECT = 1 << 0,
|
||||||
|
CO_RIGID_BODY = 1 << 1,
|
||||||
|
CO_GHOST_OBJECT = 1 << 2,
|
||||||
|
CO_SOFT_BODY = 1 << 3,
|
||||||
|
CO_HF_FLUID = 1 << 4,
|
||||||
|
CO_USER_TYPE = 1 << 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values used by Bullet and BulletSim to control object properties.
|
// Values used by Bullet and BulletSim to control object properties.
|
||||||
|
@ -244,77 +344,60 @@ public enum CollisionFlags : uint
|
||||||
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
|
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
|
||||||
// Following used by BulletSim to control collisions
|
// Following used by BulletSim to control collisions
|
||||||
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
|
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
|
||||||
BS_VOLUME_DETECT_OBJECT = 1 << 11,
|
// BS_VOLUME_DETECT_OBJECT = 1 << 11,
|
||||||
BS_PHANTOM_OBJECT = 1 << 12,
|
// BS_PHANTOM_OBJECT = 1 << 12,
|
||||||
BS_PHYSICAL_OBJECT = 1 << 13,
|
// BS_PHYSICAL_OBJECT = 1 << 13,
|
||||||
BS_TERRAIN_OBJECT = 1 << 14,
|
// BS_TERRAIN_OBJECT = 1 << 14,
|
||||||
BS_NONE = 0,
|
BS_NONE = 0,
|
||||||
BS_ALL = 0xFFFFFFFF
|
BS_ALL = 0xFFFFFFFF,
|
||||||
|
|
||||||
|
// These are the collision flags switched depending on physical state.
|
||||||
|
// The other flags are used for other things and should not be fooled with.
|
||||||
|
BS_ACTIVE = CF_STATIC_OBJECT
|
||||||
|
| CF_KINEMATIC_OBJECT
|
||||||
|
| CF_NO_CONTACT_RESPONSE
|
||||||
|
// | BS_VOLUME_DETECT_OBJECT
|
||||||
|
// | BS_PHANTOM_OBJECT
|
||||||
|
// | BS_PHYSICAL_OBJECT,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for collisions groups and masks
|
// Values for collisions groups and masks
|
||||||
public enum CollisionFilterGroups : uint
|
public enum CollisionFilterGroups : uint
|
||||||
{
|
{
|
||||||
NoneFilter = 0,
|
// Don't use the bit definitions!! Define the use in a
|
||||||
DefaultFilter = 1 << 0,
|
// filter/mask definition below. This way collision interactions
|
||||||
StaticFilter = 1 << 1,
|
// are more easily debugged.
|
||||||
KinematicFilter = 1 << 2,
|
BNoneFilter = 0,
|
||||||
DebrisFilter = 1 << 3,
|
BDefaultFilter = 1 << 0,
|
||||||
SensorTrigger = 1 << 4,
|
BStaticFilter = 1 << 1,
|
||||||
CharacterFilter = 1 << 5,
|
BKinematicFilter = 1 << 2,
|
||||||
AllFilter = 0xFFFFFFFF,
|
BDebrisFilter = 1 << 3,
|
||||||
|
BSensorTrigger = 1 << 4,
|
||||||
|
BCharacterFilter = 1 << 5,
|
||||||
|
BAllFilter = 0xFFFFFFFF,
|
||||||
// Filter groups defined by BulletSim
|
// Filter groups defined by BulletSim
|
||||||
GroundPlaneFilter = 1 << 10,
|
BGroundPlaneFilter = 1 << 10,
|
||||||
TerrainFilter = 1 << 11,
|
BTerrainFilter = 1 << 11,
|
||||||
RaycastFilter = 1 << 12,
|
BRaycastFilter = 1 << 12,
|
||||||
SolidFilter = 1 << 13,
|
BSolidFilter = 1 << 13,
|
||||||
|
|
||||||
|
// The collsion filters and masked are defined in one place -- don't want them scattered
|
||||||
|
AvatarFilter = BCharacterFilter,
|
||||||
|
AvatarMask = BAllFilter,
|
||||||
|
ObjectFilter = BSolidFilter,
|
||||||
|
ObjectMask = BAllFilter,
|
||||||
|
StaticObjectFilter = BStaticFilter,
|
||||||
|
StaticObjectMask = BAllFilter,
|
||||||
|
VolumeDetectFilter = BSensorTrigger,
|
||||||
|
VolumeDetectMask = ~BSensorTrigger,
|
||||||
|
TerrainFilter = BTerrainFilter,
|
||||||
|
TerrainMask = BAllFilter & ~BStaticFilter,
|
||||||
|
GroundPlaneFilter = BAllFilter,
|
||||||
|
GroundPlaneMask = BAllFilter
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// For each type, we first clear and then set the collision flags
|
|
||||||
public enum ClearCollisionFlag : uint
|
|
||||||
{
|
|
||||||
Terrain = CollisionFlags.BS_ALL,
|
|
||||||
Phantom = CollisionFlags.BS_ALL,
|
|
||||||
VolumeDetect = CollisionFlags.BS_ALL,
|
|
||||||
PhysicalObject = CollisionFlags.BS_ALL,
|
|
||||||
StaticObject = CollisionFlags.BS_ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SetCollisionFlag : uint
|
|
||||||
{
|
|
||||||
Terrain = CollisionFlags.CF_STATIC_OBJECT
|
|
||||||
| CollisionFlags.BS_TERRAIN_OBJECT,
|
|
||||||
Phantom = CollisionFlags.CF_STATIC_OBJECT
|
|
||||||
| CollisionFlags.BS_PHANTOM_OBJECT
|
|
||||||
| CollisionFlags.CF_NO_CONTACT_RESPONSE,
|
|
||||||
VolumeDetect = CollisionFlags.CF_STATIC_OBJECT
|
|
||||||
| CollisionFlags.BS_VOLUME_DETECT_OBJECT
|
|
||||||
| CollisionFlags.CF_NO_CONTACT_RESPONSE,
|
|
||||||
PhysicalObject = CollisionFlags.BS_PHYSICAL_OBJECT,
|
|
||||||
StaticObject = CollisionFlags.CF_STATIC_OBJECT,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collision filters used for different types of objects
|
|
||||||
public enum SetCollisionFilter : uint
|
|
||||||
{
|
|
||||||
Terrain = CollisionFilterGroups.AllFilter,
|
|
||||||
Phantom = CollisionFilterGroups.GroundPlaneFilter
|
|
||||||
| CollisionFilterGroups.TerrainFilter,
|
|
||||||
VolumeDetect = CollisionFilterGroups.AllFilter,
|
|
||||||
PhysicalObject = CollisionFilterGroups.AllFilter,
|
|
||||||
StaticObject = CollisionFilterGroups.AllFilter,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collision masks used for different types of objects
|
|
||||||
public enum SetCollisionMask : uint
|
|
||||||
{
|
|
||||||
Terrain = CollisionFilterGroups.AllFilter,
|
|
||||||
Phantom = CollisionFilterGroups.GroundPlaneFilter
|
|
||||||
| CollisionFilterGroups.TerrainFilter,
|
|
||||||
VolumeDetect = CollisionFilterGroups.AllFilter,
|
|
||||||
PhysicalObject = CollisionFilterGroups.AllFilter,
|
|
||||||
StaticObject = CollisionFilterGroups.AllFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
|
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
|
||||||
// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
|
// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
|
||||||
|
@ -516,11 +599,10 @@ public static extern IntPtr CreateHullShape2(IntPtr world,
|
||||||
int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
|
int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr BuildHullShape2(IntPtr world, IntPtr meshShape);
|
public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr BuildNativeShape2(IntPtr world,
|
public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
|
||||||
float shapeType, float collisionMargin, Vector3 scale);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern bool IsNativeShape2(IntPtr shape);
|
public static extern bool IsNativeShape2(IntPtr shape);
|
||||||
|
@ -535,16 +617,25 @@ public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShap
|
||||||
public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
|
public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, IntPtr constructionInfo);
|
public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
|
public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, Vector3 pos, Quaternion rot);
|
public static extern int GetBodyType2(IntPtr obj);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, Vector3 pos, Quaternion rot);
|
public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
|
public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
|
||||||
|
@ -963,6 +1054,9 @@ public static extern Vector3 GetPushVelocity2(IntPtr obj);
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern Vector3 GetTurnVelocity2(IntPtr obj);
|
public static extern Vector3 GetTurnVelocity2(IntPtr obj);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// btCollisionShape entries
|
// btCollisionShape entries
|
||||||
|
|
||||||
|
@ -1014,9 +1108,6 @@ public static extern void SetMargin2(IntPtr shape, float val);
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern float GetMargin2(IntPtr shape);
|
public static extern float GetMargin2(IntPtr shape);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern void SetCollisionFilterMask(IntPtr shape, uint filter, uint mask);
|
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// Debugging
|
// Debugging
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
|
|
@ -50,8 +50,6 @@ namespace OpenSim.Services.Interfaces
|
||||||
public DateTime Login;
|
public DateTime Login;
|
||||||
public DateTime Logout;
|
public DateTime Logout;
|
||||||
|
|
||||||
public string TOS = string.Empty;
|
|
||||||
|
|
||||||
public GridUserInfo() {}
|
public GridUserInfo() {}
|
||||||
|
|
||||||
public GridUserInfo(Dictionary<string, object> kvp)
|
public GridUserInfo(Dictionary<string, object> kvp)
|
||||||
|
@ -80,11 +78,6 @@ namespace OpenSim.Services.Interfaces
|
||||||
if (kvp.ContainsKey("Online"))
|
if (kvp.ContainsKey("Online"))
|
||||||
Boolean.TryParse(kvp["Online"].ToString(), out Online);
|
Boolean.TryParse(kvp["Online"].ToString(), out Online);
|
||||||
|
|
||||||
if (kvp.ContainsKey("TOS"))
|
|
||||||
TOS = kvp["TOS"].ToString();
|
|
||||||
else
|
|
||||||
TOS = string.Empty;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> ToKeyValuePairs()
|
public Dictionary<string, object> ToKeyValuePairs()
|
||||||
|
@ -104,8 +97,6 @@ namespace OpenSim.Services.Interfaces
|
||||||
result["Login"] = Login.ToString();
|
result["Login"] = Login.ToString();
|
||||||
result["Logout"] = Logout.ToString();
|
result["Logout"] = Logout.ToString();
|
||||||
|
|
||||||
result["TOS"] = TOS;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,6 @@ namespace OpenSim.Services.UserAccountService
|
||||||
info.Login = Util.ToDateTime(Convert.ToInt32(d.Data["Login"]));
|
info.Login = Util.ToDateTime(Convert.ToInt32(d.Data["Login"]));
|
||||||
info.Logout = Util.ToDateTime(Convert.ToInt32(d.Data["Logout"]));
|
info.Logout = Util.ToDateTime(Convert.ToInt32(d.Data["Logout"]));
|
||||||
|
|
||||||
info.TOS = d.Data["TOS"];
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -947,35 +947,6 @@
|
||||||
;# {InitialTerrain} {} {Initial terrain type} {pinhead-island flat} pinhead-island
|
;# {InitialTerrain} {} {Initial terrain type} {pinhead-island flat} pinhead-island
|
||||||
; InitialTerrain = "pinhead-island"
|
; InitialTerrain = "pinhead-island"
|
||||||
|
|
||||||
[TOSModule]
|
|
||||||
;; Terms of Service module. It requires an external web script. Unless you
|
|
||||||
;; have that in place, don't enable this module.
|
|
||||||
|
|
||||||
;# {Enabled} {} {Enable TOS facilities} {true false} false
|
|
||||||
; Enabled = false
|
|
||||||
|
|
||||||
;; Should local users be shown the TOS on first login?
|
|
||||||
;# {ShowToLocalUsers} {} {Show TOS to local users} {true false} false
|
|
||||||
; ShowToLocalUsers = false
|
|
||||||
;; Should foreign users be shown the TOS on first HG login?
|
|
||||||
;# {ShowToForeignUsers} {} {Show TOS to foreign users} {true false} true
|
|
||||||
; ShowToForeignUsers = true
|
|
||||||
|
|
||||||
;; Tell the users what this is about
|
|
||||||
; Message = "Please read and agree to the Terms of Service"
|
|
||||||
|
|
||||||
;; How much time do the users have to accept the TOS before they get kicked out?
|
|
||||||
;; (in minutes)
|
|
||||||
; Timeout = 5
|
|
||||||
|
|
||||||
;; This page should have Accept/Decline links somewhere
|
|
||||||
;; that affect the GridUsers table. If you don't have such
|
|
||||||
;; script in place, don't use the TOSModule. The TOSModule appends this URL
|
|
||||||
;; with a query ?user={userid}&sid={sessionid}
|
|
||||||
;# {TOS_URL} {} {The URL for the TOS page} {}
|
|
||||||
TOS_URL = "http://mygrid.com/tos"
|
|
||||||
|
|
||||||
|
|
||||||
[Architecture]
|
[Architecture]
|
||||||
;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini
|
;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini
|
||||||
;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim,
|
;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim,
|
||||||
|
|
|
@ -932,10 +932,10 @@
|
||||||
MaxPersistantManifoldPoolSize = 0
|
MaxPersistantManifoldPoolSize = 0
|
||||||
ShouldDisableContactPoolDynamicAllocation = False
|
ShouldDisableContactPoolDynamicAllocation = False
|
||||||
ShouldForceUpdateAllAabbs = False
|
ShouldForceUpdateAllAabbs = False
|
||||||
ShouldRandomizeSolverOrder = False
|
ShouldRandomizeSolverOrder = True
|
||||||
ShouldSplitSimulationIslands = False
|
ShouldSplitSimulationIslands = True
|
||||||
ShouldEnableFrictionCaching = False
|
ShouldEnableFrictionCaching = False
|
||||||
NumberOfSolverIterations = 0;
|
NumberOfSolverIterations = 0
|
||||||
|
|
||||||
; Linkset constraint parameters
|
; Linkset constraint parameters
|
||||||
LinkConstraintUseFrameOffset = False
|
LinkConstraintUseFrameOffset = False
|
||||||
|
@ -1033,30 +1033,31 @@
|
||||||
;default_appearance = default_appearance.xml
|
;default_appearance = default_appearance.xml
|
||||||
|
|
||||||
|
|
||||||
[RestPlugins]
|
; RestPlugins are not currently operational.
|
||||||
; Change this to true to enable REST Plugins. This must be true if you wish to use
|
;[RestPlugins]
|
||||||
; REST Region or REST Asset and Inventory Plugins
|
; ; Change this to true to enable REST Plugins. This must be true if you wish to use
|
||||||
enabled = false
|
; ; REST Region or REST Asset and Inventory Plugins
|
||||||
god_key = SECRET
|
; enabled = false
|
||||||
prefix = /admin
|
; god_key = SECRET
|
||||||
|
; prefix = /admin
|
||||||
|
|
||||||
|
|
||||||
[RestRegionPlugin]
|
;[RestRegionPlugin]
|
||||||
; Change this to true to enable the REST Region Plugin
|
; ; Change this to true to enable the REST Region Plugin
|
||||||
enabled = false
|
; enabled = false
|
||||||
|
|
||||||
|
|
||||||
[RestHandler]
|
;[RestHandler]
|
||||||
; Change this to true to enable the REST Asset and Inventory Plugin
|
; ; Change this to true to enable the REST Asset and Inventory Plugin
|
||||||
enabled = false
|
; enabled = false
|
||||||
authenticate = true
|
; authenticate = true
|
||||||
secured = true
|
; secured = true
|
||||||
extended-escape = true
|
; extended-escape = true
|
||||||
realm = OpenSim REST
|
; realm = OpenSim REST
|
||||||
dump-asset = false
|
; dump-asset = false
|
||||||
path-fill = true
|
; path-fill = true
|
||||||
dump-line-size = 32
|
; dump-line-size = 32
|
||||||
flush-on-error = true
|
; flush-on-error = true
|
||||||
|
|
||||||
|
|
||||||
; IRC bridge is experimental, so if it breaks... keep both parts... yada yada
|
; IRC bridge is experimental, so if it breaks... keep both parts... yada yada
|
||||||
|
@ -1624,10 +1625,6 @@
|
||||||
[Terrain]
|
[Terrain]
|
||||||
InitialTerrain = "pinhead-island"
|
InitialTerrain = "pinhead-island"
|
||||||
|
|
||||||
[TOSModule]
|
|
||||||
;; Enable TOS facilities
|
|
||||||
Enabled = false
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; If you are using a simian grid frontend you can enable
|
;; If you are using a simian grid frontend you can enable
|
||||||
;; this module to upload tile images for the mapping fn
|
;; this module to upload tile images for the mapping fn
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue