aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs87
-rw-r--r--OpenSim/Framework/Pool.cs15
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs89
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs51
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs40
-rw-r--r--OpenSim/Region/Framework/Scenes/SimStatsReporter.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs10
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs15
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs368
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs385
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs20
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs7
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs61
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs4
17 files changed, 767 insertions, 417 deletions
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 31989e5..4844336 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -207,7 +207,7 @@ namespace OpenSim.Framework.Monitoring
207 return false; 207 return false;
208 208
209 newContainer = new Dictionary<string, Stat>(container); 209 newContainer = new Dictionary<string, Stat>(container);
210 newContainer.Remove(stat.UniqueName); 210 newContainer.Remove(stat.ShortName);
211 211
212 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category); 212 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
213 newCategory.Remove(stat.Container); 213 newCategory.Remove(stat.Container);
@@ -249,6 +249,19 @@ namespace OpenSim.Framework.Monitoring
249 } 249 }
250 250
251 /// <summary> 251 /// <summary>
252 /// Stat type.
253 /// </summary>
254 /// <remarks>
255 /// A push stat is one which is continually updated and so it's value can simply by read.
256 /// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated.
257 /// </remarks>
258 public enum StatType
259 {
260 Push,
261 Pull
262 }
263
264 /// <summary>
252 /// Verbosity of stat. 265 /// Verbosity of stat.
253 /// </summary> 266 /// </summary>
254 /// <remarks> 267 /// <remarks>
@@ -266,11 +279,6 @@ namespace OpenSim.Framework.Monitoring
266 public class Stat 279 public class Stat
267 { 280 {
268 /// <summary> 281 /// <summary>
269 /// Unique stat name used for indexing. Each ShortName in a Category must be unique.
270 /// </summary>
271 public string UniqueName { get; private set; }
272
273 /// <summary>
274 /// Category of this stat (e.g. cache, scene, etc). 282 /// Category of this stat (e.g. cache, scene, etc).
275 /// </summary> 283 /// </summary>
276 public string Category { get; private set; } 284 public string Category { get; private set; }
@@ -285,29 +293,65 @@ namespace OpenSim.Framework.Monitoring
285 /// </value> 293 /// </value>
286 public string Container { get; private set; } 294 public string Container { get; private set; }
287 295
296 public StatType StatType { get; private set; }
297
298 /// <summary>
299 /// Action used to update this stat when the value is requested if it's a pull type.
300 /// </summary>
301 public Action<Stat> PullAction { get; private set; }
302
288 public StatVerbosity Verbosity { get; private set; } 303 public StatVerbosity Verbosity { get; private set; }
289 public string ShortName { get; private set; } 304 public string ShortName { get; private set; }
290 public string Name { get; private set; } 305 public string Name { get; private set; }
291 public string Description { get; private set; } 306 public string Description { get; private set; }
292 public virtual string UnitName { get; private set; } 307 public virtual string UnitName { get; private set; }
293 308
294 public virtual double Value { get; set; } 309 public virtual double Value
310 {
311 get
312 {
313 // Asking for an update here means that the updater cannot access this value without infinite recursion.
314 // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
315 // called by the pull action and just return the value.
316 if (StatType == StatType.Pull)
317 PullAction(this);
318
319 return m_value;
320 }
321
322 set
323 {
324 m_value = value;
325 }
326 }
327
328 private double m_value;
295 329
296 /// <summary> 330 /// <summary>
297 /// Constructor 331 /// Constructor
298 /// </summary> 332 /// </summary>
299 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param> 333 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
300 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param> 334 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
335 /// <param name='description'>Description of stat</param>
301 /// <param name='unitName'> 336 /// <param name='unitName'>
302 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value. 337 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
303 /// e.g. " frames" 338 /// e.g. " frames"
304 /// </param> 339 /// </param>
305 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param> 340 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
306 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param> 341 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
342 /// <param name='type'>Push or pull</param>
343 /// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
307 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param> 344 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
308 /// <param name='description'>Description of stat</param>
309 public Stat( 345 public Stat(
310 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) 346 string shortName,
347 string name,
348 string description,
349 string unitName,
350 string category,
351 string container,
352 StatType type,
353 Action<Stat> pullAction,
354 StatVerbosity verbosity)
311 { 355 {
312 if (StatsManager.SubCommands.Contains(category)) 356 if (StatsManager.SubCommands.Contains(category))
313 throw new Exception( 357 throw new Exception(
@@ -315,18 +359,18 @@ namespace OpenSim.Framework.Monitoring
315 359
316 ShortName = shortName; 360 ShortName = shortName;
317 Name = name; 361 Name = name;
362 Description = description;
318 UnitName = unitName; 363 UnitName = unitName;
319 Category = category; 364 Category = category;
320 Container = container; 365 Container = container;
321 Verbosity = verbosity; 366 StatType = type;
322 Description = description;
323 367
324 UniqueName = GenUniqueName(Container, Category, ShortName); 368 if (StatType == StatType.Push && pullAction != null)
325 } 369 throw new Exception("A push stat cannot have a pull action");
370 else
371 PullAction = pullAction;
326 372
327 public static string GenUniqueName(string container, string category, string shortName) 373 Verbosity = verbosity;
328 {
329 return string.Format("{0}+{1}+{2}", container, category, shortName);
330 } 374 }
331 375
332 public virtual string ToConsoleString() 376 public virtual string ToConsoleString()
@@ -361,8 +405,15 @@ namespace OpenSim.Framework.Monitoring
361 } 405 }
362 406
363 public PercentageStat( 407 public PercentageStat(
364 string shortName, string name, string category, string container, StatVerbosity verbosity, string description) 408 string shortName,
365 : base(shortName, name, "%", category, container, verbosity, description) {} 409 string name,
410 string description,
411 string category,
412 string container,
413 StatType type,
414 Action<Stat> pullAction,
415 StatVerbosity verbosity)
416 : base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
366 417
367 public override string ToConsoleString() 418 public override string ToConsoleString()
368 { 419 {
diff --git a/OpenSim/Framework/Pool.cs b/OpenSim/Framework/Pool.cs
index 1ca06c3..5484f5c 100644
--- a/OpenSim/Framework/Pool.cs
+++ b/OpenSim/Framework/Pool.cs
@@ -38,8 +38,23 @@ namespace OpenSim.Framework
38 /// </remarks> 38 /// </remarks>
39 public class Pool<T> 39 public class Pool<T>
40 { 40 {
41 /// <summary>
42 /// Number of objects in the pool.
43 /// </summary>
44 public int Count
45 {
46 get
47 {
48 lock (m_pool)
49 return m_pool.Count;
50 }
51 }
52
41 private Stack<T> m_pool; 53 private Stack<T> m_pool;
42 54
55 /// <summary>
56 /// Maximum pool size. Beyond this, any returned objects are not pooled.
57 /// </summary>
43 private int m_maxPoolSize; 58 private int m_maxPoolSize;
44 59
45 private Func<T> m_createFunction; 60 private Func<T> m_createFunction;
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index b3e31a6..3198891 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -543,11 +543,8 @@ namespace OpenSim.Framework.Servers.HttpServer
543 { 543 {
544 case null: 544 case null:
545 case "text/html": 545 case "text/html":
546
547 if (DebugLevel >= 3) 546 if (DebugLevel >= 3)
548 m_log.DebugFormat( 547 LogIncomingToContentTypeHandler(request);
549 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
550 RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
551 548
552 buffer = HandleHTTPRequest(request, response); 549 buffer = HandleHTTPRequest(request, response);
553 break; 550 break;
@@ -555,11 +552,8 @@ namespace OpenSim.Framework.Servers.HttpServer
555 case "application/llsd+xml": 552 case "application/llsd+xml":
556 case "application/xml+llsd": 553 case "application/xml+llsd":
557 case "application/llsd+json": 554 case "application/llsd+json":
558
559 if (DebugLevel >= 3) 555 if (DebugLevel >= 3)
560 m_log.DebugFormat( 556 LogIncomingToContentTypeHandler(request);
561 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
562 RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
563 557
564 buffer = HandleLLSDRequests(request, response); 558 buffer = HandleLLSDRequests(request, response);
565 break; 559 break;
@@ -694,7 +688,7 @@ namespace OpenSim.Framework.Servers.HttpServer
694 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", 688 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
695 RequestNumber, 689 RequestNumber,
696 Port, 690 Port,
697 request.ContentType, 691 (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType,
698 request.HttpMethod, 692 request.HttpMethod,
699 request.Url.PathAndQuery, 693 request.Url.PathAndQuery,
700 request.RemoteIPEndPoint); 694 request.RemoteIPEndPoint);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index df4bbb3..b8951d9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -173,6 +173,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
173 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 173 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
174 private Pool<IncomingPacket> m_incomingPacketPool; 174 private Pool<IncomingPacket> m_incomingPacketPool;
175 175
176 private Stat m_incomingPacketPoolStat;
177
176 private int m_defaultRTO = 0; 178 private int m_defaultRTO = 0;
177 private int m_maxRTO = 0; 179 private int m_maxRTO = 0;
178 private int m_ackTimeout = 0; 180 private int m_ackTimeout = 0;
@@ -217,6 +219,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
217 219
218 m_circuitManager = circuitManager; 220 m_circuitManager = circuitManager;
219 int sceneThrottleBps = 0; 221 int sceneThrottleBps = 0;
222 bool usePools = false;
220 223
221 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 224 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
222 if (config != null) 225 if (config != null)
@@ -249,7 +252,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
249 { 252 {
250 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); 253 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
251 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true); 254 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
252 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false); 255 usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
253 } 256 }
254 257
255 #region BinaryStats 258 #region BinaryStats
@@ -280,8 +283,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
280 m_throttle = new TokenBucket(null, sceneThrottleBps); 283 m_throttle = new TokenBucket(null, sceneThrottleBps);
281 ThrottleRates = new ThrottleRates(configSource); 284 ThrottleRates = new ThrottleRates(configSource);
282 285
283 if (UsePools) 286 if (usePools)
284 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500); 287 EnablePools();
285 } 288 }
286 289
287 public void Start() 290 public void Start()
@@ -334,6 +337,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
334 base.StopInbound(); 337 base.StopInbound();
335 } 338 }
336 339
340 protected override bool EnablePools()
341 {
342 if (!UsePools)
343 {
344 base.EnablePools();
345
346 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
347
348 m_incomingPacketPoolStat
349 = new Stat(
350 "IncomingPacketPoolCount",
351 "Objects within incoming packet pool",
352 "The number of objects currently stored within the incoming packet pool",
353 "",
354 "clientstack",
355 "packetpool",
356 StatType.Pull,
357 stat => stat.Value = m_incomingPacketPool.Count,
358 StatVerbosity.Debug);
359
360 StatsManager.RegisterStat(m_incomingPacketPoolStat);
361
362 return true;
363 }
364
365 return false;
366 }
367
368 protected override bool DisablePools()
369 {
370 if (UsePools)
371 {
372 base.DisablePools();
373
374 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
375
376 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
377
378 return true;
379 }
380
381 return false;
382 }
383
337 /// <summary> 384 /// <summary>
338 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. 385 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
339 /// </summary> 386 /// </summary>
@@ -400,6 +447,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
400 MainConsole.Instance.Commands.AddCommand( 447 MainConsole.Instance.Commands.AddCommand(
401 "Debug", 448 "Debug",
402 false, 449 false,
450 "debug lludp pool",
451 "debug lludp pool <on|off>",
452 "Turn object pooling within the lludp component on or off.",
453 HandlePoolCommand);
454
455 MainConsole.Instance.Commands.AddCommand(
456 "Debug",
457 false,
403 "debug lludp status", 458 "debug lludp status",
404 "debug lludp status", 459 "debug lludp status",
405 "Return status of LLUDP packet processing.", 460 "Return status of LLUDP packet processing.",
@@ -440,6 +495,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
440 StopOutbound(); 495 StopOutbound();
441 } 496 }
442 497
498 private void HandlePoolCommand(string module, string[] args)
499 {
500 if (args.Length != 4)
501 {
502 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
503 return;
504 }
505
506 string enabled = args[3];
507
508 if (enabled == "on")
509 {
510 if (EnablePools())
511 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
512 }
513 else if (enabled == "off")
514 {
515 if (DisablePools())
516 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
517 }
518 else
519 {
520 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
521 }
522 }
523
443 private void HandleStatusCommand(string module, string[] args) 524 private void HandleStatusCommand(string module, string[] args)
444 { 525 {
445 MainConsole.Instance.OutputFormat( 526 MainConsole.Instance.OutputFormat(
@@ -447,6 +528,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 528
448 MainConsole.Instance.OutputFormat( 529 MainConsole.Instance.OutputFormat(
449 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 530 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
531
532 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
450 } 533 }
451 534
452 public bool HandlesRegion(Location x) 535 public bool HandlesRegion(Location x)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index e7d8a30..8bd3461 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -31,6 +31,7 @@ using System.Net.Sockets;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34 35
35namespace OpenMetaverse 36namespace OpenMetaverse
36{ 37{
@@ -76,6 +77,8 @@ namespace OpenMetaverse
76 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks> 77 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
77 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
78 79
80 private Stat m_poolCountStat;
81
79 /// <summary> 82 /// <summary>
80 /// Default constructor 83 /// Default constructor
81 /// </summary> 84 /// </summary>
@@ -106,11 +109,6 @@ namespace OpenMetaverse
106 /// necessary</remarks> 109 /// necessary</remarks>
107 public void StartInbound(int recvBufferSize, bool asyncPacketHandling) 110 public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
108 { 111 {
109 if (UsePools)
110 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
111 else
112 m_pool = null;
113
114 m_asyncPacketHandling = asyncPacketHandling; 112 m_asyncPacketHandling = asyncPacketHandling;
115 113
116 if (!IsRunningInbound) 114 if (!IsRunningInbound)
@@ -176,6 +174,49 @@ namespace OpenMetaverse
176 IsRunningOutbound = false; 174 IsRunningOutbound = false;
177 } 175 }
178 176
177 protected virtual bool EnablePools()
178 {
179 if (!UsePools)
180 {
181 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
182
183 m_poolCountStat
184 = new Stat(
185 "UDPPacketBufferPoolCount",
186 "Objects within the UDPPacketBuffer pool",
187 "The number of objects currently stored within the UDPPacketBuffer pool",
188 "",
189 "clientstack",
190 "packetpool",
191 StatType.Pull,
192 stat => stat.Value = m_pool.Count,
193 StatVerbosity.Debug);
194
195 StatsManager.RegisterStat(m_poolCountStat);
196
197 UsePools = true;
198
199 return true;
200 }
201
202 return false;
203 }
204
205 protected virtual bool DisablePools()
206 {
207 if (UsePools)
208 {
209 UsePools = false;
210 StatsManager.DeregisterStat(m_poolCountStat);
211
212 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
213
214 return true;
215 }
216
217 return false;
218 }
219
179 private void AsyncBeginReceive() 220 private void AsyncBeginReceive()
180 { 221 {
181 UDPPacketBuffer buf; 222 UDPPacketBuffer buf;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 2a3d14f..9f22fb4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -47,18 +47,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
47 private PercentageStat m_packetsReusedStat = new PercentageStat( 47 private PercentageStat m_packetsReusedStat = new PercentageStat(
48 "PacketsReused", 48 "PacketsReused",
49 "Packets reused", 49 "Packets reused",
50 "Number of packets reused out of all requests to the packet pool",
50 "clientstack", 51 "clientstack",
51 "packetpool", 52 "packetpool",
52 StatVerbosity.Debug, 53 StatType.Push,
53 "Number of packets reused out of all requests to the packet pool"); 54 null,
55 StatVerbosity.Debug);
54 56
55 private PercentageStat m_blocksReusedStat = new PercentageStat( 57 private PercentageStat m_blocksReusedStat = new PercentageStat(
56 "BlocksReused", 58 "PacketDataBlocksReused",
57 "Blocks reused", 59 "Packet data blocks reused",
60 "Number of data blocks reused out of all requests to the packet pool",
58 "clientstack", 61 "clientstack",
59 "packetpool", 62 "packetpool",
60 StatVerbosity.Debug, 63 StatType.Push,
61 "Number of data blocks reused out of all requests to the packet pool"); 64 null,
65 StatVerbosity.Debug);
62 66
63 /// <summary> 67 /// <summary>
64 /// Pool of packets available for reuse. 68 /// Pool of packets available for reuse.
@@ -88,6 +92,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
88 { 92 {
89 StatsManager.RegisterStat(m_packetsReusedStat); 93 StatsManager.RegisterStat(m_packetsReusedStat);
90 StatsManager.RegisterStat(m_blocksReusedStat); 94 StatsManager.RegisterStat(m_blocksReusedStat);
95
96 StatsManager.RegisterStat(
97 new Stat(
98 "PacketsPoolCount",
99 "Objects within the packet pool",
100 "The number of objects currently stored within the packet pool",
101 "",
102 "clientstack",
103 "packetpool",
104 StatType.Pull,
105 stat => { lock (pool) { stat.Value = pool.Count; } },
106 StatVerbosity.Debug));
107
108 StatsManager.RegisterStat(
109 new Stat(
110 "PacketDataBlocksPoolCount",
111 "Objects within the packet data block pool",
112 "The number of objects currently stored within the packet data block pool",
113 "",
114 "clientstack",
115 "packetpool",
116 StatType.Pull,
117 stat => { lock (DataBlocks) { stat.Value = DataBlocks.Count; } },
118 StatVerbosity.Debug));
91 } 119 }
92 120
93 /// <summary> 121 /// <summary>
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 0d359b9..5398ab9 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -246,11 +246,13 @@ namespace OpenSim.Region.Framework.Scenes
246 = new Stat( 246 = new Stat(
247 "SlowFrames", 247 "SlowFrames",
248 "Slow Frames", 248 "Slow Frames",
249 "Number of frames where frame time has been significantly longer than the desired frame time.",
249 " frames", 250 " frames",
250 "scene", 251 "scene",
251 m_scene.Name, 252 m_scene.Name,
252 StatVerbosity.Info, 253 StatType.Push,
253 "Number of frames where frame time has been significantly longer than the desired frame time."); 254 null,
255 StatVerbosity.Info);
254 256
255 StatsManager.RegisterStat(SlowFramesStat); 257 StatsManager.RegisterStat(SlowFramesStat);
256 } 258 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 623ac8f..07dd613 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -165,7 +165,7 @@ public class BSCharacter : BSPhysObject
165 165
166 // Do this after the object has been added to the world 166 // Do this after the object has been added to the world
167 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, 167 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
168 (uint)CollisionFilterGroups.AvatarFilter, 168 (uint)CollisionFilterGroups.AvatarFilter,
169 (uint)CollisionFilterGroups.AvatarMask); 169 (uint)CollisionFilterGroups.AvatarMask);
170 } 170 }
171 171
@@ -269,7 +269,7 @@ public class BSCharacter : BSPhysObject
269 private bool PositionSanityCheck() 269 private bool PositionSanityCheck()
270 { 270 {
271 bool ret = false; 271 bool ret = false;
272 272
273 // If below the ground, move the avatar up 273 // If below the ground, move the avatar up
274 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 274 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
275 if (Position.Z < terrainHeight) 275 if (Position.Z < terrainHeight)
@@ -413,7 +413,7 @@ public class BSCharacter : BSPhysObject
413 }); 413 });
414 } 414 }
415 } 415 }
416 // Go directly to Bullet to get/set the value. 416 // Go directly to Bullet to get/set the value.
417 public override OMV.Quaternion ForceOrientation 417 public override OMV.Quaternion ForceOrientation
418 { 418 {
419 get 419 get
@@ -478,7 +478,7 @@ public class BSCharacter : BSPhysObject
478 set { _collidingObj = value; } 478 set { _collidingObj = value; }
479 } 479 }
480 public override bool FloatOnWater { 480 public override bool FloatOnWater {
481 set { 481 set {
482 _floatOnWater = value; 482 _floatOnWater = value;
483 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 483 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
484 { 484 {
@@ -588,7 +588,7 @@ public class BSCharacter : BSPhysObject
588 newScale.X = PhysicsScene.Params.avatarCapsuleRadius; 588 newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
589 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; 589 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
590 590
591 // From the total height, remote the capsule half spheres that are at each end 591 // From the total height, remote the capsule half spheres that are at each end
592 newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y); 592 newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
593 // newScale.Z = (size.Z * 2f); 593 // newScale.Z = (size.Z * 2f);
594 Scale = newScale; 594 Scale = newScale;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index a20be3a..f017cdd 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
37 protected BulletSim m_world; 39 protected BulletSim m_world;
38 protected BulletBody m_body1; 40 protected BulletBody m_body1;
39 protected BulletBody m_body2; 41 protected BulletBody m_body2;
@@ -53,7 +55,7 @@ public abstract class BSConstraint : IDisposable
53 { 55 {
54 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 56 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
55 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 57 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
56 BSScene.DetailLogZero, 58 BSScene.DetailLogZero,
57 m_body1.ID, m_body1.ptr.ToString("X"), 59 m_body1.ID, m_body1.ptr.ToString("X"),
58 m_body2.ID, m_body2.ptr.ToString("X"), 60 m_body2.ID, m_body2.ptr.ToString("X"),
59 success); 61 success);
@@ -124,7 +126,7 @@ public abstract class BSConstraint : IDisposable
124 } 126 }
125 else 127 else
126 { 128 {
127 m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
128 } 130 }
129 } 131 }
130 return ret; 132 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 56342b8..117c878 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 *
27 27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system. 29 * call the BulletSim system.
@@ -352,7 +352,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
352 // m_bankingMix = 1; 352 // m_bankingMix = 1;
353 // m_bankingTimescale = 1; 353 // m_bankingTimescale = 1;
354 // m_referenceFrame = Quaternion.Identity; 354 // m_referenceFrame = Quaternion.Identity;
355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
356 | VehicleFlag.LIMIT_ROLL_ONLY 356 | VehicleFlag.LIMIT_ROLL_ONLY
357 | VehicleFlag.LIMIT_MOTOR_UP); 357 | VehicleFlag.LIMIT_MOTOR_UP);
358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
@@ -382,7 +382,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
382 // m_bankingTimescale = 1; 382 // m_bankingTimescale = 1;
383 // m_referenceFrame = Quaternion.Identity; 383 // m_referenceFrame = Quaternion.Identity;
384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY 384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
385 | VehicleFlag.HOVER_GLOBAL_HEIGHT 385 | VehicleFlag.HOVER_GLOBAL_HEIGHT
386 | VehicleFlag.LIMIT_ROLL_ONLY 386 | VehicleFlag.LIMIT_ROLL_ONLY
387 | VehicleFlag.HOVER_UP_ONLY); 387 | VehicleFlag.HOVER_UP_ONLY);
388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@@ -458,14 +458,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
458 // Do any updating needed for a vehicle 458 // Do any updating needed for a vehicle
459 public void Refresh() 459 public void Refresh()
460 { 460 {
461 if (!IsActive) 461 if (!IsActive)
462 return; 462 return;
463 463
464 // Set the prim's inertia to zero. The vehicle code handles that and this 464 // Set the prim's inertia to zero. The vehicle code handles that and this
465 // removes the motion and torque actions introduced by Bullet. 465 // removes the motion and torque actions introduced by Bullet.
466 Vector3 inertia = Vector3.Zero; 466 Vector3 inertia = Vector3.Zero;
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); 467 // comment out for DEBUG test
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); 468 // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
469 // BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
469 } 470 }
470 471
471 // One step of the vehicle properties for the next 'pTimestep' seconds. 472 // One step of the vehicle properties for the next 'pTimestep' seconds.
@@ -791,7 +792,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
791 792
792 // Sum velocities 793 // Sum velocities
793 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 794 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
794 795
795 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 796 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
796 { 797 {
797 m_lastAngularVelocity.X = 0; 798 m_lastAngularVelocity.X = 0;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 43b1262..c984824 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,10 +32,27 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public abstract class BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 // Create the correct type of linkset for this child
40 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
41 {
42 BSLinkset ret = null;
43 /*
44 if (parent.IsPhysical)
45 ret = new BSLinksetConstraints(physScene, parent);
46 else
47 ret = new BSLinksetManual(physScene, parent);
48 */
49
50 // at the moment, there is only one
51 ret = new BSLinksetConstraints(physScene, parent);
52
53 return ret;
54 }
55
39 public BSPhysObject LinksetRoot { get; protected set; } 56 public BSPhysObject LinksetRoot { get; protected set; }
40 57
41 public BSScene PhysicsScene { get; private set; } 58 public BSScene PhysicsScene { get; private set; }
@@ -52,16 +69,16 @@ public class BSLinkset
52 // the physical 'taint' children separately. 69 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these 70 // After taint processing and before the simulation step, these
54 // two lists must be the same. 71 // two lists must be the same.
55 private HashSet<BSPhysObject> m_children; 72 protected HashSet<BSPhysObject> m_children;
56 private HashSet<BSPhysObject> m_taintChildren; 73 protected HashSet<BSPhysObject> m_taintChildren;
57 74
58 // We lock the diddling of linkset classes to prevent any badness. 75 // We lock the diddling of linkset classes to prevent any badness.
59 // This locks the modification of the instances of this class. Changes 76 // This locks the modification of the instances of this class. Changes
60 // to the physical representation is done via the tainting mechenism. 77 // to the physical representation is done via the tainting mechenism.
61 private object m_linksetActivityLock = new Object(); 78 protected object m_linksetActivityLock = new Object();
62 79
63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 80 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
64 private float m_mass; 81 protected float m_mass;
65 public float LinksetMass 82 public float LinksetMass
66 { 83 {
67 get 84 get
@@ -81,7 +98,7 @@ public class BSLinkset
81 get { return ComputeLinksetGeometricCenter(); } 98 get { return ComputeLinksetGeometricCenter(); }
82 } 99 }
83 100
84 public BSLinkset(BSScene scene, BSPhysObject parent) 101 protected void Initialize(BSScene scene, BSPhysObject parent)
85 { 102 {
86 // A simple linkset of one (no children) 103 // A simple linkset of one (no children)
87 LinksetID = m_nextLinksetID++; 104 LinksetID = m_nextLinksetID++;
@@ -128,7 +145,7 @@ public class BSLinkset
128 } 145 }
129 146
130 // The child is down to a linkset of just itself 147 // The child is down to a linkset of just itself
131 return new BSLinkset(PhysicsScene, child); 148 return BSLinkset.Factory(PhysicsScene, child);
132 } 149 }
133 150
134 // Return 'true' if the passed object is the root object of this linkset 151 // Return 'true' if the passed object is the root object of this linkset
@@ -148,6 +165,9 @@ public class BSLinkset
148 bool ret = false; 165 bool ret = false;
149 lock (m_linksetActivityLock) 166 lock (m_linksetActivityLock)
150 { 167 {
168 if (m_children.Contains(child))
169 ret = true;
170 /*
151 foreach (BSPhysObject bp in m_children) 171 foreach (BSPhysObject bp in m_children)
152 { 172 {
153 if (child.LocalID == bp.LocalID) 173 if (child.LocalID == bp.LocalID)
@@ -156,6 +176,7 @@ public class BSLinkset
156 break; 176 break;
157 } 177 }
158 } 178 }
179 */
159 } 180 }
160 return ret; 181 return ret;
161 } 182 }
@@ -163,24 +184,7 @@ public class BSLinkset
163 // When physical properties are changed the linkset needs to recalculate 184 // When physical properties are changed the linkset needs to recalculate
164 // its internal properties. 185 // its internal properties.
165 // May be called at runtime or taint-time (just pass the appropriate flag). 186 // May be called at runtime or taint-time (just pass the appropriate flag).
166 public void Refresh(BSPhysObject requestor, bool inTaintTime) 187 public abstract void Refresh(BSPhysObject requestor, bool inTaintTime);
167 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints
169 // (For the moment, static linksets do create constraints so remove the test for physical.)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
171 return;
172
173 BSScene.TaintCallback refreshOperation = delegate()
174 {
175 RecomputeLinksetConstraintVariables();
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
178 };
179 if (inTaintTime)
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 }
184 188
185 // The object is going dynamic (physical). Do any setup necessary 189 // The object is going dynamic (physical). Do any setup necessary
186 // for a dynamic linkset. 190 // for a dynamic linkset.
@@ -188,102 +192,35 @@ public class BSLinkset
188 // has not yet been fully constructed. 192 // has not yet been fully constructed.
189 // Return 'true' if any properties updated on the passed object. 193 // Return 'true' if any properties updated on the passed object.
190 // Called at taint-time! 194 // Called at taint-time!
191 public bool MakeDynamic(BSPhysObject child) 195 public abstract bool MakeDynamic(BSPhysObject child);
192 {
193 // What is done for each object in BSPrim is what we want.
194 return false;
195 }
196 196
197 // The object is going static (non-physical). Do any setup necessary 197 // The object is going static (non-physical). Do any setup necessary
198 // for a static linkset. 198 // for a static linkset.
199 // Return 'true' if any properties updated on the passed object. 199 // Return 'true' if any properties updated on the passed object.
200 // Called at taint-time! 200 // Called at taint-time!
201 public bool MakeStatic(BSPhysObject child) 201 public abstract bool MakeStatic(BSPhysObject child);
202 {
203 // What is done for each object in BSPrim is what we want.
204 return false;
205 }
206 202
207 // If the software is handling the movement of all the objects in a linkset 203 // Called when a parameter update comes from the physics engine for any object
208 // (like if one doesn't use constraints for static linksets), this is called 204 // of the linkset is received.
209 // when an update for the root of the linkset is received.
210 // Called at taint-time!! 205 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject) 206 public abstract void UpdateProperties(BSPhysObject physObject);
212 {
213 // The root local properties have been updated. Apply to the children if appropriate.
214 if (IsRoot(physObject) && HasAnyChildren)
215 {
216 if (!physObject.IsPhysical)
217 {
218 // TODO: implement software linkset update for static object linksets
219 }
220 }
221 }
222 207
223 // Routine used when rebuilding the body of the root of the linkset 208 // Routine used when rebuilding the body of the root of the linkset
224 // Destroy all the constraints have have been made to root. 209 // Destroy all the constraints have have been made to root.
225 // This is called when the root body is changing. 210 // This is called when the root body is changing.
226 // Returns 'true' of something eas actually removed and would need restoring 211 // Returns 'true' of something was actually removed and would need restoring
227 // Called at taint-time!! 212 // Called at taint-time!!
228 public bool RemoveBodyDependencies(BSPrim child) 213 public abstract bool RemoveBodyDependencies(BSPrim child);
229 {
230 bool ret = false;
231
232 lock (m_linksetActivityLock)
233 {
234 if (IsRoot(child))
235 {
236 // If the one with the dependency is root, must undo all children
237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
239
240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
241 }
242 else
243 {
244 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
245 child.LocalID,
246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
247 child.LocalID, child.BSBody.ptr.ToString("X"));
248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
249 // Despite the function name, this removes any link to the specified object.
250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
251 }
252 }
253 return ret;
254 }
255 214
256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
257 // this routine will restore the removed constraints. 216 // this routine will restore the removed constraints.
258 // Called at taint-time!! 217 // Called at taint-time!!
259 public void RestoreBodyDependencies(BSPrim child) 218 public abstract void RestoreBodyDependencies(BSPrim child);
260 {
261 lock (m_linksetActivityLock)
262 {
263 if (IsRoot(child))
264 {
265 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
267 foreach (BSPhysObject bpo in m_taintChildren)
268 {
269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
270 }
271 }
272 else
273 {
274 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
275 LinksetRoot.LocalID,
276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
277 child.LocalID, child.BSBody.ptr.ToString("X"));
278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
279 }
280 }
281 }
282 219
283 // ================================================================ 220 // ================================================================
284 // Below this point is internal magic 221 // Below this point is internal magic
285 222
286 private float ComputeLinksetMass() 223 protected virtual float ComputeLinksetMass()
287 { 224 {
288 float mass; 225 float mass;
289 lock (m_linksetActivityLock) 226 lock (m_linksetActivityLock)
@@ -297,7 +234,7 @@ public class BSLinkset
297 return mass; 234 return mass;
298 } 235 }
299 236
300 private OMV.Vector3 ComputeLinksetCenterOfMass() 237 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
301 { 238 {
302 OMV.Vector3 com; 239 OMV.Vector3 com;
303 lock (m_linksetActivityLock) 240 lock (m_linksetActivityLock)
@@ -317,7 +254,7 @@ public class BSLinkset
317 return com; 254 return com;
318 } 255 }
319 256
320 private OMV.Vector3 ComputeLinksetGeometricCenter() 257 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
321 { 258 {
322 OMV.Vector3 com; 259 OMV.Vector3 com;
323 lock (m_linksetActivityLock) 260 lock (m_linksetActivityLock)
@@ -336,236 +273,21 @@ public class BSLinkset
336 273
337 // I am the root of a linkset and a new child is being added 274 // I am the root of a linkset and a new child is being added
338 // Called while LinkActivity is locked. 275 // Called while LinkActivity is locked.
339 private void AddChildToLinkset(BSPhysObject child) 276 protected abstract void AddChildToLinkset(BSPhysObject child);
340 {
341 if (!HasChild(child))
342 {
343 m_children.Add(child);
344
345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
346 BSPhysObject childx = child;
347
348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
349
350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
351 {
352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
353 rootx.LocalID,
354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
356 // Since this is taint-time, the body and shape could have changed for the child
357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
361 });
362 }
363 return;
364 }
365 277
366 // Forcefully removing a child from a linkset. 278 // Forcefully removing a child from a linkset.
367 // This is not being called by the child so we have to make sure the child doesn't think 279 // This is not being called by the child so we have to make sure the child doesn't think
368 // it's still connected to the linkset. 280 // it's still connected to the linkset.
369 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 281 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
370 // also has to be updated (like pointer to prim's parent). 282 // also has to be updated (like pointer to prim's parent).
371 private void RemoveChildFromOtherLinkset(BSPhysObject pchild) 283 protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
372 {
373 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
374 RemoveChildFromLinkset(pchild);
375 }
376 284
377 // I am the root of a linkset and one of my children is being removed. 285 // I am the root of a linkset and one of my children is being removed.
378 // Safe to call even if the child is not really in my linkset. 286 // Safe to call even if the child is not really in my linkset.
379 private void RemoveChildFromLinkset(BSPhysObject child) 287 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
380 {
381 if (m_children.Remove(child))
382 {
383 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
384 BSPhysObject childx = child;
385
386 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
387 childx.LocalID,
388 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
389 childx.LocalID, childx.BSBody.ptr.ToString("X"));
390
391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
392 {
393 m_taintChildren.Remove(child);
394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
395 RecomputeLinksetConstraintVariables();
396 });
397
398 }
399 else
400 {
401 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
402 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
403 }
404 return;
405 }
406
407 // Create a constraint between me (root of linkset) and the passed prim (the child).
408 // Called at taint time!
409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
410 {
411 // Zero motion for children so they don't interpolate
412 childPrim.ZeroMotion();
413
414 // Relative position normalized to the root prim
415 // Essentually a vector pointing from center of rootPrim to center of childPrim
416 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
417
418 // real world coordinate of midpoint between the two objects
419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
420
421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
422 rootPrim.LocalID,
423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
425 rootPrim.Position, childPrim.Position, midPoint);
426
427 // create a constraint that allows no freedom of movement between the two objects
428 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
429
430 BS6DofConstraint constrain = new BS6DofConstraint(
431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
432
433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
435 * of the objects.
436 * Code left as a warning to future programmers.
437 // ==================================================================================
438 // relative position normalized to the root prim
439 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
440 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
441
442 // relative rotation of the child to the parent
443 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
444 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
445
446 // create a constraint that allows no freedom of movement between the two objects
447 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
449 BS6DofConstraint constrain = new BS6DofConstraint(
450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
451 OMV.Vector3.Zero,
452 OMV.Quaternion.Inverse(rootPrim.Orientation),
453 OMV.Vector3.Zero,
454 OMV.Quaternion.Inverse(childPrim.Orientation),
455 // A point half way between the parent and child
456 // childRelativePosition/2,
457 // childRelativeRotation,
458 // childRelativePosition/2,
459 // inverseChildRelativeRotation,
460 true,
461 true
462 );
463 // ==================================================================================
464 */
465
466 PhysicsScene.Constraints.AddConstraint(constrain);
467
468 // zero linear and angular limits makes the objects unable to move in relation to each other
469 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
470 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
471
472 // tweek the constraint to increase stability
473 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
474 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
475 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
476 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
477 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
478 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
479 {
480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
481 }
482 }
483
484 // Remove linkage between myself and a particular child
485 // The root and child bodies are passed in because we need to remove the constraint between
486 // the bodies that were at unlink time.
487 // Called at taint time!
488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
489 {
490 bool ret = false;
491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
492 rootPrim.LocalID,
493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
495
496 // Find the constraint for this link and get rid of it from the overall collection and from my list
497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
503
504 return ret;
505 }
506
507 // Remove linkage between myself and any possible children I might have.
508 // Called at taint time!
509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
510 {
511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
512 bool ret = false;
513
514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
519 }
520
521 // Call each of the constraints that make up this linkset and recompute the
522 // various transforms and variables. Used when objects are added or removed
523 // from a linkset to make sure the constraints know about the new mass and
524 // geometry.
525 // Must only be called at taint time!!
526 private void RecomputeLinksetConstraintVariables()
527 {
528 float linksetMass = LinksetMass;
529 foreach (BSPhysObject child in m_taintChildren)
530 {
531 BSConstraint constrain;
532 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
533 {
534 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
535 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
536 constrain.RecomputeConstraintVariables(linksetMass);
537 }
538 else
539 {
540 // Non-fatal error that happens when children are being added to the linkset but
541 // their constraints have not been created yet.
542 break;
543 }
544 }
545
546 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
547 if (m_children.Count == m_taintChildren.Count)
548 {
549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
555 foreach (BSPhysObject child in m_taintChildren)
556 {
557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
562 }
563 return;
564 }
565
566 288
567 // Invoke the detailed logger and output something if it's enabled. 289 // Invoke the detailed logger and output something if it's enabled.
568 private void DetailLog(string msg, params Object[] args) 290 protected void DetailLog(string msg, params Object[] args)
569 { 291 {
570 if (PhysicsScene.PhysicsLogging.Enabled) 292 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args); 293 PhysicsScene.DetailLog(msg, args);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000..8a750b5
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,385 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties.
46 // May be called at runtime or taint-time (just pass the appropriate flag).
47 public override void Refresh(BSPhysObject requestor, bool inTaintTime)
48 {
49 // If there are no children or not root, I am not the one that recomputes the constraints
50 if (!HasAnyChildren || !IsRoot(requestor))
51 return;
52
53 BSScene.TaintCallback refreshOperation = delegate()
54 {
55 RecomputeLinksetConstraintVariables();
56 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
57 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
58 };
59 if (inTaintTime)
60 refreshOperation();
61 else
62 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
63 }
64
65 // The object is going dynamic (physical). Do any setup necessary
66 // for a dynamic linkset.
67 // Only the state of the passed object can be modified. The rest of the linkset
68 // has not yet been fully constructed.
69 // Return 'true' if any properties updated on the passed object.
70 // Called at taint-time!
71 public override bool MakeDynamic(BSPhysObject child)
72 {
73 // What is done for each object in BSPrim is what we want.
74 return false;
75 }
76
77 // The object is going static (non-physical). Do any setup necessary
78 // for a static linkset.
79 // Return 'true' if any properties updated on the passed object.
80 // Called at taint-time!
81 public override bool MakeStatic(BSPhysObject child)
82 {
83 // What is done for each object in BSPrim is what we want.
84 return false;
85 }
86
87 // Called at taint-time!!
88 public override void UpdateProperties(BSPhysObject updated)
89 {
90 // Nothing to do for constraints on property updates
91 }
92
93 // Routine used when rebuilding the body of the root of the linkset
94 // Destroy all the constraints have have been made to root.
95 // This is called when the root body is changing.
96 // Returns 'true' of something eas actually removed and would need restoring
97 // Called at taint-time!!
98 public override bool RemoveBodyDependencies(BSPrim child)
99 {
100 bool ret = false;
101
102 lock (m_linksetActivityLock)
103 {
104 if (IsRoot(child))
105 {
106 // If the one with the dependency is root, must undo all children
107 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
108 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
109
110 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
111 }
112 else
113 {
114 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
115 child.LocalID,
116 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
117 child.LocalID, child.BSBody.ptr.ToString("X"));
118 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
119 // Despite the function name, this removes any link to the specified object.
120 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
121 }
122 }
123 return ret;
124 }
125
126 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
127 // this routine will restore the removed constraints.
128 // Called at taint-time!!
129 public override void RestoreBodyDependencies(BSPrim child)
130 {
131 lock (m_linksetActivityLock)
132 {
133 if (IsRoot(child))
134 {
135 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
136 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
137 foreach (BSPhysObject bpo in m_taintChildren)
138 {
139 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
140 }
141 }
142 else
143 {
144 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
145 LinksetRoot.LocalID,
146 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
147 child.LocalID, child.BSBody.ptr.ToString("X"));
148 PhysicallyLinkAChildToRoot(LinksetRoot, child);
149 }
150 }
151 }
152
153 // ================================================================
154 // Below this point is internal magic
155
156 // I am the root of a linkset and a new child is being added
157 // Called while LinkActivity is locked.
158 protected override void AddChildToLinkset(BSPhysObject child)
159 {
160 if (!HasChild(child))
161 {
162 m_children.Add(child);
163
164 BSPhysObject rootx = LinksetRoot; // capture the root as of now
165 BSPhysObject childx = child;
166
167 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
168
169 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
170 {
171 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
172 rootx.LocalID,
173 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
174 childx.LocalID, childx.BSBody.ptr.ToString("X"));
175 // Since this is taint-time, the body and shape could have changed for the child
176 rootx.ForcePosition = rootx.Position; // DEBUG
177 childx.ForcePosition = childx.Position; // DEBUG
178 PhysicallyLinkAChildToRoot(rootx, childx);
179 m_taintChildren.Add(child);
180 });
181 }
182 return;
183 }
184
185 // Forcefully removing a child from a linkset.
186 // This is not being called by the child so we have to make sure the child doesn't think
187 // it's still connected to the linkset.
188 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
189 // also has to be updated (like pointer to prim's parent).
190 protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
191 {
192 pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
193 RemoveChildFromLinkset(pchild);
194 }
195
196 // I am the root of a linkset and one of my children is being removed.
197 // Safe to call even if the child is not really in my linkset.
198 protected override void RemoveChildFromLinkset(BSPhysObject child)
199 {
200 if (m_children.Remove(child))
201 {
202 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
203 BSPhysObject childx = child;
204
205 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
206 childx.LocalID,
207 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
208 childx.LocalID, childx.BSBody.ptr.ToString("X"));
209
210 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
211 {
212 m_taintChildren.Remove(child);
213 PhysicallyUnlinkAChildFromRoot(rootx, childx);
214 RecomputeLinksetConstraintVariables();
215 });
216
217 }
218 else
219 {
220 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
221 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
222 }
223 return;
224 }
225
226 // Create a constraint between me (root of linkset) and the passed prim (the child).
227 // Called at taint time!
228 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
229 {
230 // Zero motion for children so they don't interpolate
231 childPrim.ZeroMotion();
232
233 // Relative position normalized to the root prim
234 // Essentually a vector pointing from center of rootPrim to center of childPrim
235 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
236
237 // real world coordinate of midpoint between the two objects
238 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
239
240 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
241 rootPrim.LocalID,
242 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
243 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
244 rootPrim.Position, childPrim.Position, midPoint);
245
246 // create a constraint that allows no freedom of movement between the two objects
247 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
248
249 BS6DofConstraint constrain = new BS6DofConstraint(
250 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
251
252 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
253 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
254 * of the objects.
255 * Code left as a warning to future programmers.
256 // ==================================================================================
257 // relative position normalized to the root prim
258 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
259 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
260
261 // relative rotation of the child to the parent
262 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
263 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
264
265 // create a constraint that allows no freedom of movement between the two objects
266 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
267 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
268 BS6DofConstraint constrain = new BS6DofConstraint(
269 PhysicsScene.World, rootPrim.Body, childPrim.Body,
270 OMV.Vector3.Zero,
271 OMV.Quaternion.Inverse(rootPrim.Orientation),
272 OMV.Vector3.Zero,
273 OMV.Quaternion.Inverse(childPrim.Orientation),
274 // A point half way between the parent and child
275 // childRelativePosition/2,
276 // childRelativeRotation,
277 // childRelativePosition/2,
278 // inverseChildRelativeRotation,
279 true,
280 true
281 );
282 // ==================================================================================
283 */
284
285 PhysicsScene.Constraints.AddConstraint(constrain);
286
287 // zero linear and angular limits makes the objects unable to move in relation to each other
288 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
289 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
290
291 // tweek the constraint to increase stability
292 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
293 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
294 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
295 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
296 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
297 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
298 {
299 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
300 }
301 }
302
303 // Remove linkage between myself and a particular child
304 // The root and child bodies are passed in because we need to remove the constraint between
305 // the bodies that were at unlink time.
306 // Called at taint time!
307 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
308 {
309 bool ret = false;
310 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
311 rootPrim.LocalID,
312 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
313 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
314
315 // Find the constraint for this link and get rid of it from the overall collection and from my list
316 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
317 {
318 // Make the child refresh its location
319 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
320 ret = true;
321 }
322
323 return ret;
324 }
325
326 // Remove linkage between myself and any possible children I might have.
327 // Called at taint time!
328 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
329 {
330 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
331 bool ret = false;
332
333 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
334 {
335 ret = true;
336 }
337 return ret;
338 }
339
340 // Call each of the constraints that make up this linkset and recompute the
341 // various transforms and variables. Used when objects are added or removed
342 // from a linkset to make sure the constraints know about the new mass and
343 // geometry.
344 // Must only be called at taint time!!
345 private void RecomputeLinksetConstraintVariables()
346 {
347 float linksetMass = LinksetMass;
348 foreach (BSPhysObject child in m_taintChildren)
349 {
350 BSConstraint constrain;
351 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
352 {
353 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
354 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
355 constrain.RecomputeConstraintVariables(linksetMass);
356 }
357 else
358 {
359 // Non-fatal error that happens when children are being added to the linkset but
360 // their constraints have not been created yet.
361 break;
362 }
363 }
364
365 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
366 if (m_children.Count == m_taintChildren.Count)
367 {
368 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
369 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
370 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
371 centerOfMass, OMV.Quaternion.Identity);
372 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
373 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
374 foreach (BSPhysObject child in m_taintChildren)
375 {
376 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
377 centerOfMass, OMV.Quaternion.Identity);
378 }
379
380 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
381 }
382 return;
383 }
384}
385}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index ead6a08..538f905 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -46,7 +46,7 @@ public abstract class BSPhysObject : PhysicsActor
46 PhysObjectName = name; 46 PhysObjectName = name;
47 TypeName = typeName; 47 TypeName = typeName;
48 48
49 Linkset = new BSLinkset(PhysicsScene, this); 49 Linkset = BSLinkset.Factory(PhysicsScene, this);
50 LastAssetBuildFailed = false; 50 LastAssetBuildFailed = false;
51 51
52 CollisionCollection = new CollisionEventUpdate(); 52 CollisionCollection = new CollisionEventUpdate();
@@ -78,7 +78,7 @@ public abstract class BSPhysObject : PhysicsActor
78 public PrimitiveBaseShape BaseShape { get; protected set; } 78 public PrimitiveBaseShape BaseShape { get; protected set; }
79 79
80 // When the physical properties are updated, an EntityProperty holds the update values. 80 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences 81 // Keep the current and last EntityProperties to enable computation of differences
82 // between the current update and the previous values. 82 // between the current update and the previous values.
83 public EntityProperties CurrentEntityProperties { get; set; } 83 public EntityProperties CurrentEntityProperties { get; set; }
84 public EntityProperties LastEntityProperties { get; set; } 84 public EntityProperties LastEntityProperties { get; set; }
@@ -213,7 +213,7 @@ public abstract class BSPhysObject : PhysicsActor
213 UnSubscribeEvents(); 213 UnSubscribeEvents();
214 } 214 }
215 } 215 }
216 public override void UnSubscribeEvents() { 216 public override void UnSubscribeEvents() {
217 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); 217 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
218 SubscribedEventsMs = 0; 218 SubscribedEventsMs = 0;
219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
@@ -222,7 +222,7 @@ public abstract class BSPhysObject : PhysicsActor
222 }); 222 });
223 } 223 }
224 // Return 'true' if the simulator wants collision events 224 // Return 'true' if the simulator wants collision events
225 public override bool SubscribedEvents() { 225 public override bool SubscribedEvents() {
226 return (SubscribedEventsMs > 0); 226 return (SubscribedEventsMs > 0);
227 } 227 }
228 228
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index aeeb4dd..38ab3de 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -173,6 +173,7 @@ public sealed class BSPrim : BSPhysObject
173 } 173 }
174 public override bool ForceBodyShapeRebuild(bool inTaintTime) 174 public override bool ForceBodyShapeRebuild(bool inTaintTime)
175 { 175 {
176 LastAssetBuildFailed = false;
176 BSScene.TaintCallback rebuildOperation = delegate() 177 BSScene.TaintCallback rebuildOperation = delegate()
177 { 178 {
178 _mass = CalculateMass(); // changing the shape changes the mass 179 _mass = CalculateMass(); // changing the shape changes the mass
@@ -295,7 +296,7 @@ public sealed class BSPrim : BSPhysObject
295 private bool PositionSanityCheck() 296 private bool PositionSanityCheck()
296 { 297 {
297 bool ret = false; 298 bool ret = false;
298 299
299 // If totally below the ground, move the prim up 300 // If totally below the ground, move the prim up
300 // TODO: figure out the right solution for this... only for dynamic objects? 301 // TODO: figure out the right solution for this... only for dynamic objects?
301 /* 302 /*
@@ -398,7 +399,7 @@ public sealed class BSPrim : BSPhysObject
398 { 399 {
399 // Done at taint time so we're sure the physics engine is not using the variables 400 // Done at taint time so we're sure the physics engine is not using the variables
400 // Vehicle code changes the parameters for this vehicle type. 401 // Vehicle code changes the parameters for this vehicle type.
401 this._vehicle.ProcessTypeChange(type); 402 _vehicle.ProcessTypeChange(type);
402 }); 403 });
403 } 404 }
404 } 405 }
@@ -510,7 +511,7 @@ public sealed class BSPrim : BSPhysObject
510 }); 511 });
511 } 512 }
512 } 513 }
513 // Go directly to Bullet to get/set the value. 514 // Go directly to Bullet to get/set the value.
514 public override OMV.Quaternion ForceOrientation 515 public override OMV.Quaternion ForceOrientation
515 { 516 {
516 get 517 get
@@ -768,7 +769,7 @@ public sealed class BSPrim : BSPhysObject
768 } 769 }
769 } 770 }
770 public override bool FloatOnWater { 771 public override bool FloatOnWater {
771 set { 772 set {
772 _floatOnWater = value; 773 _floatOnWater = value;
773 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 774 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
774 { 775 {
@@ -971,7 +972,7 @@ public sealed class BSPrim : BSPhysObject
971 if (hollowAmount > 0.0) 972 if (hollowAmount > 0.0)
972 { 973 {
973 hollowVolume *= hollowAmount; 974 hollowVolume *= hollowAmount;
974 975
975 switch (BaseShape.HollowShape) 976 switch (BaseShape.HollowShape)
976 { 977 {
977 case HollowShape.Square: 978 case HollowShape.Square:
@@ -1245,13 +1246,14 @@ public sealed class BSPrim : BSPhysObject
1245 FillShapeInfo(out shapeData); 1246 FillShapeInfo(out shapeData);
1246 1247
1247 // If this prim is part of a linkset, we must remove and restore the physical 1248 // If this prim is part of a linkset, we must remove and restore the physical
1248 // links of the body is rebuilt. 1249 // links if the body is rebuilt.
1249 bool needToRestoreLinkset = false; 1250 bool needToRestoreLinkset = false;
1250 1251
1251 // Create the correct physical representation for this type of object. 1252 // Create the correct physical representation for this type of object.
1252 // Updates BSBody and BSShape with the new information. 1253 // Updates BSBody and BSShape with the new information.
1253 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1254 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1254 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, 1255 // Returns 'true' if either the body or the shape was changed.
1256 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
1255 null, delegate(BulletBody dBody) 1257 null, delegate(BulletBody dBody)
1256 { 1258 {
1257 // Called if the current prim body is about to be destroyed. 1259 // Called if the current prim body is about to be destroyed.
@@ -1354,7 +1356,7 @@ public sealed class BSPrim : BSPhysObject
1354 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1356 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1355 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1357 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1356 1358
1357 // BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr); 1359 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1358 1360
1359 base.RequestPhysicsterseUpdate(); 1361 base.RequestPhysicsterseUpdate();
1360 } 1362 }
@@ -1367,8 +1369,8 @@ public sealed class BSPrim : BSPhysObject
1367 entprop.Acceleration, entprop.RotationalVelocity); 1369 entprop.Acceleration, entprop.RotationalVelocity);
1368 } 1370 }
1369 */ 1371 */
1370 // The linkset implimentation might want to know about this.
1371 1372
1373 // The linkset implimentation might want to know about this.
1372 Linkset.UpdateProperties(this); 1374 Linkset.UpdateProperties(this);
1373 } 1375 }
1374} 1376}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 6621d39..e686f2f 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -320,7 +320,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
320 { 320 {
321 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 321 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
322 } 322 }
323 323
324 // Called directly from unmanaged code so don't do much 324 // Called directly from unmanaged code so don't do much
325 private void BulletLoggerPhysLog(string msg) 325 private void BulletLoggerPhysLog(string msg)
326 { 326 {
@@ -545,7 +545,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
545 } 545 }
546 546
547 // This is a kludge to get avatar movement updates. 547 // This is a kludge to get avatar movement updates.
548 // The simulator expects collisions for avatars even if there are have been no collisions. 548 // The simulator expects collisions for avatars even if there are have been no collisions.
549 // The event updates avatar animations and stuff. 549 // The event updates avatar animations and stuff.
550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. 550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
551 foreach (BSPhysObject bsp in m_avatars) 551 foreach (BSPhysObject bsp in m_avatars)
@@ -716,6 +716,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
716 } 716 }
717 catch (Exception e) 717 catch (Exception e)
718 { 718 {
719 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); 720 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 } 721 }
721 } 722 }
@@ -1333,7 +1334,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1333 // Add the Flush() if debugging crashes to get all the messages written out. 1334 // Add the Flush() if debugging crashes to get all the messages written out.
1334 // PhysicsLogging.Flush(); 1335 // PhysicsLogging.Flush();
1335 } 1336 }
1336 // used to fill in the LocalID when there isn't one 1337 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1337 public const string DetailLogZero = "0000000000"; 1338 public const string DetailLogZero = "0000000000";
1338 1339
1339} 1340}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d3ba273..b1833c5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -36,7 +36,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSShapeCollection : IDisposable 37public class BSShapeCollection : IDisposable
38{ 38{
39 // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 protected BSScene PhysicsScene { get; set; } 41 protected BSScene PhysicsScene { get; set; }
42 42
@@ -89,7 +89,7 @@ public class BSShapeCollection : IDisposable
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to 89 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed. 90 // remove the physical constraints before the body is destroyed.
91 // Called at taint-time!! 91 // Called at taint-time!!
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeData shapeData, PrimitiveBaseShape pbs, 93 ShapeData shapeData, PrimitiveBaseShape pbs,
94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
95 { 95 {
@@ -105,7 +105,7 @@ public class BSShapeCollection : IDisposable
105 // If we had to select a new shape geometry for the object, 105 // If we had to select a new shape geometry for the object,
106 // rebuild the body around it. 106 // rebuild the body around it.
107 // Updates prim.BSBody with information/pointers to requested body 107 // Updates prim.BSBody with information/pointers to requested body
108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
109 prim.BSShape, shapeData, bodyCallback); 109 prim.BSShape, shapeData, bodyCallback);
110 ret = newGeom || newBody; 110 ret = newGeom || newBody;
111 } 111 }
@@ -325,7 +325,7 @@ public class BSShapeCollection : IDisposable
325 // Info in prim.BSShape is updated to the new shape. 325 // Info in prim.BSShape is updated to the new shape.
326 // Returns 'true' if the geometry was rebuilt. 326 // Returns 'true' if the geometry was rebuilt.
327 // Called at taint-time! 327 // Called at taint-time!
328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, 328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) 329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
330 { 330 {
331 bool ret = false; 331 bool ret = false;
@@ -335,7 +335,7 @@ public class BSShapeCollection : IDisposable
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 { 336 {
337 // an avatar capsule is close to a native shape (it is not shared) 337 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); 339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); 340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
341 haveShape = true; 341 haveShape = true;
@@ -362,7 +362,7 @@ public class BSShapeCollection : IDisposable
362 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE 362 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
363 ) 363 )
364 { 364 {
365 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, 365 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
366 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); 366 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
367 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 367 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
368 prim.LocalID, forceRebuild, prim.BSShape); 368 prim.LocalID, forceRebuild, prim.BSShape);
@@ -376,7 +376,7 @@ public class BSShapeCollection : IDisposable
376 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX 376 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
377 ) 377 )
378 { 378 {
379 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, 379 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
380 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); 380 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
381 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 381 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
382 prim.LocalID, forceRebuild, prim.BSShape); 382 prim.LocalID, forceRebuild, prim.BSShape);
@@ -423,27 +423,37 @@ public class BSShapeCollection : IDisposable
423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); 423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
424 424
425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale); 427 shapeData.ID, newShape, shapeData.Scale);
428 428
429 prim.BSShape = newShape; 429 prim.BSShape = newShape;
430 return true; 430 return true;
431 } 431 }
432 432
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, 433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) 434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
435 { 435 {
436 BulletShape newShape; 436 BulletShape newShape;
437 // Need to make sure the passed shape information is for the native type.
438 ShapeData nativeShapeData = shapeData;
439 nativeShapeData.Type = shapeType;
440 nativeShapeData.MeshKey = (ulong)shapeKey;
441 nativeShapeData.HullKey = (ulong)shapeKey;
437 442
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 443 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
439 { 444 {
440 newShape = new BulletShape( 445 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), 446 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, nativeShapeData.Scale), shapeType);
442 shapeType); 447 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale);
443 } 448 }
444 else 449 else
445 { 450 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); 451 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
452 }
453 if (newShape.ptr == IntPtr.Zero)
454 {
455 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
456 LogHeader, nativeShapeData.ID, nativeShapeData.Type);
447 } 457 }
448 newShape.shapeKey = (System.UInt64)shapeKey; 458 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true; 459 newShape.isNativeShape = true;
@@ -698,19 +708,26 @@ public class BSShapeCollection : IDisposable
698 return ComputeShapeKey(shapeData, pbs, out lod); 708 return ComputeShapeKey(shapeData, pbs, out lod);
699 } 709 }
700 710
711 // The creation of a mesh or hull can fail if an underlying asset is not available.
712 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
713 // and 2) the asset cannot be converted (like decompressing JPEG2000s).
714 // The first case causes the asset to be fetched. The second case just requires
715 // us to not loop forever.
716 // Called after creating a physical mesh or hull. If the physical shape was created,
717 // just return.
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) 718 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
702 { 719 {
703 // If the shape was successfully created, nothing more to do 720 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero) 721 if (newShape.ptr != IntPtr.Zero)
705 return newShape; 722 return newShape;
706 723
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 724 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) 725 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
711 { 726 {
712 prim.LastAssetBuildFailed = true; 727 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim; 728 BSPhysObject xprim = prim;
729 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
730 LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed);
714 Util.FireAndForget(delegate 731 Util.FireAndForget(delegate
715 { 732 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 733 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -724,20 +741,28 @@ public class BSShapeCollection : IDisposable
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) 741 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return; 742 return;
726 743
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length]; 744 yprim.BaseShape.SculptData = asset.Data;
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right 745 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object. 746 // one and try again to build the object.
747 // No race condition with the native sphere setting since the rebuild is at taint time.
731 yprim.ForceBodyShapeRebuild(false); 748 yprim.ForceBodyShapeRebuild(false);
732 749
733 }); 750 });
734 } 751 }
735 }); 752 });
736 } 753 }
754 else
755 {
756 if (prim.LastAssetBuildFailed)
757 {
758 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
759 LogHeader, shapeData.ID, pbs.SculptTexture);
760 }
761 }
737 762
738 // While we figure out the real problem, stick a simple native shape on the object. 763 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape = 764 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); 765 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX);
741 766
742 return fillinShape; 767 return fillinShape;
743 } 768 }
@@ -746,7 +771,7 @@ public class BSShapeCollection : IDisposable
746 // Updates prim.BSBody with the information about the new body if one is created. 771 // Updates prim.BSBody with the information about the new body if one is created.
747 // Returns 'true' if an object was actually created. 772 // Returns 'true' if an object was actually created.
748 // Called at taint-time. 773 // Called at taint-time.
749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 774 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
750 ShapeData shapeData, BodyDestructionCallback bodyCallback) 775 ShapeData shapeData, BodyDestructionCallback bodyCallback)
751 { 776 {
752 bool ret = false; 777 bool ret = false;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 4106534..ae267e3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -201,9 +201,7 @@ public class BSTerrainManager
201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
202 // terrain shape is created and added to the body. 202 // terrain shape is created and added to the body.
203 // This call is most often used to update the heightMap and parameters of the terrain. 203 // This call is most often used to update the heightMap and parameters of the terrain.
204 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when 204 // (The above does suggest that some simplification/refactoring is in order.)
205 // calling this routine from initialization or taint-time routines) or whether to delay
206 // all the unmanaged activities to taint-time.
207 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 205 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
208 { 206 {
209 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 207 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",